增加 spring boot + feign 示例

This commit is contained in:
YunaiV
2020-05-17 19:24:47 +08:00
parent 653a27a9a7
commit 5e36ed1faa
25 changed files with 571 additions and 4 deletions

View File

@@ -0,0 +1,46 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.2.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>lab-42-demo02</artifactId>
<dependencies>
<!-- 实现对 Spring MVC 的自动化配置 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 实现对数据库连接池的自动化配置 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency> <!-- 本示例,我们使用 MySQL -->
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.46</version>
</dependency>
<!-- 方便等会写单元测试 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.h2database</groupId> <!-- 单元测试,我们采用 H2 作为数据库 -->
<artifactId>h2</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,13 @@
package cn.iocoder.springboot.lab23.testdemo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}

View File

@@ -0,0 +1,33 @@
package cn.iocoder.springboot.lab23.testdemo.controller;
import cn.iocoder.springboot.lab23.testdemo.dataobject.UserDO;
import cn.iocoder.springboot.lab23.testdemo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
/**
* 用户 Controller
*/
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
/**
* 获得指定用户编号的用户
*
* @param id 用户编号
* @return 用户
*/
@GetMapping("/get") // URL 修改成 /get
public UserDO get(@RequestParam("id") Integer id) {
// 查询并返回用户
return userService.get(id);
}
}

View File

@@ -0,0 +1,21 @@
package cn.iocoder.springboot.lab23.testdemo.dao;
import cn.iocoder.springboot.lab23.testdemo.dataobject.UserDO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
@Repository
public class UserDao {
@Autowired
private JdbcTemplate template;
public UserDO selectById(Integer id) {
return template.queryForObject("SELECT id, username, password FROM t_user WHERE id = ?",
new BeanPropertyRowMapper<>(UserDO.class), // 结果转换成对应的对象
id);
}
}

View File

@@ -0,0 +1,50 @@
package cn.iocoder.springboot.lab23.testdemo.dataobject;
/**
* 用户 DO
*/
public class UserDO {
/**
* 用户编号
*/
private Integer id;
/**
* 账号
*/
private String username;
/**
* 密码(明文)
*
* ps生产环境下千万不要明文噢
*/
private String password;
public Integer getId() {
return id;
}
public UserDO setId(Integer id) {
this.id = id;
return this;
}
public String getUsername() {
return username;
}
public UserDO setUsername(String username) {
this.username = username;
return this;
}
public String getPassword() {
return password;
}
public UserDO setPassword(String password) {
this.password = password;
return this;
}
}

View File

@@ -0,0 +1,29 @@
package cn.iocoder.springboot.lab23.testdemo.service;
import cn.iocoder.springboot.lab23.testdemo.dao.UserDao;
import cn.iocoder.springboot.lab23.testdemo.dataobject.UserDO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class UserService {
@Autowired
private UserDao userDao;
public UserDO get(Integer id) {
return userDao.selectById(id);
}
public boolean exists(String username) {
return true;
}
public Integer add(String username, String password) {
if (exists(username)) {
return null;
}
return 1;
}
}

View File

@@ -0,0 +1,7 @@
spring:
# datasource 数据源配置内容
datasource:
url: jdbc:mysql://127.0.0.1:3306/lab-39-mysql?useSSL=false&useUnicode=true&characterEncoding=UTF-8
driver-class-name: com.mysql.jdbc.Driver
username: root
password:

View File

@@ -0,0 +1,58 @@
package cn.iocoder.springboot.lab23.testdemo.controller;
import cn.iocoder.springboot.lab23.testdemo.dataobject.UserDO;
import cn.iocoder.springboot.lab23.testdemo.service.UserService;
import org.hamcrest.core.IsEqual;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
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.boot.test.mock.mockito.MockBean;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.ResultActions;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
/**
* UserController 单元测试
*/
@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
public class UserControllerTest {
@Autowired
private MockMvc mvc;
@MockBean
private UserService userService;
@Test
public void testGet() throws Exception {
// Mock UserService 的 get 方法
Mockito.when(userService.get(1)).thenReturn(
new UserDO().setId(1).setUsername("username:1").setPassword("password:1"));
// 查询用户
ResultActions resultActions = mvc.perform(MockMvcRequestBuilders.get("/user/get?id=1"));
// 校验响应状态码
resultActions.andExpect(MockMvcResultMatchers.status().isOk()); // 响应状态码 200
// 校验响应内容方式一:直接全部匹配
resultActions.andExpect(MockMvcResultMatchers.content().json("{\n" +
" \"id\": 1,\n" +
" \"username\": \"username:1\",\n" +
" \"password\": \"password:1\"\n" +
"}", true)); // 响应结果
// 校验响应内容方式二:逐个字段匹配
resultActions.andExpect(MockMvcResultMatchers.jsonPath("id", IsEqual.equalTo(1)));
resultActions.andExpect(MockMvcResultMatchers.jsonPath("username", IsEqual.equalTo("username:1")));
resultActions.andExpect(MockMvcResultMatchers.jsonPath("password", IsEqual.equalTo("password:1")));
}
}

