手写mybatis拦截器自动填充数据

文章目录

  • 🌞 Sun Frame:SpringBoot 的轻量级开发框架(个人开源项目推荐)
    • 🌟 亮点功能
    • 📦 spring cloud模块概览
      • 常用工具
    • 🔗 更多信息
    • 1.将sun-club-subject模块的登录拦截器放到sun-club-common包中
        • 1.将context包和LoginUtil放到common包中,这样其他的子模块也可以获取loginId
        • 2.修改一个bug,当不使用网关请求时,空指针异常 LoginInterceptor.java
    • 2.sun-club-infra 编写MybatisInterceptor.java 对通用字段进行填充
        • 1.MybatisInterceptor.java
        • 2.测试

🌞 Sun Frame:SpringBoot 的轻量级开发框架(个人开源项目推荐)

Sun Frame Banner

轻松高效的现代化开发体验

Sun Frame 是我个人开源的一款基于 SpringBoot 的轻量级框架,专为中小型企业设计。它提供了一种快速、简单且易于扩展的开发方式。

我们的开发文档记录了整个项目从0到1的任何细节,实属不易,请给我们一个Star!🌟
您的支持是我们持续改进的动力。

🌟 亮点功能

  • 组件化开发:灵活选择,简化流程。
  • 高性能:通过异步日志和 Redis 缓存提升性能。
  • 易扩展:支持多种数据库和消息队列。

📦 spring cloud模块概览

  • Nacos 服务:高效的服务注册与发现。
  • Feign 远程调用:简化服务间通信。
  • 强大网关:路由与限流。

常用工具

  • 日志管理:异步处理与链路追踪。
  • Redis 集成:支持分布式锁与缓存。
  • Swagger 文档:便捷的 API 入口。
  • 测试支持:SpringBoot-Test 集成。
  • EasyCode:自定义EasyCode模板引擎,一键生成CRUD。

🔗 更多信息

  • 开源地址:Gitee Sun Frame
  • 详细文档:语雀文档
    在这里插入图片描述

1.将sun-club-subject模块的登录拦截器放到sun-club-common包中

1.将context包和LoginUtil放到common包中,这样其他的子模块也可以获取loginId

image-20240621141949336

2.修改一个bug,当不使用网关请求时,空指针异常 LoginInterceptor.java

image-20240621142147066

2.sun-club-infra 编写MybatisInterceptor.java 对通用字段进行填充

