springboot结合注解动态获取数据库表

1 对于分表的处理,可以通过Mybatis-Plus动态表名插件(DynamicTableNameInnerInterceptor)来实现,实现的思路主要如下:

自定义注解@MPShardingAnno来声明需要分表操作的方法,以及@Param声明需要进行补充表名的后缀。在注解解析器中,获取当前的表后缀存放到ThreadLocal中,在插件解析的时候从ThreadLocal中获取表后缀进行表名替换,等处理完后再释放对应的资源,出于扩展的考虑,还支持SpEL表达式

自定义注解import java.lang.annotation.*;@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Inherited
public @interface MPShardingAnno {/*** 获取分表日期的SpEL表达式*/String dateExp() default "";/*** 已经拼装好的分天表后缀。如果配置了dateExp,则自动忽略该配置*/String tableSuffix() default "";}
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER)
public @interface Param {String value();}
定义切面import ch.qos.logback.core.pattern.parser.Parser;
import com.example.eeuse.util.ShardingUtil;import com.sun.javafx.scene.paint.GradientUtils;
import com.sun.xml.internal.ws.api.wsdl.parser.XMLEntityResolver;
import org.apache.commons.lang.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
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.core.annotation.Order;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;
import sun.nio.cs.Surrogate;import javax.swing.text.html.HTMLEditorKit;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;@Component
@Aspect
@Order(1)
public class MPShardingAspect {@Pointcut("@annotation(com.example.eeuse.aspect.MPShardingAnno)")public void pointcut() {}/*** 从代理的参数中获取表表后缀*/@Before("pointcut()")public void beforeExecute(JoinPoint joinPoint) throws NoSuchMethodException, ParseException {Object target = joinPoint.getTarget();MethodSignature methdSignature = (MethodSignature) joinPoint.getSignature();Method method = methdSignature.getMethod();// 获取注解所在方法的参数定义Parameter[] parameters = method.getParameters();if (parameters == null || parameters.length == 0) {parameters = new Parameter[0];}MPShardingAnno shardingAnno = method.getAnnotation(MPShardingAnno.class);// 针对jdk代理做兼容if (shardingAnno == null) {Method declaredMethod = target.getClass().getDeclaredMethod(method.getName(), method.getParameterTypes());shardingAnno = declaredMethod.getAnnotation(MPShardingAnno.class);parameters = declaredMethod.getParameters();}String dateExp = shardingAnno.dateExp();shardingAnno.tableSuffix();// 获取spring的SpEL表达式解析器ExpressionParser parser = new SpelExpressionParser();StandardEvaluationContext context = new StandardEvaluationContext();// 获取注解所在方法的参数值List<String> paramNameList = new ArrayList<>();Object[] args = joinPoint.getArgs();for (Parameter parameter : parameters) {Param paramNameAnno = parameter.getAnnotation(Param.class);if (paramNameAnno != null) {String paramName = paramNameAnno.value();paramNameList.add(paramName);} else {paramNameList.add(parameter.getName());}}for (int i = 0; i < paramNameList.size(); i++) {context.setVariable(paramNameList.get(i), args[i]);}// 获取分表后缀String tableSuffix = "";if (StringUtils.isNotBlank(dateExp)) {tableSuffix = ShardingUtil.getTableSuffix(getDateFromExp(dateExp, parser, context));} else {tableSuffix = getTableSuffixFromExp(shardingAnno.tableSuffix(), parser, context);}// 记录表后缀TableNameContext.initSuffix(tableSuffix);// 记录调用的深度TableNameContext.addThreadNum();}@After("pointcut()")public void afterExecute() {Integer number = TableNameContext.reduceThreadNum();if(number <= 0){TableNameContext.release();}}/*** 根据日期的表达式,获取日期值** @param dateExp 日期表达式* @param parser  表达式解析器* @param context 自定义上下文*/private Date getDateFromExp(String dateExp, ExpressionParser parser, StandardEvaluationContext context) throws ParseException {if (StringUtils.isBlank(dateExp)) {throw new IllegalArgumentException("dateExp is empty");}Object dateObj = parser.parseExpression(dateExp).getValue(context);if (dateObj == null) {throw new IllegalArgumentException("dateExp is empty");}Date dateVal = null;if (dateObj instanceof Date) {dateVal = (Date) dateObj;} else if (dateObj instanceof Long) {dateVal = new Date((Long) dateObj);}  else if ((dateObj instanceof String)) {dateVal =  new SimpleDateFormat("yyyy-MM-dd").parse(dateObj.toString());} else if (dateObj.getClass().isPrimitive() && "long".equals(dateObj.getClass().getTypeName())) {dateVal = new Date(dateVal.getTime());} else {throw new IllegalArgumentException("dateExp support dataType:java.util.Date/java.lang.Long/java.lang.String/Long");}return dateVal;}private String getTableSuffixFromExp(String suffixExp, ExpressionParser parser, StandardEvaluationContext context) {if (StringUtils.isBlank(suffixExp)) {return "";}Object msgTypeObj = parser.parseExpression(suffixExp).getValue(context);return msgTypeObj != null ? msgTypeObj.toString() : null;}}
Mybatis-Plus插件中引入动态表名插件,进行表名替换import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.DynamicTableNameInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.apache.commons.lang.StringUtils;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
@MapperScan("com.example.eeuse.mapper")
public class MybatisPlusConfig {@Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor() {MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();//动态表名插件DynamicTableNameInnerInterceptor innerInterceptor = new DynamicTableNameInnerInterceptor();innerInterceptor.setTableNameHandler((sql, tableName) -> {String suffix = TableNameContext.getSuffix();if(StringUtils.isNotBlank(suffix)){tableName += "_"+suffix;}return tableName;});interceptor.addInnerInterceptor(innerInterceptor);return interceptor;}}

/*** 切换表名的上线文 出来拼接表名的逻辑*/public class TableNameContext {private TableNameContext() {}/*** 维护表后缀*/private static ThreadLocal<String> suffixTableLocal = new ThreadLocal<>();/*** 维护方法嵌套关系*/private static ThreadLocal<Integer> numberThreadLocal = ThreadLocal.withInitial(() -> 0);/*** 初始化表后缀* @param tableSuffix*/public static void initSuffix(String tableSuffix) {suffixTableLocal.set(tableSuffix);}/*** 获取表后缀* @return*/public static String getSuffix(){return suffixTableLocal.get();}/*** 记录当前进入声明了{@link MPShardingAnno}的方法数*/public static void addThreadNum() {Integer number = numberThreadLocal.get();number++;numberThreadLocal.set(number);}/*** 记录当前结束声明了{@link MPShardingAnno}的方法数* @return*/public static Integer reduceThreadNum(){Integer number = numberThreadLocal.get();number--;numberThreadLocal.set(number);return number;}/*** 释放资源*/public static void release(){suffixTableLocal.remove();numberThreadLocal.remove();}}

测试

@MPShardingAnno(dateExp = "#postTime")@GetMapping("/test03")public String getMsgFrameByCancel(long packId, @Param("postTime") String postTime) {System.out.println(postTime);try {testAspectMapper.query(packId,postTime);}catch (Exception e){System.out.println("1111111111111");}int i = Runtime.getRuntime().availableProcessors();System.out.println("i="+i);testAspectMapper.selectList(null);return null ;}最后打印的sql语句 select *  from tbl_pidinfo-2022-01-10 where ........

springboot结合注解动态获取数据库表相关推荐

