栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

MyBatis初级实战之四:druid多数据源

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

MyBatis初级实战之四:druid多数据源

欢迎访问我的GitHub

github.com/zq2599/blog_demos

内容:所有原创文章分类汇总及配套源码,涉及Java、Docker、Kubernetes、DevOPS等;

关于druid多数据源

本文是《MyBatis初级实战》系列的第四篇,一个springboot应用同时操作两个数据库的场景,在平时也会遇到,今天要实战的就是通过druid配置两个数据源,让一个springboot应用同时使用这两个数据源;

多数据源配置的基本思路
  1. 首先要明确的是:数据源是通过配置类实现的,因此要去掉springboot中和数据源相关的自动装配;
  2. 最核心的问题有两个,第一个是确定表和数据源的关系,这个关系是在SqlSessionFactory实例中确立的,代码如下所示:
    @Bean(name = "secondSqlSessionFactory")
    public SqlSessionFactory sqlSessionFactory(@Qualifier("secondDataSource") DataSource dataSource) throws Exception {
 SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
 bean.setDataSource(dataSource);
 bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mappers/second*Mapper.xml"));
 return bean.getObject();
    }
  1. 第二个核心问题是包扫描,即指定的mapper接口要使用指定的sqlSessionTemplat,这个关系在SqlSessionTemplate配置类中(相当于旧版的xml配置bean),如下图所示:


4. 从上述代码可见,如果上层的业务代码想操作secondDataSource这个数据源的表,只要把对应的*Mapper.xml文件和Mapper接口文件对应的目录下即可;
5. 整个配置的关键步骤如下图所示:

实战概览

本次实战的内容如下:

  1. 一共有两个数据库:mybatismybatis_second
  2. mybatis中有名为user的表,mybatis_second中有名为address的表;
  3. 新建名为druidtwosource的springboot应用,里面有两个controller,可以分别对user、address这两个表进行操作;
  4. 编写单元测试用例,通过调用controller接口验证应用功能正常;
  5. 启动springboot应用,通过swagger验证功能正常;
  6. 进入druid监控页面;
源码下载
  1. 如果您不想编码,可以在GitHub下载所有源码,地址和链接信息如下表所示(github.com/zq2599/blog_demos):
名称 链接 备注
项目主页 github.com/zq2599/blog_demos 该项目在GitHub上的主页
git仓库地址(https) github.com/zq2599/blog_demos.git 该项目源码的仓库地址,https协议
git仓库地址(ssh) git@github.com:zq2599/blog_demos.git 该项目源码的仓库地址,ssh协议
  1. 这个git项目中有多个文件夹,本章的应用在mybatis文件夹下,如下图红框所示:

创建数据库和表
  1. 创建名为mybatis的数据库,建表语句如下:
DROp TABLE IF EXISTS `user`;

