JC framework - DB module

explain

Introduce DB module under jc scaffold for automatic addressing of multiple data sources;
Taking dci component database and local database as examples, the following shows how to introduce DB module and configure it under jc scaffold

Necessity of introducing DB module

During development, it is often necessary to obtain data from other component databases. There are usually two methods:
(1) Call through Feign; Directly call the interface of related components to obtain data
However, sometimes the component interface does not have or cannot be called. At this time, the second method can be used:
(2) The DB module is introduced to directly connect to the component database and obtain data directly from the database

1. Related pom dependencies

Introduce the following pom dependencies into the pom file under the business folder:

<!--Multi data source addressing pom rely on-->
        <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. Configuration file

2.1 connection configuration of multiple data sources

Configure the required connection information of multiple data sources in the dev configuration file

#------------This component database--------------
localDburl=jdbc:postgresql://127.0.0.1:5432/postgres
localUserName=postgres
localingPwd=123456
#-----------dci component database information----------
dciDburl=jdbc:postgresql://10.196.1.64:7017/dci_dcidb
dciUserName=dci_dcidb_user
dciPwd=ULCwLO9p

2.2 other configurations

These configurations do not know whether they are necessary, but in addition, they have no impact. After they are removed, they do not know whether an error will be reported

#------Open the paging plug-in of mybatis plus-------------------
starfish.data.jdbc.mybatis-plus.pagination.interceptor=true
#Mybatis plus configuration
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
#Whether to enable mybatis plus SQL execution efficiency plug-in when the profile is dev
starfish.data.jdbc.mybatis-plus.dev.performancce.interceptor=true

3. Introduce DB module

3.1 DataSourceSwitchAspect file

What needs to be changed in this document is the directory address in parentheses after the @ Pointcut annotation
In this article, only two data sources need to be switched. If more data sources need to be switched in the actual development, create the third and fourth data sources in this file according to the db1Aspect() and db2Aspect() methods

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) //This is to ensure that AOP takes effect before the transaction annotation. The smaller the value of Order, the higher the priority
public class DataSourceSwitchAspect {

    private final static Logger log = LoggerFactory.getLogger(DataSourceSwitchAspect.class);

    //For the data to be obtained from the local database, create a local folder under the mapper folder, define the mapper file under the local folder, and change the address in parentheses according to the actual project directory
    @Pointcut("execution(* com.aries.jc.dciTest.modules.mapper.local..*.*(..))")
    private void db1Aspect() {
    }

    //For the data to be obtained from the dci database, create a dci folder under the mapper folder and define the mapper file under the dci folder. The address in parentheses is changed according to the actual project directory
    @Pointcut("execution(* com.aries.jc.dciTest.modules.mapper.dci..*.*(..))")
    private void db2Aspect() {
    }


    @Before("db1Aspect()")
    public void db1() {
        log.debug("Switch to local data source...");
        DbContextHolder.setDbType(DBTypeEnum.db1);
    }

    @Before("db2Aspect()")
    public void db2() {
        log.debug("Switch to dci data source...");
        DbContextHolder.setDbType(DBTypeEnum.db2);
    }
}

3.2 DbConfig file

Modify 1: the directory address in parentheses after the @ MapperScan annotation
Modification 2: the contents in parentheses after @ Value annotation are modified according to the configuration in the configuration file
In this article, only two data sources need to be switched. If more data sources are needed in actual development, you can refer to @ Bean(name = "db1") and @ Bean(name = "db2") in this document to create beans of other data sources

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);

    //Component representation information: it is also configured in the configuration file
    @Value("${base.application.componentId}")
    private String componentId;

    //Information about the database in the configuration file
    @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("Initialize the new component database > > > > > > > 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;
    }

    /**
     * Dynamic data source configuration
     *
     * @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); // The default data source of the program, which often takes the frequently called data source as the default according to the frequency of the program calling the data source
        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()
        //Add paging function
        sqlSessionFactory.setPlugins(new Interceptor[]{
                paginationInterceptor()
        });
//        sqlSessionFactory.setGlobalConfig(globalConfiguration()); // Comment out the global configuration because reading in xml is the global configuration
        return sqlSessionFactory.getObject();
    }
}

3.3 DbContextHolder file

This file does not need to be modified

package com.aries.jc.dciTest.modules.db;

public class DbContextHolder {

    private static final ThreadLocal contextHolder = new ThreadLocal<>();

    /**
     * set up data sources
     *
     * @param dbTypeEnum
     */

    public static void setDbType(DBTypeEnum dbTypeEnum) {
        contextHolder.set(dbTypeEnum.getValue());
    }


    /**
     * Get current data source
     *
     * @return
     */

    public static String getDbType() {
        return (String) contextHolder.get();
    }


    /**
     * Clear context data
     */

    public static void clearDbType() {
        contextHolder.remove();
    }
}