  1. 怎么动态获取数据库表中自动递增id的值

    描述:现在有两张表,emp员工表和calling行业表 两者是多对多的关系,一个员工可以有多种行业,而一个行业内也有很多员工所以需要建立一个中间表id_calling.如下图: 前段数据页面在这不演示 ...

  2. 通过表单设计器动态生成数据库表以及动态查询的功能实现

    表单设计器动态生成数据库表以及动态查询的功能实现 前言 1. 功能实现 1.1 效果说明 1.2 功能流程图 1.3 具体后端实现 1.4 实现效果 2. 尾声 前言 前两天安排了作为Java小码农的 ...

  3. Java获取数据库表的字段信息,及如何将ResultSet转为json

    为什么80%的码农都做不了架构师?>>>    一.Java获取数据库表的各个字段的相关信息 在某些开发情景中,需要获取数据库中表的各个字段的相关信息,如字段名,字段类型,字段大小等 ...

  4. ASP获取数据库表名,字段名以及对字段的一些操作

    最近,在ASP论坛上看到很多网友问怎么获取数据库表名,字段名以及如何对字段进行删除,增添的操作故写此文. 本人对SQLServer比较熟一些,故以SQLServer为列:    <%       ...

  5. SpringBoot 结合 Mybatis 实现创建数据库表

