当前位置: 首页 > news >正文

苍穹外卖day03

店铺状态接口

引入Redis,因为像存储店铺状态这种只有一个字段(没必要存储在数据库),且登录后台就要被访问的数据(加快查询速度,减少数据库压力)

使用步骤:导入相关maven依赖、配置yml、连接工厂和Key序列化器(这里可以创建一个RedisTemplate做这些事并将其交给ioc容器管理,这样就不用每次用到RedisTemplate都去做一些重复的事情)

依赖

<dependency>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-data-redis</artifactId>
       <version>2.7.3</version>
</dependency>

配置yml

spring:
   redis:
     host: ${sky.redis.host}
     port: ${sky.redis.port}
     password: ${sky.redis.password}

创建redis配置类选择连接工程和做序列化

@Configuration
public class RedisConfiguration {
    @Bean
    public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate redisTemplate = new RedisTemplate();
        redisTemplate.setConnectionFactory(redisConnectionFactory); //设置连接工程
        redisTemplate.setKeySerializer(new StringRedisSerializer()); // 设置key序列化方式
        return redisTemplate;
    }
}
​

写接口(读写店铺状态)

@RestController
@RequestMapping("/admin/shop")
@Slf4j
public class ShopController {
    
    @Autowired
    private RedisTemplate redisTemplate;
    public static final String Key = "SHOP_STATUS";
    @PutMapping("/{status}")
    public Result setStatus(@PathVariable Integer status){
        log.info("设置店铺状态:{}",status);
        //将店铺状态存入redis
        redisTemplate.opsForValue().set(Key,status);
        return Result.success();
    }
​
    @GetMapping("/status")
    public Result<Integer> getStatus(){
        log.info("获取店铺状态");
        Integer status = (Integer) redisTemplate.opsForValue().get(Key);
        return Result.success(status);
    }
}
​

用户小程序登录

整个流程

用户请求-> 后端服务器 -> 微信官方的服务器 -> 后端服务器(得到响应,老用户就用微信官方返回的结构和查询本地数据库的数据进行对比,新用户就插入数据到本地) -> 响应给用户登录状态

导入依赖

<dependency>
        <groupId>org.apache.httpcomponents</groupId>
        <artifactId>httpclient</artifactId>
        <version>4.5.13</version>
</dependency>

配置yml

sky:
​
  wechat:
    appid: ${sky.wechat.appid}
    secret: ${sky.wechat.secret}
    # 设置jwt签名加密时使用的秘钥-用户端
  jwt:
    user-secret-key: itheima
    user-ttl: 7200000
    user-token-name: authentication

根据前端传过来的数据设计DTO

Body 参数 application/json code string { "code": "string" }

package com.sky.dto;
​
import lombok.Data;
​
import java.io.Serializable;
​
/**
 * C端用户登录
 */
@Data
public class UserLoginDTO implements Serializable {
​
    private String code;
​
}

设计VO...

Controller层开发

@Autowired
    private UserService userService;
​
    // jwt配置属性
    @Autowired
    private JwtProperties jwtProperties;
​
    @RequestMapping("/login")
    public Result login(@RequestBody UserLoginDTO userLoginDTO) {
        log.info("用户登录:{}", userLoginDTO);
        //登录实现
        User user = userService.login(userLoginDTO);
​
        //生成jwt令牌
        HashMap<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);
    }

UserServiceImpl业务开发

@Autowired
    private UserMapper userMapper;
​
    // 微信小程序的配置属性类
    @Autowired
    private WeChatProperties weChatProperties;
​
    // 向微信后台请求地址
    public static final String WX_LOGIN = "https://api.weixin.qq.com/sns/jscode2session";
    @Override
    public User login(UserLoginDTO userLoginDTO) {
        // 1.调用微信接口服务,获取微信用户信息
        String code = getOpenid(userLoginDTO.getCode());
        // 2.判断openid是否为空,如果为空则登录失败
        if(code == null) {
            throw new LoginFailedException(MessageConstant.LOGIN_FAILED);
        }
        
        // 3.根据openid查询用户是否为新用户
        User user = userMapper.getByOpenid(code);
        //新用户, 自动注册
        if(user == null){
            user = User.builder()
                    .openid(code)
                    .createTime(LocalDateTime.now())
                    .build();
            userMapper.insert(user);
        }
        return user;
    }
    private String getOpenid(String code){
        HashMap<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;
​
    }

注册拦截器

 @Autowired
    private JwtProperties jwtProperties;
​
    /**
     * 校验jwt
     *
     * @param request
     * @param response
     * @param handler
     * @return
     * @throws Exception
     */
    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());
            log.info("当前用户的id:", userId);
            BaseContext.setCurrentId(userId);
            //3、通过,放行
            return true;
        } catch (Exception ex) {
            //4、不通过,响应401状态码
            response.setStatus(401);
            return false;
        }
    }
    @Autowired
    private JwtTokenUserInterceptor jwtTokenUserInterceptor;