3.4 DBTypeEnum file

In this article, there are only two data sources for switching. If three, four or more data sources are involved, they can be added directly to the file
db1("db1"),
db2("db2"),
db3("db3"),
db4("db4");
...
that will do

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 file

This file does not need to be modified

package com.aries.jc.dciTest.modules.db;

import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;

public class DynamicDataSource extends AbstractRoutingDataSource {

    /**
     * Gets which data source is currently used
     *
     * @return
     */
    @Override
    protected Object determineCurrentLookupKey() {
        return DbContextHolder.getDbType();
    }
}

4. Test

4.1 create entity class

Create an entity folder under the business folder, and create dci and local folders under the entity folder
Create an entity class in the dci folder:

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;
}

Create an entity class in the local folder:

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("Point type name")
    private String pointName;

    @TableField("point_type")
    @ApiModelProperty("Point type 0-General type 1-Blue sky guard; two-Key monitoring")
    private Integer pointType;

    @TableField("point_icon_url")
    @ApiModelProperty("Point icon url")
    private String pointIconUrl;

    @TableField("point_icon_name")
    @ApiModelProperty("Point icon name")
    private String pointIconName;

    @TableField("aggre_icon_url")
    @ApiModelProperty("Aggregate Icon url")
    private String aggreIconUrl;

    @TableField("aggre_icon_name")
    @ApiModelProperty("Aggregate Icon name")
    private String aggreIconName;

    @TableField("create_time")
    @ApiModelProperty("Creation time")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private Timestamp createTime;

    @TableField("create_user")
    @ApiModelProperty("Creator name")
    private String createUser;

    @TableField("update_time")
    @ApiModelProperty("Update time")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private Timestamp updateTime;

    @TableField("update_user")
    @ApiModelProperty("Updated by name")
    private String updateUser;

    @TableField("delete")
    @ApiModelProperty("Delete 1-Not deleted  -1-To delete")
    private Integer delete;
}

4.2 creating Mapper

Create dci and local folders under the mapper folder,
Create mapper under dci folder:

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();
}

Create mapper under local folder:

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 creating a service interface

In the service layer, there is no need to distinguish between dci data source and local data source. The interfaces of the two can be directly defined in a service interface file

4.4 create a service interface implementation class

In the service layer interface implementation class, there is no need to distinguish between dci data source and local data source. Their interfaces can be directly defined in a service interface implementation class file

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;

    /**
     * Get org in dci database_ info_ Count all the data in the table, and test the switching of multiple data sources
     * @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("Get success");
            return baseResult;
        }catch (Exception e){
            LOGGER.error("Get failed:{}", e);
        }
        baseResult.setCode("-1");
        baseResult.setMsg("Acquisition failed");
        return baseResult;
    }

    /**
     * Get TB in local database_ point_ Config table all data, test multi data source switching
     * @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("Get success");
            return baseResult;
        }catch (Exception e){
            LOGGER.error("Get failed:{}", e);
        }
        baseResult.setCode("-1");
        baseResult.setMsg("Acquisition failed");
        return baseResult;
    }


}

4.5 create controller layer

The controller layer also does not need to distinguish different data sources, and can be defined in the same controller file

4.6 swagger test

(1) Get data from local data source


(2) Obtaining data from dci data source

Keywords: Java

Added by why2k on Wed, 05 Jan 2022 18:41:39 +0200