1.MybatisInterceptor.java
package com.sunxiansheng.subject.infra.config;import com.sunxiansheng.subject.common.util.LoginUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.plugin.*;
import org.springframework.stereotype.Component;import java.lang.reflect.Field;
import java.util.*;/*** Description: 填充created_by、created_time、update_by、update_time、is_deleted等公共字段的拦截器* @Author sun* @Create 2024/6/21 14:23* @Version 1.0*/
@Component
@Slf4j
// sql拦截器常规配置
@Intercepts({@Signature(type = Executor.class, method = "update", args = {MappedStatement.class,Object.class
})})
public class MybatisInterceptor implements Interceptor {@Overridepublic Object intercept(Invocation invocation) throws Throwable {MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];// 获取sql的类型SqlCommandType sqlCommandType = mappedStatement.getSqlCommandType();// 获取sql的参数对象Object parameter = invocation.getArgs()[1];// 如果参数对象为空,就直接放行if (parameter == null) {return invocation.proceed();}// 获取当前用户登录的idString loginId = LoginUtil.getLoginId();if (StringUtils.isBlank(loginId)) {return invocation.proceed();}// 如果sql的类型是插入或者更新,对参数做替换,填充created_by、created_time、update_by、update_time、is_deletedif (SqlCommandType.INSERT == sqlCommandType || SqlCommandType.UPDATE == sqlCommandType) {replaceEntityProperty(parameter, loginId, sqlCommandType);}// 放行return invocation.proceed();}// 填充created_by、created_time、update_by、update_time、is_deletedprivate void replaceEntityProperty(Object parameter, String loginId, SqlCommandType sqlCommandType) {if (parameter instanceof Map) {// Map类型,就相当于批量插入的那种情况replaceMap((Map) parameter, loginId, sqlCommandType);} else {// 普通的eneity类型replace(parameter, loginId, sqlCommandType);}}private void replaceMap(Map parameter, String loginId, SqlCommandType sqlCommandType) {// 获取到所有的参数对象Collection values = parameter.values();for (Object value : values) {// 将每个参数对象都进行替换replace(value, loginId, sqlCommandType);}}/*** 填充数据的逻辑* @param parameter* @param loginId* @param sqlCommandType*/private void replace(Object parameter, String loginId, SqlCommandType sqlCommandType) {// 如果是插入类型的sqlif (SqlCommandType.INSERT == sqlCommandType) {dealInsert(parameter, loginId);} else {// 由于只有插入类型和更新类型的sql类型会走到这里,所以这里一定就是更新类型了dealUpdate(parameter, loginId);}}/*** 更新类型的sql,填充数据的方式,对update_by、update_time进行填充* @param parameter* @param loginId*/private void dealUpdate(Object parameter, String loginId) {// 获取这个对象对应类的所有字段Field[] allFields = getAllFields(parameter);// 遍历字段for (Field field : allFields) {// 使用try-catch捕捉异常,使其不影响主程序的执行try {// 设置这个字段为可访问的field.setAccessible(true);// 得到字段的值,后面指定对象Object o = field.get(parameter);if (Objects.nonNull(o)) {// 如果字段的值不是空的,将这个字段设置成不可访问的field.setAccessible(false);// 然后跳过这次循环,遍历下一个字段continue;}// 如果字段的值是空的,则根据字段的名字来填充数据if ("updateBy".equals(field.getName())) {// 设置为用户的loginIdfield.set(parameter, loginId);// 设置字段为不可访问field.setAccessible(false);} else if ("updateTime".equals(field.getName())) {// 设置为当前时间field.set(parameter, new Date());// 设置字段为不可访问field.setAccessible(false);} else {// 如果不是这三个字段,就直接将这个字段设置为不可访问,然后遍历下一个字段field.setAccessible(false);}} catch (Exception e) {log.error("dealInsert.error:{}", e.getMessage(), e);}}}/*** 插入类型的sql,填充数据的方式,对created_by、created_time、is_deleted进行填充* @param parameter* @param loginId*/private void dealInsert(Object parameter, String loginId) {// 获取这个对象对应类的所有字段Field[] allFields = getAllFields(parameter);// 遍历字段for (Field field : allFields) {// 使用try-catch捕捉异常,使其不影响主程序的执行try {// 设置这个字段为可访问的field.setAccessible(true);// 得到字段的值,后面指定对象Object o = field.get(parameter);if (Objects.nonNull(o)) {// 如果字段的值不是空的,将这个字段设置成不可访问的field.setAccessible(false);// 然后跳过这次循环,遍历下一个字段continue;}// 如果字段的值是空的,则根据字段的名字来填充数据if ("isDeleted".equals(field.getName())) {// 默认设置为0,即未删除field.set(parameter, 0);// 设置字段为不可访问field.setAccessible(false);} else if ("createdBy".equals(field.getName())) {// 设置为用户的loginIdfield.set(parameter, loginId);// 设置字段为不可访问field.setAccessible(false);} else if ("createdTime".equals(field.getName())) {// 设置为当前时间field.set(parameter, new Date());// 设置字段为不可访问field.setAccessible(false);} else {// 如果不是这三个字段,就直接将这个字段设置为不可访问,然后遍历下一个字段field.setAccessible(false);}} catch (Exception e) {log.error("dealInsert.error:{}", e.getMessage(), e);}}}/*** 反射获取类的所有字段,并以字段数组的形式返回* @param object* @return*/private Field[] getAllFields(Object object) {// 获取当前对象对应类的Class对象Class<?> clazz = object.getClass();// 使用一个列表存储该类的所有字段信息List<Field> fieldList = new ArrayList<>();while (clazz != null) {// 将字段信息放到字段列表中fieldList.addAll(new ArrayList<>(Arrays.asList(clazz.getDeclaredFields())));// clazz指向父类clazz = clazz.getSuperclass();}// 循环完成后,就会将当前的对象对应的类以及父类的字段对象放到字段列表中// 创建一个Field类型的数组,大小跟字段列表相同Field[] fields = new Field[fieldList.size()];// 将字段列表的元素放到数组中fieldList.toArray(fields);return fields;}@Overridepublic Object plugin(Object target) {// 返回一个代理对象,用于在方法调用时进行拦截处理return Plugin.wrap(target, this);}@Overridepublic void setProperties(Properties properties) {// 不需要任何处理}}
2.测试

image-20240621162204922

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

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

相关文章

Prometheus+Grafana保姆笔记(1)——Prometheus+Grafana的安装

Prometheus Grafana 的组合在微服务项目中可以完成许多DevOps任务&#xff0c;它们共同提供了强大的监控和可视化功能。 我们陆续介绍Prometheus Grafana 的相关用法。 首先介绍PrometheusGrafana的安装。 安装 Prometheus Prometheus 是GO写的&#xff0c;并不依赖于 Ja…

HIT CSAPP——程序人生-Hello’s P2P

本文链接&#xff1a;https://blog.csdn.net/QingFeng_0813/article/details/139468749?spm1001.2014.3001.5502 计算机系统 大作业 题 目 程序人生-Hello’s P2P 专 业 医学与健康学院 学   号 2022110762 班 级 2252003 …

(回溯) LeetCode 47. 全排列||

原题链接 建议先练习&#xff1a;全排列| 一. 题目描述 给定一个可包含重复数字的序列 nums &#xff0c;按任意顺序 返回所有不重复的全排列。 示例 1&#xff1a; 输入&#xff1a;nums [1,1,2] 输出&#xff1a; [[1,1,2],[1,2,1],[2,1,1]]示例 2&#xff1a; 输入&a…

Java流程控制01:用户交互Scanner

本节教学视频链接&#xff1a;https://www.bilibili.com/video/BV12J41137hu?p33&vd_sourceb5775c3a4ea16a5306db9c7c1c1486b5https://www.bilibili.com/video/BV12J41137hu?p33&vd_sourceb5775c3a4ea16a5306db9c7c1c1486b5 Scanner 类用于扫描输入文本从字符串中提…

Bug 解决 | 组件库报错、或样式丢失不生效

目录 一、前言 二、版本问题 1、使用 VantUI 的 toast 组件报错&#xff1f; 2、引入 VantUI 组件库后&#xff0c;toast 组件样式丢失了&#xff1f; 3、使用 Ant Design Vue 组件库&#xff0c;启动后显示 antd.css 不存在&#xff1f; 4、Vant UI 组件库引入的 tabs 组…

数据中心安全建设整体解决方案(DOC原件22页)

数据中心的安全体系建设并非安全产品的堆砌&#xff0c;它是一个根据用户具体业务环境、使用习惯、安全策略要求等多个方面构建的一套生态体系&#xff0c;涉及众多的安全技术&#xff0c;实施过程需要涉及大量的调研、咨询等工作&#xff0c;还会涉及到众多的安全厂家之间的协…

LangChain 推出 LangGraph Studio:首款用于可视化、交互和调试复杂代理应用的代理 IDE

嘿&#xff0c;听说了吗&#xff1f;Langchain最近发布了一项重大更新&#xff0c;他们推出了官方Agent IDE&#xff0c;并且免费开放了LangGraph平台。这对于AI开发者来说是个好消息&#xff0c;意味着我们现在有了更强大的工具来构建智能应用。 今天&#xff0c;我们就来分享…

编译自定义Linux内核,使WSL支持访问Windows下USB设备

版权归作者所有&#xff0c;如有转发&#xff0c;请注明文章出处&#xff1a;https://cyrus-studio.github.io/blog/ WSL 本身并不支持连接 USB 设备&#xff0c;因此你需要安装开源 usbipd-win 项目。 usbip 可以让你在网络上共享和使用 USB 设备。它由两个主要组件组成&…

一个Indie Hacker的微SaaS技术栈

如今&#xff0c;可用的技术非常多&#xff0c;我们每个月都会看到各种新的 JS 框架发布&#xff0c;有时&#xff0c;如果你一开始没有选择正确的技术堆栈&#xff0c;以后扩展起来就会很困难。因此&#xff0c;在今天的文章中&#xff0c;我将与你分享我用于开发微型 SaaS 的…

分布式存储ceph知识点整理

一、Ceph概述 如何选择存储 底层协议兼容性产品要有定位&#xff0c;功能有所取舍针对特定市场的应用存储被市场认可的存储系统 稳定性是第一位的性能第二数据功能要够用 一&#xff09;存储分类 1、本地存储 本地的文件系统&#xff0c;不能在网络上用。 如&#xff1a;ext3、…

Python图像背景去除

目录 &#x1f381;库的导入 &#x1f380;库的安装 &#x1f381;rembg库去除背景 &#x1f381;效果 &#x1f381;文末彩蛋 今天来介绍一个特别有趣的python库&#xff0c;rembg库&#xff0c;全称是“Remove Background”的缩写&#xff0c;意为“去除背景”&#xff…

内存泄漏工具valgrind初使用

工具下载&#xff1a; sudo apt install valgrind简单使用流程&#xff1a; 编写源文件编译&#xff08;-g方式&#xff09;valgrind使用memcheck工具运行程序 编写文件&#xff1a; #include <stdlib.h> #include <sys/types.h> #include <unistd.h> #i…

Github 2024-08-12 开源项目日报 Top10

根据Github Trendings的统计,今日(2024-08-12统计)共有10个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量Python项目3Java项目2JavaScript项目1TypeScript项目1Vue项目1Clojure项目1Dockerfile项目1HTML项目1C项目1Jupyter Notebook项目1Node.js最佳实…

【秋招笔试】2024-08-07-YT游戏(研发岗)-三语言题解(CPP/Python/Java)

🍭 大家好这里是 春秋招笔试突围,一起备战大厂笔试 💻 ACM金牌团队🏅️ | 多次AK大厂笔试 | 编程一对一辅导 ✨ 本系列打算持续跟新 秋招笔试题 👏 感谢大家的订阅➕ 和 喜欢💗 和 手里的小花花🌸 ✨ 笔试合集传送们 -> 🧷春秋招笔试合集 本次的题目比较典,…

docker的swarm技术

docker中swarm技术 docker swarm技术是docker社区提供的docker的集群管理调度工具&#xff0c;通过api来管理多个主机上的docker&#xff0c;通过overlay网络来实现不同主机之间容器的通信与访问。实现容器的调度&#xff0c;资源的分配&#xff0c;以及副本。 docker swarm中…

Keepalived超详解,里面有你最爱看的Keepalived+LVS与Keepalived+HAProxy

文章目录 VRRPVRRP相关术语VRRP相关技术 keepalived介绍keepalived环境准备keepalived配置说明全局配置虚拟路由器配置开启通信功能启用keepalived日志实现独立子配置文件 keepalived企业应用实例抢占模式和非抢占模式非抢占模式延迟抢占模式 VIP单播模式keepalived通知脚本配置…

JVM知识总结(CMS收集器)

文章收录在网站&#xff1a;http://hardyfish.top/ 文章收录在网站&#xff1a;http://hardyfish.top/ 文章收录在网站&#xff1a;http://hardyfish.top/ 文章收录在网站&#xff1a;http://hardyfish.top/ CMS收集器 CMS&#xff08;Concurrent Mark Sweep&#xff09;收集…

14.3 Matplotlib与Seaborn数据可视化

欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;欢迎订阅相关专栏&#xff1a; 工&#x1f497;重&#x1f497;hao&#x1f497;&#xff1a;野老杂谈 ⭐️ 全网最全IT互联网公司面试宝典&#xff1a;收集整理全网各大IT互联网公司技术、项目、HR面试真题.…

tiktok 搜索接口请求与翻页

这几天有小伙伴问tk的搜索接口的问题, 一个是搜索热门接口请求返回 {“status_code”: 0},这个使用curl_cffi的requests库改一下指纹请求就行了。 再一个就是翻页问题 细心一些比对一下翻页参数都能做到的(小伙伴以为只改个offset就完事了) 要不然你只能得到这样的结果:…

音视频概要

YUV原理的讲解 YUV是一种常见的视频像素格式&#xff0c;经常用在视频编解码上面&#xff0c;YUV分别由Y分量和U、V分量(红色投影Cr)组成。Y分量指的是亮度分量&#xff0c;也就是我们经常说的灰阶值&#xff0c;相当于一副灰色的图像。而U分量和V分量表示的是色度分量&#x…