protected void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(jwtTokenUserInterceptor)
                .addPathPatterns("/user/**")
                .excludePathPatterns("/user/user/login")
                .excludePathPatterns("/user/shop/status");
    }

购物车开发

购物地址开发

业务为基本增删改查,注意的是在做增删改查的时候首先要考虑好本次数据操作涉及哪几个表,理清整条线的逻辑,再进行业务开发。

订单功能开发

用户下单

该业务就是数据字段相比于前面会大上不少,其它基本和前面一样的增删改查。理清关系就ok。

ServiceImpl

@Override
    @Transactional
    public OrderSubmitVO submitOrder(OrdersSubmitDTO ordersSubmitDTO) {
        // 此业务的数据变更涉及到以下两张表
        // 订单表是主表,部分数据是从地址表中获取的,所以需要先查询地址数据
        // 订单详情表为补充订单信息,部分数据是从购物车中获取的,所以需要查询购物车数据
        // 而返回给前端打印小票等信息的是订单表的部分主要数据
​
        // 下单要完成:
        // 1. 下单
        // 拿到用户地址,判断是否地址为空、超出范围
        AddressBook addressBook = addressBookMapper.getAddressBookById(ordersSubmitDTO.getAddressBookId());
        if(addressBook == null){
            throw new RuntimeException("地址为空");
        }
        // 购物车是否为空
        Long userId = BaseContext.getCurrentId();
        List<ShoppingCart> ShoppingList = shoppingCartMapper.list(userId);
        if(ShoppingList.size() == 0){
            throw new RuntimeException("购物车为空");
        }
​
        //封装好上面查询的地址数据
        Orders order = new Orders();
        BeanUtils.copyProperties(ordersSubmitDTO, order);
        order.setPhone(addressBook.getPhone());
        order.setAddress(addressBook.getDetail());
        order.setConsignee(addressBook.getConsignee());
        order.setNumber(String.valueOf(System.currentTimeMillis()));
        order.setUserId(userId);
        order.setStatus(Orders.PENDING_PAYMENT);
        order.setPayStatus(Orders.UN_PAID);
        order.setOrderTime(LocalDateTime.now());
        // 向订单表中插入数据
        orderMapper.insertOrder(order);
​
        //封装好上面查询的菜品数据
        List<OrderDetail> orderDetailList = new ArrayList<>();
        for(ShoppingCart cart : ShoppingList){
            OrderDetail orderDetail = new OrderDetail();
            BeanUtils.copyProperties(cart, orderDetail);
            orderDetail.setOrderId(order.getId());
            orderDetailList.add(orderDetail);
        }
        // 向订单明细表中插入数据
        oderDetailMapper.insertBatch(orderDetailList);
​
        // 2. 清空购物车
        shoppingCartMapper.deleteAllByUserId(userId);
​
        // 3. 封装返回结果
        OrderSubmitVO orderSubmitVO = new OrderSubmitVO();
        orderSubmitVO.setId(order.getId());
        orderSubmitVO.setOrderNumber(order.getNumber());
        orderSubmitVO.setOrderAmount(order.getAmount());
        orderSubmitVO.setOrderTime(order.getOrderTime());
        return orderSubmitVO;
    }

相关文章:

  • Redis之缓存更新策略
  • 10-常见笔试题-mk
  • 破解 MCP 认证难题方法深入了解考试内容
  • [MySQL] 索引
  • 使用Apache POI实现Java操作Office文件:从Excel、Word到PPT模板写入
  • 码界奇缘 Java 觉醒 后记 第二十二章 Epsilon无为秘境 - 寂静之地的内存试炼
  • 25软考中级*高项网课+历年真题+笔记+电子书+刷题【计算机软考】
  • C++——继承、权限对继承的影响
  • ubuntu学习day1
  • RuoYi-Vue升级为https访问-后端安装SSL证书(单台Linux服务器部署)
  • 图论基础理论
  • 低资源需求的大模型训练项目---调研0.5B大语言模型
  • 2025.04.13【Density 2d】| 基因表达数据可视化
  • Linux编程c/c++程序
  • 前端vue 项目px转为rem的自适应解决方案
  • open harmony多模组子系统分析
  • BM25、BGE以及text2vec-base-chinese的区别
  • [dp8_子数组] 乘积为正数的最长子数组长度 | 等差数列划分 | 最长湍流子数组
  • UE5角色状态机中跳跃落地移动衔接问题
  • markdown导出PDF,PDF生成目录
  • 为小龙虾洗清这些“黑锅”,这份科学吃虾指南请收好
  • 西安集中整治监督教育领域不正之风和腐败问题,举报方式公布
  • 上海国际电影节将于6月3日公布排片表,6月5日中午开票
  • 住建部:推进“好房子、好小区、好社区、好城区”四好建设
  • C919上海虹桥-深圳航线开通,东航今年计划再接收10架C919
  • 广东缉捕1名象牙走私潜逃非洲“红通”逃犯