苍穹外卖-day10

发布于:2025-02-10 ⋅ 阅读:(108) ⋅ 点赞:(0)

苍穹外卖-day10

Spring Task

Spring Task 是Spring框架提供的任务调度工具,可以按照约定的时间自动执行某个代码逻辑。

cron表达式

cron表达式其实就是一个字符串,通过cron表达式可以定义任务触发的时间

**构成规则:**分为6或7个域,由空格分隔开,每个域代表一个含义

每个域的含义分别为:秒、分钟、小时、日、月、周、年(可选)

举例:

2022年10月12日上午9点整 对应的cron表达式为:0 0 9 12 10 ? 2022

请添加图片描述

说明:一般的值不同时设置,其中一个设置,另一个用?表示。

**比如:**描述2月份的最后一天,最后一天具体是几号呢?可能是28号,也有可能是29号,所以就不能写具体数字。

为了描述这些信息,提供一些特殊的字符。这些具体的细节,我们就不用自己去手写,因为这个cron表达式,它其实有在线生成器。

cron表达式在线生成器:https://cron.qqe2.com/
请添加图片描述

可以直接在这个网站上面,只要根据自己的要求去生成corn表达式即可。所以一般就不用自己去编写这个表达式。

使用步骤

1). 导入maven坐标 spring-context(已存在)

2). 启动类添加注解 @EnableScheduling 开启任务调度

3). 自定义定时任务类

订单状态定时处理

  • 下单后未支付,订单一直处于**“待支付”**状态

  • 用户收货后管理端未点击完成按钮,订单一直处于**“派送中”**状态

  • 通过定时任务每分钟检查一次是否存在支付超时订单(下单后超过15分钟仍未支付则判定为支付超时订单),如果存在则修改订单状态为“已取消”

  • 通过定时任务每天凌晨1点检查一次是否存在“派送中”的订单,如果存在则修改订单状态为“已完成”

1. 自定义定时任务类OrderTask

处理支付超时订单

1.在方法上面加上注解@Scheduled来定义cron表达式设置为每分钟执行一次

2.调用localDateTime的方法算出当前时间减去十五分钟

3.调用mapper方法查询超时订单,返回订单列表

4.if判断集合是否为空,遍历订单集合,完善每个订单的状态 取消原因和的时间 然后更新数据库

处理“派送中”状态的订单

1.在方法上面加上注解@Scheduled来定义cron表达式设置为每天凌晨一点执行一次

2…调用localDateTime的方法算出当前时间减去一个小时来设置超时一个小时阈值

3.查询带派送且超时一小时的订单集合

4.遍历并完善订单,改状态为已完成,并更新数据库

	/**
     * 处理支付超时订单
     */
    @Scheduled(cron = "0 * * * * ?")
    public void processTimeoutOrder(){
        log.info("处理支付超时订单:{}", new Date());

        LocalDateTime time = LocalDateTime.now().plusMinutes(-15);

        // select * from orders where status = 1 and order_time < 当前时间-15分钟
        List<Orders> ordersList = orderMapper.getByStatusAndOrdertimeLT(Orders.PENDING_PAYMENT, time);
        if(ordersList != null && ordersList.size() > 0){
            ordersList.forEach(order -> {
                order.setStatus(Orders.CANCELLED);
                order.setCancelReason("支付超时,自动取消");
                order.setCancelTime(LocalDateTime.now());
                orderMapper.update(order);
            });
        }
    }
/**
     * 处理“派送中”状态的订单
     */
    @Scheduled(cron = "0 0 1 * * ?")
    public void processDeliveryOrder(){
        log.info("处理派送中订单:{}", new Date());
        // select * from orders where status = 4 and order_time < 当前时间-1小时
        LocalDateTime time = LocalDateTime.now().plusMinutes(-60);
        List<Orders> ordersList = orderMapper.getByStatusAndOrdertimeLT(Orders.DELIVERY_IN_PROGRESS, time);

        if(ordersList != null && ordersList.size() > 0){
            ordersList.forEach(order -> {
                order.setStatus(Orders.COMPLETED);
                orderMapper.update(order);
            });
        }
    }

WebSocket

WebSocket 是基于 TCP 的一种新的网络协议。它实现了浏览器与服务器全双工通信——浏览器和服务器只需要完成一次握手,两者之间就可以创建持久性的连接, 并进行双向数据传输。

HTTP协议和WebSocket协议对比:

  • HTTP是短连接
  • WebSocket是长连接
  • HTTP通信是单向的,基于请求响应模式
  • WebSocket支持双向通信
  • HTTP和WebSocket底层都是TCP连接

请添加图片描述
请添加图片描述

**思考:**既然WebSocket支持双向通信,功能看似比HTTP强大,那么我们是不是可以基于WebSocket开发所有的业务功能?

WebSocket缺点:

服务器长期维护长连接需要一定的成本
各个浏览器支持程度不一
WebSocket 是长连接,受网络限制比较大,需要处理好重连

**结论:**WebSocket并不能完全取代HTTP,它只适合在特定的场景下使用

