delete from user where id= #{id}
- address的映射配置:
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}
- 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方法
}
- 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方法
}
- 启动类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);
}
}
- 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();
}
}
- 数据源配置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();
}
}
- 第一个数据源的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);
}
}
- 第二个数据源的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);
}
}
- 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);
}
- 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);
}
- 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);
}
}
- 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);
}
}
- 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);
}
}
- 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);
}
}
- 至此,编码完成,接下来编写单元测试代码;
单元测试
- 新增配置文件application-test.yml,其内容仅有下图红框位置与application.yml不同,其他的全部一致:
- 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());
}
}
- address表的单元测试如下:
总结
至此,文章终于到了尾声。总结一下,我们谈论了简历制作过程中需要注意的以下三个部分,并分别给出了一些建议:
- 技术能力:先写岗位所需能力,再写加分能力,不要写无关能力;
- 项目经历:只写明星项目,描述遵循 STAR 法则;
- 简历印象:简历遵循三大原则:清晰,简短,必要,要有的放矢,不要海投;
以及最后为大家准备的福利时间:简历模板+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());
}
}
- address表的单元测试如下:
总结
至此,文章终于到了尾声。总结一下,我们谈论了简历制作过程中需要注意的以下三个部分,并分别给出了一些建议:
- 技术能力:先写岗位所需能力,再写加分能力,不要写无关能力;
- 项目经历:只写明星项目,描述遵循 STAR 法则;
- 简历印象:简历遵循三大原则:清晰,简短,必要,要有的放矢,不要海投;
以及最后为大家准备的福利时间:简历模板+Java面试题+热门技术系列教程视频
[外链图片转存中…(img-eChPCUSt-1714141974696)]
[外链图片转存中…(img-aZavRe8s-1714141974697)]
[外链图片转存中…(img-S0ty4vYL-1714141974697)]