    SpringBoot 结合 Mybatis 实现创建数据库表 目录 博主介绍 前言 为什么要通过应用实现创建表的功能 准备创建表的 SQL 语句 实现通过 MyBatis 创建数据库表示例 在 Mav ...

  6. Java获取数据库表名、字段名、字段类型及注释等信息

    以前有小伙伴在公众号留言问过如何通过java获取数据库的所有表.及表里字段的信息,只是私信回复过. 在最近的项目中架构部提出了一个数据源的配置需求,就是需要配置公司所有系统的数据库.表等信息,便于大数 ...

  7. mysql 一键获取数据库表结构

    作用: 1.获取当前数据库所有的表信息 2.获取当前表结构信息 查询数据库中的表: -- 查询数据库中的表 SELECT * FROM information_schema.`TABLES` wher ...

  8. C#获取数据库表信息,列信息

    获取表的信息: conn.Open();string[] restrictions = new string[4];restrictions[1] = "dbo"; DataTab ...

  9. python动态生成数据库表 orm_Python自动化 【第十二篇】:Python进阶-MySQL和ORM

    本节内容 数据库介绍 mysql 数据库安装使用 mysql管理 mysql 数据类型 常用mysql命令 创建数据库 外键 增删改查表 权限 事务 索引 python 操作mysql ORM sql ...

最新文章

  1. 图像拼接--Coarse-to-fine Seam Estimation for Image Stitching
  2. 怎样评价推荐系统的结果质量?
  3. 在非主线程中创建窗口
  4. 第九十期:哪种人是软件设计中的稀缺型人才?
  5. 解决 “数据大屏“ 展示的屏幕适配问题
  6. JS面向对象——class定义类、类的构造函数、实例方法、访问器方法、静态方法、继承、super、多态
  7. Java如何封装JDK_java7JDK的常用封装类型
  8. UVa - 1617 - Laptop
  9. iOS版微信跟上了!已支持改微信号,修改后好友不会收到提醒
  10. Linux驱动段错误,linux驱动调试--段错误之oops信息分析
  11. python绘图多子图 分别美化
  12. 创业公司如何做好信息安全(下)
  13. 一图秒懂:打开oracle归档模式,rman备份的前提条件
  14. java 图像合成加相框_合成走进相框人物照片效果的PS教程
  15. 数据工程指南高级技能:处理框架
  16. alias简化k8s命令,节约生命
  17. Maven多模块项目编译失败:依赖程序包xxx不存在
  18. 18. 地下城与勇士
  19. 一加5t升级 android p,第三方速度够快,一加1、一加5和一加5T火速升级AndroidP
  20. debian armhf mysql_Debian for ARM

热门文章

  1. 用SDK包开发K66FX18学习笔记(1)
  2. 华为p4支持鸿蒙功能吗_华为鸿蒙2.0系统支持的手机型号 华为鸿蒙2.0系统详解[多图]...
  3. 第五卷《鏖战雁门(下)》第47章《抉择》
  4. 空间句法插件Axwoman 6.3安装教程
  5. #Java教程:集合 #Collection、List、Set #ArrayList、LinkedList、Vector、HashSet、TreeSet #一个斗地主小游戏@FDDLC
  6. C语言蓝桥杯刷题:数字三角形
  7. 康考迪亚大学应用计算机科学,康考迪亚大学计算机
  8. 什么是AMD;什么是CMD
  9. 计算机控制系统生产现场应用,浅析计算机控制系统在工业现场生产中的应用.doc...
  10. Launching unittests with arguments python -m unittest