filter动态参数 maven_Mybatis动态数据源

业务场景

现有股票与基金业务,不同的业务分在不同的库中,但有些业务类似可以基于同一套代码,例如组织架构、权限控制与客户管理,但是为区分业务线,要将数据拆分在不同的数据库中

达成效果

不同的业务传对应的业务参数,保存到相应的库中

基金业务

新增用户

732ecdc5c6ae477d32e4ce903768c982.png
image-20201202214530335

查询用户

9c20a30afb2e5b5f673a502cc7bc2f43.png
image-20201202214834950

股票业务

新增用户

a147df07afb6f3580ce7b502160529ea.png
image-20201202214736326

查询用户

666567ed7395ce87fd97401a412201fb.png
image-20201202215006443

具体实现

项目结构

c64d8508fa15504f68a3394c2bde3c32.png
image-20201202212630462

数据库

be0c71ba53cd4046e3d4fe7adcb124f2.png
image-20201202213814882

表结构

CREATE TABLE `rbac_user` (  `id` int(11) NOT NULL AUTO_INCREMENT,  `name` varchar(64) DEFAULT NULL,  PRIMARY KEY (`id`)) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci

代码实现

1. POM依赖

xml version="1.0" encoding="UTF-8"?>    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">    4.0.0            org.springframework.boot        spring-boot-starter-parent        2.4.0                 com.sure    learn-mybatis-dynamic-datasource    0.0.1-SNAPSHOT    learn-mybatis-dynamic-datasource    Demo project for Spring Boot            1.8                            org.springframework.boot            spring-boot-starter-web                            org.mybatis.spring.boot            mybatis-spring-boot-starter            2.1.4                            mysql            mysql-connector-java            runtime                            org.projectlombok            lombok            true                                    org.springframework.boot            spring-boot-starter-aop                            org.springframework.boot            spring-boot-starter-test            test                                                    org.springframework.boot                spring-boot-maven-plugin                        

2. 配置文件

不同的业务线配置不同的数据库

spring:  datasource:    fund:      driverClassName: com.mysql.cj.jdbc.Driver      username: root      password: root      jdbcUrl: jdbc:mysql://localhost:3306/fund?useUnicode=true&characterEncoding=utf8    stock:      driverClassName: com.mysql.cj.jdbc.Driver      username: root      password: root      jdbcUrl: jdbc:mysql://localhost:3306/stock?useUnicode=true&characterEncoding=utf8logging:  level:    com.sure: debug

3. 创建业务平台枚举类型

/** * 业务平台枚举 * * @author sure */public enum PlatformEnum {    FUND("fund"),    STOCK("stock");    public String value;    PlatformEnum(String value){        this.value = value;    }}

4. 动态数据源上下文管理

/** * 动态数据源上下文管理 *  * @author sure  */public class DataSourceContextHolder {    private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();    /**     * 设置数据源     *      * @param dataSourceKey     */    public static void setDataSource(String dataSourceKey){        contextHolder.set(dataSourceKey);    }    /**     * 获取数据源     * @return     */    public static String getDataSource(){        return contextHolder.get();    }    /**     * 清空数据源设置     */    public static void clearDataSource(){        contextHolder.remove();    }}

5.动态数据源

/** * 动态数据源 */public class DynamicDataSource extends AbstractRoutingDataSource {    @Override    protected Object determineCurrentLookupKey() {        return DataSourceContextHolder.getDataSource();    }}

6. Mybatis多数据源配置

