苍穹外卖DAY10

Spring Task

是什么?

是一个定时任务框架,能定时自动执行某段Java代码。只要是需要定时处理的场景都可以使用Spring Task。

什么时候用?

1). 信用卡每月还款提醒

2). 银行贷款每月还款提醒

3). 火车票售票系统处理未支付订单

4). 入职纪念日为用户发送通知

cron表达式

这些具体的细节,我们就不用自己去手写,因为这个cron表达式,它其实有在线生成器。在线生成器:在线Cron表达式生成器

通配符:

* 表示所有值;

? 表示未说明的值,即不关心它为何值;

- 表示一个指定的范围;

, 表示附加一个可能值;

/ 符号前表示开始时间,符号后表示每次递增的值;

cron表达式案例:

*/5 * * * * ? 每隔5秒执行一次

0 */1 * * * ? 每隔1分钟执行一次

0 0 5-15 * * ? 每天5-15点整点触发

0 0/3 * * * ? 每三分钟触发一次

0 0-5 14 * * ? 在每天下午2点到下午2:05期间的每1分钟触发

0 0/5 14 * * ? 在每天下午2点到下午2:55期间的每5分钟触发

0 0/5 14,18 * * ? 在每天下午2点到2:55期间和下午6点到6:55期间的每5分钟触发

0 0/30 9-17 * * ? 朝九晚五工作时间内每半小时

0 0 10,14,16 * * ? 每天上午10点,下午2点,4点

入门案例

@EnableScheduling // 开启SpringTask任务调度
@Slf4j
public class SkyApplication {
    public static void main(String[] args) {
        SpringApplication.run(SkyApplication.class, args);
        log.info("server started");
    }
}
/**
 * 自定义的定时任务类
 */
@Component
@Slf4j
public class MyTask {

    /**
     * 定时任务,每间隔5秒触发一次
     */
    @Scheduled(cron = "0/5 * * * * ?")
    public void executeTask() {
        log.info("定时任务开始执行:{}", new Date());
    }
}

订单状态定时处理

需求分析

支付超时的订单如何处理? 派送中的订单一直不点击完成如何处理?

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

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

代码开发

/**
 * 定时任务类:定时处理订单状态
 */
@Component
@Slf4j
public class OrderTask {

    @Autowired
    private OrderMapper orderMapper;

    /**
     * 处理支付超时订单的方法
     */
    @Scheduled(cron = "0 * * * * ?") // 每分钟触发一次
    public void processTimeoutOrder() {
        log.info("定时处理超时订单:{}", LocalDateTime.now());
        LocalDateTime time = LocalDateTime.now().plusMinutes(-15); // 当前时间 - 15分钟
        // select * from orders where status = ? and order_time < (当前时间 - 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 * * ?") // 每天凌晨一点触发一次
    public void processDeliveryOrder() {
        log.info("定时处理处于派送中的订单:{}", LocalDateTime.now());
        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);
                orders.setCancelTime(LocalDateTime.now());
                orderMapper.update(orders);
            }
        }
    }
}

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

测试

Day10-06-订单状态定时处理_功能测试_哔哩哔哩_bilibili

WebSocket

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

HTTP协议和WebSocket协议对比:

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

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

WebSocket缺点:

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

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

使用场景:

1). 视频弹幕

2). 网页聊天

3). 体育实况更新

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

入门案例

Day10-09-WebSocket_入门案例_2_哔哩哔哩_bilibili

来单提醒

需求分析

代码开发

/**
 * 订单
 */
@Service
@Slf4j
public class OrderServiceImpl implements OrderService {

    @Autowired
    private WebSocketServer webSocketServer;

    /**
     * 支付成功,修改订单状态
     */
    public void paySuccess(String outTradeNo) {

        // 根据订单号查询订单
        Orders ordersDB = orderMapper.getByNumber(outTradeNo);

        // 根据订单id更新订单的状态、支付方式、支付状态、结账时间
        Orders orders = Orders.builder()
                .id(ordersDB.getId())
                .status(Orders.TO_BE_CONFIRMED)
                .payStatus(Orders.PAID)
                .checkoutTime(LocalDateTime.now())
                .build();

        orderMapper.update(orders);

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

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

客户催单

需求分析

 

代码开发

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

    /**
     * 用户催单
     * @param id
     */
    void reminder(Long id);

    /**
     * 用户催单
     * @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));
    }

    /**
     * 根据id查询订单
     * @param id
     * @return
     */
    @Select("select * from orders where id = #{id}")
    Orders getById(Long id);

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值