目录
Spring Task
cron表达式
使用步骤
订单状态定时处理
WebSocket
来单提醒
客户催单
Spring Task是Spring框架提供的任务调度工具,可以按照约定的时间自动执行某个代码逻辑。
cron表达式其实就是一个字符串,通过cron表达式可以定义任务触发的时间构成规则:分为6或7个域,由空格分隔开,每个域代表一个含义分别为:秒、分钟、小时、日、月、周、年(可选)。我们可以通过在线网址生产cron表达式。
1.导入maven坐标spring-context
2.启动类添加注解@EnableScheduling开启任务调度
3.自定义定时任务类(需要交给容器管理,在方法上使用@Scheduled注解)
由于可能存在用户下单后付款超时和订单一直处于派送的情况,需要使用定时处理这两种情况。
@Scheduled(cron = "0 * * * * ?")
public void processTimeoutOrder(){
LocalDateTime time = LocalDateTime.now().plusMinutes(-15);
List ordersList = orderMapper.getByStatusAndTimeLT(Orders.PENDING_PAYMENT, time);
for (Orders order : ordersList) {
order.setStatus(Orders.CANCELLED);
order.setCancelReason("订单超时,自动取消");
order.setCancelTime(LocalDateTime.now());
orderMapper.update(order);
}
}
/mapper
@Select("select * from sky_take_out.orders where status=#{status} and order_time < #{time}")
List getByStatusAndTimeLT(Integer status, LocalDateTime time);
对于支付超时的订单,一分钟查询一次,如果发现则将其订单状态修改为“已取消”。对于派送中的订单,每天的凌晨1点检查一次,如果发现则将其订单修改为“已完成”
@Scheduled(cron = "0 0 1 * * ?")
public void processDeliveryOrder(){
LocalDateTime localDateTime = LocalDateTime.now().plusMinutes(-60);
List byStatusAndTimeLT = orderMapper.getByStatusAndTimeLT(Orders.DELIVERY_IN_PROGRESS, localDateTime);
for (Orders order : byStatusAndTimeLT) {
order.setStatus(Orders.COMPLETED);
orderMapper.update(order);
}
}
WebSocket是基于TCP的一种新的网络协议。它实现了浏览器与服务器全双工通信——浏览器和服务器只需要完成一次握手,两者之间就可以创建持久性的连接,并进行双向数据传输。应用场景:视频弹幕、网页聊天、体育实况更新、股票基金报价实时更新
@Component
@ServerEndpoint("/ws/{sid}")
public class WebSocketServer {
//存放会话对象
private static Map 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 sessions = sessionMap.values();
for (Session session : sessions) {
try {
//服务器向客户端发送消息
session.getBasicRemote().sendText(message);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
//OrderServiceImpl.paysuccess
orderMapper.update(orders);
Map map=new HashMap<>();
map.put("type",1);
map.put("orderId",ordersDB.getId());
map.put("content","订单号:"+outTradeNo);
String json= JSON.toJSONString(map);
websocketserve.sendToAllClient(json);
一开始自己做的时候发现,前端没有反应。我们要确保将订单状态变成已支付后调用websocket就可以了。但是,我们支付的回调是不行的。因此这里的解决方案是在用户提交订单的时候,将订单状态修改成已支付带派送,并在之后调用websocket。完整的用户提交订单代码如下:
@Transactional
public OrderSubmitVO submitOrder(OrdersSubmitDTO ordersSubmitDTO) {
//异常情况的处理(收货地址为空、购物车为空)
AddressBook addressBook = addressBookMapper.getById(ordersSubmitDTO.getAddressBookId());
if (addressBook == null) {
throw new AddressBookBusinessException(MessageConstant.ADDRESS_BOOK_IS_NULL);
}
Long userId = BaseContext.getCurrentId();
ShoppingCart shoppingCart = new ShoppingCart();
shoppingCart.setUserId(userId);
//查询当前用户的购物车数据
List shoppingCartList = shoppingCartMapper.list(shoppingCart);
if (shoppingCartList == null || shoppingCartList.size() == 0) {
throw new ShoppingCartBusinessException(MessageConstant.SHOPPING_CART_IS_NULL);
}
//构造订单数据
Orders order = new Orders();
BeanUtils.copyProperties(ordersSubmitDTO,order);
order.setPhone(addressBook.getPhone());
order.setAddress(addressBook.getDetail());
order.setConsignee(addressBook.getConsignee());
order.setNumber(String.valueOf(System.currentTimeMillis()));
order.setUserId(userId);
//order.setStatus(Orders.PENDING_PAYMENT);
order.setStatus(Orders.TO_BE_CONFIRMED);
//order.setPayStatus(Orders.UN_PAID);
order.setPayStatus(Orders.PAID);
order.setOrderTime(LocalDateTime.now());
//向订单表插入1条数据
orderMapper.insert(order);
//订单明细数据
List orderDetailList = new ArrayList<>();
for (ShoppingCart cart : shoppingCartList) {
OrderDetail orderDetail = new OrderDetail();
BeanUtils.copyProperties(cart, orderDetail);
orderDetail.setOrderId(order.getId());
orderDetailList.add(orderDetail);
}
//向明细表插入n条数据
orderDetailMapper.insertBatch(orderDetailList);
//清理购物车中的数据
shoppingCartMapper.deleteByUseId(userId);
Map map=new HashMap<>();
map.put("type",1);
map.put("orderId",order.getId());
map.put("content","订单号:"+order.getNumber());
String json= JSON.toJSONString(map);
websocketserve.sendToAllClient(json);
//封装返回结果
OrderSubmitVO orderSubmitVO = OrderSubmitVO.builder()
.id(order.getId())
.orderNumber(order.getNumber())
.orderAmount(order.getAmount())
.orderTime(order.getOrderTime())
.build();
return orderSubmitVO;
}
@Override
public void reminder(Long id) {
Orders order = orderMapper.getById(id);
if(order == null){
throw new OrderBusinessException(MessageConstant.ORDER_NOT_FOUND);
}
Map map=new HashMap();
map.put("type",2);
map.put("orderId",id);
map.put("content","订单号: "+order.getNumber());
websocketserve.sendToAllClient(JSON.toJSONString(map));
}