Bläddra i källkod

动态表明注解

wangtong 1 år sedan
förälder
incheckning
4faddc2bb3

+ 3 - 2
pom.xml

@@ -44,6 +44,7 @@
         <aws-java-sdk-s3.version>1.12.540</aws-java-sdk-s3.version>
         <!-- SMS 配置 -->
         <sms4j.version>2.2.0</sms4j.version>
+        <sharding-sphere.version>4.1.1</sharding-sphere.version>
     </properties>
 
     <profiles>
@@ -80,6 +81,7 @@
     <dependencyManagement>
         <dependencies>
 
+
             <!-- SpringBoot的依赖配置-->
             <dependency>
                 <groupId>org.springframework.boot</groupId>
@@ -98,6 +100,7 @@
                 <scope>import</scope>
             </dependency>
 
+
             <dependency>
                 <groupId>org.springdoc</groupId>
                 <artifactId>springdoc-openapi-webmvc-core</artifactId>
@@ -264,8 +267,6 @@
                 <artifactId>bcprov-jdk15to18</artifactId>
                 <version>${bouncycastle.version}</version>
             </dependency>
-
-            <!-- 定时任务 -->
             <dependency>
                 <groupId>com.ruoyi</groupId>
                 <artifactId>ruoyi-job</artifactId>

+ 8 - 4
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysUserController.java

@@ -36,10 +36,13 @@ import org.springframework.web.bind.annotation.*;
 import org.springframework.web.multipart.MultipartFile;
 
 import javax.servlet.http.HttpServletResponse;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import java.text.SimpleDateFormat;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.ZoneId;
+import java.time.ZonedDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.*;
 
 /**
  * 用户信息
@@ -63,6 +66,7 @@ public class SysUserController extends BaseController {
     @SaCheckPermission("system:user:list")
     @GetMapping("/list")
     public TableDataInfo<SysUser> list(SysUser user, PageQuery pageQuery) {
+        user.setCreateTime(new Date());
         return userService.selectPageUserList(user, pageQuery);
     }
 

+ 5 - 0
ruoyi-admin/src/main/resources/application-dev.yml

@@ -180,3 +180,8 @@ sms:
     sdkAppId: appid
     #地域信息默认为 ap-guangzhou 如无特殊改变可不用设置
     territory: ap-guangzhou
+tableNames:
+  #动态表名月分(该处为需要动态表的表名,号分割)
+  Month: z_engineering_review,z_engiineering_photo,z_engineering_info,z_engineering_material,z_engineering_node
+  #动态表名年度
+  Year: z_engineering_review

+ 22 - 0
ruoyi-common/src/main/java/com/ruoyi/common/annotation/DynamicName.java

@@ -0,0 +1,22 @@
+package com.ruoyi.common.annotation;
+
+import java.lang.annotation.*;
+import java.util.Date;
+
+/**
+ * 动态表名注解
+ * 通过spel表达式。自动注入到{@link DynamicTableNameHelper}中。而无需手动注入。减少代码侵入性
+ *
+ * @author: wt
+ */
+@Target({ElementType.TYPE, ElementType.METHOD})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface DynamicName {
+
+    /**
+     * spel 表达式  传入el表达式应为入参变量中的date类型参数,列:#user.createTime
+     *             不传入参数默认为当前年月,
+     */
+    String spel() ;
+}

+ 87 - 0
ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/DynamicNameAspect.java

