From 74757c1628e0e1f7a8988a1467081267e541d0c0 Mon Sep 17 00:00:00 2001 From: yidao620 Date: Wed, 28 Feb 2018 13:43:17 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E4=BB=A3=E7=A0=81=E7=A4=BA?= =?UTF-8?q?=E4=BE=8Bspringboot-multisource?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- springboot-multisource/.gitignore | 10 + springboot-multisource/LICENSE | 20 ++ springboot-multisource/README.md | 37 +++ springboot-multisource/pom.xml | 118 +++++++++ springboot-multisource/run.sh | 72 +++++ .../java/com/xncoding/pos/Application.java | 12 + .../pos/common/annotion/DataSource.java | 17 ++ .../pos/common/aop/MultiSourceExAop.java | 75 ++++++ .../xncoding/pos/common/dao/entity/User.java | 249 ++++++++++++++++++ .../pos/common/dao/repository/UserMapper.java | 15 ++ .../pos/common/mutidatesource/DSEnum.java | 14 + .../DataSourceContextHolder.java | 34 +++ .../mutidatesource/DynamicDataSource.java | 18 ++ .../pos/config/MybatisPlusConfig.java | 99 +++++++ .../config/properties/DruidProperties.java | 249 ++++++++++++++++++ .../properties/MutiDataSourceProperties.java | 52 ++++ .../com/xncoding/pos/service/UserService.java | 64 +++++ .../src/main/resources/application.yml | 88 +++++++ .../src/main/resources/banner.txt | 23 ++ .../src/main/resources/sql/schema.sql | 37 +++ .../com/xncoding/pos/ApplicationTests.java | 42 +++ 21 files changed, 1345 insertions(+) create mode 100644 springboot-multisource/.gitignore create mode 100644 springboot-multisource/LICENSE create mode 100644 springboot-multisource/README.md create mode 100644 springboot-multisource/pom.xml create mode 100644 springboot-multisource/run.sh create mode 100644 springboot-multisource/src/main/java/com/xncoding/pos/Application.java create mode 100644 springboot-multisource/src/main/java/com/xncoding/pos/common/annotion/DataSource.java create mode 100644 springboot-multisource/src/main/java/com/xncoding/pos/common/aop/MultiSourceExAop.java create mode 100644 springboot-multisource/src/main/java/com/xncoding/pos/common/dao/entity/User.java create mode 100644 springboot-multisource/src/main/java/com/xncoding/pos/common/dao/repository/UserMapper.java create mode 100644 springboot-multisource/src/main/java/com/xncoding/pos/common/mutidatesource/DSEnum.java create mode 100644 springboot-multisource/src/main/java/com/xncoding/pos/common/mutidatesource/DataSourceContextHolder.java create mode 100644 springboot-multisource/src/main/java/com/xncoding/pos/common/mutidatesource/DynamicDataSource.java create mode 100644 springboot-multisource/src/main/java/com/xncoding/pos/config/MybatisPlusConfig.java create mode 100644 springboot-multisource/src/main/java/com/xncoding/pos/config/properties/DruidProperties.java create mode 100644 springboot-multisource/src/main/java/com/xncoding/pos/config/properties/MutiDataSourceProperties.java create mode 100644 springboot-multisource/src/main/java/com/xncoding/pos/service/UserService.java create mode 100644 springboot-multisource/src/main/resources/application.yml create mode 100644 springboot-multisource/src/main/resources/banner.txt create mode 100644 springboot-multisource/src/main/resources/sql/schema.sql create mode 100644 springboot-multisource/src/test/java/com/xncoding/pos/ApplicationTests.java diff --git a/springboot-multisource/.gitignore b/springboot-multisource/.gitignore new file mode 100644 index 0000000..9d8e7cc --- /dev/null +++ b/springboot-multisource/.gitignore @@ -0,0 +1,10 @@ +.idea/ +target/ +*.iml +*.ipr +*.iws +*.log +.svn/ +.project +rebel.xml +.rebel-remote.xml.* diff --git a/springboot-multisource/LICENSE b/springboot-multisource/LICENSE new file mode 100644 index 0000000..83cd47d --- /dev/null +++ b/springboot-multisource/LICENSE @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2018 Xiong Neng + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/springboot-multisource/README.md b/springboot-multisource/README.md new file mode 100644 index 0000000..33d7ec2 --- /dev/null +++ b/springboot-multisource/README.md @@ -0,0 +1,37 @@ +## 配置多数据源 + +SpringBoot配置多数据源,使用MyBatis作为DAO层演示 + +## 安装MySQL数据库 + +数据库的安装教程网上非常多,版本最好是mysql5.5+,配置数据库的账号和密码。 +并且创建两个数据库pos和biz来测试多数据源。 + +## 修改application.yml + +修改配置文件,主要是mysql的账号和密码,两个数据库都要配置 + +## 数据库初始化 + +然后执行SQL文件`src/main/resources/sql/schema.sql` + +``` +# 下面是核心数据库中的插入数据 +INSERT INTO `t_user` VALUES (1,'admin','系统管理员','123456','www', '17890908889', '系统管理员', 1, '2017-12-12 09:46:12', '2017-12-12 09:46:12'); +INSERT INTO `t_user` VALUES (2,'aix','张三','123456','eee', '17859569358', '', 1, '2017-12-12 09:46:12', '2017-12-12 09:46:12'); + +# 下面是biz数据库中的插入数据 +INSERT INTO `t_user` VALUES (1,'admin1','系统管理员','123456','www', '17890908889', '系统管理员', 1, '2017-12-12 09:46:12', '2017-12-12 09:46:12'); +INSERT INTO `t_user` VALUES (2,'aix1','张三','123456','eee', '17859569358', '', 1, '2017-12-12 09:46:12', '2017-12-12 09:46:12'); + +``` + +## 运行测试用例 + +执行对用户表增/删/改/查的测试用例:`com.xncoding.pos.ApplicationTests.java` + +## 许可证 + +Copyright (c) 2018 Xiong Neng + +基于 MIT 协议发布: diff --git a/springboot-multisource/pom.xml b/springboot-multisource/pom.xml new file mode 100644 index 0000000..76da936 --- /dev/null +++ b/springboot-multisource/pom.xml @@ -0,0 +1,118 @@ + + + 4.0.0 + + com.xncoding + springboot-multisource + 1.0.0-SNAPSHOT + jar + + springboot-multisource + SpringBoot配置多数据源 + + + org.springframework.boot + spring-boot-starter-parent + 1.5.9.RELEASE + + + + + UTF-8 + UTF-8 + 1.8 + 1.1.2 + 8.0.7-dmr + 2.1.8 + 1.0.5 + + + + + org.springframework.boot + spring-boot-starter-aop + + + org.springframework.boot + spring-boot-starter-jdbc + + + mysql + mysql-connector-java + ${mysql-connector.version} + runtime + + + com.alibaba + druid + ${druid.version} + + + + com.baomidou + mybatis-plus + ${mybatis-plus.version} + + + com.baomidou + mybatisplus-spring-boot-starter + ${mybatisplus-spring-boot-starter.version} + + + + org.springframework.boot + spring-boot-starter-test + test + + + org.hamcrest + hamcrest-all + 1.3 + test + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.6.1 + + + 1.8 + 1.8 + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.20 + + true + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + + + src/main/resources + + + src/main/java + + **/*.xml + + + + + + \ No newline at end of file diff --git a/springboot-multisource/run.sh b/springboot-multisource/run.sh new file mode 100644 index 0000000..955efb1 --- /dev/null +++ b/springboot-multisource/run.sh @@ -0,0 +1,72 @@ +#!/bin/bash +# 项目自动更新脚本 +# 先clone相应的分支下来: +# git clone ssh://git@120.24.173.142:7999/xxx.git +# 远程调试启动: +# nohup java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005 -Xms512m -Xmx1024m -jar -Dspring.profiles.active=${profile} ${jarfile} >/dev/null 2>&1 & + +function start { + profile="$1" + echo "启动环境profile=${profile}" + jarfile=$(ls target/*.jar) + if [[ "$?" == "0" ]]; then + stop $profile $jarfile + fi + branch=$(git branch |awk '{print $2}') + git pull origin ${branch} + echo "更新完代码开始重新打包" + mvn clean && mvn clean && mvn package -DskipTests=true + if [[ "$?" != "0" ]]; then + echo "编译出错,退出!" + exit 1 + fi + echo "nohup java -Xms512m -Xmx1024m -jar -Dspring.profiles.active=${profile} ${jarfile} >/dev/null 2>&1 &" + nohup java -Xms512m -Xmx1024m -jar -Dspring.profiles.active=${profile} ${jarfile} >/dev/null 2>&1 & + echo "启动应用中,请查看日志文件..." +} + +function stop { + profile="$1" + jarfile="$2" + ps aux | grep "${jarfile}" | grep "spring.profiles.active=${profile}" | grep -v grep > /dev/null + if [[ "$?" == "0" ]]; then + echo "该应用还在跑,我先停了它" + pid=$(ps aux | grep "${jarfile}" | grep "spring.profiles.active=${profile}" | grep -v grep |awk '{print $2}') + if [[ "$pid" != "" ]]; then + kill -9 $pid + fi + echo "停止应用成功..." + fi +} + +if [[ "$1" == "start" ]]; then + if [[ "$#" < 2 ]]; then + echo "请输入正确参数:./epay.sh start {profile}" + exit 1 + fi + profile="$2" + if [[ "$profile" != "dev" && "$profile" != "test" && "$profile" != "show" && "$profile" != "production" ]]; then + echo "参数错误,请输入正确的profile参数,使用方法:" + echo "./epay.sh start {profile} ==> 启动应用,{profile}取值:dev|test|show|production" + exit 1 + fi + start "${profile}" +elif [[ "$1" == "stop" ]]; then + if [[ "$#" < 2 ]]; then + echo "请输入正确参数:./epay.sh stop {profile}" + exit 1 + fi + profile="$2" + if [[ "$profile" != "dev" && "$profile" != "test" && "$profile" != "show" && "$profile" != "production" ]]; then + echo "参数错误,请输入正确的profile参数,使用方法:" + echo "./epay.sh stop {profile} ==> 停止应用,{profile}取值:dev|test|show|production" + exit 1 + fi + jarfile=$(ls target/*.jar) + stop $profile $jarfile +else + echo "参数错误,使用方法:{}参数是必填的,[]参数可选" + echo "./epay.sh start {profile} ==> 启动应用,{profile}取值:dev|test|show|production" + echo "./epay.sh stop {profile} ==> 停止应用,{profile}取值:dev|test|show|production" + exit 1 +fi diff --git a/springboot-multisource/src/main/java/com/xncoding/pos/Application.java b/springboot-multisource/src/main/java/com/xncoding/pos/Application.java new file mode 100644 index 0000000..adc4c48 --- /dev/null +++ b/springboot-multisource/src/main/java/com/xncoding/pos/Application.java @@ -0,0 +1,12 @@ +package com.xncoding.pos; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class Application { + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } + +} diff --git a/springboot-multisource/src/main/java/com/xncoding/pos/common/annotion/DataSource.java b/springboot-multisource/src/main/java/com/xncoding/pos/common/annotion/DataSource.java new file mode 100644 index 0000000..3d573b4 --- /dev/null +++ b/springboot-multisource/src/main/java/com/xncoding/pos/common/annotion/DataSource.java @@ -0,0 +1,17 @@ +package com.xncoding.pos.common.annotion; + +import java.lang.annotation.*; + +/** + * 多数据源标识 + * + * @author xiongneng + * @since 2017年3月5日 上午9:44:24 + */ +@Inherited +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.METHOD}) +public @interface DataSource { + + String name() default ""; +} diff --git a/springboot-multisource/src/main/java/com/xncoding/pos/common/aop/MultiSourceExAop.java b/springboot-multisource/src/main/java/com/xncoding/pos/common/aop/MultiSourceExAop.java new file mode 100644 index 0000000..f161268 --- /dev/null +++ b/springboot-multisource/src/main/java/com/xncoding/pos/common/aop/MultiSourceExAop.java @@ -0,0 +1,75 @@ +package com.xncoding.pos.common.aop; + +import com.xncoding.pos.common.annotion.DataSource; +import com.xncoding.pos.common.mutidatesource.DSEnum; +import com.xncoding.pos.common.mutidatesource.DataSourceContextHolder; +import org.apache.log4j.Logger; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.Signature; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Pointcut; +import org.aspectj.lang.reflect.MethodSignature; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.core.Ordered; +import org.springframework.stereotype.Component; + +import java.lang.reflect.Method; + +/** + * 多数据源切换的aop + * + * @author xiongneng + * @since 2017年3月5日 上午10:22:16 + */ +@Aspect +@Component +@ConditionalOnProperty(prefix = "xncoding", name = "muti-datasource-open", havingValue = "true") +public class MultiSourceExAop implements Ordered { + + private Logger log = Logger.getLogger(this.getClass()); + + @Pointcut(value = "@annotation(com.xncoding.pos.common.annotion.DataSource)") + private void cut() { + + } + + @Around("cut()") + public Object around(ProceedingJoinPoint point) throws Throwable { + + Signature signature = point.getSignature(); + MethodSignature methodSignature = null; + if (!(signature instanceof MethodSignature)) { + throw new IllegalArgumentException("该注解只能用于方法"); + } + methodSignature = (MethodSignature) signature; + + Object target = point.getTarget(); + Method currentMethod = target.getClass().getMethod(methodSignature.getName(), methodSignature.getParameterTypes()); + + DataSource datasource = currentMethod.getAnnotation(DataSource.class); + if (datasource != null) { + DataSourceContextHolder.setDataSourceType(datasource.name()); + log.debug("设置数据源为:" + datasource.name()); + } else { + DataSourceContextHolder.setDataSourceType(DSEnum.DATA_SOURCE_CORE); + log.debug("设置数据源为:dataSourceCore"); + } + try { + return point.proceed(); + } finally { + log.debug("清空数据源信息!"); + DataSourceContextHolder.clearDataSourceType(); + } + } + + + /** + * aop的顺序要早于spring的事务 + */ + @Override + public int getOrder() { + return 1; + } + +} diff --git a/springboot-multisource/src/main/java/com/xncoding/pos/common/dao/entity/User.java b/springboot-multisource/src/main/java/com/xncoding/pos/common/dao/entity/User.java new file mode 100644 index 0000000..a05c48e --- /dev/null +++ b/springboot-multisource/src/main/java/com/xncoding/pos/common/dao/entity/User.java @@ -0,0 +1,249 @@ +package com.xncoding.pos.common.dao.entity; + +import java.util.Date; +import com.baomidou.mybatisplus.annotations.TableName; +import com.baomidou.mybatisplus.enums.IdType; +import com.baomidou.mybatisplus.annotations.TableId; +import com.baomidou.mybatisplus.activerecord.Model; +import java.io.Serializable; + +/** + * 后台管理用户表 + * + * @author 熊能 + * @version 1.0 + * @since 2018/01/02 + */ +@TableName(value = "t_user") +public class User extends Model { + +private static final long serialVersionUID = 1L; + + /** + * 主键ID + */ + @TableId(value="id", type= IdType.AUTO) + private Integer id; + /** + * 账号 + */ + private String username; + /** + * 名字 + */ + private String name; + /** + * 密码 + */ + private String password; + /** + * md5密码盐 + */ + private String salt; + /** + * 联系电话 + */ + private String phone; + /** + * 备注 + */ + private String tips; + /** + * 状态 1:正常 2:禁用 + */ + private Integer state; + /** + * 创建时间 + */ + private Date createdTime; + /** + * 更新时间 + */ + private Date updatedTime; + + /** + * 获取 主键ID. + * + * @return 主键ID. + */ + public Integer getId() { + return id; + } + + /** + * 设置 主键ID. + * + * @param id 主键ID. + */ + public void setId(Integer id) { + this.id = id; + } + + /** + * 获取 账号. + * + * @return 账号. + */ + public String getUsername() { + return username; + } + + /** + * 设置 账号. + * + * @param username 账号. + */ + public void setUsername(String username) { + this.username = username; + } + + /** + * 获取 名字. + * + * @return 名字. + */ + public String getName() { + return name; + } + + /** + * 设置 名字. + * + * @param name 名字. + */ + public void setName(String name) { + this.name = name; + } + + /** + * 获取 密码. + * + * @return 密码. + */ + public String getPassword() { + return password; + } + + /** + * 设置 密码. + * + * @param password 密码. + */ + public void setPassword(String password) { + this.password = password; + } + + /** + * 获取 md5密码盐. + * + * @return md5密码盐. + */ + public String getSalt() { + return salt; + } + + /** + * 设置 md5密码盐. + * + * @param salt md5密码盐. + */ + public void setSalt(String salt) { + this.salt = salt; + } + + /** + * 获取 联系电话. + * + * @return 联系电话. + */ + public String getPhone() { + return phone; + } + + /** + * 设置 联系电话. + * + * @param phone 联系电话. + */ + public void setPhone(String phone) { + this.phone = phone; + } + + /** + * 获取 备注. + * + * @return 备注. + */ + public String getTips() { + return tips; + } + + /** + * 设置 备注. + * + * @param tips 备注. + */ + public void setTips(String tips) { + this.tips = tips; + } + + /** + * 获取 状态 1:正常 2:禁用. + * + * @return 状态 1:正常 2:禁用. + */ + public Integer getState() { + return state; + } + + /** + * 设置 状态 1:正常 2:禁用. + * + * @param state 状态 1:正常 2:禁用. + */ + public void setState(Integer state) { + this.state = state; + } + + /** + * 获取 创建时间. + * + * @return 创建时间. + */ + public Date getCreatedTime() { + return createdTime; + } + + /** + * 设置 创建时间. + * + * @param createdTime 创建时间. + */ + public void setCreatedTime(Date createdTime) { + this.createdTime = createdTime; + } + + /** + * 获取 更新时间. + * + * @return 更新时间. + */ + public Date getUpdatedTime() { + return updatedTime; + } + + /** + * 设置 更新时间. + * + * @param updatedTime 更新时间. + */ + public void setUpdatedTime(Date updatedTime) { + this.updatedTime = updatedTime; + } + + @Override + protected Serializable pkVal() { + return this.id; + } + +} diff --git a/springboot-multisource/src/main/java/com/xncoding/pos/common/dao/repository/UserMapper.java b/springboot-multisource/src/main/java/com/xncoding/pos/common/dao/repository/UserMapper.java new file mode 100644 index 0000000..3ab1560 --- /dev/null +++ b/springboot-multisource/src/main/java/com/xncoding/pos/common/dao/repository/UserMapper.java @@ -0,0 +1,15 @@ +package com.xncoding.pos.common.dao.repository; + +import com.xncoding.pos.common.dao.entity.User; +import com.baomidou.mybatisplus.mapper.BaseMapper; + +/** + * 后台管理用户表 Mapper + * + * @author 熊能 + * @version 1.0 + * @since 2018/01/02 + */ +public interface UserMapper extends BaseMapper { + +} diff --git a/springboot-multisource/src/main/java/com/xncoding/pos/common/mutidatesource/DSEnum.java b/springboot-multisource/src/main/java/com/xncoding/pos/common/mutidatesource/DSEnum.java new file mode 100644 index 0000000..d45c594 --- /dev/null +++ b/springboot-multisource/src/main/java/com/xncoding/pos/common/mutidatesource/DSEnum.java @@ -0,0 +1,14 @@ +package com.xncoding.pos.common.mutidatesource; + +/** + * 多数据源的枚举 + * + * @author xiongneng + * @since 2017年3月5日 上午10:15:02 + */ +public interface DSEnum { + + String DATA_SOURCE_CORE = "dataSourceCore"; //核心数据源 + + String DATA_SOURCE_BIZ = "dataSourceBiz"; //其他业务的数据源 +} diff --git a/springboot-multisource/src/main/java/com/xncoding/pos/common/mutidatesource/DataSourceContextHolder.java b/springboot-multisource/src/main/java/com/xncoding/pos/common/mutidatesource/DataSourceContextHolder.java new file mode 100644 index 0000000..b1f6ae8 --- /dev/null +++ b/springboot-multisource/src/main/java/com/xncoding/pos/common/mutidatesource/DataSourceContextHolder.java @@ -0,0 +1,34 @@ +package com.xncoding.pos.common.mutidatesource; + +/** + * datasource的上下文 + * + * @author xiongneng + * @since 2017年3月5日 上午9:10:58 + */ +public class DataSourceContextHolder { + + private static final ThreadLocal contextHolder = new ThreadLocal(); + + /** + * @param dataSourceType 数据库类型 + * @Description: 设置数据源类型 + */ + public static void setDataSourceType(String dataSourceType) { + contextHolder.set(dataSourceType); + } + + /** + * @Description: 获取数据源类型 + */ + public static String getDataSourceType() { + return contextHolder.get(); + } + + /** + * @Description: 清除数据源类型 + */ + public static void clearDataSourceType() { + contextHolder.remove(); + } +} diff --git a/springboot-multisource/src/main/java/com/xncoding/pos/common/mutidatesource/DynamicDataSource.java b/springboot-multisource/src/main/java/com/xncoding/pos/common/mutidatesource/DynamicDataSource.java new file mode 100644 index 0000000..00566de --- /dev/null +++ b/springboot-multisource/src/main/java/com/xncoding/pos/common/mutidatesource/DynamicDataSource.java @@ -0,0 +1,18 @@ +package com.xncoding.pos.common.mutidatesource; + +import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; + +/** + * 动态数据源 + * + * @author xiongneng + * @since 2017年3月5日 上午9:11:49 + */ +public class DynamicDataSource extends AbstractRoutingDataSource { + + @Override + protected Object determineCurrentLookupKey() { + return DataSourceContextHolder.getDataSourceType(); + } + +} diff --git a/springboot-multisource/src/main/java/com/xncoding/pos/config/MybatisPlusConfig.java b/springboot-multisource/src/main/java/com/xncoding/pos/config/MybatisPlusConfig.java new file mode 100644 index 0000000..4e8cfe6 --- /dev/null +++ b/springboot-multisource/src/main/java/com/xncoding/pos/config/MybatisPlusConfig.java @@ -0,0 +1,99 @@ +package com.xncoding.pos.config; + +import com.alibaba.druid.pool.DruidDataSource; +import com.baomidou.mybatisplus.plugins.PaginationInterceptor; +import com.xncoding.pos.common.mutidatesource.DSEnum; +import com.xncoding.pos.common.mutidatesource.DynamicDataSource; +import com.xncoding.pos.config.properties.DruidProperties; +import com.xncoding.pos.config.properties.MutiDataSourceProperties; +import org.mybatis.spring.annotation.MapperScan; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.transaction.annotation.EnableTransactionManagement; + +import java.sql.SQLException; +import java.util.HashMap; + +/** + * MybatisPlus配置 + * + * @author xiongneng + * @since 2017/5/20 21:58 + */ +@Configuration +@EnableTransactionManagement(order = 2) +@MapperScan(basePackages = { + "com.xncoding.pos.common.dao.repository", + "com.xncoding.pos.dao.repository"}) +public class MybatisPlusConfig { + + @Autowired + DruidProperties druidProperties; + + @Autowired + MutiDataSourceProperties mutiDataSourceProperties; + + /** + * 核心数据源 + */ + private DruidDataSource coreDataSource() { + DruidDataSource dataSource = new DruidDataSource(); + druidProperties.config(dataSource); + return dataSource; + } + + /** + * 另一个数据源 + */ + private DruidDataSource bizDataSource() { + DruidDataSource dataSource = new DruidDataSource(); + druidProperties.config(dataSource); + mutiDataSourceProperties.config(dataSource); + return dataSource; + } + + /** + * 单数据源连接池配置 + */ + @Bean + @ConditionalOnProperty(prefix = "xncoding", name = "muti-datasource-open", havingValue = "false") + public DruidDataSource singleDatasource() { + return coreDataSource(); + } + + /** + * 多数据源连接池配置 + */ + @Bean + @ConditionalOnProperty(prefix = "xncoding", name = "muti-datasource-open", havingValue = "true") + public DynamicDataSource mutiDataSource() { + + DruidDataSource coreDataSource = coreDataSource(); + DruidDataSource bizDataSource = bizDataSource(); + + try { + coreDataSource.init(); + bizDataSource.init(); + } catch (SQLException sql) { + sql.printStackTrace(); + } + + DynamicDataSource dynamicDataSource = new DynamicDataSource(); + HashMap hashMap = new HashMap<>(); + hashMap.put(DSEnum.DATA_SOURCE_CORE, coreDataSource); + hashMap.put(DSEnum.DATA_SOURCE_BIZ, bizDataSource); + dynamicDataSource.setTargetDataSources(hashMap); + dynamicDataSource.setDefaultTargetDataSource(coreDataSource); + return dynamicDataSource; + } + + /** + * mybatis-plus分页插件 + */ + @Bean + public PaginationInterceptor paginationInterceptor() { + return new PaginationInterceptor(); + } +} diff --git a/springboot-multisource/src/main/java/com/xncoding/pos/config/properties/DruidProperties.java b/springboot-multisource/src/main/java/com/xncoding/pos/config/properties/DruidProperties.java new file mode 100644 index 0000000..7cb4424 --- /dev/null +++ b/springboot-multisource/src/main/java/com/xncoding/pos/config/properties/DruidProperties.java @@ -0,0 +1,249 @@ +package com.xncoding.pos.config.properties; + +import com.alibaba.druid.pool.DruidDataSource; +import com.alibaba.druid.util.JdbcConstants; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +import java.sql.SQLException; + +/** + *

