第二章:RESTful API

学习内容

  使用Spring MVC编写Restful API

  使用Spring MVC处理其他web应用常见的需求和场景

    如何处理静态资源和异常,如何使用Spring MVC的拦截器,文件的上传下载,如何进行请求的异步开发

  RESTful API开发常用辅助框架

    Swagger-生成服务文档,WireMock-伪造服务

RESTful API介绍

  特点:

  1.用URL描述资源

  2.使用HTTP方法描述行为,使用HTTP状态码来表示不同结果

    增删改查对应POST、DELETE、PUT、GET,使用状态码来表示结果而不是用报文里面的内容。

  3.使用json交互数据

  4.RESTful只是一种风格,并不是强制标准

编写第一个RESTful API

  使用注解声明RESTful API

    常用注解

      @RestController 标明此Controller提供RESTful API

      @RequestMapping及其变体 映射http请求url到java方法

      @RequestParam 映射请求参数到java方法的参数

      @PageableDefault 指定分页参数的默认值

  在RESTful API中传递参数

    @RequestParam

      required,name,defaultValue,required表示参数是否必须,name表示HTTP请求参数名,defaultValue表示未传参数时使用的默认值。

@RequestMapping(value = "/user", method = RequestMethod.GET)
public List<User> query(@RequestParam(required = true, name = "username", defaultValue = "Tom") String username) {
    System.out.println(username);
    List<User> users = new ArrayList<User>();
    users.add(new User());
    users.add(new User());
    users.add(new User());
    return users;
}

      如果传递参数太多,Spring MVC可以自动将参数组装到对象中,可以声明一个类UserQueryCondition有多个属性。

public class UserQueryCondition {
    
    private String username;
    private int age;
    private int ageTo;
    
    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public int getAgeTo() {
        return ageTo;
    }
    public void setAgeTo(int ageTo) {
        this.ageTo = ageTo;
    }

}
@RequestMapping(value = "/user", method = RequestMethod.GET)
public List<User> query(UserQueryCondition condition) {
    System.out.println(ReflectionToStringBuilder.toString(condition, ToStringStyle.MULTI_LINE_STYLE));
    List<User> users = new ArrayList<User>();
    users.add(new User());
    users.add(new User());
    users.add(new User());
    return users;
}
@Test
public void whenQuerySuccess() throws Exception {
    mockMvc.perform(get("/user")
            .param("username", "jojo")
            .param("age", "10")
            .param("ageTo", "20")
            .contentType(MediaType.APPLICATION_JSON_UTF8))
            .andExpect(status().isOk())
            .andExpect(jsonPath("$.length()").value(3));
}

     @PageableDefault

      page,size,sort,表示默认查第几页,一页数据条数,排序

@RequestMapping(value = "/user", method = RequestMethod.GET)
public List<User> query(UserQueryCondition condition, @PageableDefault(page = 1, size = 10, sort = "username,asc") 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<User>();
    users.add(new User(1));
    users.add(new User(2));
    users.add(new User(3));return users;
}
@Test
public void whenQuerySuccess() throws Exception {
    mockMvc.perform(get("/user")
            .param("username", "jojo")
            .param("age", "10")
            .param("ageTo", "20")
            .param("size", "5")
            .param("page", "2")
            .param("sort", "age,desc")
            .contentType(MediaType.APPLICATION_JSON_UTF8))
            .andExpect(status().isOk());
}

编写用户详情服务

  @PathVariable 映射url片段到java方法的参数

    name,required,name要和url片段相同,required表示是否必须

@RequestMapping(value = "/user/{id}", method = RequestMethod.GET)
public User getInfo(@PathVariable(name = "id") String userid) {
    User user = new User();
    user.setId(userid);
    user.setUsername("Tom");
    return user;
}
@Test
public void whenGetInfoSuccess() throws Exception {
    String result = mockMvc.perform(get("/user/1")
            .contentType(MediaType.APPLICATION_JSON_UTF8))
    .andExpect(status().isOk())
    .andExpect(jsonPath("$.username").value("Tom"))
    .andReturn().getResponse().getContentAsString();
    System.out.println(result);
}  

  在url片段的声明中使用正则表达式

@RequestMapping(value = "/user/{id:\\d+}", method = RequestMethod.GET)
public User getInfo(@PathVariable(name = "id") String userid) {
    User user = new User();
    user.setId(userid);
    user.setUsername("Tom");
    return user;
}
@Test
public void whenGetInfoFail() throws Exception {
    mockMvc.perform(get("/user/a")
            .contentType(MediaType.APPLICATION_JSON_UTF8))
            .andExpect(status().is4xxClientError());
}

  @JsonView控制json输出内容

    假设query不想返回用户密码,getInfo时返回给前台用户密码,即在返回相同对象时控制返回哪些字段。

    使用步骤:

      1.使用接口声明多个视图 2.在值对象的get方法上指定视图 3.在Controller方法上指定视图

public class User {
    
    public interface UserSimpleView {}; //视图1
    public interface UserDetailView extends UserSimpleView {}; //视图2,因继承视图1,所以使用视图2也会显示视图1的属性
    
    private String id;
    private String username;
    private int age;
    private String password;
    
    @JsonView(UserSimpleView.class)
    public String getId() {
        return id;
    }
    public void setId(String id) {
        this.id = id;
    }
    @JsonView(UserSimpleView.class)
    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    @JsonView(UserSimpleView.class)
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    @JsonView(UserDetailView.class)
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }

}
@RequestMapping(value = "/user", method = RequestMethod.GET)
@JsonView(User.UserSimpleView.class)
public List<User> query(UserQueryCondition condition, @PageableDefault(page = 1, size = 10, sort = "username,asc") 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<User>();
    users.add(new User());
    users.add(new User());
    users.add(new User());
    return users;
}

@RequestMapping(value = "/user/{id:\\d+}", method = RequestMethod.GET)
@JsonView(User.UserDetailView.class)
public User getInfo(@PathVariable(name = "id") String userid) {
    User user = new User();
    user.setId(userid);
    user.setUsername("Tom");
    return user;
}

   代码重构

    1.将url相同部分提到类上声明

    2.使用RequestMapping的变体GetMapping

@RestController
@RequestMapping("/user")
public class UserController {
    
    @GetMapping()
    @JsonView(User.UserSimpleView.class)
    public List<User> query(UserQueryCondition condition, @PageableDefault(page = 1, size = 10, sort = "username,asc") 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<User>();
        users.add(new User());
        users.add(new User());
        users.add(new User());
        return users;
    }
    
    @GetMapping("/{id:\\d+}")
    @JsonView(User.UserDetailView.class)
    public User getInfo(@PathVariable(name = "id") String userid) {
        User user = new User();
        user.setId(userid);
        user.setUsername("Tom");
        return user;
    }

}

 

 

 

  

 

posted @ 2018-08-24 14:49  ejrover  阅读(153)  评论(0编辑  收藏  举报