CREATE TABLE `user` (
  `id` int(32) NOT NULL AUTO_INCREMENT,
  `name` varchar(32) NOT NULL,
  `age` int(32) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
  1. 创建名为mybatis_second的数据库,建表语句如下:
DROP TABLE IF EXISTS `address`;

CREATE TABLE `address` (
  `id` int(32) NOT NULL AUTO_INCREMENT,
  `city` varchar(32) NOT NULL,
  `street` varchar(32) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
编码
  1. 前文[《MyBatis初级实战之一:Spring Boot集成》]创建了父工程mybatis,本文继续在此工程中新增子工程,名为druidtwosource,先提前看整个子工程文件结构,如下图,要注意的是红框1中的mapper接口,以及红框2中的mapper映射文件,这两处都按照数据库的不同放入各自文件夹:

  1. druidtwosource工程的pom.xml内容如下:
<?xml version="1.0" encoding="UTF-8"?" style="color:rgb(0,0,0);">>
4.0.0com.bolingcavalrymybatis1.0-SNAPSHOT../pom.xmlcom.bolingcavalrydruidtwosource0.0.1-SNAPSHOTdruidtwosourceDemo project for Mybatis Druid (two datasource) in Spring Boot1.8org.springframework.bootspring-boot-starter-weborg.mybatis.spring.bootmybatis-spring-boot-startermysqlmysql-connector-javaruntimeorg.springframework.bootspring-boot-starter-testtestorg.junit.vintagejunit-vintage-engineio.springfoxspringfox-swagger2io.springfoxspringfox-swagger-uicom.alibabadruid-spring-boot-starterjunitjunittestcom.google.code.gsongsonorg.springframework.bootspring-boot-maven-plugin
  1. 配置文件application.yml,可见这里面有firstsecond两个数据源配置,而druid的web-stat-filterstat-view-servlet这两个配置是公用的:
server:
  port: 8080

spring:
  #1.JDBC数据源
  datasource:
    druid:
      first:
 username: root
 password: 123456
 url: jdbc:mysql://192.168.50.43:3306/mybatis?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=UTC
 driver-class-name: com.mysql.cj.jdbc.Driver
 #初始化连接池的连接数量 大小,最小,最大
 initial-size: 5
 min-idle: 5
 max-active: 20
 #配置获取连接等待超时的时间
 max-wait: 60000
 #配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
 time-between-eviction-runs-millis: 60000
 # 配置一个连接在池中最小生存的时间,单位是毫秒
 min-evictable-idle-time-millis: 30000
 # 配置一个连接在池中最大生存的时间,单位是毫秒
 max-evictable-idle-time-millis: 300000
 validation-query: SELECT 1 FROM user
 test-while-idle: true
 test-on-borrow: true
 test-on-return: false
 # 是否缓存preparedStatement,也就是PSCache  官方建议MySQL下建议关闭   个人建议如果想用SQL防火墙 建议打开
 pool-prepared-statements: true
 max-pool-prepared-statement-per-connection-size: 20
 # 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙
 filters: stat,wall,slf4j
 filter:
   stat:
     merge-sql: true
     slow-sql-millis: 5000

      second:
 username: root
 password: 123456
 url: jdbc:mysql://192.168.50.43:3306/mybatis_second?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=UTC
 driver-class-name: com.mysql.cj.jdbc.Driver
 #初始化连接池的连接数量 大小,最小,最大
 initial-size: 5
 min-idle: 5
 max-active: 20
 #配置获取连接等待超时的时间
 max-wait: 60000
 #配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
 time-between-eviction-runs-millis: 60000
 # 配置一个连接在池中最小生存的时间,单位是毫秒
 min-evictable-idle-time-millis: 30000
 # 配置一个连接在池中最大生存的时间,单位是毫秒
 max-evictable-idle-time-millis: 300000
 validation-query: SELECt 1 FROM user
 test-while-idle: true
 test-on-borrow: true
 test-on-return: false
 # 是否缓存preparedStatement,也就是PSCache  官方建议MySQL下建议关闭   个人建议如果想用SQL防火墙 建议打开
 pool-prepared-statements: true
 max-pool-prepared-statement-per-connection-size: 20
 # 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙
 filters: stat,wall,slf4j
 filter:
   stat:
     merge-sql: true###
     slow-sql-millis: 5000

      #3.基础监控配置
      web-stat-filter:
 enabled: true
 url-pattern: 
@Configuration
@EnableSwagger2
public class SwaggerConfig {

    @Bean
    public Docket createRestApi() {
 return new Docket(documentationType.SWAGGER_2)
  .apiInfo(apiInfo())
  .tags(new Tag("UserController", "用户服务"),
   new Tag("AddressController", "地址服务"))
  .select()
  // 当前包路径
  .apis(RequestHandlerSelectors.basePackage("com.bolingcavalry.druidtwosource.controller"))
  .paths(PathSelectors.any())
  .build();
    }

    //构建 api文档的详细信息函数,注意这里的注解引用的是哪个
    private ApiInfo apiInfo() {
 return new ApiInfoBuilder()
  //页面标题
  .title("MyBatis CURD操作")
  //创建人
  .contact(new Contact("程序员欣宸", "https://github.com/zq2599/blog_demos", "zq2599@gmail.com"))
  //版本号
  .version("1.0")
  //描述
  .description("API 描述")
  .build();
    }
}
  1. 数据源配置TwoDataSourceConfig.java,可见是通过ConfigurationProperties注解来确定配置信息,另外不要忘记在默认数据源上添加Primary注解:
package com.bolingcavalry.druidtwosource;

import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;

import javax.sql.DataSource;


@Configuration
public class TwoDataSourceConfig {

    @Primary
    @Bean(name = "firstDataSource")
    @ConfigurationProperties("spring.datasource.druid.first")
    public DataSource first() {
 return DruidDataSourceBuilder.create().build();
    }

    @Bean(name = "secondDataSource")
    @ConfigurationProperties("spring.datasource.druid.second")
    public DataSource second() {
 return DruidDataSourceBuilder.create().build();
    }
}
  1. 第一个数据源的mybatis配置类DruidConfigFirst.java,可以结合本篇的第一幅图来看,注意MapperScan注解的两个属性basePackagessqlSessionTemplateRef是关键,它们最终决定了哪些mapper接口使用哪个数据源,另外注意要带上Primary注解:
package com.bolingcavalry.druidtwosource;

import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
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 org.springframework.jdbc.datasource.DataSourceTransactionManager;

import javax.sql.DataSource;


@Configuration
@MapperScan(basePackages = "com.bolingcavalry.druidtwosource.mapper.first", sqlSessionTemplateRef  = "firstSqlSessionTemplate")
public class DruidConfigFirst {

    @Bean(name = "firstSqlSessionFactory")
    @Primary
    public SqlSessionFactory sqlSessionFactory(@Qualifier("firstDataSource") DataSource dataSource) throws Exception {
 SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
 bean.setDataSource(dataSource);
 bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mappers/first*Mapper.xml"));
 return bean.getObject();
    }

    @Bean(name = "firstTransactionManager")
    @Primary
    public DataSourceTransactionManager transactionManager(@Qualifier("firstDataSource") DataSource dataSource) {
 return new DataSourceTransactionManager(dataSource);
    }

    @Bean(name = "firstSqlSessionTemplate")
    @Primary
    public SqlSessionTemplate sqlSessionTemplate(@Qualifier("firstSqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {
 return new SqlSessionTemplate(sqlSessionFactory);
    }
}
  1. 第二个数据源的mybatis配置DruidConfigSecond.java,注意不要带Primary注解:
package com.bolingcavalry.druidtwosource;

import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;

import javax.sql.DataSource;


@Configuration
@MapperScan(basePackages = "com.bolingcavalry.druidtwosource.mapper.second", sqlSessionTemplateRef  = "secondSqlSessionTemplate")
public class DruidConfigSecond {

    @Bean(name = "secondSqlSessionFactory")
    public SqlSessionFactory sqlSessionFactory(@Qualifier("secondDataSource") DataSource dataSource) throws Exception {
 SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
 bean.setDataSource(dataSource);
 bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mappers/second*Mapper.xml"));
 return bean.getObject();
    }

    @Bean(name = "secondTransactionManager")
    public DataSourceTransactionManager transactionManager(@Qualifier("secondDataSource") DataSource dataSource) {
 return new DataSourceTransactionManager(dataSource);
    }

    @Bean(name = "secondSqlSessionTemplate")
    public SqlSessionTemplate sqlSessionTemplate(@Qualifier("secondSqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {
 return new SqlSessionTemplate(sqlSessionFactory);
    }

}
  1. user表的mapper接口类很简单,只有三个接口,注意package位置:
package com.bolingcavalry.druidtwosource.mapper.first;

import com.bolingcavalry.druidtwosource.entity.User;
import org.springframework.stereotype.Repository;

import java.util.List;

@Repository
public interface UserMapper {

    int insertWithFields(User user);

    List findByName(String name);

    int delete(int id);
}

  1. address表的Mapper接口类:
package com.bolingcavalry.druidtwosource.mapper.second;

import com.bolingcavalry.druidtwosource.entity.Address;
import org.springframework.stereotype.Repository;

import java.util.List;



@Repository
public interface AddressMapper {

    int insertWithFields(Address address);

    List
findByCityName(String cityName); int delete(int id); }
  1. user表的service类:
package com.bolingcavalry.druidtwosource.service;

import com.bolingcavalry.druidtwosource.entity.User;
import com.bolingcavalry.druidtwosource.mapper.first.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;

public class UserService {
    @Autowired
    UserMapper userMapper;

    public User insertWithFields(User user) {
 userMapper.insertWithFields(user);
 return user;
    }

    public List findByName(String name) {
 return userMapper.findByName(name);
    }

    public int delete(int id) {
 return userMapper.delete(id);
    }

}

  1. address表的service类:
package com.bolingcavalry.druidtwosource.service;

import com.bolingcavalry.druidtwosource.entity.Address;
import com.bolingcavalry.druidtwosource.entity.User;
import com.bolingcavalry.druidtwosource.mapper.first.UserMapper;
import com.bolingcavalry.druidtwosource.mapper.second.AddressMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;

@Service
public class AddressService {

    @Autowired
    AddressMapper addressMapper;

    public Address insertWithFields(Address address) {
 addressMapper.insertWithFields(address);
 return address;
    }

    public List
findByCityName(String cityName) { return addressMapper.findByCityName(cityName); } public int delete(int id) { return addressMapper.delete(id); } }
  1. user表的controller:
package com.bolingcavalry.druidtwosource.controller;

import com.bolingcavalry.druidtwosource.entity.User;
import com.bolingcavalry.druidtwosource.service.UserService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;

@RestController
@RequestMapping("/user")
@Api(tags = {"UserController"})
public class UserController {

    @Autowired
    private UserService userService;

    @ApiOperation(value = "新增user记录", notes="新增user记录")
    @RequestMapping(value = "/insertwithfields",method = RequestMethod.PUT)
    public User create(@RequestBody User user) {
 return userService.insertWithFields(user);
    }

    @ApiOperation(value = "删除指定ID的user记录", notes="删除指定ID的user记录")
    @ApiImplicitParam(name = "id", value = "用户ID", paramType = "path", required = true, dataType = "Integer")
    @RequestMapping(value = "/{id}", method = RequestMethod.DELETE)
    public int delete(@PathVariable int id){
 return userService.delete(id);
    }

    @ApiOperation(value = "根据名称模糊查找所有user记录", notes="根据名称模糊查找所有user记录")
    @ApiImplicitParam(name = "name", value = "用户名", paramType = "path", required = true, dataType = "String")
    @RequestMapping(value = "/findbyname/{name}", method = RequestMethod.GET)
    public List findByName(@PathVariable("name") String name){
 return userService.findByName(name);
    }
}

  1. address表的controller:
package com.bolingcavalry.druidtwosource.controller;

import com.bolingcavalry.druidtwosource.entity.Address;
import com.bolingcavalry.druidtwosource.service.AddressService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;


@RestController
@RequestMapping("/address")
@Api(tags = {"AddressController"})
public class AddressController {

    @Autowired
    private AddressService addressService;


    @ApiOperation(value = "新增address记录", notes="新增address记录")
    @RequestMapping(value = "/insertwithfields",method = RequestMethod.PUT)
    public Address create(@RequestBody Address address) {
 return addressService.insertWithFields(address);
    }

    @ApiOperation(value = "删除指定ID的address记录", notes="删除指定ID的address记录")
    @ApiImplicitParam(name = "id", value = "地址ID", paramType = "path", required = true, dataType = "Integer")
    @RequestMapping(value = "/{id}", method = RequestMethod.DELETE)
    public int delete(@PathVariable int id){
 return addressService.delete(id);
    }

    @ApiOperation(value = "根据城市名模糊查找所address记录", notes="根据城市名模糊查找所address记录")
    @ApiImplicitParam(name = "name", value = "城市名", paramType = "path", required = true, dataType = "String")
    @RequestMapping(value = "/findbycityname/{cityname}", method = RequestMethod.GET)
    public List
findByName(@PathVariable("cityname") String cityName){ return addressService.findByCityName(cityName); } }
  • 至此,编码完成,接下来编写单元测试代码;
单元测试
  1. 新增配置文件application-test.yml,其内容仅有下图红框位置与application.yml不同,其他的全部一致:


2. user表的测试用例如下:

package com.bolingcavalry.druidtwosource.controller;

import com.bolingcavalry.druidtwosource.entity.User;
import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonParser;
import org.junit.jupiter.api.*;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;

import java.util.UUID;

import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.core.IsEqual.equalTo;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;



@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
@ActiveProfiles("test")
class UserControllerTest {

    @Autowired
    private MockMvc mvc;

    // user表的name字段,这里为了保证测试时新增和删除的记录是同一条,用UUID作为用户名
    static String testName;

    @BeforeAll
    static void init() {
 testName = UUID.randomUUID().toString().replaceAll("-","");
    }

    @Test
    @Order(1)
    void insertWithFields() throws Exception {
 String jsonStr = "{"name": "" + testName + "", "age": 10}";

 mvc.perform(
  MockMvcRequestBuilders.put("/user/insertwithfields")
   .contentType(MediaType.APPLICATION_JSON)
   .content(jsonStr)
   .accept(MediaType.APPLICATION_JSON))
  .andExpect(status().isOk())
  .andExpect(jsonPath("$.name", is(testName)))
  .andDo(print())
  .andReturn()
  .getResponse()
  .getContentAsString();
    }

    @Test
    @Order(2)
    void findByName() throws Exception {
 mvc.perform(MockMvcRequestBuilders.get("/user/findbyname/"+ testName).accept(MediaType.APPLICATION_JSON))
  .andExpect(status().isOk())
  .andExpect(jsonPath("$", hasSize(1)))
  .andDo(print());
    }


    @Test
    @Order(3)
    void delete() throws Exception {
 // 先根据名称查出记录
 String responseString = mvc.perform(MockMvcRequestBuilders.get("/user/findbyname/"+ testName).accept(MediaType.APPLICATION_JSON))
  .andExpect(status().isOk())
  .andExpect(jsonPath("$", hasSize(1)))
  .andDo(print())
  .andReturn()
  .getResponse()
  .getContentAsString();

 // 反序列化得到数组
 JsonArray jsonArray = JsonParser.parseString(responseString).getAsJsonArray();

 // 反序列化得到user实例
 User user = new Gson().fromJson(jsonArray.get(0), User.class);

 // 执行删除
 mvc.perform(MockMvcRequestBuilders.delete("/user/"+ user.getId()).accept(MediaType.APPLICATION_JSON))
  .andExpect(status().isOk())
  .andExpect(content().string(equalTo("1")))
  .andDo(print());
    }
}
  1. address表的单元测试如下:
package com.bolingcavalry.druidtwosource.controller;

import com.bolingcavalry.druidtwosource.entity.Address;
import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonParser;
import org.junit.jupiter.api.*;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;

import java.util.UUID;

import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.core.IsEqual.equalTo;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;

@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
@ActiveProfiles("test")
class AddrestControllerTest {

    @Autowired
    private MockMvc mvc;

    // address表的cityName字段,这里为了保证测试时新增和删除的记录是同一条,用UUID作为用户名
    static String testCityName;

    @BeforeAll
    static void init() {
 testCityName = UUID.randomUUID().toString().replaceAll("-","");
    }

    @Test
    @Order(1)
    void insertWithFields() throws Exception {
 String jsonStr = "{"city": "" + testCityName + "", "street": "streetName"}";

 mvc.perform(
  MockMvcRequestBuilders.put("/address/insertwithfields")
   .contentType(MediaType.APPLICATION_JSON)
   .content(jsonStr)
   .accept(MediaType.APPLICATION_JSON))
  .andExpect(status().isOk())
  .andExpect(jsonPath("$.city", is(testCityName)))
  .andDo(print())
  .andReturn()
  .getResponse()
  .getContentAsString();
    }

    @Test
    @Order(2)
    void findByName() throws Exception {
 mvc.perform(MockMvcRequestBuilders.get("/address/findbycityname/"+ testCityName).accept(MediaType.APPLICATION_JSON))
  .andExpect(status().isOk())
  .andExpect(jsonPath("$", hasSize(1)))
  .andDo(print());
    }


    @Test
    @Order(3)
    void delete() throws Exception {
 // 先根据名称查出记录
 String responseString = mvc.perform(MockMvcRequestBuilders.get("/address/findbycityname/"+ testCityName).accept(MediaType.APPLICATION_JSON))
  .andExpect(status().isOk())
  .andExpect(jsonPath("$", hasSize(1)))
  .andDo(print())
  .andReturn()
  .getResponse()
  .getContentAsString();

 // 反序列化得到数组
 JsonArray jsonArray = JsonParser.parseString(responseString).getAsJsonArray();

 // 反序列化得到user实例
 Address address = new Gson().fromJson(jsonArray.get(0), Address.class);

 // 执行删除
 mvc.perform(MockMvcRequestBuilders.delete("/address/"+ address.getId()).accept(MediaType.APPLICATION_JSON))
  .andExpect(status().isOk())
  .andExpect(content().string(equalTo("1")))
  .andDo(print());
    }
}
  • 至此,编码完成,而可以开始验证了;
验证,单元测试
  1. user表对应的单元测试操作如下图,三个测试方法先后新增记录,查询记录,然后删除掉:


2. AddrestControllerTest也按照上图做同样的操作;

验证,swagger
  1. 浏览器访问:http://localhost:8080/swagger-ui.html ,会展示swagger页面如下:


2. 先来试试新增操作:


3. 返回数据如下图:


4. 以下是用MySQL数据库客户端工具查看到的mybatis.user表的数据,可见服务功能正常:


5. 其他接口请自行操作验证;

进入druid监控页面
  1. druid监控页面地址是:http://localhost:8080/druid , 账号密码都是admin:


2. 登录后可见数据库操作:


3. 在数据源页面可以见到两个数据源,如下图:

  • 以上就是完整的springboot+mybatis+druid多数据源开发和验证过程,希望能给您一些参考;

我是欣宸,期待与您一同畅游Java世界…

转载请注明:文章转载自 www.mshxw.com
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号