共计 13844 个字符,预计需要花费 35 分钟才能阅读完成。
阐明
在 jc 脚手架下引入 DB 模块,进行多数据源的主动寻址;
上面以 dci 组件数据库和本地数据库为例,展现如何在 jc 脚手架下引入 DB 模块并如何进行配置
引入 DB 模块的必要性
在开发中,常常会须要获取其余组件数据库中的数据,通常有两种方法:
(1)通过 Feign 调用;间接调用相干组件的接口获取数据
但有时候组件的接口没有或者不能调用,这个时候能够采纳第二种办法:
(2)引入 DB 模块,间接连贯组件的数据库,从数据库间接获取数据
1. 相干的 pom 依赖
在 business 文件夹下的 pom 文件中引入以下 pom 依赖:
<!-- 多数据源寻址 pom 依赖 --> | |
<dependency> | |
<groupId>com.alibaba</groupId> | |
<artifactId>druid-spring-boot-starter</artifactId> | |
<version>1.1.10</version> | |
</dependency> | |
<dependency> | |
<groupId>org.mybatis</groupId> | |
<artifactId>mybatis-spring</artifactId> | |
<version>2.0.6</version> | |
</dependency> | |
<dependency> | |
<groupId>com.baomidou</groupId> | |
<artifactId>mybatis-plus-core</artifactId> | |
<version>3.2.0</version> | |
</dependency> | |
<dependency> | |
<groupId>com.baomidou</groupId> | |
<artifactId>mybatis-plus-extension</artifactId> | |
<version>3.2.0</version> | |
</dependency> | |
<dependency> | |
<groupId>com.baomidou</groupId> | |
<artifactId>mybatis-plus-extension</artifactId> | |
<version>3.2.0</version> | |
</dependency> | |
<dependency> | |
<groupId>org.springframework</groupId> | |
<artifactId>spring-jdbc</artifactId> | |
<version>5.3.9</version> | |
</dependency> | |
<dependency> | |
<groupId>com.aries.jc.common</groupId> | |
<artifactId>aries-jc-bic-resttemplate</artifactId> | |
</dependency> |
2. 配置文件
2.1 多数据源的连贯配置
在 dev 配置文件中配置须要的多数据源的连贯信息
#------------ 本组件数据库 -------------- | |
localDburl=jdbc:postgresql://127.0.0.1:5432/postgres | |
localUserName=postgres | |
localingPwd=123456 | |
#-----------dci 组件数据库信息 ---------- | |
dciDburl=jdbc:postgresql://10.196.1.64:7017/dci_dcidb | |
dciUserName=dci_dcidb_user | |
dciPwd=ULCwLO9p |
2.2 其余配置
这些配置不晓得是否有必要配置,但加上没有影响,去掉后不晓得是否会报错
#------ 是否开启 mybatis-plus 的分页插件 ------------------- | |
starfish.data.jdbc.mybatis-plus.pagination.interceptor=true | |
#mybatis-plus 配置 | |
mybatis-plus.mapper-locations=classpath*:mapper/*Mapper.xml | |
mybatis-plus.type-aliases-package=com.aries.jc.dciTest.modules.entity | |
mybatis-plus.configuration.map-underscore-to-camel-case=true | |
#profile 为 dev 时是否开启 mybatis-plus SQL 执行效率插件 | |
starfish.data.jdbc.mybatis-plus.dev.performancce.interceptor=true |
3. 引入 DB 模块
3.1 DataSourceSwitchAspect 文件
本文件中须要更改的是 @Pointcut 注解前面括号中的目录地址
在本文中只有两个数据源须要切换,如果理论开发中有更多的数据源须要切换,则在该文件中依照 db1Aspect()、db2Aspect()办法创立第三个、第四个
package com.aries.jc.dciTest.modules.db; | |
import org.aspectj.lang.annotation.Aspect; | |
import org.aspectj.lang.annotation.Before; | |
import org.aspectj.lang.annotation.Pointcut; | |
import org.slf4j.Logger; | |
import org.slf4j.LoggerFactory; | |
import org.springframework.core.annotation.Order; | |
import org.springframework.stereotype.Component; | |
@Component | |
@Aspect | |
@Order(-1) // 这是为了保障 AOP 在事务注解之前失效,Order 的值越小, 优先级越高 | |
public class DataSourceSwitchAspect {private final static Logger log = LoggerFactory.getLogger(DataSourceSwitchAspect.class); | |
// 须要从本地数据库获取的数据,须要在 mapper 文件夹下创立 local 文件夹,并将 mapper 文件定义在 local 文件夹下,括号中的地址依据理论我的项目目录进行更改 | |
@Pointcut("execution(* com.aries.jc.dciTest.modules.mapper.local..*.*(..))") | |
private void db1Aspect() {} | |
// 须要从 dci 数据库获取的数据,须要在 mapper 文件夹下创立 dci 文件夹,并将 mapper 文件定义在 dci 文件夹下,括号中的地址依据理论我的项目目录进行更改 | |
@Pointcut("execution(* com.aries.jc.dciTest.modules.mapper.dci..*.*(..))") | |
private void db2Aspect() {} | |
@Before("db1Aspect()") | |
public void db1() {log.debug("切换到 local 数据源..."); | |
DbContextHolder.setDbType(DBTypeEnum.db1); | |
} | |
@Before("db2Aspect()") | |
public void db2() {log.debug("切换到 dci 数据源..."); | |
DbContextHolder.setDbType(DBTypeEnum.db2); | |
} | |
} |
3.2 DbConfig 文件
批改 1:@MapperScan 注解前面括号中的目录地址
批改 2:@Value 注解前面括号中的内容,依据配置文件中的配置做出具体批改
本文中只有两个数据源须要切换,如果理论开发中须要更多数据源,则可在本文件中参考 @Bean(name = “db1”)、@Bean(name = “db2”),创立其余数据源的 Bean
package com.aries.jc.dciTest.modules.db; | |
import com.alibaba.druid.pool.DruidDataSource; | |
import com.baomidou.mybatisplus.core.MybatisConfiguration; | |
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor; | |
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean; | |
import org.apache.ibatis.plugin.Interceptor; | |
import org.apache.ibatis.session.SqlSessionFactory; | |
import org.apache.ibatis.type.JdbcType; | |
import org.mybatis.spring.annotation.MapperScan; | |
import org.slf4j.Logger; | |
import org.slf4j.LoggerFactory; | |
import org.springframework.beans.factory.annotation.Qualifier; | |
import org.springframework.beans.factory.annotation.Value; | |
import org.springframework.context.annotation.Bean; | |
import org.springframework.context.annotation.Configuration; | |
import org.springframework.context.annotation.Primary; | |
import org.springframework.core.io.support.PathMatchingResourcePatternResolver; | |
import javax.sql.DataSource; | |
import java.util.HashMap; | |
import java.util.Map; | |
@Configuration | |
@MapperScan("com.aries.jc.dciTest.**.mapper*") | |
public class DbConfig {private final static Logger log = LoggerFactory.getLogger(DbConfig.class); | |
// 组件示意信息:也是在配置文件中进行配置 | |
@Value("${base.application.componentId}") | |
private String componentId; | |
// 配置文件中数据库的信息 | |
@Value("${localDburl}") | |
private String localDburl; | |
@Value("${localUserName}") | |
private String localUserName; | |
@Value("${localingPwd}") | |
private String localingPwd; | |
@Value("${dciDburl}") | |
private String dciDburl; | |
@Value("${dciUserName}") | |
private String dciUserName; | |
@Value("${dciPwd}") | |
private String dciPwd; | |
private static String driverClass = "org.postgresql.Driver"; | |
@Bean | |
public PaginationInterceptor paginationInterceptor() {return new PaginationInterceptor(); | |
} | |
@Bean(name = "db1") | |
public DataSource db1() {// SegmentInfo segmentInfo = myHikDiscoveryClient.findAmqServer(componentId,dbSegmentId); | |
/* log.info("初始化新组件数据库 >>>>>>componentId="+componentId+",dbSegmentId="+dbSegmentId+",segmentInfo="+ JSONObject.toJSONString(segmentInfo)); | |
DruidDataSource dataSource = new DruidDataSource(); | |
dataSource.setDriverClassName(driverClass); | |
dataSource.setUrl("jdbc:postgresql://"+segmentInfo.getIp()+":"+segmentInfo.getPort()+"/"+segmentInfo.getDbName()); | |
dataSource.setUsername(segmentInfo.getDbusername()); | |
dataSource.setPassword(segmentInfo.getDbpassword());*/ | |
DruidDataSource dataSource = new DruidDataSource(); | |
dataSource.setDriverClassName(driverClass); | |
dataSource.setUrl(localDburl); | |
dataSource.setUsername(localUserName); | |
dataSource.setPassword(localingPwd); | |
return dataSource; | |
} | |
@Bean(name = "db2") | |
public DataSource db2() {DruidDataSource dataSource = new DruidDataSource(); | |
dataSource.setDriverClassName(driverClass); | |
dataSource.setUrl(dciDburl); | |
dataSource.setUsername(dciUserName); | |
dataSource.setPassword(dciPwd); | |
return dataSource; | |
} | |
/** | |
* 动静数据源配置 | |
* | |
* @return | |
*/ | |
@Bean | |
@Primary | |
public DataSource multipleDataSource(@Qualifier("db1") DataSource db1, | |
@Qualifier("db2") DataSource db2 | |
) {DynamicDataSource dynamicDataSource = new DynamicDataSource(); | |
Map<Object, Object> targetDataSources = new HashMap<>(); | |
targetDataSources.put(DBTypeEnum.db1.getValue(), db1); | |
targetDataSources.put(DBTypeEnum.db2.getValue(), db2); | |
dynamicDataSource.setTargetDataSources(targetDataSources); | |
dynamicDataSource.setDefaultTargetDataSource(db1); // 程序默认数据源,这个要依据程序调用数据源频次,常常把常调用的数据源作为默认 | |
return dynamicDataSource; | |
} | |
@Bean("sqlSessionFactory") | |
public SqlSessionFactory sqlSessionFactory() throws Exception {MybatisSqlSessionFactoryBean sqlSessionFactory = new MybatisSqlSessionFactoryBean(); | |
sqlSessionFactory.setDataSource(multipleDataSource(db1(), db2())); | |
MybatisConfiguration configuration = new MybatisConfiguration(); | |
configuration.setJdbcTypeForNull(JdbcType.NULL); | |
configuration.setMapUnderscoreToCamelCase(true); | |
configuration.setCacheEnabled(false); | |
sqlSessionFactory.setConfiguration(configuration); | |
sqlSessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath*:mapper/*Mapper.xml")); | |
//PerformanceInterceptor(),OptimisticLockerInterceptor() | |
// 增加分页性能 | |
sqlSessionFactory.setPlugins(new Interceptor[]{paginationInterceptor() | |
}); | |
// sqlSessionFactory.setGlobalConfig(globalConfiguration()); // 正文掉全局配置,因为在 xml 中读取就是全局配置 | |
return sqlSessionFactory.getObject();} | |
} |
3.3 DbContextHolder 文件
此文件不须要批改
package com.aries.jc.dciTest.modules.db; | |
public class DbContextHolder {private static final ThreadLocal contextHolder = new ThreadLocal<>(); | |
/** | |
* 设置数据源 | |
* | |
* @param dbTypeEnum | |
*/ | |
public static void setDbType(DBTypeEnum dbTypeEnum) {contextHolder.set(dbTypeEnum.getValue()); | |
} | |
/** | |
* 获得以后数据源 | |
* | |
* @return | |
*/ | |
public static String getDbType() {return (String) contextHolder.get();} | |
/** | |
* 革除上下文数据 | |
*/ | |
public static void clearDbType() {contextHolder.remove(); | |
} | |
} |
3.4 DBTypeEnum 文件
本文只有两个数据源进行切换,如果波及到 3 个、4 个或者更多,间接在文件中增加
db1(“db1”),
db2(“db2”),
db3(“db3”),
db4(“db4”);
…
即可
package com.aries.jc.dciTest.modules.db; | |
public enum DBTypeEnum {db1("db1"), | |
db2("db2"); | |
private String value; | |
DBTypeEnum(String value) {this.value = value;} | |
public String getValue() {return value;} | |
} |
3.5 DynamicDataSource 文件
此文件不须要批改
package com.aries.jc.dciTest.modules.db; | |
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; | |
public class DynamicDataSource extends AbstractRoutingDataSource { | |
/** | |
* 获得以后应用哪个数据源 | |
* | |
* @return | |
*/ | |
@Override | |
protected Object determineCurrentLookupKey() {return DbContextHolder.getDbType(); | |
} | |
} |
4. 测试
4.1 创立实体类
在 business 文件夹下创立 entity 文件夹,在 entity 文件夹下创立 dci、local 文件夹
在 dci 文件夹下创立实体类:
package com.aries.jc.dciTest.modules.entity.dci; | |
import com.baomidou.mybatisplus.annotation.TableField; | |
import com.baomidou.mybatisplus.annotation.TableId; | |
import com.baomidou.mybatisplus.annotation.TableName; | |
import io.swagger.models.auth.In; | |
import lombok.Data; | |
import java.sql.Timestamp; | |
@Data | |
@TableName("org_info_count") | |
public class OrgInfoCount {@TableField("org_index_code") | |
private String orgIndexCode; | |
@TableField("org_index_code_in") | |
private String orgIndexCodeIn; | |
@TableField("org_index_name") | |
private String orgIndexName; | |
@TableField("org_index_type") | |
private String orgIndexType; | |
@TableField("insert_count") | |
private Integer insertCount; | |
@TableField("not_insert_count") | |
private Integer notInsertCount; | |
@TableField("total") | |
private Integer total; | |
@TableField("update_time") | |
private Timestamp updateTime; | |
} |
在 local 文件夹下创立实体类:
package com.aries.jc.dciTest.modules.entity.local; | |
import com.baomidou.mybatisplus.annotation.TableField; | |
import com.baomidou.mybatisplus.annotation.TableName; | |
import com.fasterxml.jackson.annotation.JsonFormat; | |
import io.swagger.annotations.ApiModelProperty; | |
import lombok.Data; | |
import java.sql.Timestamp; | |
@Data | |
@TableName("tb_point_config") | |
public class pointConfig {@TableField("point_name") | |
@ApiModelProperty("点位类型名称") | |
private String pointName; | |
@TableField("point_type") | |
@ApiModelProperty("点位类型 0- 个别类型 1- 蓝天卫士;2- 重点监控") | |
private Integer pointType; | |
@TableField("point_icon_url") | |
@ApiModelProperty("点位图标 url") | |
private String pointIconUrl; | |
@TableField("point_icon_name") | |
@ApiModelProperty("点位图标名称") | |
private String pointIconName; | |
@TableField("aggre_icon_url") | |
@ApiModelProperty("聚合图标 url") | |
private String aggreIconUrl; | |
@TableField("aggre_icon_name") | |
@ApiModelProperty("聚合图标 name") | |
private String aggreIconName; | |
@TableField("create_time") | |
@ApiModelProperty("创立工夫") | |
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") | |
private Timestamp createTime; | |
@TableField("create_user") | |
@ApiModelProperty("创建人名称") | |
private String createUser; | |
@TableField("update_time") | |
@ApiModelProperty("更新工夫") | |
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") | |
private Timestamp updateTime; | |
@TableField("update_user") | |
@ApiModelProperty("更新人名称") | |
private String updateUser; | |
@TableField("delete") | |
@ApiModelProperty("是否删除 1- 未删除 -1- 以删除") | |
private Integer delete; | |
} |
4.2 创立 Mapper
在 mapper 文件夹下创立 dci、local 文件夹,
在 dci 文件夹下创立 mapper:
package com.aries.jc.dciTest.modules.mapper.dci; | |
import com.aries.jc.dciTest.modules.entity.dci.OrgInfoCount; | |
import com.baomidou.mybatisplus.core.mapper.BaseMapper; | |
import com.hikvision.ga.common.BaseResult; | |
import org.apache.ibatis.annotations.Mapper; | |
import org.apache.ibatis.annotations.Select; | |
import java.util.List; | |
@Mapper | |
public interface OrgInfoCountMapper extends BaseMapper<OrgInfoCount> {@Select("select * from org_info_count") | |
List<OrgInfoCount> getAllOrgInfo();} |
在 local 文件夹下创立 mapper:
package com.aries.jc.dciTest.modules.mapper.local; | |
import com.aries.jc.dciTest.modules.entity.local.PointConfig; | |
import com.baomidou.mybatisplus.core.mapper.BaseMapper; | |
import org.apache.ibatis.annotations.Mapper; | |
import org.apache.ibatis.annotations.Select; | |
import java.util.List; | |
@Mapper | |
public interface PointConfigMapper extends BaseMapper<PointConfig> {@Select("select * from tb_point_config") | |
List<PointConfig> getAllPoint();} |
4.3 创立 service 接口
在 service 层中不须要辨别 dci 数据源和 local 数据源,可间接将两者的接口定义在一个 service 接口文件中
4.4 创立 service 接口实现类
在 service 层接口实现类中不须要辨别 dci 数据源和 local 数据源,可间接将两者的接口定义在一个 service 接口实现类文件中
package com.aries.jc.dciTest.modules.service.impl; | |
import com.aries.jc.dciTest.modules.entity.dci.OrgInfoCount; | |
import com.aries.jc.dciTest.modules.entity.local.PointConfig; | |
import com.aries.jc.dciTest.modules.mapper.dci.OrgInfoCountMapper; | |
import com.aries.jc.dciTest.modules.mapper.local.PointConfigMapper; | |
import com.aries.jc.dciTest.modules.rs.DciClientV1; | |
import com.aries.jc.dciTest.modules.rs.DciClientV2; | |
import com.aries.jc.dciTest.modules.rs.DciClientV3; | |
import com.aries.jc.dciTest.modules.service.DciService; | |
import com.hikvision.ga.common.BaseResult; | |
import com.hikvision.ga.dci.api.v1.dto.BasePageDto; | |
import com.hikvision.ga.dci.api.v1.dto.UnitListDto; | |
import com.hikvision.ga.dci.api.v2.param.ParamUnitList; | |
import com.hikvision.ga.dci.api.v3.dto.CountReq; | |
import org.slf4j.Logger; | |
import org.slf4j.LoggerFactory; | |
import org.springframework.beans.factory.annotation.Autowired; | |
import org.springframework.stereotype.Service; | |
import java.util.ArrayList; | |
import java.util.HashSet; | |
import java.util.List; | |
import java.util.Set; | |
@Service | |
public class DciServiceImpl implements DciService {private static final Logger LOGGER = LoggerFactory.getLogger(DciServiceImpl.class); | |
@Autowired | |
private OrgInfoCountMapper orgInfoCountMapper; | |
@Autowired | |
private PointConfigMapper pointConfigMapper; | |
/** | |
* 获取 dci 数据库中 org_info_count 表所有数据,测试多数据源切换 | |
* @return | |
*/ | |
@Override | |
public BaseResult<List<OrgInfoCount>> getAllInfo() {BaseResult<List<OrgInfoCount>> baseResult = new BaseResult<>(); | |
List<OrgInfoCount> list = new ArrayList<>(); | |
try {list = orgInfoCountMapper.getAllOrgInfo(); | |
baseResult.setData(list); | |
baseResult.setCode("0"); | |
baseResult.setMsg("获取胜利"); | |
return baseResult; | |
}catch (Exception e){LOGGER.error("获取失败:{}", e); | |
} | |
baseResult.setCode("-1"); | |
baseResult.setMsg("获取失败"); | |
return baseResult; | |
} | |
/** | |
* 获取 local 数据库中 tb_point_config 表所有数据,测试多数据源切换 | |
* @return | |
*/ | |
@Override | |
public BaseResult<List<PointConfig>> getAllPoint() {BaseResult<List<PointConfig>> baseResult = new BaseResult<>(); | |
List<PointConfig> list = new ArrayList<>(); | |
try {list = pointConfigMapper.getAllPoint(); | |
baseResult.setData(list); | |
baseResult.setCode("0"); | |
baseResult.setMsg("获取胜利"); | |
return baseResult; | |
}catch (Exception e){LOGGER.error("获取失败:{}", e); | |
} | |
baseResult.setCode("-1"); | |
baseResult.setMsg("获取失败"); | |
return baseResult; | |
} | |
} |
4.5 创立 controller 层
controller 层同样不须要辨别不同的数据源,能够定义在同一个 controller 文件中
4.6 swagger 测试
(1)local 数据源获取数据
(2)dci 数据源获取数据