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

文章详细介绍了如何在SpringBoot应用中使用Druid实现多数据源配置,配合MyBatis进行CRUD操作,并使用Swagger进行API文档的生成。内容涉及数据库操作SQL、实体类映射、Spring配置、单元测试和Swagger配置等。
摘要由CSDN通过智能技术生成

delete from user where id= #{id}

  1. address的映射配置:
<?xml version="1.0" encoding="UTF-8"?>

insert into address (id, city, street) values (#{id}, #{city}, #{street})

select id, city, street from address where city like concat(‘%’, #{cityname}, ‘%’)

delete from address where id= #{id}

  1. user表的实体类,注意swagger用到的注解:

package com.bolingcavalry.druidtwosource.entity;

import io.swagger.annotations.ApiModel;

import io.swagger.annotations.ApiModelProperty;

@ApiModel(description = “用户实体类”)

public class User {

@ApiModelProperty(value = “用户ID”)

private Integer id;

@ApiModelProperty(value = “用户名”, required = true)

private String name;

@ApiModelProperty(value = “用户地址”, required = false)

private Integer age;

@Override

public String toString() {

return “User{” +

“id=” + id +

“, name='” + name + ‘’’ +

“, age=” + age +

‘}’;

}

…省略get和set方法

}

  1. address表的实体类:

package com.bolingcavalry.druidtwosource.entity;

import io.swagger.annotations.ApiModel;

import io.swagger.annotations.ApiModelProperty;

@ApiModel(description = “地址实体类”)

public class Address {

@ApiModelProperty(value = “地址ID”)

private Integer id;

@ApiModelProperty(value = “城市名”, required = true)

private String city;

@ApiModelProperty(value = “街道名”, required = true)

private String street;

@Override

public String toString() {

return “Address{” +

“id=” + id +

“, city='” + city + ‘’’ +

“, street='” + street + ‘’’ +

‘}’;

}

…省略get和set方法

}

  1. 启动类DuridTwoSourceApplication.java,要注意的是排除掉数据源和事务的自动装配,因为后面会手动编码执行这些配置:

package com.bolingcavalry.druidtwosource;

import org.springframework.boot.SpringApplication;

import org.springframework.boot.autoconfigure.SpringBootApplication;

import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;

import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration;

@SpringBootApplication(exclude={

DataSourceAutoConfiguration.class,

DataSourceTransactionManagerAutoConfiguration.class,

})

public class DuridTwoSourceApplication {

public static void main(String[] args) {

SpringApplication.run(DuridTwoSourceApplication.class, args);

}

}

  1. swagger配置:

package com.bolingcavalry.druidtwosource;

import springfox.documentation.service.Contact;

import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Configuration;

import springfox.documentation.builders.ApiInfoBuilder;

import springfox.documentation.builders.PathSelectors;

import springfox.documentation.builders.RequestHandlerSelectors;

import springfox.documentation.service.ApiInfo;

import springfox.documentation.service.Tag;

import springfox.documentation.spi.DocumentationType;

import springfox.documentation.spring.web.plugins.Docket;

import springfox.documentation.swagger2.annotations.EnableSwagger2;

/**

  • @Description: swagger配置类

  • @author: willzhao E-mail: zq2599@gmail.com

  • @date: 2020/8/11 7:54

*/

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

/**

  • @Description: druid配置类

  • @author: willzhao E-mail: zq2599@gmail.com

  • @date: 2020/8/18 08:12

*/

@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注解的两个属性basePackages和sqlSessionTemplateRef是关键,它们最终决定了哪些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;

/**

  • @Description: druid配置类

  • @author: willzhao E-mail: zq2599@gmail.com

  • @date: 2020/8/18 08:12

*/

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

/**

  • @Description: druid配置类

  • @author: willzhao E-mail: zq2599@gmail.com

  • @date: 2020/8/18 08:12

*/

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

/**

  • @Description: 地址实体的接口类

  • @author: willzhao E-mail: zq2599@gmail.com

  • @date: 2020/8/4 8:32

*/

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

/**

  • @Description: user表操作的web接口

  • @author: willzhao E-mail: zq2599@gmail.com

  • @date: 2020/8/4 8:31

*/

@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不同,其他的全部一致:

在这里插入图片描述

  1. 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.*;

/**

  • @Description: 单元测试类

  • @author: willzhao E-mail: zq2599@gmail.com

  • @date: 2020/8/9 23:55

*/

@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表的单元测试如下:

总结

至此,文章终于到了尾声。总结一下,我们谈论了简历制作过程中需要注意的以下三个部分,并分别给出了一些建议:

  1. 技术能力:先写岗位所需能力,再写加分能力,不要写无关能力;
  2. 项目经历:只写明星项目,描述遵循 STAR 法则;
  3. 简历印象:简历遵循三大原则:清晰,简短,必要,要有的放矢,不要海投;

以及最后为大家准备的福利时间:简历模板+Java面试题+热门技术系列教程视频

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

me/"+ 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表的单元测试如下:

总结

至此,文章终于到了尾声。总结一下,我们谈论了简历制作过程中需要注意的以下三个部分,并分别给出了一些建议:

  1. 技术能力:先写岗位所需能力,再写加分能力,不要写无关能力;
  2. 项目经历:只写明星项目,描述遵循 STAR 法则;
  3. 简历印象:简历遵循三大原则:清晰,简短,必要,要有的放矢,不要海投;

以及最后为大家准备的福利时间:简历模板+Java面试题+热门技术系列教程视频

[外链图片转存中…(img-eChPCUSt-1714141974696)]

[外链图片转存中…(img-aZavRe8s-1714141974697)]

[外链图片转存中…(img-S0ty4vYL-1714141974697)]

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

  • 28
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值