前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Restful API详解

Restful API详解

作者头像
用户7386338
发布2020-05-29 15:32:18
2.1K0
发布2020-05-29 15:32:18
举报
文章被收录于专栏:Java患者Java患者

Restful API介绍

Restful API是一种网络应用程序的设计风格和开发方式,基于HTTP,可以使用XML格式定义或JSON格式定义,它使用URL定位资源,用HTTP动词(GET,POST,DELETE,DETC)描述操作。

Restful API特点

  • 用URL描述资源。
  • 使用HTTP方法描述行为,使用HTTP状态码表示不同的结果。
  • 使用json交互数据。
  • Restful只是一种风格,并不是强制的标准。

Restful API的成熟模型

Level 0:使用HTTP作为传输方式。

Level 1:引入资源概念,每一个资源都有对应的URL。

Level 2:使用HTTP方法进行不同的操作,使用HTTP状态码来表示不同的结果。

Level 3:使用超媒体,在资源的表达中包含了链接信息。需要注意的是,在我们实际的工作中,并没有达到这个级别。

与传统请求方式对比

Restful API常用映射注解

  • @Controller:在一个类上添加@Controller注解,表明了这个类是一个控制器类。
  • @ResponseBody:表示方法的返回值直接以指定的格式写入Http response body中,而不是解析为跳转路径。
  • @RestController:相当于@Controller+@ResponseBody注解。
  • @RequestMapping:这个注解会将 HTTP 请求映射到 MVC 和 REST 控制器的处理方法上。
  • @GetMapping:这个注解是@RequestMapping的变体,可以接收GET的请求方式,在RestFul在处理获取资源的请求。
  • @PostMapping:这个注解是@RequestMapping的变体,可以接收Post的请求方式,在RestFul在处理创建资源的请求。
  • @PutMapping:这个注解是@RequestMapping的变体,可以接收Put的请求方式,在RestFul在处理修改资源的请求。
  • @DeleteMapping:这个注解是@RequestMapping的变体,可以接收Delete的请求方式,在RestFul在处理删除资源的请求。
  • @RequestParam:将请求参数绑定到你控制器的方法参数上。
  • @PathVariable:接收请求路径中占位符的值。
  • @RequestBody:用来接收前端传递给后端的json字符串中的数据的(请求体中的数据的)。

Restful API的测试用例

在我们实际开发中,需要对我们的接口进行测试,确保我们后端接口的可用,这时我们在不启动整个项目的情况下,可以利用到spring的测试框架辅助我们的开发。

在security-demo工程pom文件导入一下的依赖:

代码语言:javascript
复制
<!-- 引入spring 的测试框架 -->
<dependency>
    <artifactId>spring-boot-starter-test</artifactId>
    <groupId>org.springframework.boot</groupId>
</dependency>

然后就可以在我们项目工程中的test目录下创建我们的测试用例了,如:

代码语言:javascript
复制
// 如何运行测试用例
@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的静态方法导入特性。简化我们的代码。

接下来实现我们的第一个控制器:

代码语言:javascript
复制
@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对象接收分页参数。

代码语言:javascript
复制
  @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;
  }

这时候我们可以把测试用例写成这样:

代码语言:javascript
复制
  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();
}

@PathVariable的使用

由于在Restful API中,有时候需要把参数直接放在URL中,那么我们该如何映射到我们的参数上呢?

下面我们以一个获取用户信息为例:

代码语言:javascript
复制
  @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中加入正则表达式进行校验。

下面是我们的测试用例:

代码语言:javascript
复制
  @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();
      }
  }

如果我们发送一个错误的请求,那么可以使用以下的方式说明这个请求是错误的,并且测试运行时控制台不会不爆红。

代码语言:javascript
复制
  @Test
  public void whenGenInfoFail() {
      try {
          mockMvc.perform(get("/user/a")
                  .contentType(MediaType.APPLICATION_JSON_UTF8))
                  // 判断服务端返回的是一个4xx的状态码
                  .andExpect(status().is4xxClientError());
      } catch (Exception e) {
          e.printStackTrace();
      }
  }

@JsonView的使用

在某一些请求返回的JSON中,我们并不希望返回某些字段,而在另一些请求中需要返回某些字段。比如我们在上面的代码中我们希望调用查询user集合只返回name,而查询每一个user返回的是name和password。我们可以在User类中使用接口的方式定义过个返回的视图。

代码语言:javascript
复制
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的方法上面也指定视图,这样就会自动过滤不需要返回的字段。

代码语言:javascript
复制
@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){}
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-03-22,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Java患者 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Restful API特点
  • Restful API的成熟模型
  • 与传统请求方式对比
  • Restful API常用映射注解
  • Restful API的测试用例
  • 使用对象接收请求的参数
  • @PathVariable的使用
  • @JsonView的使用
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档