苍穹外卖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 {@Autowiredprivate 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 {@Autowiredprivate 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 contentMap 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);