苍穹外卖心得体会
1 登录认证
技术点:JWT令牌技术(JSON Web Token)
JWT(JSON Web Token)是一种令牌技术,主要由三部分组成:Header头部、Payload载荷和Signature签名。Header头部存储令牌的类型(如JWT)和使用的加密算法(如HS256)。Payload载荷包含具体信息,如用户身份、权限、过期时间等声明(Claims)。Signature签名通过加密算法对Header和Payload进行签名,用于验证数据完整性和发行者身份。
在实际业务中,用户登录时,后端服务器接收客户端请求并解析传递的登录信息,验证用户名和密码是否正确。若验证成功,服务器生成JWT令牌返回给前端。后端无需存储Token,只需保存密钥(Secret Key)。后续请求时,服务器通过拦截器在请求前拦截,提取JWT并进行解析与验证:首先检查签名是否有效(防止篡改),再校验Payload中的声明(如是否过期、权限是否有效)。验证通过后,放行请求并执行业务逻辑。
Session与Token的对比
2 分页查询
PageHelper是一个基于MyBatis的分页插件,通过拦截MyBatis的执行器实现分页功能。
当调用 PageHelper.startPage()
设置分页参数后,MyBatis 会通过其拦截器机制自动触发分页逻辑,动态修改后续的 SQL 语句以实现分页。
分页参数通过 ThreadLocal
存储到当前线程的上下文中(PageContext
),确保同一线程内的后续操作可获取这些参数。PageHelper 在处理完当前 SQL 后,自动清除 ThreadLocal
中的分页参数,因此同一线程后续的查询不会被分页,除非再次调用 startPage()
。
/*** 分页查询套餐** @param setmealPageQueryDTO* @return*/@Overridepublic PageResult pageQuery(SetmealPageQueryDTO setmealPageQueryDTO) {int pageNum = setmealPageQueryDTO.getPage();int pageSize = setmealPageQueryDTO.getPageSize();PageHelper.startPage(pageNum, pageSize);Page<SetmealVO> page = setmealMapper.pageQuery(setmealPageQueryDTO);return new PageResult(page.getTotal(), page.getResult());}
-- 原始SQL
SELECT * FROM table;
-- 重写后(MySQL示例)
SELECT * FROM table LIMIT offset, pageSize;
3 MVC当中的参数注解
1 @RequestBoby:绑定HTTP请求体,反序列化为java对象。-(JSON,XML)
2 @RequestParam:绑定查询参数。(URL后-问号传参,参数用 ?
分隔,参数间用 &
连接。)
3 @PathVariable:绑定URL路径变量。(URL中-路径传参,参数用用 {}
包裹,/连接。)
4 @RequestHeader :绑定HTTP请求头。
5 @CookieValue:绑定Cookie
4 ThreadLocal
ThreadLocal是Java中的一个线程变量,它可以为每个线程提供一个独立的变量副本。ThreadLocal实例是共享的,但每个线程通过它访问的是自己的ThreadLocalMap中的值。
ThreadLocal的主要作用是在多线程的环境下提供线程安全的变量访问。它常用于解决线程间数据共享的问题,特别是在并发编程中,当多个线程需要使用同一个变量时,可以使用ThreadLocal确保每个线程访问的都是自己的变量副本,从而避免了线程安全问题。
ThreadLocal底层是通过ThreadLocalMap来实现的,每一个Thread(线程)对象中都存在一个ThreadLocalMap,Map的key为ThreadLocal对象,Map的value为需要缓存的值。
static修饰的ThreadLocal对象属于类级别,在JVM的整个生命周期中仅初始化一次,后续所有的线程通过BaseContext.threadLocal访问同一个ThreadLocal实例,但每个线程的变量副本独立存储,避免重复创建对象。
内存泄漏问题:当ThreadLocal对象使用完之后,应该将Entry对象(即key和value)回收。而线程对象是通过强引用指向ThreadLocalMap,ThreadLocalMap也是通过强引用指向Entry对象。在Entry中,key是弱引用,会触发自动回收机制,但value是强引用不会自动回收,最终导致Entry整体无法被回收机制回收。最终导致线程池中的线程因ThreadLocalMap未清理而出现内存泄漏。解决方法是手动调用ThreadLocal的remove()方法,清除Entry对象。
package com.sky.context;public class BaseContext {public static ThreadLocal<Long> threadLocal = new ThreadLocal<>();public static void setCurrentId(Long id) {threadLocal.set(id);}public static Long getCurrentId() {return threadLocal.get();}public static void removeCurrentId() {threadLocal.remove();}}
示例:
public class ThreadLocalExample {// 定义一个ThreadLocal变量private static final ThreadLocal<Integer> threadLocal = new ThreadLocal<>();public static void main(String[] args) {// 线程A设置值Thread threadA = new Thread(() -> {threadLocal.set(100); // 线程A的值为100System.out.println("线程A的值:" + threadLocal.get()); // 输出100});// 线程B尝试获取值Thread threadB = new Thread(() -> {System.out.println("线程B的值:" + threadLocal.get()); // 输出null(未设置时默认值)threadLocal.set(200); // 线程B的值为200System.out.println("线程B的值:" + threadLocal.get()); // 输出200});threadA.start();threadB.start();}
}
项目当中便可使用这个来存储用户的id值其可全局获取,并且不需要多次实例化对象,在jwt校验结束便可设置。
5 @JSONFormat
在业务需求当中可能会出现前端给我们传递过来的时间参数,其格式不一定符合我们变量的格式。
因此我们需要对前端的时间参数进行格式化,将前端传递的参数指定为pattern当中的参数格式。
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")private LocalDateTime createTime;
6 基于注解和AOP的公共字段填充
在业务开发中,由于存在大量数据表且字段重叠较多,我们可以使用AOP技术结合注解技术对公共字段进行填充,从而减少代码的冗杂性。
首先,我们需要创建一个自定义注解,用于标记需要自动填充公共字段的方法。
注解:AutoFill
注解的目的作用在Mapper业务层,对那些需要对数据库操作的进行字段填充。
package com.sky.annotation;import com.sky.enumeration.OperationType;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;/*** 自定义注解,用于标识需要自动填充的字段*/// 标识在方法上
@Target(ElementType.METHOD)
// 标识在运行时
@Retention(RetentionPolicy.RUNTIME)
public @interface AutoFill {//数据库操作类型 UPDATE INSERTOperationType value();}
然后,AOP切面拦截这些注解的方法
切面:AutoFillAspect
使用的是前置通知,目标方法执行前自动调用,拦截带有@AutoFill的方法,业务当中通过反射的思想进行字段赋值。
package com.sky.aspect;import com.sky.annotation.AutoFill;
import com.sky.constant.AutoFillConstant;
import com.sky.context.BaseContext;
import com.sky.enumeration.OperationType;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;import java.lang.reflect.Method;
import java.time.LocalDateTime;/*** 自定义切面,用于自动填充公共字段处理逻辑*/@Aspect
@Component
@Slf4j
public class AutoFillAspect {/*** 切入点表达式 com.sky.mapper 包下的所有类中的所有方法并且有 @AutoFill 注解的方法*/@Pointcut("execution(* com.sky.mapper.*.*(..)) && @annotation(com.sky.annotation.AutoFill)")public void autoFillPointCut() {}/*** 前置通知,在目标方法执行前执行*/@Before("autoFillPointCut()")public void autoFill(JoinPoint joinPoint) {log.info("开始进行公共字段自动填充...");// 通过方法签名获取方法上的注解MethodSignature signature = (MethodSignature) joinPoint.getSignature();AutoFill autoFill = signature.getMethod().getAnnotation(AutoFill.class); // 关键修改if (autoFill == null) {log.info("当前方法没有 @AutoFill 注解,不需要自动填充");return;}OperationType operationType = autoFill.value();//数据库操作类型//获取当前杯拦截的方法的参数--实体对象Object[] args = joinPoint.getArgs();if (args == null || args.length == 0) {log.info("当前方法没有参数,不需要自动填充");return;}Object entity = args[0];log.info("当前自动填充的实体对象:{}", entity.toString());//准备赋值的数据LocalDateTime now = LocalDateTime.now();Long currentId = BaseContext.getCurrentId();log.info("当前操作的用户id:{}", currentId);//根据当前不同的操作类型,为对应的实体对象通过反射来赋值if (operationType == OperationType.INSERT) {//四个公共字段:createTime、createUser、updateTime、updateUser赋值try {//获取当前实体类中的对应方法(使用本地的常量方法名)Method createTimeMethod = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_TIME, LocalDateTime.class);Method createUserMethod = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_USER, Long.class);Method updateTimeMethod = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);Method updateUserMethod = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);//通过反射为实体对象赋值createTimeMethod.invoke(entity, now);createUserMethod.invoke(entity, currentId);updateTimeMethod.invoke(entity, now);updateUserMethod.invoke(entity, currentId);log.info("为实体类 {} 赋值成功", entity);} catch (Exception e) {e.printStackTrace();}} else if (operationType == OperationType.UPDATE) {try {//两个公共字段:updateTime、updateUser赋值Method updateTimeMethod = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);Method updateUserMethod = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);updateTimeMethod.invoke(entity, now);updateUserMethod.invoke(entity, currentId);log.info("为实体类 {} 赋值成功", entity);} catch (Exception e) {e.printStackTrace();}}}
}
示例:(这段代码就实现了对公共字段的填充)
/*** 新增套餐** @param setmeal*/@AutoFill(OperationType.INSERT)void insert(Setmeal setmeal);
7 个人感悟
在初次接触项目时第一感觉就是觉得太复杂了,当时看见那么多的类文件,觉得自己肯定学不好也学不会,但是不断的接触才发现,是有其自己的一套方法,也是可以接受的,也能跟着照葫芦画瓢,其三层架构十分具有条理性的将代码进行分割将业务代码进行拆分,在这个项目当中解除了后端方面对基础业务CRUD的实现,同时也有一些常见开发规范的学习,以及小程序端的开发,实现前后端的联调实现业务的完整性,但是学习的过程也是有不足的很多实现的过程都是跟着老师进行开发的很多都没有由自己开发实现,自己单独分析接口文档进行接口编写的能力还是有所欠缺。在学习过程中也发现自己之前的遗漏点,也是一种学习的方法,遇到不会的再向前学习,再进行运用,
相关文章:

苍穹外卖心得体会
1 登录认证 技术点:JWT令牌技术(JSON Web Token) JWT(JSON Web Token)是一种令牌技术,主要由三部分组成:Header头部、Payload载荷和Signature签名。Header头部存储令牌的类型(如JW…...
Python爬虫实战:获取jd商城最新5060ti 16g显卡销量排行榜商品数据并做分析,为显卡选购做参考
一、引言 1.1 研究目的 本研究旨在利用 Python 爬虫技术,从京东商城获取 “5060ti 16g” 型号显卡的商品数据,并对这些数据进行深入分析。具体目标包括: 实现京东商城的模拟登录,突破登录验证机制,获取登录后的访问权限。高效稳定地爬取按销量排名前 20 的 “5060ti 16g…...
Fedora升级Google Chrome出现GPG check FAILED问题解决办法
https://dl.google.com/linux/linux_signing_key.pub 的 GPG 公钥(0x7FAC5991)已安装 https://dl.google.com/linux/linux_signing_key.pub 的 GPG 公钥(0xD38B4796)已安装 仓库 "google-chrome" 的 GPG 公钥已安装,但是不适用于此软件包。 请检查此仓库的…...
信息系统监理师第二版教材模拟题第三组(含解析)
信息系统监理师模拟题第三组(30题) 监理基础理论 信息系统工程监理的性质是( ) A. 服务性、独立性、公正性、科学性 B. 强制性、营利性、行政性、技术性 C. 临时性、从属性、随意性、主观性 D. 单一性、封闭性、被动性、保守性答案:A 解析:监理具有服务性、独立性、公正…...

Zcanpro搭配USBCANFD-200U在新能源汽车研发测试中的应用指南(周立功/致远电子)
——国产工具链的崛起与智能汽车测试新范式 引言:新能源汽车测试的国产化突围 随着新能源汽车智能化、网联化程度的提升,研发测试面临三大核心挑战:多协议融合(CAN FD/LIN/以太网)、高实时性数据交互需求、复杂工况下…...

青少年抑郁症患者亚群结构和功能连接耦合的重构
目录 1 研究背景及目的 2 研究方法 2.1 数据来源与参与者 2.1.1 MDD患者: 2.1.2 健康对照组: 2.2 神经影像分析流程 2.2.1 图像采集与预处理: 2.2.2 网络构建: 2.2.3 区域结构-功能耦合(SC-FC耦合)…...

SQL手工注入(DVWA)
手工SQL注入攻击的标准思路 Low等级 (1)判断是否存在注入 (2)猜解字段个数 (3)确定字段顺序 (4)获取当前数据库 (5)获取当前数据库中的表 (…...

【大模型系列篇】Qwen3开源全新一代大语言模型来了,深入思考,更快行动
Qwen3开源模型全览 Qwen3是全球最强开源模型(MoEDense) Qwen3 采用混合专家(MoE)架构,总参数量 235B,激活仅需 22B。 Qwen3 预训练数据量达 36T,并在后训练阶段多轮强化学习,将非思…...
第 11 届蓝桥杯 C++ 青少组中 / 高级组省赛 2020 年真题,选择题详细解释
一、选择题 第 2 题 在二维数组按行优先存储的情况下,元素 a[i][j] 前的元素个数计算如下: 1. **前面的完整行**:共有 i 行,每行 n 个元素,总计 i * n 个元素。 2. **当前行的前面元素**:在行内&#x…...

flutter 专题 一百零四 Flutter环境搭建
Flutter简介 Flutter 是Google开发的一个移动跨平台(Android 和 iOS)的开发框架,使用的是 Dart 语言。和 React Native 不同的是,Flutter 框架并不是一个严格意义上的原生应用开发框架。Flutter 的目标是用来创建高性能、高稳定性…...
Android之Button、ImageButton、ChipGroup用法
一 控件名称及UI代码 Button、ImageButton、ChipGroup <?xml version="1.0" encoding="utf-8"?> <androidx.coordinatorlayout.widget.CoordinatorLayoutxmlns:android="http://schemas.android.com/apk/res/android"xmlns:app=&qu…...
【AI提示词】二八法则专家
提示说明 精通二八法则(帕累托法则)的广泛应用,擅长将其应用于商业、管理、个人发展等领域,深入理解其在不同场景中的具体表现和实际意义。 提示词 # Role: 二八法则专家## Profile - language: 中文 - description: 精通二八法…...

玩玩OCR
一、Tesseract: 1.下载windows版: tesseract 2. 安装并记下路径,等会要填 3.保存.py文件 import pytesseract from PIL import Image def ocr_local_image(image_path):try:pytesseract.pytesseract.tesseract_cmd rD:\Programs\Tesseract-OCR\tesse…...
set autotrace报错
报错: SQL> set autotrace traceonly SP2-0618: Cannot find the Session Identifier. Check PLUSTRACE role is enabled SP2-0611: Error enabling STATISTICS report原因分析: 根据上面的错误提示“SP2-0618: Cannot find the Session Identifie…...
C++如何设计和实现缓存(cache)来减少对后端存储的访问压力
随着数据量的激增和用户对低延迟、高吞吐量需求的不断提升,如何减少系统瓶颈、提升响应速度成为了开发者的核心挑战之一。在这一背景下,缓存(cache)作为一种关键的技术手段,逐渐成为解决性能问题的核心策略。缓存的本质是通过存储频繁访问的数据或计算结果,减少对后端存储…...

“Everything“工具 是 Windows 上文件名搜索引擎神奇
01 Everything 和其他搜索引擎有何不同 轻量安装文件。 干净简洁的用户界面。 快速文件索引。 快速搜索。 快速启动。 最小资源使用。 轻量数据库。 实时更新。 官网:https://www.voidtools.com/zh-cn/downloads/ 通过网盘分享的文件:Every…...

TIME_WAIT状态+UDP概念及模拟实现服务器和客户端收发数据
目录 一、TIME_WAIT状态存在的原因 二、TIME_WAIT状态存在的意义 三、TIME_WAIT状态的作用 四、UDP的基本概念 4.1 概念 4.2 特点 五、模拟实现UDP服务器和客户端收发数据 5.1 服务器udpser 5.2 客户端udpcil 一、TIME_WAIT状态存在的原因 1.可靠的终止TCP连接。 2.…...
Rust 学习笔记:关于枚举与模式匹配的练习题
Rust 学习笔记:关于枚举与模式匹配的练习题 Rust 学习笔记:关于枚举与模式匹配的练习题以下程序能否通过编译?若能,输出是什么?考虑这两种表示结果类型的方式,若计算成功,则包含值 T;…...
快速了解Go+微服务(概念和一个例子)
更多个人笔记:(仅供参考,非盈利) gitee: https 文章目录 基本概念grpc和简单demo 基本概念 特点: 单一职责:一个服务用来解决一个业务问题面向服务:一个服务封装并对外提供服务&am…...

一篇撸清 Http,SSE 与 WebSocket
HTTP,SSE 和WebSocket都是网络传输的协议,本篇快速介绍三者的概念和比较。 SSE(Server-Sent Events) 是什么? SSE(Server-Sent Events),服务器发送事件, 是一种基于 HTTP 的轻量级协议,允许服务器主动向客户端(如浏览器)推送实时数据。它设计用于单向通信(服务器到…...

56、【OS】【Nuttx】编码规范解读(四)
背景 接之前 blog 53、【OS】【Nuttx】编码规范解读(一) 54、【OS】【Nuttx】编码规范解读(二) 55、【OS】【Nuttx】编码规范解读(三) 分析了行宽格式,注释要求,花括号风格等&#…...

IOT项目——DIY 气象站
开源项目:ESP32 气象站 作者:GiovanniAggiustatutto 原文链接:原文 开源项目:太阳能 WiFi 气象站 V4.0 作者:opengreenenergy 原文链接:原文 DIY 气象站 简介1-制版2-物料 温度设备塔风向标风速计雨量计框…...

MODSIM选型指南:汽车与航空航天企业如何选择仿真平台
1. 引言 在竞争激烈的汽车与航空航天领域,仿真技术已成为产品研发不可或缺的环节。通过在设计阶段验证概念并优化性能,仿真平台能有效缩短开发周期并降低物理样机制作成本。 MODSIM(建模与仿真)作为达索系统3DEXPERIENCE平台的核…...

【JavaEE】springMVC返回Http响应
目录 一、返回页面二、Controller和ResponseBody与RestController区别三、返回HTML代码⽚段四、返回JSON五、HttpServletResponse设置状态码六、设置Header6.1 HttpServletResponse设置6.2 RequestMapping设置 一、返回页面 步骤如下: 我们先要在static目录下创建…...

计算机网络八股文--day4 --传输层TCP与UDP
这是面试中最常考到的一层:端到端(也就是进程之间)的透明数据传输服务,差错控制和流量控制 该层呈上启下,像上面的资源子网提高服务,并使用下面通信子网的服务 端口,用于唯一标识主机上进程的&…...

个人开发免费好用
聊一聊 现在输入法非常多,有时候都不知道哪个更好用。 其实,只有多尝试,才能找到适合自己的。 今天给大家分享一款输入法,用起来比较顺手,大家可以试试。 软件介绍 BL输入法 这是一款绿色纯净,安全放心…...

[随笔] 升级uniapp旧项目的vue、pinia、vite、dcloudio依赖包等
汇总 # 升级uniapp项目dcloudio整体依赖,建议执行多次 # 会顺带自动更新/升级vue的版本 npx dcloudio/uvmlatest alpha# 检查 pinia 的最新版本 npm view pinia version# 更新项目 pinia 到最新版本 npm update pinia# 更新项目 pinia 到特定的版本 # 首先…...

第十六届蓝桥杯 2025 C/C++组 密密摆放
目录 题目: 题目描述: 题目链接: 思路: 思路详解: 发个牢骚: 代码: 代码详解: 题目: 题目描述: 题目链接: P12337 [蓝桥杯 2025 省 AB/Python B 第二…...

【QT】QT中的网络编程(TCP 和 UDP通信)
QT中的网络编程(TCP 和 UDP通信) 1.tcp1.1 tcp通信1.1.1 相比linux中tcp通信:1.1.2 QT中的tcp通信: 1.2 tcp通信流程1.2.1 服务器流程:1.2.1.1 示例代码1.2.1.2 现象 1.2.2 客户端流程:1.2.2.1 示例代码1.2.2.2 现象: …...
Spring MVC @RequestBody 注解怎么用?接收什么格式的数据?
RequestBody 注解的作用 RequestBody 将方法上的参数绑定到 HTTP 请求的 Body(请求体)的内容上。 当客户端发送一个包含数据的请求体(通常在 POST, PUT, PATCH 请求中)时,RequestBody 告诉 Spring MVC 读取这个请求体…...