@@ -0,0 +1,87 @@
+package com.ruoyi.framework.aspectj;
+
+import com.ruoyi.common.annotation.DynamicName;
+import com.ruoyi.framework.handler.MonthTableNameHandler;
+
+import org.aspectj.lang.JoinPoint;
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.annotation.Around;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.annotation.Before;
+import org.aspectj.lang.reflect.MethodSignature;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.core.DefaultParameterNameDiscoverer;
+import org.springframework.expression.EvaluationContext;
+import org.springframework.expression.Expression;
+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 org.springframework.util.StringUtils;
+
+import java.lang.reflect.Method;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+/**
+ * 切面。用户解析spel表达式,并且赋值到 {@link MonthTableNameHandler}中
+ *
+ * @author: pinlin
+ */
+@Aspect
+@Component
+public class DynamicNameAspect {
+
+    /**
+     * spel解析器
+     */
+    private static final ExpressionParser EXPRESSION_PARSER = new SpelExpressionParser();
+
+
+    /**
+     * 方法形参名解析器
+     */
+    private static final DefaultParameterNameDiscoverer NAME_DISCOVERER = new DefaultParameterNameDiscoverer();
+    private static final Logger log = LoggerFactory.getLogger(DynamicNameAspect.class);
+    @Around("execution(public * *(..))&&@annotation(com.ruoyi.common.annotation.DynamicName)")
+    public Object around(ProceedingJoinPoint joinPoint ) throws Throwable {
+        try {
+            // 获取到spel表达式为空,默认表名则为当前日期
+            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
+            Method method = signature.getMethod();
+            DynamicName dynamicName=method.getAnnotation(DynamicName.class);
+            if (!StringUtils.hasText(dynamicName.spel())) {
+                String date=  new SimpleDateFormat("yyyy_MM").format(new Date());
+                MonthTableNameHandler.setData(date);
+                return joinPoint.proceed();
+            }
+            Object[] args = joinPoint.getArgs();
+            String[] paramNames = NAME_DISCOVERER.getParameterNames(method);
+            Expression expression = EXPRESSION_PARSER.parseExpression(dynamicName.spel());
+            EvaluationContext context = new StandardEvaluationContext();
+            for (int i = 0; i < args.length; i++) {
+                assert paramNames != null;
+                context.setVariable(paramNames[i], args[i]);
+            }
+            Date tableName = expression.getValue(context, Date.class);
+            log.info(tableName.toString());
+            //防止注入若想查询大于当前日期之后的表默认返回当前日期
+            if (StringUtils.hasText(tableName.toString())&&new Date().after(tableName)) {
+              String date=  new SimpleDateFormat("yyyy_MM").format(tableName);
+                //将年月存入线程
+                MonthTableNameHandler.setData(date);
+            }else {
+                String date=  new SimpleDateFormat("yyyy_MM").format(new Date());
+                //将年月存入线程
+                MonthTableNameHandler.setData(date);
+            }
+
+            return joinPoint.proceed();
+        } finally {
+            // 释放缓存内容
+            MonthTableNameHandler.removeData();
+        }
+    }
+
+}

+ 46 - 0
ruoyi-framework/src/main/java/com/ruoyi/framework/config/MybatisPlusConfig.java

@@ -5,15 +5,22 @@ import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
 import com.baomidou.mybatisplus.core.incrementer.DefaultIdentifierGenerator;
 import com.baomidou.mybatisplus.core.incrementer.IdentifierGenerator;
 import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
+import com.baomidou.mybatisplus.extension.plugins.inner.DynamicTableNameInnerInterceptor;
 import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
 import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
+import com.ruoyi.common.utils.StringUtils;
 import com.ruoyi.framework.handler.CreateAndUpdateMetaObjectHandler;
+import com.ruoyi.framework.handler.MonthTableNameHandler;
+import com.ruoyi.framework.handler.YearTableNameHandler;
 import com.ruoyi.framework.interceptor.PlusDataPermissionInterceptor;
 import org.mybatis.spring.annotation.MapperScan;
+import org.springframework.beans.factory.annotation.Value;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.transaction.annotation.EnableTransactionManagement;
 
