外卖开发(八)—— SpringTask(定时任务) 和 WebSocket网络协议

一、利用SpringTask完成定时任务

Spring Task是Spring框架提供的任务调度工具,可以按照约定的时间自动执行某个代码逻辑。

定位: 定时任务框架
作用: 定时自动执行某段Java代码

应用场景:
信用卡每月还款提醒
银行贷款每月还款提醒
火车票售票系统处理未支付订单。入职纪念日为用户发送通知

只要是需要定时处理的场景都可以使用Spring Task

1、cron表达式

@Scheduled(cron = "0 0 1 * * ? ") 注解

cron表达式其实就是一个字符串,通过cron表达式可以定义任务触发的时间

构成规则:分为6或7个域,由空格分隔开,每个域代表一个含义

每个域的含义分别为:秒、分钟、小时、日、月、周、年(可选)
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
cron表达式在线生成: https://cron.qqe2.com/

在这里插入图片描述

2、springtask实现

使用springtask解决外卖订单已经派送成功,用户迟迟不点击已送达,需要我们在一个特点的时间点(凌晨一点)检查一天前的所有 “正在派送” 的订单,并修改状态为已完成。

在这里插入图片描述

需求分析:
用户收货后管理端未点击完成按钮,订单一直处于“派送中”状态
通过定时任务每天凌晨1点检查一次是否存在“派送中”的订单,如果存在则修改订单状态为“已完成”

1、自定义定时任务类

OrderTask.java

@Component
@Slf4j
public class OrderTask {


    @Autowired
    private OrderMapper orderMapper;

    /**
     * 每天夜里一点检查是否存在已派送未完成的订单
     */
    @Scheduled(cron = "0 0 1 * * ? ")
    public void processDeliveryOrder(){
        log.info("系统处理未支付订单:{}",LocalDateTime.now());
        LocalDateTime localDateTime = LocalDateTime.now().plusHours(-1); //检查时间小于0:00的订单
        List<Orders> orders = orderMapper.checkDeliveryUnsuccess(Orders.DELIVERY_IN_PROGRESS,localDateTime);
        if(orders != null && orders.size() > 0){
            for (Orders order : orders){
                order.setPayStatus(Orders.COMPLETED);
                order.setDeliveryTime(LocalDateTime.now());
                orderMapper.update(order);
            }
        }

    }
}

2、mapper接口

/**
     * 每天一点检查前一日正在派送的订单,改为已完成
     * @param status
     * @param deliveryTime
     * @return
     */
    @Select("select * from orders where status = #{status} and delivery_time < #{deliveryTime}")
    List<Orders> checkDeliveryUnsuccess(Integer status,LocalDateTime deliveryTime);

通过上述springtask类,实现了每天凌晨1点,定时去数据库中搜索前一天的派送中的订单,并统一完成订单。

二、使用webSocket实现接单、催单提醒

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

在这里插入图片描述
在这里插入图片描述

1、代码分析

websocket配置类

WebSocketConfiguration.java

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

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

}

websocket服务

WebSocketServer.java

/**
 * 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、催单提醒

用户在小程序中点击催单按钮后,需要第一时间通知外卖商家。
在这里插入图片描述

设计:

通过WebSocket实现管理端页面和服务端保持长连接状态

当用户点击催单按钮后,调用WebSocket的相关API实现服务端向客户端推送消息

客户端浏览器解析服务端推送的消息,判断是来单提醒还是客户催单,进行相应的消息提示。约定服务端发送给客户端浏览器的数据格式为JSON,字段包括: type,orderld, content

  • type为消息类型,1为来单提醒2为客户催单
  • orderld为订单id
  • content为消息内容

在这里插入图片描述

OrderController.java

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

OrderService.java

/**
     * 用户催单
     * @param id
     */
    @Override
    public void userReminder(Long id) {
        Orders orders = orderMapper.queryOrderById(id);  //根据id查询订单详情
        String number = orders.getNumber();
        Map map = new HashMap();
        map.put("type",2);
        map.put("orderId",id);
        map.put("content","订单号:" + number);
        String json = JSON.toJSONString(map);
        webSocketServer.sendToAllClient(json);
    }

