欢迎光临
我们一直在努力

苍穹外卖个人技术总结Day06

1.Spring task

1.1介绍

(1)SpringTask 是Spring框架提供的一个任务调度工具,它可以按照所约定的时间定时自动执行设定的某个代码块。

(2)常见应用场景有:定时批量处理订单,银行贷款还款提醒等

1.2 cron表达式

(1)前言:Spring Task 作为一个定时处理任务的一个框架,这个定时便是基于这个cron表达式来实现的

(2)cron表达式就是一个字符串,通过该表达式就可以定义该代码逻辑执行的时机。常见形式由6个或7个域组成,每个域分别代表秒,分钟,小时,日,月,周,年(可有可无) 。

案例:每年的1月1日0点0分 对应的cron表达式为:(cron=" 0 0 0 1 1 ? * " )

cron表达式生成器:在线Cron表达式生成器 (qqe2.com)

1.3 定时处理订单状态实现

1.3.1 需求分析

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

(1)下单后未支付,订单一直处于待支付状态

(2)用户收货后管理端未点击完成按钮,订单一直处于派送中状态

对于上面两种情况我们不可能随时随地及时处理,所以需要通过定时任务来处理,让程序自动修改订单状态,此处采用以下处理方案:

(1)每分钟检查一次是否存在支付超时订单,如果存在则修改订单状态为“已取消”

(2)每天凌晨1点检查一次是否存在“派送中”订单,存在则修改订单状态为“已完成”

1.3.2 代码实现

(1)开启权限 :在skyApplication类中开启任务调度权限,打上@EnableScheduling注解 ![[Pasted image 20260314142655.png]]

(2)定义专门的定时任务类 :在sky-server包下定义一个task包,在该包下定义Mytask类专门处理定时任务逻辑 ![[Pasted image 20260314143539.png]]

(3)编写定时任务类的方法:

处理支付超时订单:

@Autowired
private OrderMapper orderMapper;

/**
* 处理超时订单
*/

@Scheduled(cron = "0 * * * * ?")//每分钟执行一次
public void processTimeOutOrder(){
//查看数据库,去查订单状态为待支付的订单数据,如果超时15分钟,就自动取消订单,并设置订单取消原因
Integer payStatus = Orders.PENDING_PAYMENT;//订单状态为待付款
LocalDateTime now = LocalDateTime.now().plusMinutes(15);//订单支付时间超过15分钟
log.info("超时时间:{}", now);

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

处理派送中订单 :

/**
* 处理配送中订单
*/

@Scheduled(cron = "0 0 1 * * ?")//每天凌晨一点统一处理
public void processDeliveryOrder(){
Integer deliveryStatus = Orders.DELIVERY_IN_PROGRESS;
LocalDateTime now = LocalDateTime.now().plusHours(1);
log.info("待配送时间:{}", now);

List<Orders> outTimeOrdersList = orderMapper.getOutTimeOrders(deliveryStatus, now);
if(outTimeOrdersList != null && outTimeOrdersList.size() > 0){
for (Orders orders : outTimeOrdersList) {
orders.setStatus(Orders.COMPLETED);
orders.setDeliveryTime(LocalDateTime.now());
orderMapper.update(orders);
}
}
}

在OrderMapper接口中添加查询方法

/**
* 根据状态和时间查询订单
*/

@Select("select * from orders where status = #{status} and order_time < #{time}")
List<Orders> getOutTimeOrders(Integer status, LocalDateTime time);

2.WebSocket

2.1 介绍

WebSocket是基于TCP的一种新的网络协议,可以只通过完成一次握手就实现服务器和客户端的双向数据传输,建立长连接。

提问:前期该项目的功能实现都是基于Http协议实现的,为什么此处还要用到WebSocket这个新协议?

解释:(1) Http协议是支持单向通信,即客户端发起一次请求,服务器就响应一次请求,是基于请求响应模式的,并且由于Http协议的特性,客户端每次的请求都是独立的,即新的请求是不具备上一次请求的信息的,服务器和客户端是建立了短连接。这就会导致在一些需要客户端和服务器实时共享信息的情况下基于Http协议不能很好的实现,所以这时候就需要基于WebSocket协议。

(2)Websocket协议是支持双向通信的,即客户端与服务器完成一次握手后,客户端可以向服务器发消息的同时,服务器也可以向客户端主动发消息,就不必基于请求响应模式。服务器和客户端是建立了长连接,在视频弹幕或者体育赛事更新等需要实时更新信息的场景下就需要WebSocket。

2.2 环境配置

(1)导入Maven坐标:在sky-server包下的pom.xml中(已定义)

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>

(2)定义WebSocket的配置类

/**
* WebSocket配置类,用于注册WebSocket的Bean
*/
@Configuration
public class WebSocketConfiguration {

@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}

(3)定义WebSocket的服务端组件:在sky-server包下创建WebSocket包,定义专门的WebSocket类,再在类中定义相关代码 ![[Pasted image 20260314153426.png]]

/**
* 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
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();
}
}
}

}

2.3来电提醒

2.3.1 需求分析

用户在小程序端提交订单并支付成功后,需要提醒商家有新的订单要处理,此处是通过WebSocket将服务器和客户端建立连接后,由服务器向客户端推送信息,然后由客户端解析后产生相对应的语音播报和提示框提示。

2.3.2 代码实现

在OrderServiceImpl中注入WebSocketServer对象,此处因为是订单提醒,所以直接在OrderServiceImpl中的paySuccess方法中进行修改,添加下列代码

//根据websocket向商家推送订单信息
Map<String, Object> map = new HashMap<>();
map.put("type", 1);//1表示订单提示,2表示催单
map.put("orderId", orders.getId());
map.put("content", "订单号:" + ordersDB.getNumber());
log.info("向商家推送订单信息:{}", map);

webSocketServer.sendToAllClient(JSON.toJSONString(map));

2.4 客户催单

2.4.1 需求分析

用户在小程序端点击催单按钮后,需要提醒商家有订单要及时处理,此处还是通过WebSocket将服务器和客户端建立连接后,由服务器向客户端推送信息,然后由客户端解析后产生相对应的语音播报和提示框提示。

2.4.2 代码实现

(1)用户端的OrderController层新增催单方法remindOrder

/**
* 用户催单
* @param id
* @return
*/

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

(2)OrderService层

/**
* 催单
* @param id
*/

void remindOrder(Long id);
}

(3)OrderServiceImpl层

/**
* 催单
* @param id
*/

@Override
public void remindOrder(Long id) {
Orders orders = orderMapper.getDetail(id);

//判断订单状态是否为待接单,是就可以催单,不是则不能
if (orders.getStatus().equals(Orders.TO_BE_CONFIRMED)) {
//根据websocket向商家催单
Map<String, Object> map = new HashMap<>();
map.put("type", 2);//1表示订单提示,2表示催单
map.put("orderId", id);
map.put("content", "订单号:" + orders.getNumber());
log.info("向商家推送订单信息:{}", map);

webSocketServer.sendToAllClient(JSON.toJSONString(map));
}
}

(4)OrderMapper层

/**
* 根据id查询订单详情
* @param id
*/

@Select("select * from orders where id = #{id}")
Orders getDetail(Long id);

赞(0)
未经允许不得转载:171主机测评 » 苍穹外卖个人技术总结Day06
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址