Sfoglia il codice sorgente

MyBatis封装代码提交,多数据源切换支持

yucheng 3 anni fa
parent
commit
53a5f854f0

+ 0 - 6
fm-common/pom.xml

@@ -30,12 +30,6 @@
             <artifactId>spring-boot-starter-web</artifactId>
         </dependency>
 
-        <!-- mybatisPlus相关的依赖 start -->
-        <!-- mybatisPlus -->
-        <dependency>
-            <groupId>com.baomidou</groupId>
-            <artifactId>mybatis-plus-boot-starter</artifactId>
-        </dependency>
         <!-- jackson -->
         <dependency>
             <groupId>com.fasterxml.jackson.core</groupId>

+ 5 - 4
fm-common/src/main/java/com/persagy/fm/common/config/WebConfig.java

@@ -1,5 +1,6 @@
 package com.persagy.fm.common.config;
 
+import com.persagy.fm.common.handler.AppContextHandler;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
@@ -13,16 +14,16 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
  * @version: V1.0
  **/
 @Configuration
-public class WebConfig implements WebMvcConfigurer {
+public class CommonWebConfigurer implements WebMvcConfigurer {
 
     @Bean
-    public RequiredParamsHandler requiredParamsHandler() {
-        return new RequiredParamsHandler();
+    public AppContextHandler appContextHandler() {
+        return new AppContextHandler();
     }
 
     @Override
     public void addInterceptors(InterceptorRegistry registry) {
         // 设置拦截的路径、不拦截的路径、优先级等等
-        registry.addInterceptor(requiredParamsHandler()).addPathPatterns("/**");
+        registry.addInterceptor(appContextHandler()).addPathPatterns("/**");
     }
 }

+ 0 - 81
fm-common/src/main/java/com/persagy/fm/common/config/RequiredParamsHandler.java

@@ -1,81 +0,0 @@
-package com.persagy.fm.common.config;
-
-import com.alibaba.fastjson.JSONObject;
-import com.persagy.fm.common.constant.RequiredParamsConstants;
-import com.persagy.fm.common.context.DefaultAppContext;
-import com.persagy.fm.common.context.DefaultAppContextFactory;
-import com.persagy.fm.common.utils.SecureAES;
-import org.apache.commons.lang3.StringUtils;
-import org.springframework.web.servlet.ModelAndView;
-import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-/**
- * @description:
- * @author: lixing
- * @company: Persagy Technology Co.,Ltd
- * @since: 2021/3/8 9:35 上午
- * @version: V1.0
- **/
-public class RequiredParamsHandler extends HandlerInterceptorAdapter {
-    @Override
-    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
-        String requestURI = request.getRequestURI();
-        // swagger的文档不校验必填项
-        if (requestURI.indexOf(".html") != -1
-                || requestURI.indexOf(".js") != -1
-                || requestURI.indexOf(".css") != -1
-                || requestURI.indexOf("/swagger-resources") != -1
-        ) {
-            return true;
-        }
-
-        // 从token中解析数据
-        SecureAES aes = new SecureAES("63499E35378AE1B0733E3FED7F780B68", "C0E7BD39B52A15C7");
-        String tokenStr = request.getHeader("token");
-        JSONObject tokenObj = aes.decrypt(tokenStr);
-
-        DefaultAppContext.getContext().setAccountId(
-                tokenObj.getString(RequiredParamsConstants.ACCOUNT_ID)
-        );
-        DefaultAppContext.getContext().setGroupCode(
-                tokenObj.getString(RequiredParamsConstants.GROUP_CODE)
-        );
-        DefaultAppContext.getContext().setAppId(
-                tokenObj.getString(RequiredParamsConstants.APP_ID)
-        );
-
-        return true;
-    }
-
-    /**
-     * @description: 校验必填参数
-     * @param: request
-     * @return: void
-     * @exception:
-     * @author: lixing
-     * @company: Persagy Technology Co.,Ltd
-     * @since: 2021/3/9 6:29 下午
-     * @version: V1.0
-     */
-    private void checkeRequiredParams(HttpServletRequest request) {
-        String[] requiredParams = {"groupCode", "projectId", "appId", "userId"};
-        for (String requiredParam : requiredParams) {
-            if (StringUtils.isBlank(request.getParameter(requiredParam))) {
-                throw new IllegalArgumentException("缺少必填参数" + requiredParam);
-            }
-        }
-    }
-
-    @Override
-    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
-        DefaultAppContext.getFactory().unloadContext();
-    }
-
-    @Override
-    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
-        DefaultAppContext.getFactory().unloadContext();
-    }
-}