View File

@@ -0,0 +1,33 @@
package cn.iocoder.springboot.lab23.testdemo.dao;
import cn.iocoder.springboot.lab23.testdemo.dataobject.UserDO;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.jdbc.Sql;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest
public class UserDaoTest {
@Autowired
private UserDao userDao;
@Test
@Sql(scripts = "/sql/create_tables.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD)
@Sql(statements = "INSERT INTO `t_user`(`id`, `username`, `password`) VALUES (1, 'username:1', 'password:1');", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD)
@Sql(scripts = "/sql/clean.sql", executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD)
public void testSelectById() {
// 查询用户
UserDO user = userDao.selectById(1);
// 校验结果
Assert.assertEquals("编号不匹配", 1, (int) user.getId());
Assert.assertEquals("用户名不匹配", "username:1", user.getUsername());
Assert.assertEquals("密码不匹配", "password:1", user.getPassword());
}
}

View File

@@ -0,0 +1 @@
package cn.iocoder.springboot.lab23.testdemo;

View File

@@ -0,0 +1,39 @@
package cn.iocoder.springboot.lab23.testdemo.service;
import cn.iocoder.springboot.lab23.testdemo.dao.UserDao;
import cn.iocoder.springboot.lab23.testdemo.dataobject.UserDO;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest
public class UserServiceTest {
@MockBean
private UserDao userDao;
@Autowired
private UserService userService;
@Test
public void testGet() {
// Mock UserDao 的 selectById 方法
Mockito.when(userDao.selectById(1)).thenReturn(
new UserDO().setId(1).setUsername("username:1").setPassword("password:1"));
// 查询用户
UserDO user = userService.get(1);
// 校验结果
Assert.assertEquals("编号不匹配", 1, (int) user.getId());
Assert.assertEquals("用户名不匹配", "username:1", user.getUsername());
Assert.assertEquals("密码不匹配", "password:1", user.getPassword());
}
}

View File

@@ -0,0 +1,37 @@
package cn.iocoder.springboot.lab23.testdemo.service;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.SpyBean;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest
public class UserServiceTest2 {
@SpyBean
private UserService userService;
@Test
public void testAddSuccess() {
System.out.println("testAddSuccess");
// Mock UserService 的 exists 方法
Mockito.when(userService.exists("username")).thenReturn(
false);
Assert.assertNotNull("注册返回为 null注册失败",
userService.add("username", "password"));
}
@Test
public void testAddFailure() {
System.out.println("testAddFailure");
Assert.assertNull("注册返回为 null注册失败",
userService.add("username", "password"));
}
}

View File

@@ -0,0 +1,7 @@
spring:
# datasource 数据源配置内容
datasource:
url: jdbc:h2:mem:testdb
driver-class-name: org.h2.Driver
username: sa
password:

View File

@@ -0,0 +1 @@
DROP TABLE `t_user`

View File

@@ -0,0 +1,5 @@
CREATE TABLE `t_user` (
`id` INT AUTO_INCREMENT PRIMARY KEY COMMENT '用户编号',
`username` VARCHAR(64) NOT NULL COMMENT '账号',
`password` VARCHAR(64) NOT NULL COMMENT '密码'
);

View File

@@ -13,6 +13,7 @@
<packaging>pom</packaging>
<modules>
<module>lab-42-demo01</module>
<module>lab-42-demo02</module>
</modules>

View File

@@ -0,0 +1,52 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>lab-58</artifactId>
<groupId>cn.iocoder.springboot.labs</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>lab-58-feign-demo</artifactId>
<properties>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.source>1.8</maven.compiler.source>
<spring.boot.version>2.2.4.RELEASE</spring.boot.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>${spring.boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!-- 引入 SpringMVC 相关依赖,并实现对其的自动配置 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 引入 Feign 相关依赖 -->
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-core</artifactId>
<version>11.0</version>
</dependency>
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-gson</artifactId>
<version>11.0</version>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,13 @@
package cn.iocoder.springboot.lab58.feigndemo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class FeignDemoApplication {
public static void main(String[] args) {
SpringApplication.run(FeignDemoApplication.class, args);
}
}

View File

@@ -0,0 +1,19 @@
package cn.iocoder.springboot.lab58.feigndemo.config;
import cn.iocoder.springboot.lab58.feigndemo.feign.UserServiceFeignClient;
import feign.Feign;
import feign.gson.GsonDecoder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class FeignConfig {
@Bean
public UserServiceFeignClient userServiceFeignClient() {
return Feign.builder()
.decoder(new GsonDecoder())
.target(UserServiceFeignClient.class, "http://127.0.0.1:18080"); // 目标地址
}
}

View File

@@ -0,0 +1,41 @@
package cn.iocoder.springboot.lab58.feigndemo.controller;
import cn.iocoder.springboot.lab58.feigndemo.feign.UserServiceFeignClient;
import cn.iocoder.springboot.lab58.feigndemo.feign.response.UserResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@RestController
@RequestMapping("/demo")
public class DemoController {
@Autowired
private UserServiceFeignClient userServiceFeignClient;
@GetMapping("/test01")
public UserResponse test01() {
return userServiceFeignClient.get(1);
// System.out.println("编号:" + user.getId());
// System.out.println("昵称:" + user.getName());
// System.out.println("性别:" + user.getGender());
}
@GetMapping("/test02A")
public List<UserResponse> test02A() {
return userServiceFeignClient.list("你猜", 1);
}
@GetMapping("/test02B")
public List<UserResponse> test02B() {
Map<String, Object> queryMap = new HashMap<>();
queryMap.put("name", "昵称");
return userServiceFeignClient.list(queryMap);
}
}

View File

@@ -0,0 +1,24 @@
package cn.iocoder.springboot.lab58.feigndemo.feign;
import cn.iocoder.springboot.lab58.feigndemo.feign.response.UserResponse;
import feign.Param;
import feign.QueryMap;
import feign.RequestLine;
import java.util.List;
import java.util.Map;
public interface UserServiceFeignClient {
// 获得用户详情
@RequestLine("GET /user/get?id={id}")
UserResponse get(@Param("id") Integer id);
@RequestLine("GET /user/list?name={name}&gender={gender}")
List<UserResponse> list(@Param("name") String name,
@Param("gender") Integer gender);
@RequestLine("GET /user/list")
List<UserResponse> list(@QueryMap Map<String, Object> queryMap);
}

View File

@@ -0,0 +1,36 @@
package cn.iocoder.springboot.lab58.feigndemo.feign.response;
public class UserResponse {
private Integer id;
private String name;
private Integer gender;
public Integer getId() {
return id;
}
public UserResponse setId(Integer id) {
this.id = id;
return this;
}
public String getName() {
return name;
}
public UserResponse setName(String name) {
this.name = name;
return this;
}
public Integer getGender() {
return gender;
}
public UserResponse setGender(Integer gender) {
this.gender = gender;
return this;
}
}

View File

@@ -20,12 +20,12 @@ public class UserController {
}
@GetMapping("/list")
public List<UserResponse> list(@RequestParam("name") String name,
@RequestParam("gender") Integer gender) {
public List<UserResponse> list(@RequestParam(value = "name", required = false) String name,
@RequestParam(value = "gender", required = false) Integer gender) {
List<UserResponse> users = new ArrayList<>();
for (int id = 1; id <= 3; id++) {
users.add(new UserResponse().setId(id)
.setName(name).setGender(gender));
.setName(name + "_" + id).setGender(gender));
}
return users;
}

View File

@@ -14,6 +14,7 @@
<modules>
<module>lab-58-user-service</module>
<module>lab-58-feign-demo</module>
</modules>
</project>

View File

@@ -52,7 +52,7 @@
<!-- <module>lab-39</module>-->
<!-- <module>lab-40</module>-->
<!-- <module>lab-41</module>-->
<!-- <module>lab-42</module>-->
<module>lab-42</module>
<!-- <module>lab-43</module>-->
<!-- <module>lab-44</module>-->
<!-- <module>lab-45</module>-->