数据库数据源配置

+ *

说明:这个类中包含了许多默认配置,若这些配置符合您的情况,您可以不用管,若不符合,建议不要修改本类,建议直接在"application.yml"中配置即可

+ * + * @author xiongneng + * @since 2017-05-21 11:18 + */ +@Component +@ConfigurationProperties(prefix = "spring.datasource") +public class DruidProperties { + + private String url; + + private String username; + + private String password; + + private String driverClassName = "com.mysql.cj.jdbc.Driver"; + + private Integer initialSize = 10; + + private Integer minIdle = 3; + + private Integer maxActive = 60; + + private Integer maxWait = 60000; + + private Boolean removeAbandoned = true; + + private Integer removeAbandonedTimeout = 180; + + private Integer timeBetweenEvictionRunsMillis = 60000; + + private Integer minEvictableIdleTimeMillis = 300000; + + private String validationQuery = "SELECT 'x'"; + + private Boolean testWhileIdle = true; + + private Boolean testOnBorrow = false; + + private Boolean testOnReturn = false; + + private Boolean poolPreparedStatements = true; + + private Integer maxPoolPreparedStatementPerConnectionSize = 50; + + private String filters = "stat"; + + public void config(DruidDataSource dataSource) { + dataSource.setDbType(JdbcConstants.MYSQL); + dataSource.setUrl(url); + dataSource.setUsername(username); + dataSource.setPassword(password); + dataSource.setDriverClassName(driverClassName); + dataSource.setInitialSize(initialSize); // 定义初始连接数 + dataSource.setMinIdle(minIdle); // 最小空闲 + dataSource.setMaxActive(maxActive); // 定义最大连接数 + dataSource.setMaxWait(maxWait); // 获取连接等待超时的时间 + dataSource.setRemoveAbandoned(removeAbandoned); // 超过时间限制是否回收 + dataSource.setRemoveAbandonedTimeout(removeAbandonedTimeout); // 超过时间限制多长 + + // 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 + dataSource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis); + // 配置一个连接在池中最小生存的时间,单位是毫秒 + dataSource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis); + // 用来检测连接是否有效的sql,要求是一个查询语句 + dataSource.setValidationQuery(validationQuery); + // 申请连接的时候检测 + dataSource.setTestWhileIdle(testWhileIdle); + // 申请连接时执行validationQuery检测连接是否有效,配置为true会降低性能 + dataSource.setTestOnBorrow(testOnBorrow); + // 归还连接时执行validationQuery检测连接是否有效,配置为true会降低性能 + dataSource.setTestOnReturn(testOnReturn); + // 打开PSCache,并且指定每个连接上PSCache的大小 + dataSource.setPoolPreparedStatements(poolPreparedStatements); + dataSource.setMaxPoolPreparedStatementPerConnectionSize(maxPoolPreparedStatementPerConnectionSize); + // 属性类型是字符串,通过别名的方式配置扩展插件,常用的插件有: + // 监控统计用的filter:stat + // 日志用的filter:log4j + // 防御SQL注入的filter:wall + try { + dataSource.setFilters(filters); + } catch (SQLException e) { + e.printStackTrace(); + } + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public String getDriverClassName() { + return driverClassName; + } + + public void setDriverClassName(String driverClassName) { + this.driverClassName = driverClassName; + } + + public Integer getInitialSize() { + return initialSize; + } + + public void setInitialSize(Integer initialSize) { + this.initialSize = initialSize; + } + + public Integer getMinIdle() { + return minIdle; + } + + public void setMinIdle(Integer minIdle) { + this.minIdle = minIdle; + } + + public Integer getMaxActive() { + return maxActive; + } + + public void setMaxActive(Integer maxActive) { + this.maxActive = maxActive; + } + + public Integer getMaxWait() { + return maxWait; + } + + public void setMaxWait(Integer maxWait) { + this.maxWait = maxWait; + } + + public Integer getTimeBetweenEvictionRunsMillis() { + return timeBetweenEvictionRunsMillis; + } + + public void setTimeBetweenEvictionRunsMillis(Integer timeBetweenEvictionRunsMillis) { + this.timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis; + } + + public Integer getMinEvictableIdleTimeMillis() { + return minEvictableIdleTimeMillis; + } + + public void setMinEvictableIdleTimeMillis(Integer minEvictableIdleTimeMillis) { + this.minEvictableIdleTimeMillis = minEvictableIdleTimeMillis; + } + + public String getValidationQuery() { + return validationQuery; + } + + public void setValidationQuery(String validationQuery) { + this.validationQuery = validationQuery; + } + + public Boolean getTestWhileIdle() { + return testWhileIdle; + } + + public void setTestWhileIdle(Boolean testWhileIdle) { + this.testWhileIdle = testWhileIdle; + } + + public Boolean getTestOnBorrow() { + return testOnBorrow; + } + + public void setTestOnBorrow(Boolean testOnBorrow) { + this.testOnBorrow = testOnBorrow; + } + + public Boolean getTestOnReturn() { + return testOnReturn; + } + + public void setTestOnReturn(Boolean testOnReturn) { + this.testOnReturn = testOnReturn; + } + + public Boolean getPoolPreparedStatements() { + return poolPreparedStatements; + } + + public void setPoolPreparedStatements(Boolean poolPreparedStatements) { + this.poolPreparedStatements = poolPreparedStatements; + } + + public Integer getMaxPoolPreparedStatementPerConnectionSize() { + return maxPoolPreparedStatementPerConnectionSize; + } + + public void setMaxPoolPreparedStatementPerConnectionSize(Integer maxPoolPreparedStatementPerConnectionSize) { + this.maxPoolPreparedStatementPerConnectionSize = maxPoolPreparedStatementPerConnectionSize; + } + + public String getFilters() { + return filters; + } + + public void setFilters(String filters) { + this.filters = filters; + } + + public Boolean getRemoveAbandoned() { + return removeAbandoned; + } + + public void setRemoveAbandoned(Boolean removeAbandoned) { + this.removeAbandoned = removeAbandoned; + } + + public Integer getRemoveAbandonedTimeout() { + return removeAbandonedTimeout; + } + + public void setRemoveAbandonedTimeout(Integer removeAbandonedTimeout) { + this.removeAbandonedTimeout = removeAbandonedTimeout; + } +} diff --git a/springboot-multisource/src/main/java/com/xncoding/pos/config/properties/MutiDataSourceProperties.java b/springboot-multisource/src/main/java/com/xncoding/pos/config/properties/MutiDataSourceProperties.java new file mode 100644 index 0000000..6ab65e9 --- /dev/null +++ b/springboot-multisource/src/main/java/com/xncoding/pos/config/properties/MutiDataSourceProperties.java @@ -0,0 +1,52 @@ +package com.xncoding.pos.config.properties; + +import com.alibaba.druid.pool.DruidDataSource; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +/** + * 多数据源的配置 + * + * @author xiongneng + * @since 2017/6/23 23:05 + */ +@Component +@ConfigurationProperties(prefix = "biz.datasource") +public class MutiDataSourceProperties { + + private String url; + + private String username; + + private String password; + + public void config(DruidDataSource dataSource) { + dataSource.setUrl(url); + dataSource.setUsername(username); + dataSource.setPassword(password); + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } +} diff --git a/springboot-multisource/src/main/java/com/xncoding/pos/service/UserService.java b/springboot-multisource/src/main/java/com/xncoding/pos/service/UserService.java new file mode 100644 index 0000000..f4e6a19 --- /dev/null +++ b/springboot-multisource/src/main/java/com/xncoding/pos/service/UserService.java @@ -0,0 +1,64 @@ +package com.xncoding.pos.service; + +import com.xncoding.pos.common.annotion.DataSource; +import com.xncoding.pos.common.dao.entity.User; +import com.xncoding.pos.common.dao.repository.UserMapper; +import com.xncoding.pos.common.mutidatesource.DSEnum; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; + +/** + * 后台用户管理 + */ + +@Service +public class UserService { + + @Resource + private UserMapper userMapper; + + /** + * 通过ID查找用户 + * @param id + * @return + */ + public User findById(Integer id) { + return userMapper.selectById(id); + } + + /** + * 通过ID查找用户 + * @param id + * @return + */ + @DataSource(name = DSEnum.DATA_SOURCE_BIZ) + public User findById1(Integer id) { + return userMapper.selectById(id); + } + + /** + * 新增用户 + * @param user + */ + public void insertUser(User user) { + userMapper.insert(user); + } + + /** + * 修改用户 + * @param user + */ + public void updateUser(User user) { + userMapper.updateById(user); + } + + /** + * 删除用户 + * @param id + */ + public void deleteUser(Integer id) { + userMapper.deleteById(id); + } + +} diff --git a/springboot-multisource/src/main/resources/application.yml b/springboot-multisource/src/main/resources/application.yml new file mode 100644 index 0000000..9f45001 --- /dev/null +++ b/springboot-multisource/src/main/resources/application.yml @@ -0,0 +1,88 @@ +########################################################## +################## 所有profile共有的配置 ################# +########################################################## + +################### 自定义配置 ################### +xncoding: + muti-datasource-open: true #是否开启多数据源(true/false) + +################### spring配置 ################### +spring: + profiles: + active: dev + +################### mybatis-plus配置 ################### +mybatis-plus: + mapper-locations: classpath*:com/xncoding/pos/dao/repository/mapping/*.xml + typeAliasesPackage: > + com.xncoding.pos.common.dao.entity + global-config: + id-type: 0 # 0:数据库ID自增 1:用户输入id 2:全局唯一id(IdWorker) 3:全局唯一ID(uuid) + db-column-underline: false + refresh-mapper: true + configuration: + map-underscore-to-camel-case: true + cache-enabled: true #配置的缓存的全局开关 + lazyLoadingEnabled: true #延时加载的开关 + multipleResultSetsEnabled: true #开启的话,延时加载一个属性时会加载该对象全部属性,否则按需加载属性 + +logging: + level: + org.springframework.web.servlet: ERROR + +--- + +##################################################################### +######################## 开发环境profile ########################## +##################################################################### +spring: + profiles: dev + datasource: + url: jdbc:mysql://127.0.0.1:3306/pos?useSSL=false&autoReconnect=true&tinyInt1isBit=false&useUnicode=true&characterEncoding=utf8 + username: root + password: 123456 + thymeleaf: + cache: false + +#多数据源 +biz: + datasource: + url: jdbc:mysql://127.0.0.1:3306/biz?useSSL=false&autoReconnect=true&tinyInt1isBit=false&useUnicode=true&characterEncoding=utf8 + username: root + password: 123456 + +logging: + level: + ROOT: INFO + com: + xncoding: DEBUG + file: E:/logs/app.log + +--- + +##################################################################### +######################## 测试环境profile ########################## +##################################################################### + +spring: + profiles: test + datasource: + url: jdbc:mysql://127.0.0.1:3306/pos?useSSL=false&autoReconnect=true&tinyInt1isBit=false&useUnicode=true&characterEncoding=utf8 + username: root + password: 123456 + thymeleaf: + cache: false + +#多数据源 +biz: + datasource: + url: jdbc:mysql://127.0.0.1:3306/biz?useSSL=false&autoReconnect=true&tinyInt1isBit=false&useUnicode=true&characterEncoding=utf8 + username: root + password: 123456 + +logging: + level: + ROOT: INFO + com: + xncoding: DEBUG + file: /var/logs/app.log diff --git a/springboot-multisource/src/main/resources/banner.txt b/springboot-multisource/src/main/resources/banner.txt new file mode 100644 index 0000000..859b78f --- /dev/null +++ b/springboot-multisource/src/main/resources/banner.txt @@ -0,0 +1,23 @@ + + _____ _______ _____ _____ + /\ \ /::\ \ /\ \ /\ \ + /::\____\ /::::\ \ /::\____\ /::\ \ + /:::/ / /::::::\ \ /:::/ / /::::\ \ + /:::/ / /::::::::\ \ /:::/ / /::::::\ \ + /:::/ / /:::/~~\:::\ \ /:::/ / /:::/\:::\ \ + /:::/ / /:::/ \:::\ \ /:::/____/ /:::/__\:::\ \ + /:::/ / /:::/ / \:::\ \ |::| | /::::\ \:::\ \ + /:::/ / /:::/____/ \:::\____\ |::| | _____ /::::::\ \:::\ \ + /:::/ / |:::| | |:::| | |::| | /\ \ /:::/\:::\ \:::\ \ +/:::/____/ |:::|____| |:::| | |::| | /::\____\/:::/__\:::\ \:::\____\ +\:::\ \ \:::\ \ /:::/ / |::| | /:::/ /\:::\ \:::\ \::/ / + \:::\ \ \:::\ \ /:::/ / |::| | /:::/ / \:::\ \:::\ \/____/ + \:::\ \ \:::\ /:::/ / |::|____|/:::/ / \:::\ \:::\ \ + \:::\ \ \:::\__/:::/ / |:::::::::::/ / \:::\ \:::\____\ + \:::\ \ \::::::::/ / \::::::::::/____/ \:::\ \::/ / + \:::\ \ \::::::/ / ~~~~~~~~~~ \:::\ \/____/ + \:::\ \ \::::/ / \:::\ \ + \:::\____\ \::/____/ \:::\____\ + \::/ / ~~ \::/ / + \/____/ \/____/ + diff --git a/springboot-multisource/src/main/resources/sql/schema.sql b/springboot-multisource/src/main/resources/sql/schema.sql new file mode 100644 index 0000000..b31468c --- /dev/null +++ b/springboot-multisource/src/main/resources/sql/schema.sql @@ -0,0 +1,37 @@ +# -------------------------------------以下核心库开始------------------------------------------- +# CREATE DATABASE IF NOT EXISTS pos default charset utf8 COLLATE utf8_general_ci; +# SET FOREIGN_KEY_CHECKS=0; +# USE pos; + +# -------------------------------------以下其他业务库开始------------------------------------------- +# CREATE DATABASE IF NOT EXISTS pos default charset utf8 COLLATE utf8_general_ci; +# SET FOREIGN_KEY_CHECKS=0; +# USE biz; + +# -------------------------------------以下用户管理表开始------------------------------------------- + +-- 后台管理用户表 +DROP TABLE IF EXISTS `t_user`; +CREATE TABLE `t_user` ( + `id` INT(11) PRIMARY KEY AUTO_INCREMENT COMMENT '主键ID', + `username` VARCHAR(32) NOT NULL COMMENT '账号', + `name` VARCHAR(16) DEFAULT '' COMMENT '名字', + `password` VARCHAR(128) DEFAULT '' COMMENT '密码', + `salt` VARCHAR(64) DEFAULT '' COMMENT 'md5密码盐', + `phone` VARCHAR(32) DEFAULT '' COMMENT '联系电话', + `tips` VARCHAR(255) COMMENT '备注', + `state` TINYINT(1) DEFAULT 1 COMMENT '状态 1:正常 2:禁用', + `created_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updated_time` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间' +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='后台管理用户表'; + +# 下面是核心数据库中的插入数据 +INSERT INTO `t_user` VALUES (1,'admin','系统管理员','123456','www', '17890908889', '系统管理员', 1, '2017-12-12 09:46:12', '2017-12-12 09:46:12'); +INSERT INTO `t_user` VALUES (2,'aix','张三','123456','eee', '17859569358', '', 1, '2017-12-12 09:46:12', '2017-12-12 09:46:12'); + +# 下面是biz数据库中的插入数据 +INSERT INTO `t_user` VALUES (1,'admin1','系统管理员','123456','www', '17890908889', '系统管理员', 1, '2017-12-12 09:46:12', '2017-12-12 09:46:12'); +INSERT INTO `t_user` VALUES (2,'aix1','张三','123456','eee', '17859569358', '', 1, '2017-12-12 09:46:12', '2017-12-12 09:46:12'); + + + diff --git a/springboot-multisource/src/test/java/com/xncoding/pos/ApplicationTests.java b/springboot-multisource/src/test/java/com/xncoding/pos/ApplicationTests.java new file mode 100644 index 0000000..1c5cd84 --- /dev/null +++ b/springboot-multisource/src/test/java/com/xncoding/pos/ApplicationTests.java @@ -0,0 +1,42 @@ +package com.xncoding.pos; + +import com.xncoding.pos.common.dao.entity.User; +import com.xncoding.pos.service.UserService; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +import javax.annotation.Resource; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.nullValue; + +/** + * 测试 + */ +@RunWith(SpringRunner.class) +@SpringBootTest +public class ApplicationTests { + private static final Logger log = LoggerFactory.getLogger(ApplicationTests.class); + + @Resource + private UserService userService; + + /** + * 测试增删改查 + */ + @Test + public void test() { + // 核心数据库中的用户id=1 + User user = userService.findById(1); + assertThat(user.getUsername(), is("admin")); + + // biz数据库中的用户id=1 + User user1 = userService.findById1(1); + assertThat(user1.getUsername(), is("admin1")); + } +}