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

首先,回顾并详细说明一下在快速入门中使用的@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具体设计如下:

定义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目录:

  • Github:https://github.com/dyc87112/SpringBoot-Learning/
  • Gitee:https://gitee.com/didispace/SpringBoot-Learning/

如果您觉得本文不错,欢迎Star支持,您的关注是我坚持的动力!更多本系列免费教程连载「点击进入汇总目录」


money.jpg

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/477366.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

剑指Offer - 面试题11. 旋转数组的最小数字(二分查找)

1. 题目 把一个数组最开始的若干个元素搬到数组的末尾&#xff0c;我们称之为数组的旋转。输入一个递增排序的数组的一个旋转&#xff0c;输出旋转数组的最小元素。例如&#xff0c;数组 [3,4,5,1,2] 为 [1,2,3,4,5] 的一个旋转&#xff0c;该数组的最小值为1。 示例 1&#…

核酸检测机器人来了!体验者:捅的很温柔

编 | 袁榭、桃子源 | 新智元5月21日&#xff0c;上海人工智能研究院宣布「SAIRI赛瑞」智能核酸采样车2.0问世&#xff0c;仅需30秒便可完成一次采样。在新冠流行持续不断、核酸检测逐渐广域常态化的当下&#xff0c;不止一家机构在开发核酸检测的机器人系统2022年5月21日&#…

AI作画新高度!谷歌发布imagen,效果惊艳全场

文 | 梦晨 鱼羊 发自 凹非寺源 | 量子位在让AI搞创作这件事上&#xff0c;谷歌和OpenAI正面刚起来了。这不&#xff0c;震惊全网的DALLE 2才新鲜出炉一个月&#xff0c;谷歌就派出名为Imagen的选手来打擂台。直接上图对比&#xff0c;左边是谷歌Imagen选手眼中的“猫猫绊倒人类…

Spring Boot 2.x基础教程:配置文件详解

在快速入门一节中&#xff0c;我们轻松的实现了一个简单的RESTful API应用&#xff0c;体验了一下Spring Boot给我们带来的诸多优点&#xff0c;我们用非常少的代码量就成功的实现了一个Web应用&#xff0c;这是传统的Spring应用无法办到的&#xff0c;虽然我们在实现Controlle…

剑指Offer - 面试题12. 矩阵中的路径(DFS回溯)

1. 题目 请设计一个函数&#xff0c;用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵中的任意一格开始&#xff0c;每一步可以在矩阵中向左、右、上、下移动一格。如果一条路径经过了矩阵的某一格&#xff0c;那么该路径不能再次进入该格子。例如…

一篇论文8778个作者:人均写5个字,署名用了17页

文 | 梦晨(发自凹非寺)源 | 公众号QbitAI一篇论文有8778位作者是什么感觉&#xff1f;在PDF里&#xff0c;光作者列表就要占17页。有人试图把所有名字排版在同一页&#xff0c;字已经小到看不清。这篇论文来自欧洲核子研究中心的ATLAS对撞机合作组&#xff0c;刷新了他们在2015…

Spring Boot 2.x基础教程:工程结构推荐

Spring Boot框架本身并没有对工程结构有特别的要求&#xff0c;但是按照最佳实践的工程结构可以帮助我们减少可能会遇见的坑&#xff0c;尤其是Spring包扫描机制的存在&#xff0c;如果您使用最佳实践的工程结构&#xff0c;可以免去不少特殊的配置工作。 典型示例 以下结构是…

剑指Offer - 面试题18. 删除链表的节点

1. 题目 给定单向链表的头指针和一个要删除的节点的值&#xff0c;定义一个函数删除该节点。 返回删除后的链表的头节点。 注意&#xff1a;此题对比原题有改动 示例 1: 输入: head [4,5,1,9], val 5 输出: [4,1,9] 解释: 给定你链表中值为 5 的第二个节点&#xff0c;那么…

因为工资补贴邮件被划空银行卡?搜狐全体员工被诈骗始末

文 | 小戏“叮~”如果你的手机弹出了新邮件提示&#xff0c;弹窗显示【xx公司财务部】关于发布最新工资补贴通知……&#xff0c;你会怎么想&#xff1f;当我看到了正确的公司名&#xff0c;与或许有一定道理的工资补贴&#xff0c;这些信息还是会驱使我带着疑惑打开邮件&#…

剑指Offer - 面试题24. 反转链表(遍历/递归)

1. 题目 定义一个函数&#xff0c;输入一个链表的头节点&#xff0c;反转该链表并输出反转后链表的头节点。 示例: 输入: 1->2->3->4->5->NULL 输出: 5->4->3->2->1->NULL限制&#xff1a; 0 < 节点个数 < 5000来源&#xff1a;力扣&…

