# 毕设项目<<基于微信小程序的餐馆外卖系统的设计>>后端(九)

毕设项目<<基于微信小程序的餐馆外卖系统的设计后端>>(开发记录(九)校验收货地址是否超出配送范围和订单状态定时处理)


视频传送带

校验收货地址是否超出配送范围

1. 环境准备

注册账号:https://passport.baidu.com/v2/?reg&tt=1671699340600&overseas=&gid=CF954C2-A3D2-417F-9FE6-B0F249ED7E33&tpl=pp&u=https%3A%2F%2Flbsyun.baidu.com%2Findex.php%3Ftitle%3D%E9%A6%96%E9%A1%B5

登录百度地图开放平台:https://lbsyun.baidu.com/

进入控制台,创建应用,获取AK:
请添加图片描述
请添加图片描述

相关接口:

https://lbsyun.baidu.com/index.php?title=webapi/guide/webservice-geocoding

https://lbsyun.baidu.com/index.php?title=webapi/directionlite-v1

2. 代码开发

请添加图片描述

2.1 application.yml

请添加图片描述

2.2 OrderServiceImpl

改造OrderServiceImpl,注入上面的配置项:


    @Value("${sky.shop.address}")

    private String shopAddress;

  

    @Value("${sky.baidu.ak}")

    private String ak;

在OrderServiceImpl中提供校验方法:

/**

     * 检查客户的收货地址是否超出配送范围

     * @param address

     */

    private void checkOutOfRange(String address) {

        Map map = new HashMap();

        map.put("address",shopAddress);

        map.put("output","json");

        map.put("ak",ak);

  

        //获取店铺的经纬度坐标

        String shopCoordinate = HttpClientUtil.doGet("https://api.map.baidu.com/geocoding/v3", map);

  

        JSONObject jsonObject = JSON.parseObject(shopCoordinate);

        if(!jsonObject.getString("status").equals("0")){

            throw new OrderBusinessException("店铺地址解析失败");

        }

  

        //数据解析

        JSONObject location = jsonObject.getJSONObject("result").getJSONObject("location");

        String lat = location.getString("lat");

        String lng = location.getString("lng");

        //店铺经纬度坐标

        String shopLngLat = lat + "," + lng;

  

        map.put("address",address);

        //获取用户收货地址的经纬度坐标

        String userCoordinate = HttpClientUtil.doGet("https://api.map.baidu.com/geocoding/v3", map);

  

        jsonObject = JSON.parseObject(userCoordinate);

        if(!jsonObject.getString("status").equals("0")){

            throw new OrderBusinessException("收货地址解析失败");

        }

  

        //数据解析

        location = jsonObject.getJSONObject("result").getJSONObject("location");

        lat = location.getString("lat");

        lng = location.getString("lng");

        //用户收货地址经纬度坐标

        String userLngLat = lat + "," + lng;

  

        map.put("origin",shopLngLat);

        map.put("destination",userLngLat);

        map.put("steps_info","0");

  

        //路线规划

        String json = HttpClientUtil.doGet("https://api.map.baidu.com/directionlite/v1/driving", map);

  

        jsonObject = JSON.parseObject(json);

        if(!jsonObject.getString("status").equals("0")){

            throw new OrderBusinessException("配送路线规划失败");

        }

  

        //数据解析

        JSONObject result = jsonObject.getJSONObject("result");

        JSONArray jsonArray = (JSONArray) result.get("routes");

        Integer distance = (Integer) ((JSONObject) jsonArray.get(0)).get("distance");

  

        if(distance > 5000){

            //配送距离超过5000米

            throw new OrderBusinessException("超出配送范围");

        }

    }

在OrderServiceImpl的submitOrder方法中调用上面的校验方法:
请添加图片描述

订单状态定时处理

1. SpringTask技术

1.1介绍

Spring TaskSpring 框架提供的一种任务调度和异步处理的解决方案。可以按照约定的时间自动执行某个代码逻辑.它可以帮助开发者在 Spring 应用中轻松地实现定时任务、异步任务等功能,提高应用的效率和可维护性

1.2 主要特点

定位:定时任务框架

  • 简单易用:Spring Task 提供了简洁的注解和配置方式,使得任务调度和异步处理变得非常容易上手
  • 内置支持:Spring Task 内置于 Spring 框架中,无需额外的依赖,开发者可以直接在 Spring 应用中使用
  • 灵活的任务调度:Spring Task 支持基于 cron 表达式的定时任务调度,能够满足各种复杂的调度需求
  • 异步任务支持:除了定时任务,Spring Task 也支持异步任务的处理,能够在后台线程中执行耗时操作,提高系统的响应速度
  • 集成注解:Spring Task 提供了 @Scheduled 注解用于标识定时任务的方法,以及 @Async 注解用于标识异步任务的方法,使用起来非常方便
  • 监控和管理:Spring Task 支持任务的监控和管理,可以通过 JMX 或者 Spring Boot Actuator 进行任务的查看和控制。
