1.首先根据课件创建注册好自己的小程序。

1.1index.wxml(pages/index完整代码)
<view class="container">
  <view>
    {{msg}}
  </view>
  <view>
    <button bindtap="getUserInfo" type="warn">获取用户信息</button>
    昵称: {{nickName}}
    <image style="width: 100px;height: 100px;" src="{{url}}"></image>
  </view>
  <view>
    <button bindtap="wxLogin" type="warn">微信登录</button>
    授权码:{{code}}
  </view>
  <view>
    <button bindtap="sendRequest" type="default">发送请求</button>
  </view>
</view>
1.2index.js(pages/index完整代码)
Page({
  data:{
    msg:'hello world',
    nickName: '',
    url:'',
    code:''
  },
  //获取微信用户的头像和昵称
  getUserInfo(){
    wx.getUserProfile({
      desc: '获取用户信息',
      success: (res)=>{
        console.log(res.userInfo);
        //为数据赋值
        this.setData({
          nickName: res.userInfo.nickName,
          url: res.userInfo.avatarUrl
        })
      }
    })
  },
  //微信登录,获取微信用户的授权码
  wxLogin(){
    wx.login({
      success : (res)=>{
        console.log(res.code)
        this.setData({
          code:res.code
        })
      }
    })
  },
  //发送请求
  sendRequest(){
    wx.request({
      url: 'http://localhost:8080/user/shop/status',
      method:'GET',
      success:(res)=>{
        console.log(res.data) //data代表整个响应回来的数据
      }
    })
  }
})
1.3(微信小程序)导入

点击右上角的微信开发者工具:

点击上传按钮:

然后可以在版本管理界面看到,开发版本多了一项:

小程序代码是在day06文件夹中,需要事先解压一下:

然后在小程序开发助手点击导入:

​​

这里要确保AppID是自己的:

下面是微信登录的官方文档:

开放能力 / 用户信息 / 小程序登录 (qq.com)

点击上面的链接可以进入到如下界面:

下面是请求的参数:

使用PostMan进行测试,成功:

也可以直接在浏览器地址栏中构建:

微信登录流程:

小程序要调用wx.login获取code授权码,然后要调研wx.request()发送code授权码;

开发者服务器要向微信接口服务提交appid+appsecret+code,然后就可以获得session_key(会话密钥)和openid;

然后开发者服务器可以自定义登录状态,产生一个token令牌,然后返回自定义登录状态;

小程序可以把token令牌进行存储。然后wx.request可以法器业务请求,开发者服务器可以解析token,最终返回数据。

1.4编写配置代码

application-dev.yml

sky:
  wechat:
    appid: wx3910b10fd7db38d1
    secret: f274884c2a56466016ebbcf009404e63

application.yml

sky:
  wechat:
    appid: ${sky.wechat.appit}
    secret: ${sky.wechat.secret}

sky: jwt

user-secret-key: itheima
user-ttl: 7200000
user-token-name: authentication
1.5UserController类(/controller/user)
@RestController
@RequestMapping("/user/user")
@Api(tags="C端用户相关接口")
@Slf4j
public class UserController {
    @Autowired
    private UserService userService;
    @Autowired
    private JwtProperties jwtProperties;
    //微信登录
    @PostMapping("/login")
    @ApiOperation("微信登录")
    public Result<UserLoginVO> login(@RequestBody UserLoginDTO userLoginDTO){
        log.info("微信用户登录;{}",userLoginDTO.getCode());
        //微信登录
        User user = userService.wxLogin(userLoginDTO);
        //为微信用户生成jwt令牌
        Map<String,Object> claims =  new HashMap<>();
        claims.put(JwtClaimsConstant.USER_ID,user.getId());
        String token = JwtUtil.createJWT(jwtProperties.getUserSecretKey(),jwtProperties.getUserTtl(),claims);
        UserLoginVO userLoginVO = UserLoginVO.builder()
                .id(user.getId())
                .openid(user.getOpenid())
                .token(token)
                .build();
        return Result.success(userLoginVO);
    }
}
1.6UserService类
package com.sky.service;

import com.sky.dto.UserLoginDTO;
import com.sky.entity.User;

public interface UserService {
    //微信登录
    User wxLogin(UserLoginDTO userLoginDTO);
}
1.7UserServiceImpl类
package com.sky.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.sky.constant.MessageConstant;
import com.sky.dto.UserLoginDTO;
import com.sky.entity.User;
import com.sky.exception.LoginFailedException;
import com.sky.properties.WeChatProperties;
import com.sky.service.UserService;
import com.sky.utils.HttpClientUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;

