《苍穹外卖》项目日记_Day9

前言:

上午就把今天任务完成了,就继续往后学了一些知识,晚上写下笔记总结一下。

今日完成任务:

  • 调用百度地图开放平台,优化用户下单业务
  • 学习SpringTask,定时处理超时、派送中订单
  • 学习WebSocket,完成来单提醒、催单业务
  • 完成 数据统计四个接口
  • 学习Apache POI 在java中操作excel

今日收获:

1.学习了SpringTask这个轻量级框架,来解决一些定时处理的问题。

Spring Taskspring框架提供的任务调度工具,可以按照约定的时间自动执行某个代码逻辑。主要的作用就是定时的去执行某段Java代码。

像这种定时的去执行某个任务,在生活中是比较常见的,例如:闹钟、信用卡每月还款提醒、入职纪念日为用户发送通知等。这些操作不可能有我们开发者/管理端,每次去点击提醒,所有需要根据业务逻辑,定时的去执行某一段代码。所有说,只要是需要定时处理的场景都可以使用Spring Task,Java中还存在其他任务调度工具,如下方案:

方案复杂度分布式支持持久化管理界面适用场景
Spring Task简单否(单机)单机简单定时任务
Quartz中等是(需配置)是(可选)无(需自研)复杂调度、高可靠
ScheduledExecutorService简单并行定时任务
XXL-JOB / Elastic-Job中等分布式系统、集中管理
消息队列延迟复杂依赖MQ高可靠、解耦场景

如何去使用SpringTask任务调度工具定时的执行某段Java代码?

这个框架小到已经包含在SpringBoot的起步依赖中了,所以我们无需引入依赖。首先我们需要在启动类上加上@EnableScheduled注解。然后创建一个包,然后去定义一个task类即可,如下图:

在这里插入图片描述

注意这里的@Scheduled就可,在里面我们可以通过cron表达式去设置该任务自动执行的时间。每次到这个时间就会去执行如下方法。这里的cron表达式我们无需记忆,需要的时候可以通过在线工具去获取到https://cron.qqe2.com/。

这里在该项目中,具体的使用:

  • 超时未支付订单

每隔1min,去数据库中查询超时的订单(15分钟内未支付,订单状态为未支付的订单),然后通过循环将所有超时订单都保存在列表中,通过循环对所有订单状态进行更新。

这里做法存在一些问题

1)订单量大的时候 每隔一分钟就去查询数据库中的数所有的订单数据,对数据库的压力大。(这里可以用redis来解决吧,每隔一分钟去redis缓存中查询,只有查到超时订单的时候,才会对数据库进行更新操作,从而减小数据库的压力)

2)如果订单还要1s 倒计时 未支付 这个时候 订单并没有自动处理成已取消 导致到了时间 但是用户仍然付款了

在这里插入图片描述

  • 派送中订单

每天凌晨去数据库中查找派送中的订单(订单状态为派送中的订单),道理同上,对所有订单状态进行更新。

在这里插入图片描述

2.学习WebSocket,来完成来来单提醒、催单业务

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

HTTP协议和WebSocket协议对比:

  • HTTP协议是短连接,WebSocket是长连接
  • HTTP请求是单向的,基于请求和响应模式
  • WebSocket支持双向通信,客户端 <—>服务端
  • 二者底层都是TCP连接

在这里插入图片描述

使用WebSocket

使用前需导入WebSocket的依赖,然后创建Websocket包,创建一个WebSocket服务端组件WebSocketServer,用于和客户端通信,这个服务端组件WebSocketServer写法比较固定,可以参考下面的代码:

package com.sky.websocket;import org.springframework.stereotype.Component;
import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;/*** WebSocket服务*/
@Component
@ServerEndpoint("/ws/{sid}")
public class WebSocketServer {//存放会话对象private static Map<String, Session> sessionMap = new HashMap();/*** 连接建立成功调用的方法*/@OnOpenpublic void onOpen(Session session, @PathParam("sid") String sid) {System.out.println("客户端:" + sid + "建立连接");sessionMap.put(sid, session);}/*** 收到客户端消息后调用的方法* @param message 客户端发送过来的消息*/@OnMessagepublic void onMessage(String message, @PathParam("sid") String sid) {System.out.println("收到来自客户端:" + sid + "的信息:" + message);}/*** 连接关闭调用的方法* @param sid*/@OnClosepublic 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();}}}}

后我们需要在配置类中创建配置类WebSocketConfiguration.

package com.sky.config;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;/*** WebSocket配置类,用于注册WebSocket的Bean*/
@Configuration
public class WebSocketConfiguration {@Beanpublic ServerEndpointExporter serverEndpointExporter() {return new ServerEndpointExporter();}}

下面解释为什么需要书写这个配置类:

1)WebSocketServer 的作用
WebSocketServer 是一个具体的 WebSocket服务端实现,用于处理客户端连接、消息接收、连接关闭等逻辑。
它通过注解(如 @ServerEndpoint、@OnOpen、@OnMessage 等)定义了 WebSocket 的行为,包括:建立连接时的逻辑 (@OnOpen)。接收客户端消息时的处理逻辑(@OnMessage)。连接关闭时的清理逻辑 (@OnClose)。提供群发消息的功能。