### 苍穹外卖的技术架构分层设计 #### 一、项目整体分层概述 苍穹外卖项目的分层设计遵循典型的MVC(Model-View-Controller)模式,并结合Spring Boot框架的特点进行了扩展优化。整个项目分为多个层次,每一层都有明确的功能定位职责划分[^5]。 --- #### 二、各层具体功能及作用 ##### 1. **Annotation 层** 此层主要用于存放自定义注解类。这些注解可以用来增强代码的可读性功能性,例如用于校验输入数据或者标记某些特殊行为的注解[^1]。 ##### 2. **Aspect 切面层** 切面层主要负责实现AOP(面向切面编程)。通过定义切面类,可以在不影响原有业务逻辑的情况下,动态地添加横切关注点,比如日志记录、性能监控等功能[^1]。 ##### 3. **Config 配置层** 配置层集中管理项目的各种配置信息,包括但不限于数据库连接池设置、第三方工具集成(如Knife4j)、全局异常处理策略等。例如,在`WebMvcConfiguration.java`文件中实现了Swagger API文档的相关配置[^3]: ```java @Bean public Docket docket() { ApiInfo apiInfo = new ApiInfoBuilder() .title("苍穹外卖项目接口文档") .version("2.0") .description("苍穹外卖项目接口文档") .build(); Docket docket = new Docket(DocumentationType.SWAGGER_2) .apiInfo(apiInfo) .select() .apis(RequestHandlerSelectors.basePackage("com.sky.controller")) .paths(PathSelectors.any()) .build(); return docket; } ``` 上述代码展示了如何利用Docket对象构建API文档并指定扫描范围。 ##### 4. **Controller 控制层** 控制层作为系统的前端交互入口,接收客户端请求并将请求转发给相应的服务层进行处理。同时返回响应结果给调用方。为了提高开发效率服务质量,还可以在此处加入参数校验机制[^1]。 ##### 5. **Handler 全局异常处理器** 这一层专门用于捕获并统一处理系统运行过程中可能出现的各种异常情况,从而提升用户体验的一致性与友好度。 ##### 6. **Interceptor 拦截器** 拦截器能够对进入控制器之前或离开之后的操作流程实施干预措施,常被应用于权限验证、流量统计等领域[^1]。 ##### 7. **Mapper 数据访问层** 持久化操作由MyBatis框架下的Mapper映射文件完成,所有的CRUD方法均封装于此模块内部以便于维护更新工作开展顺利推进下去。 ##### 8. **Service 业务逻辑层** 业务逻辑层承担着最核心的任务——即针对具体的业务需求编写算法实现方案。考虑到复杂场景下可能存在多实例竞争资源的情况发生时,则需借助IoC/DI容器来协调不同组件之间的协作关系;另外如果遇到同名bean冲突现象可通过@Primary,@Qualifier等方式加以区分解决办法[^2]。 以下是关于员工分页查询的一个简单例子展示: ```java /** * 分页查询 * * @param employeePageQueryDTO 查询条件传输对象 * @return 返回包含分页结果的数据结构 */ PageResult pageQuery(EmployeePageQueryDTO employeePageQueryDTO); ``` 这里体现了良好的抽象能力使得外部只需关心输入输出而无需深入了解底层细节[^4]。 ##### 9. **Task 定时任务** 对于一些周期性的后台作业安排则交给了task包去执行,配合@EnableScheduling启用调度功能后即可轻松达成目标[^5]。 ##### 10. **WebSocket 实时通信** 最后值得一提的是webSocket子系统提供了双向通讯渠道让服务器端主动推送消息成为可能,这对于即时聊天室或者是订单状态跟踪这类应用场景尤为重要。 --- #### 三、启动引导过程分析 SkyApplication作为整个工程的起点扮演着至关重要的角色。它不仅声明了必要的依赖项还初始化了一系列基础环境准备动作最终触发实际的服务上线进程[^5]: ```java package com.sky; import lombok.extern.slf4j.Slf4j; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.cache.annotation.EnableCaching; import org.springframework.transaction.annotation.EnableTransactionManagement; @SpringBootApplication @EnableTransactionManagement @EnableCaching @EnableScheduling @Slf4j public class SkyApplication { public static void main(String[] args) { SpringApplication.run(SkyApplication.class, args); log.info("server started"); } } ``` 从中可以看出除了常规属性外还有几个特色之处值得留意:一是启用了事务管理缓存支持二是加入了计划任务的支持三是运用lombok插件减少样板代码量四是打印日志确认当前节点已经正常激活完毕等待后续指令下达[^5]。 --- ### 总结 综上所述,“苍穹外卖”的技术栈选型合理且具有较强的实用性价值,其清晰合理的分层设计理念有助于团队成员快速理解掌握各自领域内的专业知识同时也便于后期拓展升级满足日益增长变化中的市场需求趋势[^2][^3][^5]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值