+ 1 - 1
fm-common/src/main/java/com/persagy/fm/common/constant/RequiredParamsConstants.java

@@ -6,7 +6,7 @@ package com.persagy.fm.common.constant;
  * @author lixing
  * @version V1.0 2021/3/25 5:50 下午
  **/
-public class RequiredParamsConstants {
+public class AppContextConstants {
     public static final String GROUP_CODE = "groupCode";
     public static final String APP_ID = "appId";
     public static final String ACCOUNT_ID = "accountId";

+ 13 - 13
fm-common/src/main/java/com/persagy/fm/common/context/AppContext.java

@@ -92,19 +92,19 @@ public abstract class AppContext implements Serializable {
 //     * @param productLine 产品线
 //     */
 //    public abstract void setProductLine(String productLine);
-//
-//    /**
-//     * 动态数据源支持
-//     * @return java.lang.String
-//     **/
-//    public abstract String getDataSourceName();
-//
-//    /**
-//     * 设置动态数据源
-//     * @param dataSourceName 动态数据源
-//     * @return void
-//     **/
-//    public abstract void setDataSourceName(String dataSourceName);
+
+    /**
+     * 动态数据源支持
+     * @return java.lang.String
+     **/
+    public abstract String getDataSourceName();
+
+    /**
+     * 设置动态数据源
+     * @param dataSourceName 动态数据源
+     * @return void
+     **/
+    public abstract void setDataSourceName(String dataSourceName);
 
     public abstract void setAccountId(String accountId);
     public abstract void setProjectId(String projectId);

+ 5 - 5
fm-common/src/main/java/com/persagy/fm/common/context/DefaultAppContext.java

@@ -29,11 +29,11 @@ public class DefaultAppContext extends AppContext {
 //     * 所属产品线
 //     */
 //    private String productLine;
-//
-//    /**
-//     * 数据源名称
-//     */
-//    private String dataSourceName;
+
+    /**
+     * 数据源名称
+     */
+    private String dataSourceName;
 
     private String projectId;
     private String appId;

+ 63 - 0
fm-common/src/main/java/com/persagy/fm/common/handler/AppContextHandler.java

@@ -0,0 +1,63 @@
+package com.persagy.fm.common.handler;
+
+import com.alibaba.fastjson.JSONObject;
+import com.persagy.fm.common.constant.AppContextConstants;
+import com.persagy.fm.common.context.AppContext;
+import com.persagy.fm.common.context.DefaultAppContext;
+import com.persagy.fm.common.utils.SecureAES;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.web.servlet.ModelAndView;
+import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * @description:
+ * @author: lixing
+ * @company: Persagy Technology Co.,Ltd
+ * @since: 2021/3/8 9:35 上午
+ * @version: V1.0
+ */
+public class AppContextHandler extends HandlerInterceptorAdapter {
+
+    /** 忽略的url - swagger的文档不校验 */
+    private static final String[] IGNORE_URL = {".html", ".js", ".css", "/swagger-resources"};
+
+    @Override
+    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
+        String requestURI = request.getRequestURI();
+        if (StringUtils.containsAny(requestURI, IGNORE_URL)) {
+            return true;
+        }
+        ensureContextInfo(request.getHeader("token"));
+        return true;
+    }
+
+    /**
+     * 根据token获取上下文信息
+     * @param token
+     */
+    private void ensureContextInfo(String token){
+        // 从token中解析数据
+        SecureAES aes = new SecureAES("63499E35378AE1B0733E3FED7F780B68", "C0E7BD39B52A15C7");
+        JSONObject tokenObj = aes.decrypt(token);
+        // 获取值
+        String accountId = tokenObj.getString(AppContextConstants.ACCOUNT_ID);
+        String groupCode = tokenObj.getString(AppContextConstants.GROUP_CODE);
+        String appId = tokenObj.getString(AppContextConstants.APP_ID);
+        AppContext.getContext().setAccountId(accountId);
+        AppContext.getContext().setGroupCode(groupCode);
+        AppContext.getContext().setAppId(appId);
+    }
+
+    @Override
+    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
+        DefaultAppContext.getFactory().unloadContext();
+    }
+
+    @Override
+    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
+        DefaultAppContext.getFactory().unloadContext();
+    }
+}

+ 4 - 4
fm-common/src/main/java/com/persagy/fm/common/utils/SecureAES.java

@@ -6,7 +6,7 @@ import cn.hutool.crypto.SecureUtil;
 import cn.hutool.crypto.symmetric.AES;
 import com.alibaba.fastjson.JSONObject;
 import com.persagy.common.utils.StringUtil;
-import com.persagy.fm.common.constant.RequiredParamsConstants;
+import com.persagy.fm.common.constant.AppContextConstants;
 import com.persagy.security.exception.AESDecryptException;
 
 import java.nio.charset.Charset;
@@ -84,9 +84,9 @@ public class SecureAES {
 	 */
 	public String encrypt(String groupCode, String appId, String accountId) {
 		JSONObject object = new JSONObject();
-		object.put(RequiredParamsConstants.GROUP_CODE, groupCode);
-		object.put(RequiredParamsConstants.APP_ID, appId);
-		object.put(RequiredParamsConstants.ACCOUNT_ID, accountId);
+		object.put(AppContextConstants.GROUP_CODE, groupCode);
+		object.put(AppContextConstants.APP_ID, appId);
+		object.put(AppContextConstants.ACCOUNT_ID, accountId);
 		return aes.encryptHex(object.toJSONString(), CHARSET_UTF_8);
 	}
 	

+ 10 - 0
fm-mybatis/README.md

@@ -0,0 +1,10 @@
+fm-mybatis 关系数据库
+============ 
+
+说明
+---------------
+
+	
+最新变化
+---------------
+

+ 28 - 0
fm-mybatis/pom.xml

@@ -0,0 +1,28 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>com.persagy</groupId>
+        <artifactId>fm-parent</artifactId>
+        <version>3.0.0</version>
+        <relativePath>../fm-parent</relativePath>
+    </parent>
+    <artifactId>fm-mybatis</artifactId>
+    <dependencies>
+        <dependency>
+            <groupId>com.persagy</groupId>
+            <artifactId>fm-common</artifactId>
+        </dependency>
+        <!-- mybatisPlus相关的依赖 start -->
+        <!-- mybatisPlus -->
+        <dependency>
+            <groupId>com.baomidou</groupId>
+            <artifactId>mybatis-plus-boot-starter</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.baomidou</groupId>
+            <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
+            <version>3.3.2</version>
+        </dependency>
+    </dependencies>
+</project>

+ 27 - 0
fm-mybatis/src/main/java/com/persagy/fm/mybatis/config/MyBatisWebConfigurer.java

@@ -0,0 +1,27 @@
+package com.persagy.fm.mybatis.config;
+
+import com.persagy.fm.mybatis.handler.DynamicDataSourceHandler;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+/**
+ * MyBatis配置
+ * @author Charlie Yu
+ * @date 2021-03-29
+ */
+@Configuration
+public class MyBatisWebConfigurer implements WebMvcConfigurer {
+
+    @Bean
+    public DynamicDataSourceHandler dynamicDataSourceHandler() {
+        return new DynamicDataSourceHandler();
+    }
+
+    @Override
+    public void addInterceptors(InterceptorRegistry registry) {
+        // 设置拦截的路径、不拦截的路径、优先级等等
+        registry.addInterceptor(dynamicDataSourceHandler()).addPathPatterns("/**");
+    }
+}

+ 1 - 1
fm-common/src/main/java/com/persagy/fm/common/config/MybatisPlusConfig.java

@@ -1,4 +1,4 @@
-package com.persagy.fm.common.config;
+package com.persagy.fm.mybatis.config;
 
 import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
 import org.springframework.context.annotation.Bean;

+ 2 - 2
fm-common/src/main/java/com/persagy/fm/common/config/MybatisPlusMetaObjectHandler.java

@@ -1,4 +1,4 @@
-package com.persagy.fm.common.config;
+package com.persagy.fm.mybatis.handler;
 
 import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
 import com.persagy.fm.common.constant.enums.ValidEnum;
@@ -17,7 +17,7 @@ import java.util.Date;
  * @version: V1.0
  **/
 @Component
-public class MybatisPlusMetaObjectHandler implements MetaObjectHandler {
+public class CommonMetaObjectHandler implements MetaObjectHandler {
     @Override
     public void insertFill(MetaObject metaObject) {
         if (metaObject.hasSetter(AuditableEntity.DO_PROP_CREATIONTIME)) {

+ 77 - 0
fm-mybatis/src/main/java/com/persagy/fm/mybatis/handler/DynamicDataSourceHandler.java

@@ -0,0 +1,77 @@
+package com.persagy.fm.mybatis.handler;
+
+import com.baomidou.dynamic.datasource.DynamicRoutingDataSource;
+import com.baomidou.dynamic.datasource.creator.DruidDataSourceCreator;
+import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DataSourceProperty;
+import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceProperties;
+import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder;
+import com.persagy.fm.common.context.AppContext;
+import com.persagy.fm.common.helper.SpringHelper;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.sql.DataSource;
+import java.sql.SQLException;
+import java.util.Set;
+
+/**
+ * 动态数据源拦截器
+ * @author Charlie Yu
+ * @date 2021-03-29
+ */
+public class DynamicDataSourceHandler extends HandlerInterceptorAdapter {
+
+    /** 忽略的url - swagger的文档不校验 */
+    private static final String[] IGNORE_URL = {".html", ".js", ".css", "/swagger-resources"};
+
+    @Autowired
+    private DynamicRoutingDataSource dataSource;
+    @Autowired
+    private DruidDataSourceCreator dataSourceCreator;
+    @Autowired
+    private DynamicDataSourceProperties defaultProperty;
+
+    @Override
+    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
+        String requestURI = request.getRequestURI();
+        if (StringUtils.containsAny(requestURI, IGNORE_URL)) {
+            return true;
+        }
+        resetDataSource();
+        return true;
+    }
+
+    /**
+     * 多租户处理,数据源切换
+     */
+    private void resetDataSource() throws SQLException {
+        // 是否启用多数据源
+        boolean isDynamic = SpringHelper.getBoolean("spring.datasource.dynamic.enabled", false);
+        if(!isDynamic) {
+            return;
+        }
+
+        // 默认为应用名
+        String dbNameDefault = SpringHelper.getString("spring.application.name");
+        String newDsName = AppContext.getContext().getGroupCode() + "_" + dbNameDefault;
+        Set<String> dsNames = dataSource.getCurrentDataSources().keySet();
+        if(!dsNames.contains(newDsName)) {
+            // 取默认数据源
+            DataSourceProperty srcProperty = defaultProperty.getDatasource().get(dbNameDefault);
+            // 设置新数据源
+            DataSourceProperty property = new DataSourceProperty();
+            BeanUtils.copyProperties(srcProperty, property);
+            property.setPoolName(newDsName);
+            property.setUrl(StringUtils.replace(property.getUrl(), dbNameDefault, newDsName));
+            // 创建数据源
+            DataSource currDs = dataSourceCreator.createDataSource(property);
+            dataSource.addDataSource(newDsName, currDs);
+        }
+        // 设置当前数据源
+        DynamicDataSourceContextHolder.push(newDsName);
+    }
+}

+ 4 - 0
fm-server/pom.xml

@@ -22,5 +22,9 @@
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-starter-web</artifactId>
         </dependency>
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>druid-spring-boot-starter</artifactId>
+        </dependency>
     </dependencies>
 </project>

+ 2 - 2
fm-server/src/main/java/com/persagy/ServerApplication.java

@@ -1,6 +1,7 @@
 package com.persagy;
 
 import cn.hutool.extra.spring.EnableSpringUtil;
+import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure;
 import com.persagy.log.annotation.EnableControllerLog;
 import org.mybatis.spring.annotation.MapperScan;
 import org.springframework.boot.Banner;
@@ -26,8 +27,7 @@ import org.springframework.scheduling.annotation.EnableScheduling;
 @EnableScheduling
 @MapperScan(value = "com.persagy.fm.*.dao")
 @EnableSpringUtil
-@SpringBootApplication
-@MapperScan(value = "com.persagy.fm.*.dao")
+@SpringBootApplication(exclude = DruidDataSourceAutoConfigure.class)
 public class ServerApplication {
 
     public static void main(String[] args) {