1.3 应用场景
  • 信用卡每月还款提醒
  • 银行贷款每月还款提醒
  • 自动续费短信提醒
  • 火车票售票系统处理未支付订单
  • 入职纪念日为用户发送通知
1.4 使用案例
1.4.1 使用步骤
  1. 导入maven坐标,集成在spring-context中
  2. 启动类添加注解@EnableScheduling开启任务调度
  3. 自定义定时任务类
    在线Cron表达式生成器 (qqe2.com)

2. 订单状态定时处理

2.1 需求分析
用户下单后可能存在的情况:
  • 下单后未支付,订单一直处于“待支付”状态
  • 用户收货后管理端未点击完成按钮,订单一直处于“派送中”状态
实现逻辑
  • 通过定时任务每分钟检查一次是否存在支付超时的订单(下单后超过15分钟未支付的判定为支付超时订单),如果存在则修改订单状态为“已取消”
  • 通过定时任务每天凌晨1点检查一次是否存在“派送中”的订单,如果存在则修改订单状态为已完成
2.2 代码开发
@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);  
  
// 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);  
orderMapper.update(orders);  
}  
  
}  
}  
  
}
2.3功能测试

请添加图片描述

3.WebSocket

3.1 介绍

WebSocket 是 HTML5 一种新的协议。它实现了浏览器与服务器全双工通信,能更好的节省服务器资源和带宽并达到实时通讯,它建立在 TCP 之上,同 HTTP 一样通过 TCP 来传输数据,但是它和 HTTP 最大不同是:
WebScoket是基于TCP的一种新的网络协议,它实现了浏览器与服务器全双工通信——浏览器只需要完成一次握手,两者就可以创建持久性的连接,并进行双向数据传输。

  • WebSocket 是一种双向通信协议,在建立连接后,后续数据都以帧序列的形式传输。在客户端断开 WebSocket 连接或 Server 端断掉连接前,不需要客户端和服务端重新发起连接请求。在海量并发及客户端与服务器交互负载流量大的情况下,极大的节省了网络带宽资源的消耗,有明显的性能优势,且客户端发送和接受消息是在同一个持久连接上发起,实时性优势明显。WebSocket 服务器和 Browser/Client Agent 都能主动的向对方发送或接收数据,就像 Socket 一样;
  • WebSocket 需要类似 TCP 的客户端和服务器端通过握手连接,连接成功后才能相互通信。
3.1.1 应用场景
  • 视频弹幕
  • 网页聊天
  • 体育实况更新
  • 股票基金报价实时更新
3.1.2 实现步骤
  1. 直接使用websocket.html页面作为WebSocket的客户端
  2. 导入WebSocket的Maven坐标
  3. 导入WebSocket服务端组件WebSocketServer,用于和客户端通信
  4. 导入配置类WebSocketConfiguration,注册WebSocket的服务端组件
  5. 导入定时任务WebSocketTask,定时向客户端发送数据
3.1.3 测试

请添加图片描述

4. 来单提醒

4.1 需求分析和设计

用户下单并且支付成功后,需要第一时间通知外卖商家,通知的形式有两种:语音播报和弹窗提示

4.2 设计
  • 通过web Socket实现管理端页面和服务端保持长连接状态
  • 当客户支付后,调用WebSocket的相关API实现服务端向客户端推送消息
  • 当客户端浏览器解析服务端推送的消息,判断是来单提醒还是客户催单,进行相应的消息提示和语音播报
  • 约定服务端发送给客户端浏览器的数据格式为JSON,包括字段:type(标识消息类型),orderId(订单ID),content(消息内容)
4.3 代码开发
//通过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);
4.4 功能测试

请添加图片描述

5.客户催单

5.1 需求分析和设计

用户在小程序中点击催单按钮后,需要第一时间通知外卖商家,通知的形式有两种:语音播报、弹窗提醒

设计
  • 通过WebSocket实现管理端页面和服务器保持长连接状态
  • 当用户点击催单按钮后,调用web Socket和相关API实现服务端向客户端推送消息
  • 当客户端浏览器解析服务端推送的消息,判断是来单提醒还是客户催单,进行相应的消息提示和语音播报
  • 约定服务端发送给客户端浏览器的数据格式为JSON,包括字段:type(标识消息类型),orderId(订单ID),content(消息内容)
5.2 代码开发
/**  
* 客户催单  
* @param id  
*/  
public void reminder(Long id) {  
// 根据id查询订单  
Orders ordersDB = orderMapper.getById(id);  
  
// 校验订单是否存在  
if (ordersDB == null) {  
throw new OrderBusinessException(MessageConstant.ORDER_STATUS_ERROR);  
}  
  
Map map = new HashMap();  
map.put("type",2); //1表示来单提醒 2表示客户催单  
map.put("orderId",id);  
map.put("content","订单号:" + ordersDB.getNumber());  
  
//通过websocket向客户端浏览器推送消息  
webSocketServer.sendToAllClient(JSON.toJSONString(map));  
}
5.3 功能测试

请添加图片描述
请添加图片描述

  • 8
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值