├── pom.xml
└── src
├── main
├── java
│ └── com
│ │ └── xh
│ │ ├── MyGenerator.java
│ │ ├── SpringBootDynamicDataSourceApplication.java
│ │ ├── controller
│ │ └── SysUserController.java
│ │ ├── datasource
│ │ ├── CurDataSource.java
│ │ ├── DataSourceAspect.java
│ │ ├── DataSourceNames.java
│ │ ├── DynamicDataSource.java
│ │ └── DynamicDataSourceConfig.java
│ │ ├── entity
│ │ └── SysUser.java
│ │ ├── mapper
│ │ └── SysUserMapper.java
│ │ └── service
│ │ ├── SysUserService.java
│ │ └── impl
│ │ └── SysUserServiceImpl.java
└── resources
│ ├── application.properties
│ ├── doc
│ └── mysql.sql
│ └── mapper
│ └── SysUserMapper.xml
└── test
└── java
└── com
└── xh
└── SpringBootDynamicCurDataSourceApplicationTests.java
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | org.springframework.boot
7 | spring-boot-starter-parent
8 | 2.1.5.RELEASE
9 |
10 |
11 | com.xh
12 | spring-boot-dynamic-data-source
13 | 1.0.0-SNAPSHOT
14 | spring-boot-dynamic-data-source
15 | Demo project for Spring Boot
16 |
17 |
18 | 1.8
19 |
20 |
21 |
22 |
23 | org.springframework.boot
24 | spring-boot-starter-aop
25 |
26 |
27 | org.springframework.boot
28 | spring-boot-starter-web
29 |
30 |
31 |
32 |
33 | com.baomidou
34 | mybatis-plus-boot-starter
35 | 3.0.1
36 |
37 |
38 | mysql
39 | mysql-connector-java
40 | runtime
41 |
42 |
43 | org.projectlombok
44 | lombok
45 | true
46 |
47 |
48 | org.springframework.boot
49 | spring-boot-starter-test
50 | test
51 |
52 |
53 |
54 | com.alibaba
55 | druid-spring-boot-starter
56 | 1.1.10
57 |
58 |
59 |
60 | org.apache.commons
61 | commons-lang3
62 | 3.9
63 |
64 |
65 |
66 | io.springfox
67 | springfox-swagger2
68 | 2.9.2
69 |
70 |
71 | com.github.caspar-chen
72 | swagger-ui-layer
73 | 1.1.3
74 |
75 |
76 |
77 |
78 |
79 |
80 | org.springframework.boot
81 | spring-boot-maven-plugin
82 |
83 |
84 |
85 | org.apache.maven.plugins
86 | maven-surefire-plugin
87 | 2.18.1
88 |
89 | true
90 |
91 |
92 |
93 |
94 |
95 |
96 |
--------------------------------------------------------------------------------
/src/main/java/com/xh/MyGenerator.java:
--------------------------------------------------------------------------------
1 | package com.xh;
2 |
3 | import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException;
4 | import com.baomidou.mybatisplus.core.toolkit.StringPool;
5 | import com.baomidou.mybatisplus.core.toolkit.StringUtils;
6 | import com.baomidou.mybatisplus.generator.AutoGenerator;
7 | import com.baomidou.mybatisplus.generator.InjectionConfig;
8 | import com.baomidou.mybatisplus.generator.config.*;
9 | import com.baomidou.mybatisplus.generator.config.po.TableInfo;
10 | import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
11 | import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
12 |
13 | import java.util.ArrayList;
14 | import java.util.List;
15 | import java.util.Scanner;
16 |
17 | /**
18 | * 演示例子,执行 main 方法控制台输入模块表名回车自动生成对应项目目录中
19 | * 注意安装配置来生成BaseEntity、BaseController、还有包路径相关等东西。
20 | *
21 | * current table :
22 | * category,comment,post,user,user_action,user_collection,user_message
23 | *
24 | * 完成后:
25 | * 生成BaseEntity、BaseController、还有包路径相关等东西
26 | *
27 | * 代码生成之后,看到resource/mapper这里,把这个null去掉
28 | *
29 | * 注意一下:还需要配置@MapperScan("com.xh.blog.mapper")注解。说明mapper的扫描包。
30 | *
31 | * 接下来,写一个小测试,测试一下mybatis plus有没集成成功
32 | *
33 | * @author xiaohe
34 | * @version V1.0.0
35 | */
36 | public class MyGenerator {
37 |
38 | /**
39 | *
40 | * 读取控制台内容
41 | *
42 | */
43 | private static String scanner(String tip) {
44 | Scanner scanner = new Scanner(System.in);
45 | StringBuilder help = new StringBuilder();
46 | // sys_user
47 | help.append("请输入" + tip + ":");
48 | System.out.println(help.toString());
49 | if (scanner.hasNext()) {
50 | String ipt = scanner.next();
51 | if (StringUtils.isNotEmpty(ipt)) {
52 | return ipt;
53 | }
54 | }
55 | throw new MybatisPlusException("请输入正确的" + tip + "!");
56 | }
57 |
58 | public static void main(String[] args) {
59 | // 代码生成器
60 | AutoGenerator mpg = new AutoGenerator();
61 |
62 | // 全局配置
63 | GlobalConfig gc = new GlobalConfig();
64 | String projectPath = System.getProperty("user.dir");
65 | gc.setOutputDir(projectPath + "/src/main/java");
66 | // gc.setOutputDir("D:\\test")
67 | gc.setAuthor("xiaohe");
68 | gc.setOpen(false);
69 | // 实体属性 Swagger2 注解
70 | gc.setSwagger2(true);
71 | gc.setServiceName("%sService");
72 | mpg.setGlobalConfig(gc);
73 |
74 | // 数据源配置
75 | DataSourceConfig dsc = new DataSourceConfig();
76 | dsc.setUrl("jdbc:mysql://localhost:3306/renren_fast?useUnicode=true&useSSL=false&characterEncoding=utf8&serverTimezone=UTC");
77 | // dsc.setSchemaName("public")
78 | dsc.setDriverName("com.mysql.cj.jdbc.Driver");
79 | dsc.setUsername("root");
80 | dsc.setPassword("accp");
81 | mpg.setDataSource(dsc);
82 |
83 | // 包配置
84 | PackageConfig pc = new PackageConfig();
85 | pc.setModuleName(null);
86 | pc.setParent("com.xh");
87 | mpg.setPackageInfo(pc);
88 |
89 | // 自定义配置
90 | InjectionConfig cfg = new InjectionConfig() {
91 | @Override
92 | public void initMap() {
93 | // to do nothing
94 | }
95 | };
96 |
97 | // 如果模板引擎是 freemarker
98 | String templatePath = "/templates/mapper.xml.ftl";
99 | // 如果模板引擎是 velocity
100 | // String templatePath = "/templates/mapper.xml.vm";
101 |
102 | // 自定义输出配置
103 | List focList = new ArrayList<>();
104 | // 自定义配置会被优先输出
105 | focList.add(new FileOutConfig(templatePath) {
106 | @Override
107 | public String outputFile(TableInfo tableInfo) {
108 | // 自定义输出文件名 , 如果你 Entity 设置了前后缀、此处注意 xml 的名称会跟着发生变化!!
109 | return projectPath + "/src/main/resources/mapper/" + pc.getModuleName()
110 | + "/" + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML;
111 | }
112 | });
113 |
114 | cfg.setFileOutConfigList(focList);
115 | mpg.setCfg(cfg);
116 |
117 | // 配置模板
118 | TemplateConfig templateConfig = new TemplateConfig();
119 |
120 | // 配置自定义输出模板
121 | //指定自定义模板路径,注意不要带上.ftl/.vm, 会根据使用的模板引擎自动识别
122 | // templateConfig.setEntity("templates/entity2.java")
123 | // templateConfig.setService()
124 | // templateConfig.setController()
125 |
126 | templateConfig.setXml(null);
127 | mpg.setTemplate(templateConfig);
128 |
129 | // 策略配置
130 | StrategyConfig strategy = new StrategyConfig();
131 | strategy.setNaming(NamingStrategy.underline_to_camel);
132 | strategy.setColumnNaming(NamingStrategy.underline_to_camel);
133 | // strategy.setSuperEntityClass("com.xh.entity.BaseEntity")
134 | strategy.setEntityLombokModel(true);
135 | strategy.setRestControllerStyle(true);
136 | // strategy.setSuperControllerClass("com.xh.controller.BaseController")
137 | strategy.setInclude(scanner("表名,多个英文逗号分割").split(","));
138 | // strategy.setSuperEntityColumns("id", "created", "modified", "status")
139 | strategy.setControllerMappingHyphenStyle(true);
140 | strategy.setTablePrefix(pc.getModuleName() + "_");
141 | mpg.setStrategy(strategy);
142 | mpg.setTemplateEngine(new FreemarkerTemplateEngine());
143 | mpg.execute();
144 | }
145 | }
--------------------------------------------------------------------------------
/src/main/java/com/xh/SpringBootDynamicDataSourceApplication.java:
--------------------------------------------------------------------------------
1 | package com.xh;
2 |
3 | import com.xh.datasource.DynamicDataSourceConfig;
4 | import org.mybatis.spring.annotation.MapperScan;
5 | import org.springframework.boot.SpringApplication;
6 | import org.springframework.boot.autoconfigure.SpringBootApplication;
7 | import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
8 | import org.springframework.context.annotation.Import;
9 |
10 | /**
11 | * @author xiaohe
12 | */
13 | @MapperScan("com.xh.mapper")
14 | @SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
15 | @Import({DynamicDataSourceConfig.class})
16 | public class SpringBootDynamicDataSourceApplication {
17 |
18 | public static void main(String[] args) {
19 | SpringApplication.run(SpringBootDynamicDataSourceApplication.class, args);
20 | }
21 |
22 | }
23 |
--------------------------------------------------------------------------------
/src/main/java/com/xh/controller/SysUserController.java:
--------------------------------------------------------------------------------
1 | package com.xh.controller;
2 |
3 |
4 | import org.springframework.web.bind.annotation.RequestMapping;
5 |
6 | import org.springframework.web.bind.annotation.RestController;
7 |
8 | /**
9 | *
10 | * 系统用户 前端控制器
11 | *
12 | *
13 | * @author xiaohe
14 | * @since 2019-06-04
15 | */
16 | @RestController
17 | @RequestMapping("/sys-user")
18 | public class SysUserController {
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/src/main/java/com/xh/datasource/CurDataSource.java:
--------------------------------------------------------------------------------
1 | package com.xh.datasource;
2 |
3 | import java.lang.annotation.*;
4 |
5 | /**
6 | * 多数据源注解
7 | *
8 | * 指定要使用的数据源
9 | *
10 | * @author xiaohe
11 | * @version V1.0.0
12 | */
13 | @Target(ElementType.METHOD)
14 | @Retention(RetentionPolicy.RUNTIME)
15 | @Documented
16 | public @interface CurDataSource {
17 |
18 | String name() default "";
19 |
20 | }
--------------------------------------------------------------------------------
/src/main/java/com/xh/datasource/DataSourceAspect.java:
--------------------------------------------------------------------------------
1 | package com.xh.datasource;
2 |
3 | import lombok.extern.slf4j.Slf4j;
4 | import org.aspectj.lang.ProceedingJoinPoint;
5 | import org.aspectj.lang.annotation.Around;
6 | import org.aspectj.lang.annotation.Aspect;
7 | import org.aspectj.lang.annotation.Pointcut;
8 | import org.aspectj.lang.reflect.MethodSignature;
9 | import org.springframework.core.Ordered;
10 | import org.springframework.stereotype.Component;
11 |
12 | import java.lang.reflect.Method;
13 |
14 | /**
15 | * 多数据源,切面处理类
16 | *
17 | * @author xiaohe
18 | * @version V1.0.0
19 | */
20 | @Slf4j
21 | @Aspect
22 | @Component
23 | public class DataSourceAspect implements Ordered {
24 |
25 | @Pointcut("@annotation(com.xh.datasource.CurDataSource)")
26 | public void dataSourcePointCut() {
27 |
28 | }
29 |
30 | @Around("dataSourcePointCut()")
31 | public Object around(ProceedingJoinPoint point) throws Throwable {
32 | MethodSignature signature = (MethodSignature) point.getSignature();
33 | Method method = signature.getMethod();
34 |
35 | CurDataSource ds = method.getAnnotation(CurDataSource.class);
36 | if (ds == null) {
37 | DynamicDataSource.setDataSource(DataSourceNames.FIRST);
38 | log.debug("set datasource is " + DataSourceNames.FIRST);
39 | } else {
40 | DynamicDataSource.setDataSource(ds.name());
41 | log.debug("set datasource is " + ds.name());
42 | }
43 |
44 | try {
45 | return point.proceed();
46 | } finally {
47 | DynamicDataSource.clearDataSource();
48 | log.debug("clean datasource");
49 | }
50 | }
51 |
52 | @Override
53 | public int getOrder() {
54 | return 1;
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/src/main/java/com/xh/datasource/DataSourceNames.java:
--------------------------------------------------------------------------------
1 | package com.xh.datasource;
2 |
3 | /**
4 | * 增加多数据源,在此配置
5 | *
6 | * @author xiaohe
7 | * @version V1.0.0
8 | */
9 | public interface DataSourceNames {
10 |
11 | String FIRST = "first";
12 |
13 | String SECOND = "second";
14 |
15 | }
16 |
--------------------------------------------------------------------------------
/src/main/java/com/xh/datasource/DynamicDataSource.java:
--------------------------------------------------------------------------------
1 | package com.xh.datasource;
2 |
3 | import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
4 |
5 | import javax.sql.DataSource;
6 | import java.util.Map;
7 |
8 | /**
9 | * 扩展 Spring 的 AbstractRoutingDataSource 抽象类,重写 determineCurrentLookupKey 方法
10 | * 动态数据源
11 | * determineCurrentLookupKey() 方法决定使用哪个数据源
12 | *
13 | * @author xiaohe
14 | * @version V1.0.0
15 | */
16 | public class DynamicDataSource extends AbstractRoutingDataSource {
17 |
18 | /**
19 | * ThreadLocal 用于提供线程局部变量,在多线程环境可以保证各个线程里的变量独立于其它线程里的变量。
20 | * 也就是说 ThreadLocal 可以为每个线程创建一个【单独的变量副本】,相当于线程的 private static 类型变量。
21 | */
22 | private static final ThreadLocal CONTEXT_HOLDER = new ThreadLocal<>();
23 |
24 | /**
25 | * 决定使用哪个数据源之前需要把多个数据源的信息以及默认数据源信息配置好
26 | *
27 | * @param defaultTargetDataSource 默认数据源
28 | * @param targetDataSources 目标数据源
29 | */
30 | public DynamicDataSource(DataSource defaultTargetDataSource, Map