+import java.util.List;
+
 /**
  * mybatis-plus配置类(下方注释有插件介绍)
  *
@@ -24,15 +31,25 @@ import org.springframework.transaction.annotation.EnableTransactionManagement;
 @MapperScan("${mybatis-plus.mapperPackage}")
 public class MybatisPlusConfig {
 
+    @Value("${tableNames.Month}")
+    private String MonthTableNames;
+    @Value("${tableNames.Year}")
+    private String YearTableNames;
+
     @Bean
     public MybatisPlusInterceptor mybatisPlusInterceptor() {
         MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
+        //动态表名(月)
+        interceptor.addInnerInterceptor(dynamicTableNameInnerInterceptor());
+        //动态表名(年)
+        interceptor.addInnerInterceptor(dynamictableNameInnerInterceptor());
         // 数据权限处理
         interceptor.addInnerInterceptor(dataPermissionInterceptor());
         // 分页插件
         interceptor.addInnerInterceptor(paginationInnerInterceptor());
         // 乐观锁插件
         interceptor.addInnerInterceptor(optimisticLockerInnerInterceptor());
+
         return interceptor;
     }
 
@@ -56,6 +73,34 @@ public class MybatisPlusConfig {
     }
 
     /**
+     * 按月动态表名
+     * @return
+     */
+
+    public DynamicTableNameInnerInterceptor dynamicTableNameInnerInterceptor()
+
+    {
+        DynamicTableNameInnerInterceptor dynamicTableNameInnerInterceptor = new DynamicTableNameInnerInterceptor();
+        dynamicTableNameInnerInterceptor.setTableNameHandler(
+            //可以传多个表名参数,指定哪些表使用MonthTableNameHandler处理表名称
+            new MonthTableNameHandler(MonthTableNames)
+        );
+
+        return dynamicTableNameInnerInterceptor;
+    }
+    public DynamicTableNameInnerInterceptor dynamictableNameInnerInterceptor()
+
+    {
+        DynamicTableNameInnerInterceptor dynamicTableNameInnerInterceptor = new DynamicTableNameInnerInterceptor();
+        dynamicTableNameInnerInterceptor.setTableNameHandler(
+            //可以传多个表名参数,指定哪些表使用MonthTableNameHandler处理表名称
+            new YearTableNameHandler(YearTableNames)
+        );
+        return dynamicTableNameInnerInterceptor;
+    }
+
+
+    /**
      * 乐观锁插件
      */
     public OptimisticLockerInnerInterceptor optimisticLockerInnerInterceptor() {
@@ -99,4 +144,5 @@ public class MybatisPlusConfig {
      * https://baomidou.com/pages/2a45ff/
      */
 
+
 }

+ 54 - 0
ruoyi-framework/src/main/java/com/ruoyi/framework/handler/MonthTableNameHandler.java

@@ -0,0 +1,54 @@
+package com.ruoyi.framework.handler;
+
+import com.baomidou.mybatisplus.extension.plugins.handler.TableNameHandler;
+import com.ruoyi.framework.aspectj.DynamicNameAspect;
+import lombok.extern.slf4j.Slf4j;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * 按月份参数,组成动态表名
+ */
+
+public class MonthTableNameHandler implements TableNameHandler {
+
+    //用于记录哪些表可以使用该月份动态表名处理器(即哪些表按月分表)
+    private List<String> tableNames;
+    private static final Logger log = LoggerFactory.getLogger(MonthTableNameHandler.class);
+    //构造函数,构造动态表名处理器的时候,传递tableNames参数
+    public MonthTableNameHandler(String tableNames) {
+        this.tableNames = Arrays.asList(tableNames.split(","));
+    }
+
+   // 每个请求线程维护一个month数据,避免多线程数据冲突。所以使用ThreadLocal
+    private static  ThreadLocal<String> MONTH_DATA = new ThreadLocal<>();
+    //设置请求线程的month数据
+    public static void setData(String month) {
+        MONTH_DATA.set(month);
+    }
+
+    //删除当前请求线程的month数据
+    public static void removeData() {
+        MONTH_DATA.remove();
+    }
+
+    //动态表名接口实现方法
+    @Override
+    public String dynamicTableName(String sql, String tableName) {
+        if (this.tableNames.contains(tableName)){
+            if (MONTH_DATA.get()==null)
+            {
+                LocalDate date = LocalDate.now();
+                return tableName + "_" + date.format(DateTimeFormatter.ofPattern("yyyy_MM"));  //表名增加月份后缀
+            }
+            return tableName+"_"+MONTH_DATA.get();  //表名增加月份后缀
+        }else{
+            return tableName;   //表名原样返回
+        }
+    }
+}

+ 47 - 0
ruoyi-framework/src/main/java/com/ruoyi/framework/handler/YearTableNameHandler.java

@@ -0,0 +1,47 @@
+package com.ruoyi.framework.handler;
+
+import com.baomidou.mybatisplus.extension.plugins.handler.TableNameHandler;
+
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * 按年份参数,组成动态表名
+ */
+public class YearTableNameHandler implements TableNameHandler {
+
+    //用于记录哪些表可以使用该年份动态表名处理器(即哪些表按年分表)
+    private List<String> tableNames;
+    //构造函数,构造动态表名处理器的时候,传递tableNames参数
+    public YearTableNameHandler(String tableNames) {
+        this.tableNames = Arrays.asList(tableNames.split(","));
+    }
+
+    //每个请求线程维护一个年份数据,避免多线程数据冲突。所以使用ThreadLocal
+    private static final ThreadLocal<String> YEAR_DATA = new ThreadLocal<>();
+    //设置请求线程的年份数据
+    public static void setData(String month) {
+        YEAR_DATA.set(month);
+    }
+    //删除当前请求线程的年份数据
+    public static void removeData() {
+        YEAR_DATA.remove();
+    }
+
+    //动态表名接口实现方法
+    @Override
+    public String dynamicTableName(String sql, String tableName) {
+        if (this.tableNames.contains(tableName)){
+            if (YEAR_DATA.get()==null)
+            {
+                LocalDate date = LocalDate.now();
+                return tableName + "_" + date.format(DateTimeFormatter.ofPattern("yyyy"));  //表名增加年份后缀
+            }
+            return tableName + "_" + YEAR_DATA.get();  //表名增加年份后缀
+        }else{
+            return tableName;   //表名原样返回
+        }
+    }
+}

+ 2 - 0
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java

@@ -9,6 +9,7 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.ruoyi.common.annotation.DynamicName;
 import com.ruoyi.common.constant.CacheNames;
 import com.ruoyi.common.constant.UserConstants;
 import com.ruoyi.common.core.domain.PageQuery;
@@ -158,6 +159,7 @@ public class SysUserServiceImpl implements ISysUserService, UserService {
      * @return 用户对象信息
      */
     @Override
+
     public SysUser selectUserById(Long userId) {
         return baseMapper.selectUserById(userId);
     }