我是粉红猪佩奇,我要把粉色吹风机写进 IJCAI 论文!

文 | 智商掉了一地当小猪佩奇的忠实观众进行AI研究&#xff0c;论文配图居然是这样的风格……在介绍接下来的内容前&#xff0c;我们先来看一则笑话&#xff1a;小猪佩奇哭着对妈妈说&#xff1a;“小伙伴们都说我长得像粉色吹风机。” 猪妈妈安慰道&#xff1a;“尽瞎说&#…

Spring Boot 2.x基础教程:快速入门

简介 在您第1次接触和学习Spring框架的时候&#xff0c;是否因为其繁杂的配置而退却了&#xff1f;在你第n次使用Spring框架的时候&#xff0c;是否觉得一堆反复黏贴的配置有一些厌烦&#xff1f;那么您就不妨来试试使用Spring Boot来让你更易上手&#xff0c;更简单快捷地构建…

剑指Offer - 面试题64. 求1+2+…+n(递归)

1. 题目 求 12…n &#xff0c;要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句&#xff08;A?B:C&#xff09;。 示例 1&#xff1a; 输入: n 3 输出: 6示例 2&#xff1a; 输入: n 9 输出: 45限制&#xff1a; 1 < n < 10000来源&…

AI社区炸锅了!一句话哄一哄就能让GPT-3准确率暴涨61%!

文 | 梦晨 明敏 发自 凹非寺源 | 量子位一觉醒来&#xff0c;机器学习社区炸了锅。因为最新研究发现&#xff0c;只要对GPT-3说一句“让我们一步一步地思考”&#xff0c;就能让它正确回答出以前不会的问题。比如下面这个例子&#xff1a;16个球中有一半是高尔夫球&#xff0c;…

全网Star最多(近20k)的Spring Boot开源教程 2019 年要继续更新了!

从2016年1月开始写博客&#xff0c;默默地更新《Spring Boot系列教程》&#xff0c;从无人问津到千万访问&#xff0c;作为一个独立站点&#xff08;http://blog.didispace.com&#xff09;&#xff0c;相信只有那些跟我一样&#xff0c;坚持维护自己独立博客的童鞋才能体会这有…

剑指Offer - 面试题65. 不用加减乘除做加法(位运算,要看哦)

1. 题目 写一个函数&#xff0c;求两个整数之和&#xff0c;要求在函数体内不得使用 “”、“-”、“*”、“/” 四则运算符号。 示例: 输入: a 1, b 1 输出: 2提示&#xff1a; a, b 均可能是负数或 0 结果不会溢出 32 位整数来源&#xff1a;力扣&#xff08;LeetCode&am…

Spring Boot中如何扩展XML请求和响应的支持

在之前的所有Spring Boot教程中&#xff0c;我们都只提到和用到了针对HTML和JSON格式的请求与响应处理。那么对于XML格式的请求要如何快速的在Controller中包装成对象&#xff0c;以及如何以XML的格式返回一个对象呢&#xff1f; 实现原理&#xff1a;消息转换器&#xff08;M…

我在斯坦福做的科研demo…要被导师带去美国国会演讲?

文 | Jazon编 | 小戏大家好&#xff0c;我是 Jazon。时光荏苒&#xff0c;一转眼我已经快要从 Stanford CS 系毕业了。今年7月&#xff0c;我将开始谷歌总部工作&#xff0c;短期内会在硅谷定居&#xff0c;湾区的朋友们欢迎约起呀。笔者去年写过一篇文章&#xff0c;分享了我研…

剑指Offer - 面试题21. 调整数组顺序使奇数位于偶数前面(双指针,原地算法)

1. 题目 输入一个整数数组&#xff0c;实现一个函数来调整该数组中数字的顺序&#xff0c;使得所有奇数位于数组的前半部分&#xff0c;所有偶数位于数组的后半部分。 示例&#xff1a; 输入&#xff1a;nums [1,2,3,4] 输出&#xff1a;[1,3,2,4] 注&#xff1a;[3,1,2,4]…

使用Cloud Studio在线编写、调试和管理Spring Boot应用

在之前的《Spring Boot基础教程》中&#xff0c;我们介绍了通过Spring官方的构建页面来生成项目&#xff0c;也介绍了通过使用Intellij中的Spring Initializr来快速构建Spring Boot/Cloud工程。在完成了基础项目构建之后&#xff0c;我们要开始进行的就是代码的开发阶段&#x…