public class UserServiceImpl implements UserService {
    @Service
    @Slf4j
    public class UserServiceImpl implements UserService {
        //微信服务接口地址
        public static final String WX_LOGIN="http://api.weixin.qq.com/sns/jscode2session";
        @Autowired
        private WeChatProperties weChatProperties; //配置文件中传入的值会被放入配置类,所以只需要自动注入然后获取即可
        @Autowired
        private UserMapper userMapper;
        //微信登录
        public User wxLogin(UserLoginDTO userLoginDTO){
            String openid = getOpenid(userLoginDTO.getCode());
            //判断openid是否为空,如果为空登录失败,抛出业务异常
            if(openid==null){
                throw new LoginFailedException(MessageConstant.LOGIN_FAILED);
            }
            //判断当前用户是否为新用户(拿openid到用户表里查)
            User user = userMapper.getByOpenid(openid);
            //如果是新用户,自动完成注册
            if(user == null){
                user = User.builder()
                        .openid(openid)
                        .createTime(LocalDateTime.now())
                        .build();
                userMapper.insert(user);
            }
            //返回这个用户对象
            return user;
        }
        private String getOpenid(String code){
            //调用微信接口服务,来获得当前微信用户的openid
            Map<String,String> map = new HashMap<>();
            map.put("appid",weChatProperties.getAppid());
            map.put("secret",weChatProperties.getSecret());
            map.put("js_code",code);
            map.put("grant_type","authorization_code");
            String json = HttpClientUtil.doGet(WX_LOGIN,map);
            JSONObject jsonObject = JSON.parseObject(json);
            String openid = jsonObject.getString("openid");
            return openid;
        }
    }
}
1.8UserMapper类(自己创建)
package com.sky.mapper;

import com.sky.entity.User;

public interface UserMapper {

    /**
     * 插入
     * @param user
     */
    void insert(User user);

    /**
     * 根据openid查询用户
     * @param openid
     * @return
     */
    User getByOpenid(String openid);
}
1.9UserMapper.xml类
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.sky.mapper.UserMapper">
    <!--插入-->
    <!--
        useGeneratedKeys设置为true:在执行插入记录之后可以获取到数据库自动生成的主键值
        keyProperty:指定Java对象的属性名
     -->
    <insert id="insert" useGeneratedKeys="true" keyProperty="id">
        insert into user(openid,name,phone,sex,id_number,avatar,create_time)
        values (#{openid},#{name},#{phone},#{sex},#{idNumber},#{avatar},#{createTime})
    </insert>
</mapper>
1.10JwtTokenUserIntercepetor类(interceptor下创建)
@Component
@Slf4j
public class JwtTokenUserInterceptor implements HandlerInterceptor {
    @Autowired
    private JwtProperties jwtProperties;
    //校验jwt
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //判断当前拦截到的是Controller的方法还是其他资源
        if (!(handler instanceof HandlerMethod)) {
            //当前拦截到的不是动态方法,直接放行
            return true;
        }
        //1、从请求头中获取令牌
        String token = request.getHeader(jwtProperties.getUserTokenName());
        //2、校验令牌
        try {
            log.info("jwt校验:{}", token);
            Claims claims = JwtUtil.parseJWT(jwtProperties.getUserSecretKey(), token);
            Long userId = Long.valueOf(claims.get(JwtClaimsConstant.USER_ID).toString());
            BaseContext.setCurrentId(userId);
            log.info("当前员工id:", userId);
            //3、通过,放行
            return true;
        } catch (Exception ex) {
            //4、不通过,响应401状态码
            response.setStatus(401);
            return false;
        }
    }
}

然后要让这个拦截器生效:

在sky-server下的config包中的WebMvcConfiguration中写入如下代码:

@Autowired
private JwtTokenUserInterceptor jwtTokenUserInterceptor;

在addInterceptors中写入如下代码(注意下面addInterceptor里面是jwtTokenUserInterceptor):

registry.addInterceptor(jwtTokenUserInterceptor)
    .addPathPatterns("/user/**")
    .excludePathPatterns("/user/user/login")
    .excludePathPatterns("/user/shop/status");
1.11然后在资料包中day06/代码导入/商品浏览中有9个文件:

3个controller,2个service,2个serviceImpl,1个mapper,1个mapper.xml。

注意下面2点:

1.上面的controller文件都要放在controller的user这个包下面。

2.有些已有的service或者mapper仅仅只需要拷贝方法,有些缺少的需要新建。

2.缓存菜品

2.1DishController类(/user)
 // 构造Redis中的Key,规则为: dish_分类id
        // 通过这个Key去Redis中查找缓存的数据
        String key = "dish_" + categoryId;

        // 首先查询Redis中是否存在缓存的菜品数据
        List<DishVO> list = (List<DishVO>) redisTemplate.opsForValue().get(key);

        // 如果Redis中有缓存数据,直接返回
        if(list != null && list.size() > 0){
            // 返回结果封装成功,直接从缓存中返回菜品列表
            return Result.success(list);
        }

        // 如果Redis中没有缓存数据,则需要从数据库查询
        Dish dish = new Dish();
        dish.setCategoryId(categoryId);  // 设置菜品的分类ID
        dish.setStatus(StatusConstant.ENABLE);  // 设置菜品的状态为“启用”状态,即查询起售中的菜品

        // 查询数据库获取菜品列表,并包括菜品的口味信息
        List<DishVO> dishList = dishService.listWithFlavor(dish);

        // 将查询到的数据存入Redis缓存,以便下次查询时可以直接从缓存中获取
        redisTemplate.opsForValue().set(key, dishList);

        // 返回查询到的菜品列表
        return Result.success(dishList);
2.2DishController类(/admin)

添加

//清理缓存数据
private void cleanCache(String pattern){
    Set keys = redisTemplate.keys(pattern);
    redisTemplate.delete(keys);
}
/**
     * 新增菜品
     * @param dishDTO
     * @return
     */
    @PostMapping
    @ApiOperation("新增菜品")
    public Result<String> save(@RequestBody DishDTO dishDTO) {
    log.info("新增菜品:{}",dishDTO);
    dishService.saveWithFlavor(dishDTO);
    
    //添加这三行代码
    Long categoryId=dishDTO.getCategoryId();
    String key="dish_"+categoryId;
    cleanCache(key);

    return Result.success();
}
   /**
     * 菜品批量删除
     * @param ids
     * @return
     */@DeleteMapping
@ApiOperation("菜品批量删除")
public Result delete(@RequestParam List<Long> ids){
    log.info("菜品批量删除:{}",ids);
    dishService.deleteBatch(ids);
    //添加这一行
    cleanCache("dish_*");
    return Result.success();
}
    /**
     * 修改菜品
     * @param dishDTO
     * @return
     */
    @PutMapping
@ApiOperation("修改菜品")
public Result update(@RequestBody DishDTO dishDTO) {
log.info("修改菜品:{}",dishDTO);
dishService.updateWithFlavor(dishDTO);
//添加这行
cleanCache("dish_*");
return Result.success();
}
2.3Spring Cache

Spring Cache 是一个框架,实现了基于注解的缓存功能,只需要简单地加一个注解,就能实现缓存功能。

Spring Cache 提供了一层抽象,底层可以切换不同的缓存实现,例如: EHCache Caffeine Redis。

常用注解:

注解

说明

@EnableCaching

开启缓存注解功能,通常加在启动类上

@Cacheable

在方法执行前先查询缓存中是否有数据,如果有数据,则直接返回缓存数据;

如果没有缓存数据,调用方法并将方法返回值放到缓存中

@CachePut

将方法的返回值放到缓存中

@CacheEvict

将一条或多条数据从缓存中删除

3.缓存套餐

3.1导入各个类

在sky-server包下导入


        <!-- 导入Spring Data Redis-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

        <!-- 导入 Spring Cache-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-cache</artifactId>
        </dependency>

然后要在sky-server包下的启动类SkyApplication类上加如下注解:

@EnableCaching

首先是在controller/user包下的SetmealController类中的list方法上加如下注解:

@Cacheable(cacheNames="setmealCache",key="#categoryId")

然后是在controller/admin包下的SetmealController类中的save方法上加如下注解:

@CacheEvict(cacheNames="setmealCache",key="#setmealDTO.categoryId")

最后是在controller/admin包下的SetmealController类中的update、delete、startOrStop方法上加如下注解:

@CacheEvict(cacheNames = "setmealCache",allEntries = true)

4.添加购物车