2)WebSocketConfiguration 的作用
WebSocketConfiguration 是一个配置类,主要目的是注册 WebSocket 相关的 Bean
其核心是通过 ServerEndpointExporter 来扫描和注册所有使用 @ServerEndpoint 注解的类(例如 WebSocketServer)。如果没有 ServerEndpointExporter,Spring 容器不会自动识别和管理 @ServerEndpoint 注解的类,导致 WebSocket 功能无法正常工作。

3)为什么需要两个类?
职责分离:WebSocketServer 负责具体的业务逻辑,而 WebSocketConfiguration 负责基础配置。这种设计符合单一职责原则,使代码更清晰、易于维护。
Spring 管理依赖:@ServerEndpoint 注解本身是由 Java EE 提供的,Spring 并不直接支持它。通过 ServerEndpointExporter,Spring 才能将 @ServerEndpoint 注解的类纳入其管理范围。
灵活性:如果未来需要扩展 WebSocket 功能(例如添加拦截器或自定义配置),可以在 WebSocketConfiguration 中进行扩展,而无需修改 WebSocketServer。

简而言之:Spring并不识别带有@ServerEndpoint 注解的WebSocketServer类,该注解由javaEE提供的,Spring并不支持。因此我们需要通过注册配置类ServerEndpointExporter,该配置类会扫描和注册使用@ServerEndpoint注解的类,加入到IOC容器中,使得WebSocket可以正常工作

Nginx的反向代理

具体可以看Day1天的笔记

3.Apache POI

Apache POl是一个处理Miscrosoft Office各种文件格式的开源项目。简单来说就是,我们可以使用 POl在 Java 程序中对Miscrosoft Office各种文件进行读写操作。一般情况下,POI都是用于操作 Excel 文件

在这里插入图片描述

简而言之:Apache POI就是定义了一系列API供我们在java程序中操作excel。除了Apache POI 还有easyExcel等开源工具。

基本思路:1)设计excel模板 2)查询数据库 3)填充数据到模板 4)通过输出流 下载到浏览器

