Restful API介绍
Restful API是一种网络应用程序的设计风格和开发方式,基于HTTP,可以使用XML格式定义或JSON格式定义,它使用URL定位资源,用HTTP动词(GET,POST,DELETE,DETC)描述操作。
Level 0:使用HTTP作为传输方式。
Level 1:引入资源概念,每一个资源都有对应的URL。
Level 2:使用HTTP方法进行不同的操作,使用HTTP状态码来表示不同的结果。
Level 3:使用超媒体,在资源的表达中包含了链接信息。需要注意的是,在我们实际的工作中,并没有达到这个级别。
在我们实际开发中,需要对我们的接口进行测试,确保我们后端接口的可用,这时我们在不启动整个项目的情况下,可以利用到spring的测试框架辅助我们的开发。
在security-demo工程pom文件导入一下的依赖:
<!-- 引入spring 的测试框架 -->
<dependency>
<artifactId>spring-boot-starter-test</artifactId>
<groupId>org.springframework.boot</groupId>
</dependency>
然后就可以在我们项目工程中的test目录下创建我们的测试用例了,如:
// 如何运行测试用例
@RunWith(SpringRunner.class)
// 这是一个测试用例的类
@SpringBootTest
public class UserControllerTest {
@Autowired
private WebApplicationContext context;
private MockMvc mockMvc;
// 伪造mvc的环境,这样不会去启动我们的tomcat。提高测试速度。
@Before
public void setup(){
mockMvc = MockMvcBuilders.webAppContextSetup(context).build();
}
@Test
public void whenQuerySeccess() {
// perform是执行的意思
try {
mockMvc.perform(
// 构建一个get请求
MockMvcRequestBuilders.get("/user")
// 添加我们的请求参数
.param("userName","hzh")
// 设置utf8的contentType
.contentType(MediaType.APPLICATION_JSON_UTF8)
)
// 执行上面的请求结果后,我们对请求结果的期望是返回的结果是ok(200)
.andExpect(MockMvcResultMatchers.status().isOk())
// 返回的结果是集合,集合的长度是3
.andExpect(MockMvcResultMatchers.jsonPath("$.length()").value(3));
} catch (Exception e) {
e.printStackTrace();
}
}
注意:由于存在大量静态方法,我们之后的讲解使用jdk1.5的静态方法导入特性。简化我们的代码。
接下来实现我们的第一个控制器:
@RestController
@RequestMapping("user")
public class UserController {
@GetMapping
public List<User> query(@RequestParam(required = false, name = "userName", defaultValue = "hzh") String nickName) {
List<User> users = new ArrayList<>();
users.add(new User());
users.add(new User());
users.add(new User());
return users;
}
}
在上面的代码中,@RequestMapping定义了这个控制器的请求前缀,而@RequestParam对请求参数进行规范,name属性定义了请求参数名为username获取需要的参数值,若不设置name的值,默认会按照我们的方法参数名称去获取对相应的值。required和default属性定义了这个参数是可以省略的,若省略,默认值“hzh”。
写好我们的控制器后,我们可以运行从我们的测试用例去请求我们的控制器,而无需去把整个项目启动了。
若一个请求需要传递多个参数,我们直接在方法参数上写接受的参数,这样会造成我们代码的繁琐和不美观。这时候,我们可以考虑用定义一个对象去接收我们的请求的参数。若是一个分页的功能,我们还可以使用spring为我们提供好的Pageable对象接收分页参数。
@GetMapping
public List<User> query(UserQueryCondition condition, Pageable pageable) {
System.out.println(ReflectionToStringBuilder.toString(condition, ToStringStyle.MULTI_LINE_STYLE));
System.out.println(ReflectionToStringBuilder.toString(pageable, ToStringStyle.MULTI_LINE_STYLE));
List<User> users = new ArrayList<>();
users.add(new User());
users.add(new User());
users.add(new User());
return users;
}
这时候我们可以把测试用例写成这样:
try {
String result = mockMvc.perform(
// 构建一个get请求
get("/user")
// 普通的参数
.param("userName", "hzh")
.param("age", "18")
.param("ageTo", "60")
.param("xxx", "yyy")
// 分页参数相关
// size表示每页显示数目
.param("size", "10")
// page表示第几页
.param("page", "3")
// sort表示排序的方式
.param("sort", "age.desc")
// 设置utf8的contentType
.contentType(MediaType.APPLICATION_JSON_UTF8))
// 执行上面的请求结果后,我们对请求结果的期望是返回的结果是ok(200)
.andExpect(status().isOk())
// 返回的结果是集合,集合的长度是3
.andExpect(jsonPath("$.length()").value(3))
// 获取返回的数据
.andReturn().getResponse().getContentAsString();
System.out.println(result);
} catch (Exception e) {
e.printStackTrace();
}
由于在Restful API中,有时候需要把参数直接放在URL中,那么我们该如何映射到我们的参数上呢?
下面我们以一个获取用户信息为例:
@RequestMapping(value = "/user/{id:\\d+}", method = RequestMethod.GET)
public User getUserInfo(@PathVariable(name = "id") String id){
User user = new User();
user.setName("hzh");
return user;
}
我们使用到的正是@PathVariable的注解来获取url中的数据,并且为了规范我们的id只能是数字,我们还可以在@RequestMapping的value中加入正则表达式进行校验。
下面是我们的测试用例:
@Test
public void whenGenInfoSuccess() {
try {
String result = mockMvc.perform(get("/user/1")
.contentType(MediaType.APPLICATION_JSON_UTF8))
.andExpect(status().isOk())
// 返回的json中有一个值为hzh的username
.andExpect(jsonPath("$.name").value("hzh"))
// 获取返回的数据
.andReturn().getResponse().getContentAsString();
System.out.println(result);
} catch (Exception e) {
e.printStackTrace();
}
}
如果我们发送一个错误的请求,那么可以使用以下的方式说明这个请求是错误的,并且测试运行时控制台不会不爆红。
@Test
public void whenGenInfoFail() {
try {
mockMvc.perform(get("/user/a")
.contentType(MediaType.APPLICATION_JSON_UTF8))
// 判断服务端返回的是一个4xx的状态码
.andExpect(status().is4xxClientError());
} catch (Exception e) {
e.printStackTrace();
}
}
在某一些请求返回的JSON中,我们并不希望返回某些字段,而在另一些请求中需要返回某些字段。比如我们在上面的代码中我们希望调用查询user集合只返回name,而查询每一个user返回的是name和password。我们可以在User类中使用接口的方式定义过个返回的视图。
public class User {
public interface UserSimpleView{}
// 继承的方式,简化视图字段的定义
public interface UserDetailView extends UserSimpleView{}
private String name;
@NotBlank
private String password;
@JsonView(UserSimpleView.class)
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@JsonView(UserDetailView.class)
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
并在Controller的方法上面也指定视图,这样就会自动过滤不需要返回的字段。
@RequestMapping(value = "/user", method = RequestMethod.GET)
@JsonView(User.UserSimpleView.class)
public List<User> query(UserQueryCondition condition, Pageable pageable) {}
@RequestMapping(value = "/user/{id:\\d+}", method = RequestMethod.GET)
@JsonView(User.UserDetailView.class)
public User getUserInfo(@PathVariable(name = "id") String id){}
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有