重生之外卖配送时被投诉后的反思
重生之外卖配送时被投诉后的反思
写苍穹外卖时 我们发现在每一次调用sql语句时 insert update语句总会需要在service的实现类里加入例如create_time,create_user , update_time , update_user的填充 每次赋值都要重新编写代码,会造成代码冗余 ;
序号 | 字段名 | 含义 | 数据类型 |
---|---|---|---|
1 | create_time | 创建时间 | datetime |
2 | create_user | 创建人id | bigint |
3 | update_time | 修改时间 | datetime |
4 | update_user | 修改人id | bigint |
那我们有什么解决办法呢 很容易想到我们之前用的aop的通知应用实例 也就是在执行mapper层的方法前先被aop切面拦截下来 通过切面对公共字段填充(反射赋值)具体操作如下
实现 :
- 自定义注解AutoFill,用于表示需要进行公共自读那自动填充的方法
- 自定义切面类,统一拦截加入了AutoFill注解的方法,通过反射为公共字段赋值。
- 在Mapper的方法上加入AutoFill注解。
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 {//insert updateOperationType value();
}
import java.lang.reflect.Method;
import java.time.LocalDateTime;@Aspect
@Slf4j
@Component
public class AutoFillAspect {@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);OperationType operationType = autoFill.value();//获取当前被拦截方法的参数列表Object[] args = joinPoint.getArgs();if (args == null || args.length == 0) {return;}Object target = args[0];//准备数据LocalDateTime now = LocalDateTime.now();Long currentId = BaseContext.getCurrentId();if(operationType == OperationType.INSERT){try {Method setCreateTime = target.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_TIME, LocalDateTime.class);Method setCreateUser = target.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_USER, Long.class);Method setUpdateTime = target.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);Method setUpdateUser = target.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);setCreateTime.invoke(target,now);setCreateUser.invoke(target,currentId);setUpdateTime.invoke(target,now);setUpdateUser.invoke(target,currentId);} catch (Exception e) {throw new RuntimeException(e);}}else if (operationType == OperationType.UPDATE){try {Method setUpdateTime = target.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);Method setUpdateUser = target.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);setUpdateTime.invoke(target,now);setUpdateUser.invoke(target,currentId);} catch (Exception e) {throw new RuntimeException(e);}}}
}
package com.sky.constant;/*** 公共字段自动填充相关常量*/
public class AutoFillConstant {/*** 实体类中的方法名称*/public static final String SET_CREATE_TIME = "setCreateTime";public static final String SET_UPDATE_TIME = "setUpdateTime";public static final String SET_CREATE_USER = "setCreateUser";public static final String SET_UPDATE_USER = "setUpdateUser";
}
package com.sky.enumeration;/*** 数据库操作类型*/
public enum OperationType {/*** 更新操作*/UPDATE,/*** 插入操作*/INSERT}
package com.sky.mapper;import com.github.pagehelper.Page;
import com.sky.annotation.AutoFill;
import com.sky.enumeration.OperationType;
import com.sky.dto.CategoryPageQueryDTO;
import com.sky.entity.Category;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;@Mapper
public interface CategoryMapper {/*** 插入数据* @param category*/@AutoFill(OperationType.INSERT)@Insert("insert into category(type, name, sort, status, create_time, update_time, create_user, update_user)" +" VALUES" +" (#{type}, #{name}, #{sort}, #{status}, #{createTime}, #{updateTime}, #{createUser}, #{updateUser})")void insert(Category category);/*** 分页查询* @param categoryPageQueryDTO* @return*/Page<Category> pageQuery(CategoryPageQueryDTO categoryPageQueryDTO);/*** 根据id删除分类* @param id*/@Delete("delete from category where id = #{id}")void deleteById(Long id);/*** 根据id修改分类* @param category*/@AutoFill(OperationType.UPDATE)void update(Category category);/*** 根据类型查询分类* @param type* @return*/List<Category> list(Integer type);
}
注意事项
1. 切面与通知
切面(Aspect):
- 切面是一个类,其中包含了增强逻辑。它定义了切点和通知。
- 在这里,
AutoFillAspect
是一个切面类,定义了针对@AutoFill
注解的自定义操作。
通知(Advice):
- 通知是在切面类中的方法,用来在指定的切点执行增强操作。Spring AOP提供了多种通知类型(如
Before
、After
等)。 - 你使用了
@Before
注解,它会在目标方法执行之前执行自动填充逻辑。
2. 切点(Pointcut)
切点是指在执行过程中拦截哪些方法。在这里,通过@Pointcut
注解定义了切点:
@Pointcut("execution(* com.sky.mapper.*.*(..)) && @annotation(com.sky.annotation.AutoFill)")
public void autoFillPointCut(){
}
execution(* com.sky.mapper.*.*(..))
表示拦截com.sky.mapper
包中的所有方法。@annotation(com.sky.annotation.AutoFill)
表示只拦截带有@AutoFill
注解的方法。
这种结合了包路径和注解的切点表达式,可以让你精确地控制哪些方法需要进行自动填充。
3. 反射操作
在切面中,通过反射来动态调用方法填充公共字段:
Method setCreateTime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_TIME, LocalDateTime.class);
setCreateTime.invoke(entity, now);
- 使用反射获取目标方法(如
setCreateTime
)并通过invoke()
方法为对象的属性赋值。 - 反射可以使得代码不依赖具体的实现类字段和方法,而是通过方法名称动态调用,可以灵活地为不同实体类的字段赋值。
4. 注解的使用
在需要填充公共字段的方法上,使用@AutoFill
注解,指定操作类型(如INSERT
或UPDATE
):
@AutoFill(value = OperationType.INSERT)
void insert(Employee employee);
OperationType
枚举类型定义了两个操作:INSERT
和UPDATE
。根据不同的操作类型,切面类会调用不同的字段填充逻辑。INSERT
操作会填充四个字段(创建时间、创建用户、更新时间、更新用户),UPDATE
操作会填充两个字段(更新时间、更新用户)。
5. BaseContext的使用
BaseContext.getCurrentId()
用于获取当前的用户ID,在填充公共字段时,它会被用来填充“创建用户”或“更新用户”字段。确保这个方法能正确地获取到当前用户的ID。
利用新的线程来获取当前id并赋值 是很常见的不传参数的做法
相关文章:
重生之外卖配送时被投诉后的反思
重生之外卖配送时被投诉后的反思 写苍穹外卖时 我们发现在每一次调用sql语句时 insert update语句总会需要在service的实现类里加入例如create_time,create_user , update_time , update_user的填充 每次赋值都要重新编写代码,会造成代码冗余 ; 序号字…...
计算机基础复习资料整理
计算机基础复习资料整理 一、操作系统 (一)定义 操作系统(Operating System,OS)是介于计算机硬件和用户(程序或人)之间的接口。作为通用管理程序,它管理计算机系统中每个部件的活动…...
Profibus DP主站网关数据映射全解析!
Profibus DP主站网关数据映射全解析! 在工业自动化领域,Profibus DP主站网关作为一种关键的通讯设备,其数据映射的精准度和效率对整个控制系统的性能有着至关重要的影响。本文旨在深入探讨Profibus DP主站网关的数据映射过程,揭示…...
ocr-不动产权识别
目录 一、在阿里云申请ocr识别服务 二、创建springboot项目 三、后续 一、在阿里云申请ocr识别服务 在线体验:房产证图片上传 [阿里官方]不动产权证OCR文字识别_API专区_云市场-阿里云 (aliyun.com) 可以选择一毛500次这个 当然也可以白嫖100 下面有个在线调试…...
leetcode 198. House Robber
本题是动态规划问题。 第一步,明确并理解dp数组以及下标的含义 dp[i]表示从第0号房间一直到第i号房间(包含第i号房间)可以偷到的最大金额,具体怎么偷这里不考虑,第i1号及之后的房间也不考虑。换句话说,dp[i]也就是只考虑[0,i]号…...
【2025软考高级架构师】——软件架构设计(4)
摘要 本文主要介绍了几种软件架构设计相关的概念和方法。包括C2架构风格的规则,模型驱动架构(MDA)的起源、目标、核心模型及各模型之间的关系;软件架构复用的概念、历史发展、维度、类型及相关过程;特定领域架构&…...
分发饼干问题——用贪心算法解决
目录 一:问题描述 二:解决思路 贪心策略(C语言)算法复习总结3——贪心算法-CSDN博客 三:代码实现 四:复杂度分析 一:问题描述 分发饼干问题是一个经典的可以使用贪心算法解决的问题…...
深入详解MYSQL的MVCC机制
参考资料: 参考视频(注意第二个视频关于幻读的讲解是错误的,详情见本文) redoLog的结构详解 参考资料 学习内容: 1. MVCC要解决的问题 MVCC要解决的问题是,在不产生脏读等数据库问题的前提下,数据库的查询语句和更改语句不相互阻塞的情况; 在InnoDB中,MVCC仅仅存…...
DNS域名解析
目录 一.DNS 1.1DNS的简介 1.2DNS的背景 1.3DNS的架构 1.4实现DNS的方式 1.5DNS的查询类型 1.6DNS解析的基本流程 二.主从复制 2.1定义 2.2优缺点 三.DNS服务软件 3.1bind 3.1.1定义 3.1.2bind相关文件 3.2DNS服务器的核心文件 3.2.1主配置文件 3.2.2域名文件 …...
Java基础:一文讲清多线程和线程池和线程同步
01-概述 02-线程创建 继承Thread 实现Runnable(任务对象) 实现Callable接口 public class ThreadDemo3 {public static void main(String[] args) throws ExecutionException, InterruptedException {// 目标:线程创建3// 需求:求1-100的和Callable<…...
ubuntu 20.04 连不上蓝牙耳机/蓝牙鼠标
sudo gedit /etc/bluetooth/main.conf改为 ControllerMode dual然后重启蓝牙服务 sudo service bluetooth restart...
SaaS、Paas、IaaS、MaaS、BaaS五大云计算服务模式
科普版:通俗理解五大云计算服务模式 1. SaaS(软件即服务) 一句话解释:像“租用公寓”,直接使用现成的软件,无需操心维护。 案例:使用钉钉办公、在网页版WPS编辑文档。服务提供商负责软件更新和…...
【深拷贝、浅拷贝】golang函数参数传递,变量复制后,操作变量参数,是否影响原有数据?全面解析
Golang中深拷贝与浅拷贝的详细解析,以及变量复制、函数参数传递等场景下对新旧变量影响的总结: 一拷贝与浅拷贝的核心区别 1. 浅拷贝(Shallow Copy) • 定义:仅复制数据的顶层结构,对引用类型字段&#x…...
c语言编程经典习题详解3
21. 求给定正整数 n 以内的素数之积 定义:找出小于给定正整数n的所有素数,并将它们相乘。要点:使用双层for循环,外层循环遍历小于n的数,内层循环判断是否为素数,若是则累乘。应用:在数论研究、密码学等领域有应用。c #include <stdio.h>int isPrime(int num) {if…...
【HD-RK3576-PI】Docker搭建与使用
硬件:HD-RK3576-PI 软件:Linux6.1Ubuntu22.04 1. 安装Docker Docker安装脚本下载: roothd-rk3576-pi:~ $ curl -fsSL https://test.docker.com -o test-docker.sh 可以直接执行安装 roothd-rk3576-pi:~ $ sh test-docker.sh 2. 配置国内镜…...
C++进阶——异常
目录 1、异常的概念及使用 1.1 异常的概念 1.2 异常的抛出和捕获 1.3 栈展开 1.4 查找匹配的处理代码 1.5 异常的重新抛出 1.6 异常的安全问题 1.7 异常的规范 2、标准库的异常(了解) 1、异常的概念及使用 1.1 异常的概念 C语言,出错了,就报错…...
Linux安装开源版MQTT Broker——EMQX服务器环境从零到一的详细搭建教程
零、EMQX各个版本的区别 EMQX各个版本的功能对比详情https://docs.emqx.com/zh/emqx/latest/getting-started/feature-comparison.html...
C++ 编程指南36 - 使用Pimpl模式实现稳定的ABI接口
一:概述 C 的类布局(尤其是私有成员变量)直接影响它的 ABI(应用二进制接口)。如果你在类中添加或修改了私有成员,即使接口不变,编译器生成的二进制布局也会变,从而导致 ABI 不兼容。…...
笔记本电脑突然无法开机电源灯亮但是屏幕无法点亮
现象 按电源键,电源灯点亮,屏幕没动静 风扇开始运转,然后一会儿就不转了;屏幕一直没动静,屏幕没有任何反应(没有系统启动画面,没有徽标显示,就一点反应也没用) 这个问…...
mongodb 4.0+多文档事务的实现原理
1. 副本集事务实现(4.0) 非严格依赖二阶段提交 MongoDB 4.0 在副本集环境中通过 全局逻辑时钟(Logical Clock) 和 快照隔离(Snapshot Isolation) 实现多文档事务,事务提交时通过…...
decompiled.class file bytecode version50(java 6)
idea运行项目报错,跳到具体的.class中,idea会给出提示下载源码,点击下载报错,具体报错信息我没记录了(反正就是无法看到源码) 解决方式: 1、网上说下载scala插件,重启idea即可 但是…...
CSS 列表样式学习笔记
CSS 列表样式提供了强大的功能,用于定制 HTML 列表的外观。通过 CSS,可以轻松地改变列表项的标记类型、位置,甚至使用图像作为列表项标记。以下是对 CSS 列表样式的详细学习笔记。 一、HTML 列表类型 在 HTML 中,主要有两种类型…...
linux网络设置
ifconfig 查看ip地址 查看当前的liunx系统的网络参数ip地址 Ubuntu需要安装 Apt install -y net-tools 查看网络信息 Ifconfig 只能看到开启的网卡 Ifconfig -a 看到所有的网卡包括开启和关闭的 Ifconfig 网卡名称 up 开启网卡 Ifconfig 网卡名称 down 关闭网卡 If…...
抗干扰CAN总线通信技术在分布式电力系统中的应用
摘要:随着分布式电力系统的广泛应用,其通信系统的可靠性与稳定性受到了前所未有的挑战。CAN总线通信技术以其卓越的抗干扰性能和可靠性,在众多通信技术中脱颖而出,成为解决分布式电力系统通信问题的关键。本文深入剖析了CAN总线通…...
Maven工具学习使用(十二)——extension和depency的区别
在 Maven 中,extensions 和 dependencies 是两个不同的概念,它们在项目构建和依赖管理中扮演着不同的角色。 1、Dependencies dependencies 是 Maven 项目中用于管理项目所需的库和模块的部分。这些依赖可以是本地仓库中的,也可以是远程仓库…...
Python学生信息查询
利用字典设置学生信息,将这些信息放入列表中进行存储,根据输入的姓名查询展示对应的学生信息。 Student1{no:202001,name:zyt,score:87} Student2Student1.copy() Student3Student2.copy()Student2[no]202002 Student3[no]202003Student2[name]zwh Stud…...
一天时间,我用AI(deepseek)做了一个配色网站
前言 最近在开发颜色搭配主题的相关H5和小程序,想到需要补充一个web网站,因此有了这篇文章。 一、确定需求 向AI要答案之前,一定要清楚自己想要做什么。如果你没有100%了解自己的需求,可以先让AI帮你理清逻辑和思路,…...
MQ(消息队列)体系详解
消息队列(MQ,Message Queue) 是一种基于消息传递的异步通信机制,用于不同系统、服务之间进行数据传递和交互。它通常用来解耦生产者和消费者,提供高可用、高吞吐量和可靠的消息传递。 一、消息队列用途 1.系统解耦 …...
【GESP真题解析】第 3 集 GESP一级样题卷编程题 2:闰年求和
大家好,我是莫小特。 这篇文章给大家分享 GESP 一级样题卷编程题第 2 题:闰年求和。 题目链接 洛谷链接:B3846 闰年求和 一、完成输入 根据题目要求,我们需要输入两个整数,分别表示起始年份和终止年份。 要求计算…...
Windows Server 2019 安装 Docker 完整指南
博主本人使用的是离线安装 1. 安装前准备 系统要求 操作系统:Windows Server 2019(或 2016/2022)权限:管理员权限的 PowerShell网络:可访问互联网(或离线安装包) 启用容器功能 Install-Win…...
JetBrains PhpStorm v2024.3.1 Mac PHP开发工具
JetBrains PhpStorm v2024.3.1 Mac PHP开发工具 一、介绍 JetBrains PhpStorm 2024 mac,是一款PHP开发工具,直接开始编码,无需安装和配置大量插件。PhpStorm 从一开始就已包含 PHP、JavaScript 和 TypeScript 开发所需的一切,还…...
机器学习(ML)在AI驱动测试通过数据驱动的智能决策显著提升测试效率、覆盖率和准确性。
机器学习(ML)在AI驱动测试中扮演着 核心引擎 的角色,通过数据驱动的智能决策显著提升测试效率、覆盖率和准确性。以下是机器学习在测试各环节的具体作用及实现方案: 一、机器学习在测试生命周期中的作用 #mermaid-svg-u4vgPE6O2jugiZFB {font-family:"trebuchet ms&qu…...
0x06.Redis 中常见的数据类型有哪些?
回答重点 Redis 常见的数据结构主要有五种,这五种类型分别为:String(字符串)、List(列表)、Hash、Set(集合)、Zset(有序集合,也叫sorted set)。 String 字符串是Redis中最基本的数据类型,可以存储任何类型的数据,包括文本、数字和二进制数据。它的最大长度为512MB。 使…...
本地缓存方案Guava Cache
Guava Cache 是 Google 的 Guava 库提供的一个高效内存缓存解决方案,适用于需要快速访问且不频繁变更的数据。 // 普通缓存 Cache<Key, Value> cache CacheBuilder.newBuilder().maximumSize(1000) // 最大条目数.expireAfterWrite(10, TimeUnit.MINUTES) /…...
A Causal Inference Look at Unsupervised Video Anomaly Detection
标题:无监督视频异常检测的因果推断视角 原文链接:https://ojs.aaai.org/index.php/AAAI/article/view/20053 发表:AAAI-2022 文章目录 摘要引言相关工作无监督视频异常检测因果推断 方法问题公式化一般设置强基线模型 无监督视频异常检测的因…...
MQ(RabbitMQ.1)
MQ的含义及面试题 MQMQ的含义MQ之间的调用的方式MQ的作用MQ的几种产品RabbitMQRabbitMQ的安装RabbitMQ的使用RabbitMQ⼯作流程 AMQPWeb界面操作用户相关操作虚拟主机相关操作 RabbitMQ的代码应用编写生产者代码编写消费者代码 生产者代码消费者代码 MQ MQ的含义 MQ࿰…...
cursor+高德MCP:制作一份旅游攻略
高德开放平台 | 高德地图API (amap.com) 1.注册成为开发者 2.进入控制台选择应用管理----->我的应用 3.新建应用 4.点击添加Key 5.在高德开发平台找到MCP的文档 6.按照快速接入的步骤,进行操作 一定要按照最新版的cursor, 如果之前已经安装旧的版本卸载掉重新安…...
FPGA时序分析与约束(11)——时钟组
目录 一、同步时钟与异步时钟 二、逻辑与物理独立时钟 2.1 逻辑独立时钟 2.2 物理独立时钟 三、如何设置时钟组 四、注意事项 专栏目录: FPGA时序分析与约束(0)——目录与传送门https://ztzhang.blog.csdn.net/article/details/134893…...
opencv 识别运动物体
import cv2 import numpy as npcap cv2.VideoCapture(video.mp4) try:import cv2backSub cv2.createBackgroundSubtractorMOG2() except AttributeError:backSub cv2.bgsegm.createBackgroundSubtractorMOG()#形态学kernel kernel cv2.getStructuringElement(cv2.MORPH_REC…...
opencv实际应用--银行卡号识别
OpenCV(Open Source Computer Vision Library)是一个开源的计算机视觉库,主要用于图像和视频处理、目标检测、特征提取、3D重建以及机器学习任务。它支持多种编程语言(如C、Python),提供丰富的算法和工具&a…...
【软考系统架构设计师】系统架构设计知识点
1、 从需求分析到软件设计之间的过渡过程称为软件架构。 软件架构为软件系统提供了一个结构、行为和属性的高级抽象,由构件的描述、构件的相互作用(连接件)、指导构件集成的模式以及这些模式的约束组成。 软件架构不仅指定了系统的组织结构和…...
GPT - 2 文本生成任务全流程
数据集下载 数据预处理 import json import pandas as pdall_data []with open("part-00018.jsonl",encoding"utf-8") as f:for line in f.readlines():data json.loads(line)all_data.append(data["text"])batch_size 10000for i in ran…...
重返JAVA之路——面向对象
目录 面向对象 1.什么是面向对象? 2.面向对象的特点有哪些? 3.什么是对象? 4.什么是类? 5.什么是构造方法? 6.构造方法的特性有哪些? 封装 1.什么是封装? 2.封装有哪些特点? 数据隐…...
docker 安装 jenkins
拉取镜像 docker pull jenkins/jenkins:2.426.3-lts-jdk17 创建数据卷 # 创建时即设置安全权限(SGID确保组权限继承) sudo mkdir -p /var/jenkins_home sudo chmod -R 777 /var/jenkins_home 拉取镜像并运行容器 # 生产环境推荐(JDK17…...
sql 向Java的映射
优化建议,可以在SQL中控制它的类型 在 MyBatis 中,如果返回值类型设置为 java.util.Map,默认情况下可以返回 多行多列的数据...
探索Streamlit在测试领域的高效应用:文档读取与大模型用例生成的完美前奏
大模型用例生成前置工作之文档读取——构建你的自动化测试基础 在群友的极力推荐下,开始了streamlit的学习之旅。本文将介绍如何使用Streamlit开发一个多功能文档处理工具,支持读取、预览、格式转换和导出多种测试相关文档(YAML、JSON、DOCX…...
Python中数值计算、表格处理和可视化的应用
1.数值计算:Numpy import numpy as np 1.1创建数组 import numpy as np arr1 np.array([[1,2,3,4,5]]) print(arr1) print(type(arr1)) print("数组形状",arr1.shape) arr2 np.array([[1,2,3],[2,3,4]]) print(arr2) print(type(arr1)) print("…...
【数据可视化艺术·实战篇】视频AI+人流可视化:如何让数据“动”起来?
景区游玩,密密麻麻全是人,想找个拍照的好位置都难;上下班高峰挤地铁,被汹涌的人潮裹挟着,只能被动 “随波逐流”。这样的场景,相信很多人都再熟悉不过。其实,这些看似杂乱无章的人群流动现象&am…...
038-flatbuffers
flatbuffers FlatBuffers技术调研报告 一、核心原理与优势 FlatBuffers通过内存直接访问技术实现零拷贝序列化,其核心优势如下: 内存布局:数据以连续二进制块存储,包含VTable(虚拟表)和Data Object&…...
探索 Go 与 Python:性能、适用场景与开发效率对比
1 性能对比:执行速度与资源占用 1.1 Go 的性能优势 Go 语言被设计为具有高效的执行速度和低资源占用。它编译后生成的是机器码,能够直接在硬件上运行,避免了 Python 解释执行的开销。 以下是一个用 Go 实现的简单循环计算代码: …...