4.1ShoppingCartController类(controller/user下创建)
@RestController
@RequestMapping("/user/shoppingCart")
@Slf4j
@Api(tags="C端购物车相关接口")
public class ShoppingCartController {
    @Autowired
    private ShoppingCartService shoppingCartService;
    @PostMapping("/add")
    @ApiOperation("添加购物车")
    public Result add(@RequestBody ShoppingCartDTO shoppingCartDTO){
        log.info("添加购物车,商品信息为:{}",shoppingCartDTO);
        shoppingCartService.addShoppingCart(shoppingCartDTO);
        return Result.success();
    }
}
4.2ShoppingCartService类(Service下创建)
package com.sky.service;

import com.sky.dto.ShoppingCartDTO;
import com.sky.entity.ShoppingCart;

public interface ShoppingCartService {

    /**
     * 添加购物车
     * @param shoppingCartDTO
     */
    void addShoppingCart(ShoppingCartDTO shoppingCartDTO);
         //判断当前加入购物车中的商品是否已经存在了
        //如果已经存在,只需要数量+1
        //如果不存在,则需要插入一条购物车数据
}
4.3ShoppingCartMapper类
package com.sky.mapper;

import com.sky.entity.ShoppingCart;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Update;

import java.util.List;

@Mapper
public interface ShoppingCartMapper {
    /**
     * 条件查询
     * @param shoppingCart
     * @return
     */
    List<ShoppingCart> list(ShoppingCart shoppingCart);

    /**
     * 更新商品数量
     * @param shoppingCart
     */
    @Update("update shopping_cart set number=#{number} where id=#{id}")
    void updateNumberById(ShoppingCart shoppingCart);

    /**
     * 插入数据到购物车
     * @param shoppingCart
     */
    @Insert("insert into shopping_cart(name, image, user_id, dish_id, setmeal_id, dish_flavor, number, amount, create_time) " +
            "VALUES(#{name},#{image},#{userId},#{dishId},#{setmealId},#{dishFlavor},#{number},#{amount},#{createTime}) ")
    void insert(ShoppingCart shoppingCart);
}
4.4ShoppingCartMapper.xml类
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.sky.mapper.ShoppingCartMapper">
<select id="list" parameterType="ShoppingCart" resultType="ShoppingCart">
 select * from shopping_cart
<where>
<if test="userId != null">
and user_id = #{userId}
</if>
<if test="dishId != null">
and dish_id = #{dishId}
</if>
<if test="setmealId != null">
and setmeal_id = #{setmealId}
</if>
<if test="dishFlavor != null">
and dish_flavor = #{dishFlavor}
</if>
</where>
order by create_time desc                                                                                       </select>
</mapper>

5.查看购物车&清空购物车

5.1ShoppingCartController类
   /**
     * 查看购物车
     * @return
     */

    @ApiOperation("查看购物车")
    @GetMapping("/list")
    public Result<List<ShoppingCart>> list() {
        List<ShoppingCart> list = shoppingCartService.showShoppingCart();
        return Result.success(list);
    }

/**
     ** 清空购物车
     ** @return
     **/
    @DeleteMapping("/clean")
    @ApiOperation("清空购物车")
    public Result<String> clean(){
        shoppingCartService.cleanShoppingCart();
        return Result.success();
    }
5.2ShoppingCartService类
 /**
     * 清空购物车
     */
    void cleanShoppingCart();
/**
     * 查看购物车
     * @return
     */
    List<ShoppingCartDTO> showShoppingCart();
5.3ShoppingCartServiceImpl类
    /**
     ** 
     * 清空购物车
     * */
    public void cleanShoppingCart() {
        shoppingCartMapper.deleteByUserId(BaseContext.getCurrentId());
    }
/**
     * 查看购物车
     */
    @Override
    public List<ShoppingCart> showShoppingCart() {
        Long userId = BaseContext.getCurrentId();
        ShoppingCart shoppingCart = ShoppingCart.builder()
                .userId(userId)
                .build();
        List<ShoppingCart> list = shoppingCartMapper.list(shoppingCart);//只需要传userid即可
        return list;
    }



 
Logo

中国智能体开发者社区,聚焦智能体与大模型开发,提供前沿资讯、实用工具链、开源项目及行业案例。通过技术沙龙、开发者大赛等活动,促进经验交流与协作,助力开发者快速构建创新智能应用。

更多推荐