下面是Apache POI操作java的两个Demo文件 供我们熟悉POI操作的相关API

    /*** 使用POI 写入excel文件内容* @throws IOException*/@Testpublic void testWrite() throws IOException {//创建excel文件XSSFWorkbook excel = new XSSFWorkbook();//创建sheetXSSFSheet sheet = excel.createSheet("info");//创建行 这里起始行为0 类似数组XSSFRow row = sheet.createRow(1);//创建单元格 并写入值row.createCell(1).setCellValue("姓名");row.createCell(2).setCellValue("地址");row = sheet.createRow(2);row.createCell(1).setCellValue("张三");row.createCell(2).setCellValue("北京");row = sheet.createRow(3);row.createCell(1).setCellValue("李四");row.createCell(2).setCellValue("青岛");//写入文件FileOutputStream fileOutputStream = new FileOutputStream("D:\\info.xlsx");excel.write(fileOutputStream);}
 /*** 使用POI 读取文件内容**/@Testpublic void testRead() throws IOException {//打开excelXSSFWorkbook excel = new XSSFWorkbook(new FileInputStream(new File("D:\\info.xlsx")));//读取sheet页XSSFSheet sheet = excel.getSheet("info");//获取最后一行下标int lastRowNumber = sheet.getLastRowNum();for (int i = 1; i <= lastRowNumber; i++) {XSSFRow row = sheet.getRow(i);String value1 = row.getCell(1).getStringCellValue();String value2 = row.getCell(2).getStringCellValue();System.out.println(value1 + " " + value2);}}

杂项知识点:

JDK8时间API

JDK 8 引入了全新的时间 API:java.time,它是基于 ThreeTen 项目实现的,更加清晰、易用、不可变、线程安全。

主要类如下:

类名用途
LocalDate只包含日期,无时区(如:2025-09-04)
LocalTime只包含时间,无时区(如:10:30:45)
LocalDateTime日期 + 时间,无时区(如:2025-09-04T10:30:45)
ZonedDateTime带有时区的日期时间(如:2025-09-04T10:30:45+08:00[Asia/Shanghai])
Instant时间戳,表示从 1970-01-01T00:00:00Z 起的秒或纳秒数
Duration表示两个时间点之间的时间量(以秒或纳秒为单位)
Period表示两个日期之间的年月日差异(以年、月、日为单位)

获取每天的日期列表

List<LocalDate> dateList = new ArrayList<>() ;       
//1.日期列表
dateList.add(begin);
while(!begin.equals(end)){//未达到结束时间begin = begin.plusDays(1);dateList.add(begin);
}
//列表转字符串
StringUtils.join(dateList,",");

总结:

​ 今天学了挺多小的知识点,然后自己还把数据统计的那几个接口完成了,感觉那几个接口都好像,一些重复性的逻辑,然后呢把这个项目整体都完成了,后边的计划就是明天写一篇项目总结,然后休息两天,看一下后边的计划。

您的一个小小点赞,对我便是莫大的鼓励。感谢支持!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/96485.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/96485.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

人工智能学习:Transformer结构中的编码器层(Encoder Layer)

Transformer结构中的编码器层(Encoder Layer) 一、编码器层介绍 概念 编码器层(Encoder Layer)是Transformer编码器的基本构建单元,它重复堆叠形成整个编码器,负责逐步提取输入序列的特征。每个编码器层由两个核心子层组成: 多头自注意力机制(Multi-Head Self-Attentio…

2018年下半年 系统架构设计师 综合知识

1.在磁盘调度管理中&#xff0c;应先进行移臂调度&#xff0c;再进行旋转调度。假设磁盘移动臂位于21 号柱面上&#xff0c;进程的请求序列如下表所示。如果采用最短移臂调度算法&#xff0c;那么系统的响应 序列应为(D )。A. ②⑧③④⑤①⑦⑥⑨ …

数据库的连接_qt

数据库的连接形式可以通过cmd查看 1.获取 UI 输入的连接参数 // 获取主机名&#xff08;如"localhost"或IP地址&#xff09; QString hostStr hostEdit->text(); // 从hostEdit控件获取文本 QByteArray hostBa hostStr.toUtf8(); // 转换为UTF-8编码的字节数…

HTML 设计与使用入门

HTML 设计与使用入门 一、完整示例&#xff08;基础页面模板&#xff09;这是一个结构清晰、可直接拷贝运行的最小 HTML 模板&#xff1a;<!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"utf-8"><meta name"vie…

Gradio全解11——Streaming:流式传输的视频应用(2)——Twilio:网络服务提供商

Gradio全解11——Streaming&#xff1a;流式传输的视频应用&#xff08;2&#xff09;——Twilio&#xff1a;网络服务提供商11.2 Twilio&#xff1a;网络服务提供商11.2.1 Twillo穿透服务与TURN服务器1. 什么是STUN、TURN和ICE&#xff1f;2. Twilio介绍及网络穿透服务3. Twil…

【更新至2024年】2009-2024年各地级市金融科技水平数据

【更新至2024年】2009-2024年各地级市金融科技水平数据 1、时间&#xff1a;2009-2024年 2、来源&#xff1a;天眼查 3、指标&#xff1a;年份、省份、地级市、地级市代码、当年新注册金融科技公司数量、累计注册金融科技公司数量、金融科技水平 4、范围&#xff1a;地级市…

一般软件加载显示图片的流程

目录 1、一般图片浏览软件的流程&#xff08;Qt 或类似框架&#xff09;&#xff1a; 1️⃣ 读取原始数据 2️⃣ 解析图片格式 3️⃣ 存储到内部可用的绘制对象 4️⃣ 显示到界面 ✅ 总结 2、那什么叫“QPixmap 在 Qt 里就是“显示专用的像素缓存”&#xff0c;不是原始…

【论文阅读】REFRAG:一个提升RAG解码效率的新思路

引言 看到一则报道[1]&#xff0c;重组后的Meta实验室在9月1号发布了一篇关于提升RAG解码效率的论文&#xff0c;提出的思路有点启发作用&#xff0c;于是把原文下载下来仔细看下。 论文标题&#xff1a;REFRAG: Rethinking RAG based Decoding 论文地址&#xff1a;https://ar…

QT M/V架构开发实战:QFileSystemModel介绍

目录[TOC](目录)前言一、QFileSystemModel初步介绍二、基本功能1.创建2.基本属性与方法三、示例&#xff08;简单的文件浏览器&#xff09;四、性能注意事项前言 本文主要介绍的是使用代码生成的情况下对控件的介绍&#xff0c;包括拥有的功能及能修改的样式&#xff0c;也会说…

视频生成迎来效率革命!字节提出视频生成稀疏注意力机制,计算量降20倍,速度升17.79倍!

论文链接&#xff1a;https://arxiv.org/pdf/2509.01085亮点直击BSA——一种可训练的双向动态稀疏注意力框架&#xff0c;该框架首次在视频扩散训练中对全注意力机制中的查询&#xff08;Query&#xff09;及键值对&#xff08;Key-Value&#xff09;进行正交稀疏化处理以加速训…

STM32HAL库_cubeMX

ADC简介STM32f103的是12位逼近型ADC代码连续非扫描模式&#xff08;1个通道&#xff09;1&#xff1a;校准ADC&#xff08;这个可要可不要&#xff09;2&#xff1a;ADC初始化3&#xff1a;配置ADC通道&#xff08;这个函数只有一个通道时就是可要可不要&#xff09;4&#xff…

【Qt】清空QDateTimeEdit

代码 ui->startDate->setSpecialValueText(" "); //这里是空格 ui->startDate->setMinimumDate(QDate(2024, 1, 1)); ui->startDate->setDate(QDate::fromString("2024-01-01", "yyyy-MM-dd"));原理 设置特殊值显示文本&#…

LiTS 2017 datasets

下载记录 论文地址&#xff1a;https://doi.org/10.1016/j.media.2022.102680 官方下载链接&#xff1a;https://competitions.codalab.org/competitions/17094 进入链接后&#xff0c;需要先注册才能拿到下载点击Train data下面的Mirro1&#xff0c;在google云盘会看到Trai…

kafka3.8集群搭建

kafka集群需要三台机器搭建&#xff0c;并使用内置zookeeperIP10.0.0.110.0.0.210.0.0.3安装jdk # ubuntu sudo apt install -y openjdk-8-jdk-headless # centos sudo yum install -y java-1.8.0-openjdk下载kafka wget https://archive.apache.org/dist/kafka/3.8.1/kafka_2…

从15kHz 到20MHz:为什么LTE带宽不能被子载波间隔整除?

从 15 kHz 到 20 MHz&#xff1a;为什么 LTE 带宽不能被子载波间隔整除&#xff1f; 1. 引言 在 LTE 系统中&#xff0c;子载波间隔被固定为 15 kHz&#xff0c;而系统带宽却被设计为 1.4、3、5、10、15、20 MHz 六个档位。乍一看&#xff0c;这些带宽似乎无法被 15 kHz 整除&a…

html css js网页制作成品——HTML+CSS娃娃店网页设计(4页)附源码

目录 一、👨‍🎓网站题目 二、✍️网站描述 三、📚网站介绍 四、🌐网站效果 五、🪓 代码实现 🧱HTML

【计算机网络 | 第15篇】动态主机配置协议

文章目录为何需要DHCP&#xff1f;手动配置的痛点&#x1f914;DHCP的基本工作模式&#x1f95d;DHCP的核心功能&#xff1a;IP地址的动态管理&#x1f95d;租用期的特点租用期的管理机制DHCP四步工作流程&#xff1a;从“发现”到“绑定”&#x1f426;‍&#x1f525;中继代理…

嵌入式系统内存分段核心内容详解

一、嵌入式内存分段整体规则&#xff08;按地址从低到高&#xff09;嵌入式系统内存按 “功能 属性” 划分为 6 个核心段&#xff0c;地址从低到高依次分布&#xff0c;各段职责与存储对象明确&#xff0c;具体规则如下表&#xff1a;地址范围段类型&#xff08;Segment&#…

开发避坑指南(45):Java Stream 求两个List的元素交集

需求 java 中如何用stream求两个List元素的交集&#xff1f; 代码实现 直接上代码 public class ListTest {public static void main(String[] args) {List<Integer> list1 new ArrayList<>();list1.add(1);list1.add(2);list1.add(3);List<Integer> list2 …

gitlab流水线与k8s集群的联通

gitlab流水线与k8s集群的连接&#xff0c;首先是通过gitlab-ci.yml文件中的命令&#xff0c;通过runner执行器实例运行对应的kubectl命令实现的。 那么runner执行器实例执行器如何执行kubectl命令&#xff0c;执行环境的配置&#xff0c;kubectl命令如何与k8s集群互认&#xff…