/** * Mybatais 动态数据源配置 *  * @author sure  */@Configuration@MapperScan(basePackages = "com.sure.learnmybatisdynamicdatasource.mapper")public class MybaticDynamicDataSourceConfig {    @Bean    @ConfigurationProperties("spring.datasource.fund")    public DataSource fundDataSource(){        return DataSourceBuilder.create().build();    }    @Bean    @ConfigurationProperties("spring.datasource.stock")    public DataSource stockDataSource(){        return DataSourceBuilder.create().build();    }    @Bean    public DynamicDataSource dataSource(@Qualifier("fundDataSource") DataSource fundDataSource,                                        @Qualifier("stockDataSource") DataSource stockDataSource){        Map<Object,Object> dataSources = new HashMap<>();        dataSources.put(PlatformEnum.FUND.value,fundDataSource);        dataSources.put(PlatformEnum.STOCK.value,stockDataSource);        DynamicDataSource dynamicDataSource = new DynamicDataSource();        dynamicDataSource.setTargetDataSources(dataSources);        dynamicDataSource.setDefaultTargetDataSource(fundDataSource);        return dynamicDataSource;    }    @Bean    public SqlSessionFactory sqlSessionFactory(DynamicDataSource dynamicDataSource) throws Exception {        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();        sqlSessionFactoryBean.setDataSource(dynamicDataSource);        // 扫描mapper路径        Resource[] resources = new PathMatchingResourcePatternResolver().getResources("classpath:mapper/*.xml");        sqlSessionFactoryBean.setMapperLocations(resources);        return sqlSessionFactoryBean.getObject();    }    @Bean    public PlatformTransactionManager transactionManager(DynamicDataSource dynamicDataSource){        return new DataSourceTransactionManager(dynamicDataSource);    }}

7. 动态数据源切面

/** * 动态数据源切面 *  * @author sure  */@Aspect@Componentpublic class DataSourceAspect {    @Pointcut("execution(public * com.sure.learnmybatisdynamicdatasource.mapper..*.*(..))")    public void aop(){}    @Around("aop()")    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {        Object[] args = joinPoint.getArgs();        if (Objects.nonNull(args) && args.length>0){            DataSourceContextHolder.setDataSource(args[0].toString());        }        try {            return joinPoint.proceed();        }finally {            DataSourceContextHolder.clearDataSource();        }    }}

8. 编写Mapper

注意mapper中的第一个参数预留来指定数据源

@Mapperpublic interface RbacUserMapper {    Integer save(String dataSource, @Param("user") RbacUserDO rbacUserDO);    RbacUserDO get(String dataSource, @Param("id") Integer id);}
 namespace="com.sure.learnmybatisdynamicdatasource.mapper.RbacUserMapper">     id="save" keyProperty="id">        insert into rbac_user(name) values (#{user.name})         id="get" resultType="com.sure.learnmybatisdynamicdatasource.domain.RbacUserDO">        select id,name from rbac_user where id = #{id}    

9.编写service

同样注意方法参数中的数据源参数

@Servicepublic class RbacUserService {    @Autowired    private RbacUserMapper rbacUserMapper;    public Integer save(String dataSource, RbacUserDO rbacUserDO){        return rbacUserMapper.save(dataSource, rbacUserDO);    }    public RbacUserDO get(String dataSource, Integer id){        RbacUserDO rbacUserDO = rbacUserMapper.get(dataSource, id);        return rbacUserDO;    }}

10. 编写Controller层

通用返回参数

@Datapublic class Result<T> implements Serializable {    private Integer code;    private String msg;    private T data;    private Result(Integer code , String msg){        this.code = code;        this.msg = msg;    }    private Result(Integer code , String msg, T data){        this.code = code;        this.msg = msg;        this.data = data;    }    public static  Result ok(){        return new Result(ResultEnum.SUCCESS.code,ResultEnum.SUCCESS.msg);    }    public static <T> Result ok(T data){        return new Result(ResultEnum.SUCCESS.code,ResultEnum.SUCCESS.msg,data);    }    public static  Result error(){        return new Result(ResultEnum.ERROR.code,ResultEnum.ERROR.msg);    }    public static  Result error(Integer code,String msg){        return new Result(code,msg);    }}

状态码枚举

public enum ResultEnum {    SUCCESS(1,"success"),    ERROR(-1,"system error");    public Integer code;    public String msg;    ResultEnum (Integer code,String msg){        this.code = code;        this.msg = msg;    }}

使用path参数来指定业务平台

@RestController@RequestMapping("api/1")public class RbacUserController {    @Autowired    public RbacUserService rbacUserService;    @PostMapping("{platform}/user")    public Result addUser(@PathVariable String platform, RbacUserDO rbacUserDO){        return Result.ok(rbacUserService.save(platform, rbacUserDO));    }    @GetMapping("{platform}/user/{id}")    public Result getUser(@PathVariable("platform") String platform,@PathVariable("id") Integer id){        RbacUserDO rbacUserDO = rbacUserService.get(platform, id);        return Result.ok(rbacUserDO);    }}

踩到的坑

注意切面类返回值!!!

1671d587a0a1b3935d917593981be410.png
为啥返回null
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值