黑马苍穹外卖8 Spring Task+WebSocket 来单提醒和客户催单

Spring Task

Spring提供的任务调度工具,按照约定时间自动执行代码。【以前的都是基于请求(http)响应的】

cron表达式

通过cron表达式可以定义任务触发时间。

cron表达式生成器

(1)导入spring-context

(2)@EnableScheduling开启任务调度,在启动类上加。

(3)自定义定时任务类

订单状态定时处理

超时订单处理

  1. 下单后未支付,订单一直处于"待支付"状态
    每分钟检查一次,判断时候否存在支付超时订单(下单超过15分钟认为支付则判定为支付超时订单),
    存在则修改订单状态为"已取消"
  2. 用户收货,订单一直处于"派送中"
    每天凌晨一点检查是否存在"派送中"的订单,存在则修改订单状态为"已完成"

task.OrderTask.java

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

    @Autowired
    private OrderMapper orderMapper;

    /**
     * 处理超时订单
     */
    @Scheduled(cron = "0 * * * * ?")//每分钟触发一次  秒 分 时 日 月 周 年(可选)
    public void processTimeOutOrders() {
        LocalDateTime time = LocalDateTime.now().plusMinutes(-15);//当前时间-15
        // 根据这个去查 (处于待付状态的,下单时间<当前时间-15)
        List<Orders> orders = orderMapper.getByStatusAndOrderTimeLT(Orders.PENDING_PAYMENT, time);
        if (orders != null && orders.size() != 0) {
            List<Long> ids = new ArrayList<>();
            orders.forEach((order) ->
                ids.add(order.getId())
            );
            orderMapper.updateTimeOutByIds(Orders.CANCELLED, "订单超时,自动取消", LocalDateTime.now(), ids);//修改订单状态
        }
    }

    /**
     * 检查一直处于派送中的订单
     */
    @Scheduled(cron = "0 0 1 * * ?")//每天凌晨一点触发一次
    public void processDeliveringOrders() {
        LocalDateTime time = LocalDateTime.now().plusMinutes(-60);
        List<Orders> orders = orderMapper.getByStatusAndOrderTimeLT(Orders.DELIVERY_IN_PROGRESS, time);
        if (orders != null && orders.size() != 0) {
            List<Long> ids = new ArrayList<>();
            orders.forEach((order) ->
                ids.add(order.getId())
            );
            orderMapper.updateDeliveringByIds(Orders.COMPLETED, ids);
        }
    }

}
java 复制代码
@Select("select * from orders where status=#{status} and order_time<#{orderTime}")
    List<Orders> getByStatusAndOrderTimeLT(Integer status, LocalDateTime orderTime);

WebSocket

基于TCP的一种新的网络协议。实现了浏览器与服务器全双工通信 ------浏览器和服务器只需完成一次握手,两者就可以建立连接,双向数据传输

HTTP:浏览器(客户端)---服务器:浏览器请求服务器才响应。

WebSocket:两边都可以主动通信。

应用场景:网页聊天、视频弹幕,股票信息实时更新(服务器主动推送到网页上的)

java 复制代码
/**
 * WebSocket服务
 */
@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//类似@controller
    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();
            }
        }
    }

}

定时任务类:

task.WebSocketTask.java

java 复制代码
@Component
public class WebSocketTask {//定时任务类
    @Autowired
    private WebSocketServer webSocketServer;

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

来单提醒

用户下单且支付成功即使通知商家。

请求:ws://localhost/ws/0yf1emeoqu8a

先请求到ngnix,然后nginx把请求转发到后端的Tomcat服务器

基于nginx的反向代理然后把请求转发过来的

在OrderServiceImpl.java 里public void paySuccess(String outTradeNo) 类中添加

java 复制代码
 //通过websocket想客户端推送消息 type prderId content
        //来单提醒
        HashMap<String, Object> map = new HashMap<>();
        map.put("type", 1);//1 来单提醒  2 客户接单
        map.put("orderId", ordersDB.getId());
        map.put("content", "订单号:" + outTradeNo);

        //发送给客户端
        webSocketServer.sendToAllClient(JSONObject.toJSONString(map));

客户催单

客户触发,客户发起的接口请求:

Controller:

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

service

java 复制代码
 @Override
    public void reminder(Long id) {
        Orders order = orderMapper.getById(id);
        if (order == null) {
            throw new  OrderBusinessException(MessageConstant.ORDER_NOT_FOUND);
        }

        HashMap<String, Object> map = new HashMap<>();
        map.put("type",2);
        map.put("orderId",id);
        map.put("content","订单号:"+ id);

        webSocketServer.sendToAllClient(JSONObject.toJSONString(map));//向客户端推送消息
    }
相关推荐
ItKevin爱java几秒前
java八股文面试题
java·开发语言
喜欢猪猪13 分钟前
两个线程之间是如何通信的呢?
java·开发语言
co松柏16 分钟前
在非 antd pro 项目中使用 umi OpenAPI
java·前端
java66666888817 分钟前
Spring Boot中的数据加密与解密
java·spring boot·后端
NightHacker28 分钟前
什么是AOP思想?
java·开发语言
番茄炒西红柿炒蛋33 分钟前
秋招Java后端开发冲刺——非关系型数据库篇(MongoDB)
java·mongodb·nosql
虫小宝34 分钟前
高可用电商返利APP架构设计与实现分享
java·开发语言
GoodStudyAndDayDayUp1 小时前
一个简单的spring+kafka生产者
sql·spring·kafka
java6666688881 小时前
如何在Java中使用Maven进行项目管理
java·开发语言·maven
天草二十六_简村人1 小时前
nexus未开启匿名访问Anonymous Access,访问maven元数据maven-metadata,报401未授权Unauthorized错误
xml·java·ci/cd·jdk·maven·devops