itheima苍穹外卖项目学习笔记--Day10: 订单状态定时处理/来单提醒和客户催单

Day10: 订单状态定时处理/来单提醒和客户催单

订单状态定时处理/来单提醒和客户催单

  • [Day10: 订单状态定时处理/来单提醒和客户催单](#Day10: 订单状态定时处理/来单提醒和客户催单)
    • [a. 订单状态定时处理](#a. 订单状态定时处理)
    • [b. 来单提醒](#b. 来单提醒)
    • [c. 催单提醒](#c. 催单提醒)

a. 订单状态定时处理

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

  • 定位:定时任务框架
  • 作用:定时自动执行某段Java代码

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

  • 分为6或7个域,由空格分隔开,
  • 每个域代表一个含义每个域的含义分别为:秒、分钟、小时、日、月、周、年(可选)

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

cron表达式在线生成器:https://cron.qqe2.com/

Spring Task使用步骤:

  • 1.导入maven坐标spring-context

  • 2.启动类上添加@EnableScheduling开启任务调度

  • 3.自定义定时任务类

用户下单后可能存在的情况:

  • 下单后未支付,订单一直处于"待支付"状态
  • 用户收货后管理端未点击完成按钮,订单一直处于"派送中"状态

对于上面两种情况需要通过定时任务来修改订单状态,具体逻辑为:

  • 通过定时任务每分钟检查一次是否存在支付超时订单(下单后超过15分钟仍未支付则判定为支付超时订单),如果存在则修改订单状态为"已取消"
  • 通过定时任务每天凌晨1点检查一次是否存在"派送中"的订单,如果存在则修改订

创建task/OrderTask类,为定时任务类,定时出来订单状态

java 复制代码
@Component
@Slf4j
public class OrderTask {

    @Autowired
    private OrderMapper orderMapper;

    /**
     * 处理超时订单
     */
    @Scheduled(cron = "0 * * * * ? *") // 每分钟触发一次
    public void processTimeoutOrder(){
        log.info("定时处理超时订单:{}", LocalDateTime.now());

        // select * from orders where status = ? and order_time < (当前时间 - 15分钟)
        LocalDateTime time = LocalDateTime.now().plusMinutes(-15);
        List<Orders> ordersList = orderMapper.getByStatusAndOrderTimeLT(Orders.PENDING_PAYMENT, time);

        if (ordersList != null && ordersList.size() > 0){
            for (Orders orders : ordersList) {
                orders.setStatus(Orders.CANCELLED);
                orders.setCancelReason("订单超时,自动取消");
                orders.setCancelTime(LocalDateTime.now());
                orderMapper.update(orders);
            }
        }
    }

    /**
     * 处理一直处于派送中状态的订单
     */
    @Scheduled(cron = "0 0 1 * * ?") // 每天凌晨1点触发一次
    public void processDeliveryOrder(){
        log.info("定时处理处于派送中的订单:{}", LocalDateTime.now());

        // select * from orders where status = ? 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){
            for (Orders orders : ordersList) {
                orders.setStatus(Orders.COMPLETED);
                orderMapper.update(orders);
            }
        }
    }
}

在OrderMapper中,编写 根据订单状态和下单时间查询订单 方法

java 复制代码
/**
 * 根据订单状态和下单时间查询订单
 * @param status
 * @param time
 * @return
 */
@Select("select * from orders where status = #{status} and order_time < #{time} ")
List<Orders> getByStatusAndOrderTimeLT(Integer status, LocalDateTime time);

b. 来单提醒

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

HTTP协议和WebSocket协议对比:

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

设计:

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

创建websocket/WebSocketServer,实现WebSocket服务

java 复制代码
@Component
@ServerEndpoint("/ws/{sid}")
public class WebSocketServer {

    //存放会话对象
    private static Map<String, Session> sessionMap = new HashMap();

    /**
     * 连接建立成功调用的方法
     */
    @OnOpen
    public void onOpen(Session session, @PathParam("sid") String sid) {
        System.out.println("客户端:" + sid + "建立连接");
        sessionMap.put(sid, session);
    }

    /**
     * 收到客户端消息后调用的方法
     *
     * @param message 客户端发送过来的消息
     */
    @OnMessage
    public void onMessage(String message, @PathParam("sid") String sid) {
        System.out.println("收到来自客户端:" + sid + "的信息:" + message);
    }

    /**
     * 连接关闭调用的方法
     *
     * @param sid
     */
    @OnClose
    public void onClose(@PathParam("sid") String sid) {
        System.out.println("连接断开:" + sid);
        sessionMap.remove(sid);
    }

    /**
     * 群发
     *
     * @param message
     */
    public void sendToAllClient(String message) {
        Collection<Session> sessions = sessionMap.values();
        for (Session session : sessions) {
            try {
                //服务器向客户端发送消息
                session.getBasicRemote().sendText(message);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

创建WebSocketTask中,通过WebSocket向客户端发送消息

java 复制代码
@Component
public class WebSocketTask {
    @Autowired
    private WebSocketServer webSocketServer;

    /**
     * 通过WebSocket向客户端发送消息
     */
//    @Scheduled(cron = "0/5 * * * * ?")
    @Scheduled(fixedRate = Long.MAX_VALUE)
    public void sendMessageToClient() {
        webSocketServer.sendToAllClient("这是来自服务端的消息:" + DateTimeFormatter.ofPattern("HH:mm:ss").format(LocalDateTime.now()));
    }
}

在OrderServiceImpl的适当位置中写入代码,通过Websocket向客户端浏览器推送消息

java 复制代码
// 通过Websocket向客户端浏览器推送消息
Map map = new HashMap();
map.put("type", 1); // 1表示来单提醒, 2表示客户吹催单
map.put("orderId", orders.getId());
map.put("content", "订单号:" + orders.getNumber());

String json = JSON.toJSONString(map);
webSocketServer.sendToAllClient(json);

c. 催单提醒

在OrderController中,创建客户催单的接口方法

java 复制代码
/**
 * 客户催单
 * @param id
 * @return
 */
@GetMapping("/reminder/{id}")
@ApiOperation("客户催单")
public Result reminder(@PathVariable("id") Long id){
    orderService.reminder(id);
    return Result.success();
}

在OrderServiceImpl中,实现客户催单的方法,及其父类接口

java 复制代码
/**
 * 客户催单
 * @param id
 */
@Override
public void reminder(Long id) {
    // 根据id查询订单
    Orders ordersDB = orderMapper.getById(id);

    // 校验订单是否存在,并且状态为4
    if (ordersDB == null) {
        throw new OrderBusinessException(MessageConstant.ORDER_NOT_FOUND);
    }

    // 通过Websocket向客户端浏览器推送消息
    Map map = new HashMap();
    map.put("type", 2); // 1表示来单提醒, 2表示客户吹催单
    map.put("orderId", id);
    map.put("content", "订单号:" + ordersDB.getNumber());

    String json = JSON.toJSONString(map);
    webSocketServer.sendToAllClient(json);
}
相关推荐
安之若素^7 分钟前
启用不安全的HTTP方法
java·开发语言
魔芋红茶13 分钟前
spring-initializer
python·学习·spring
ruanjiananquan9914 分钟前
c,c++语言的栈内存、堆内存及任意读写内存
java·c语言·c++
西岭千秋雪_37 分钟前
Redis性能优化
数据库·redis·笔记·学习·缓存·性能优化
随便取个六字38 分钟前
GIT操作 学习
git·学习
chuanauc41 分钟前
Kubernets K8s 学习
java·学习·kubernetes
小张是铁粉1 小时前
docker学习二天之镜像操作与容器操作
学习·docker·容器
一头生产的驴1 小时前
java整合itext pdf实现自定义PDF文件格式导出
java·spring boot·pdf·itextpdf
YuTaoShao1 小时前
【LeetCode 热题 100】73. 矩阵置零——(解法二)空间复杂度 O(1)
java·算法·leetcode·矩阵
zzywxc7871 小时前
AI 正在深度重构软件开发的底层逻辑和全生命周期,从技术演进、流程重构和未来趋势三个维度进行系统性分析
java·大数据·开发语言·人工智能·spring