WebSocket应用场景:

1). 视频弹

2). 网页聊天

3). 体育实况更新

4). 股票基金报价实时更新

实现步骤:

导入WebSocket的maven坐标

导入WebSocket服务端组件WebSocketServer,用于和客户端通信

导入配置类WebSocketConfiguration,注册WebSocket的服务端组件

来单提醒

用户下单并且支付成功后,需要第一时间通知外卖商家。通知的形式有如下两种:

  • 语音播报
  • 弹出提示框

设计思路:

  • 通过WebSocket实现管理端页面和服务端保持长连接状态
  • 当客户支付后,调用WebSocket的相关API实现服务端向客户端推送消息
  • 客户端浏览器解析服务端推送的消息,判断是来单提醒还是客户催单,进行相应的消息提示和语音播报
  • 约定服务端发送给客户端浏览器的数据格式为JSON,字段包括:type,orderId,content
    • type 为消息类型,1为来单提醒 2为客户催单
    • orderId 为订单id
    • content 为消息内容

在OrderServiceImpl中注入WebSocketServer对象,修改paySuccess方法

由于我们是跳过支付功能的,所以没有调用paysucess方法,因此我们就在payment方法执行完更新数据库后面执行逻辑

1.new一个map集合,往集合里面put需要发送给前端的格式数据

2.调用webSocketServer的sendToAllClient方法,把map集合转换为json数据推送出去.

  @Override
    public OrderPaymentVO payment(OrdersPaymentDTO ordersPaymentDTO) throws Exception {
        // 当前登录用户id
        Long userId = BaseContext.getCurrentId();
        User user = userMapper.getById(userId);

//        //调用微信支付接口,生成预支付交易单
//        JSONObject jsonObject = weChatPayUtil.pay(
//                ordersPaymentDTO.getOrderNumber(), //商户订单号
//                new BigDecimal(0.01), //支付金额,单位 元
//                "苍穹外卖订单", //商品描述
//                user.getOpenid() //微信用户的openid
//        );
//
//        if (jsonObject.getString("code") != null && jsonObject.getString("code").equals("ORDERPAID")) {
//            throw new OrderBusinessException("该订单已支付");
//        }
         JSONObject jsonObject=new JSONObject();
         jsonObject.put("code","ORDERPAID");

        OrderPaymentVO vo = jsonObject.toJavaObject(OrderPaymentVO.class);
        vo.setPackageStr(jsonObject.getString("package"));
        Integer OrderStatus = Orders.TO_BE_CONFIRMED;
        Integer OrderPaidStatus = Orders.PAID;
        LocalDateTime check_out_time = LocalDateTime.now();
        orderMapper.updateStatus(OrderStatus,OrderPaidStatus,check_out_time,this.orders.getId());

        Map map = new HashMap();
        map.put("type",1);//消息类型,1表示菜单提醒
        map.put("orderId", orders.getId());
        map.put("content", "订单号:" + this.orders.getNumber());
        webSocketServer.sendToAllClient(JSONObject.toJSONString(map));

        return vo;
    }

客户催单

用户在小程序中点击催单按钮后,需要第一时间通知外卖商家。通知的形式有如下两种:

语音播报

弹出提示框

设计思路:

  • 通过WebSocket实现管理端页面和服务端保持长连接状态
  • 当用户点击催单按钮后,调用WebSocket的相关API实现服务端向客户端推送消息
  • 客户端浏览器解析服务端推送的消息,判断是来单提醒还是客户催单,进行相应的消息提示和语音播报
    约定服务端发送给客户端浏览器的数据格式为JSON,字段包括:type,orderId,content
    • type 为消息类型,1为来单提醒 2为客户催单
    • orderId 为订单id
    • content 为消息内容

当用户点击催单按钮时,向服务端发送请求。

Controller层

1.根据接口文档定义方法,参数为路径参数id

2.调用service层的方法

3.return回去result

	/**
     * 用户催单
     *
     * @param id
     * @return
     */
    @GetMapping("/reminder/{id}")
    @ApiOperation("用户催单")
    public Result reminder(@PathVariable("id") Long id) {
        orderService.reminder(id);
        return Result.success();
    }
Service层实现类

和之前来单提醒的逻辑一样

1.new一个map集合,往集合里面put需要发送给前端的格式数据

2.调用webSocketServer的sendToAllClient方法,把map集合转换为json数据推送出去.

	/**
     * 用户催单
     *
     * @param id
     */
    public void reminder(Long id) {
        // 查询订单是否存在
        Orders orders = orderMapper.getById(id);
        if (orders == null) {
            throw new OrderBusinessException(MessageConstant.ORDER_NOT_FOUND);
        }

        //基于WebSocket实现催单
        Map map = new HashMap();
        map.put("type", 2);//2代表用户催单
        map.put("orderId", id);
        map.put("content", "订单号:" + orders.getNumber());
        webSocketServer.sendToAllClient(JSON.toJSONString(map));
    }

网站公告

今日签到

点亮在社区的每一天
去签到