41

Spring Boot 2.x基础教程:构建RESTful API与单元测试

 4 years ago
source link: https://www.tuicool.com/articles/2uee2uI
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

首先,回顾并详细说明一下在快速入门中使用的 @Controller@RestController@RequestMapping 注解。如果您对Spring MVC不熟悉并且还没有尝试过快速入门案例,建议先看一下快速入门的内容。

  • @Controller :修饰class,用来创建处理http请求的对象
  • @RestController :Spring4之后加入的注解,原来在 @Controller 中返回json需要 @ResponseBody 来配合,如果直接用 @RestController 替代 @Controller 就不需要再配置 @ResponseBody ,默认返回json格式
  • @RequestMapping :配置url映射。现在更多的也会直接用以Http Method直接关联的映射注解来定义,比如: GetMappingPostMappingDeleteMappingPutMapping

下面我们通过使用Spring MVC来实现一组对User对象操作的RESTful API,配合注释详细说明在Spring MVC中如何映射HTTP请求、如何传参、如何编写单元测试。

RESTful API具体设计如下:

EJN36rz.png!web

定义User实体

@Data
public class User {

private Long id;
private String name;
private Integer age;

}

注意:相比1.x版本教程中自定义set和get函数的方式,这里使用 @Data 注解可以实现在编译器自动添加set和get函数的效果。该注解是lombok提供的,只需要在pom中引入加入下面的依赖就可以支持:

<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>

实现对User对象的操作接口

@RestController
@RequestMapping(value = "/users") // 通过这里配置使下面的映射都在/users下
public class UserController {

// 创建线程安全的Map,模拟users信息的存储
static Map<Long, User> users = Collections.synchronizedMap(new HashMap<Long, User>());

/**
* 处理"/users/"的GET请求,用来获取用户列表
*
* @return
*/
@GetMapping("/")
public List<User> getUserList() {
// 还可以通过@RequestParam从页面中传递参数来进行查询条件或者翻页信息的传递
List<User> r = new ArrayList<User>(users.values());
return r;
}

/**
* 处理"/users/"的POST请求,用来创建User
*
* @param user
* @return
*/
@PostMapping("/")
public String postUser(@RequestBody User user) {
// @RequestBody注解用来绑定通过http请求中application/json类型上传的数据
users.put(user.getId(), user);
return "success";
}

/**
* 处理"/users/{id}"的GET请求,用来获取url中id值的User信息
*
* @param id
* @return
*/
@GetMapping("/{id}")
public User getUser(@PathVariable Long id) {
// url中的id可通过@PathVariable绑定到函数的参数中
return users.get(id);
}

/**
* 处理"/users/{id}"的PUT请求,用来更新User信息
*
* @param id
* @param user
* @return
*/
@PutMapping("/{id}")
public String putUser(@PathVariable Long id, @RequestBody User user) {
User u = users.get(id);
u.setName(user.getName());
u.setAge(user.getAge());
users.put(id, u);
return "success";
}

/**
* 处理"/users/{id}"的DELETE请求,用来删除User
*
* @param id
* @return
*/
@DeleteMapping("/{id}")
public String deleteUser(@PathVariable Long id) {
users.remove(id);
return "success";
}

}

这里相较1.x版本教程中,用更细化的 @GetMapping@PostMapping 等系列注解替换了以前的 @RequestMaping 注解;另外,还使用 @RequestBody 替换了 @ModelAttribute 的参数绑定。

编写单元测试

下面针对该Controller编写测试用例验证正确性,具体如下。当然也可以通过浏览器插件等进行请求提交验证。

@RunWith(SpringRunner.class)
@SpringBootTest
public class Chapter21ApplicationTests {

private MockMvc mvc;

@Before
public void setUp() {
mvc = MockMvcBuilders.standaloneSetup(new UserController()).build();
}

@Test
public void testUserController() throws Exception {
// 测试UserController
RequestBuilder request;

// 1、get查一下user列表,应该为空
request = get("/users/");
mvc.perform(request)
.andExpect(status().isOk())
.andExpect(content().string(equalTo("[]")));

// 2、post提交一个user
request = post("/users/")
.contentType(MediaType.APPLICATION_JSON)
.content("{\"id\":1,\"name\":\"测试大师\",\"age\":20}");
mvc.perform(request)
.andExpect(content().string(equalTo("success")));

// 3、get获取user列表,应该有刚才插入的数据
request = get("/users/");
mvc.perform(request)
.andExpect(status().isOk())
.andExpect(content().string(equalTo("[{\"id\":1,\"name\":\"测试大师\",\"age\":20}]")));

// 4、put修改id为1的user
request = put("/users/1")
.contentType(MediaType.APPLICATION_JSON)
.content("{\"name\":\"测试终极大师\",\"age\":30}");
mvc.perform(request)
.andExpect(content().string(equalTo("success")));

// 5、get一个id为1的user
request = get("/users/1");
mvc.perform(request)
.andExpect(content().string(equalTo("{\"id\":1,\"name\":\"测试终极大师\",\"age\":30}")));

// 6、del删除id为1的user
request = delete("/users/1");
mvc.perform(request)
.andExpect(content().string(equalTo("success")));

// 7、get查一下user列表,应该为空
request = get("/users/");
mvc.perform(request)
.andExpect(status().isOk())
.andExpect(content().string(equalTo("[]")));

}

}

对MockMvc不熟悉的读者,可能会碰到一些函数不存在而报错。必须引入下面这些静态函数的引用:

import static org.hamcrest.Matchers.equalTo;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

这里相较1.x版本教程中,主要有两个地方不同。测试类采用 @RunWith(SpringRunner.class)@SpringBootTest 修饰启动;另外,由于POST和PUT接口的参数采用 @RequestBody 注解,所以提交的会是一个json字符串,而不是之前的参数形式,这里在定义请求的时候使用 contentType(MediaType.APPLICATION_JSON) 指定提交内容为json格式,使用 content 传入要提交的json字符串。如果用@ModelAttribute的话就得用 param 方法添加参数,具体可以看1.x版本的教程。

至此,我们通过引入web模块(没有做其他的任何配置),就可以轻松利用Spring MVC的功能,以非常简洁的代码完成了对User对象的RESTful API的创建以及单元测试的编写。其中同时介绍了Spring MVC中最为常用的几个核心注解: @RestController , RequestMapping 以及一些参数绑定的注解: @PathVariable , @RequestBody 等。

代码示例

本文的相关例子可以查看下面仓库中的 chapter2-1 目录:

如果您觉得本文不错,欢迎 Star 支持,您的关注是我坚持的动力!


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK