zoukankan      html  css  js  c++  java
  • SpringBoot系列

    REST,即Representational State Transfer的缩写,对这个词组的翻译是表现层状态转化

    RESTful是一种软件设计风格,就是目前最流行的一种互联网软件架构。它结构清晰、符合标准、易于理解、扩展方便,所以正得到越来越多网站的采用。

    SpringMVC对RESTful风格的接口有着天然的支持,本篇将讲述如何在SpringBoot中怎样写。

    几个注解

    在讲述使用之前,想要理解SpringMVC的几个常用注解:

    1. @Controller:修饰class,用来创建处理http请求的对象
    2. @RestController:Spring4之后加入的注解,原来在@Controller中返回json需要@ResponseBody来配合,如果直接用@RestController替代@Controller就不需要再配置@ResponseBody,默认返回json格式。
    3. @RequestMapping:配置url映射
    4. @PostMapping: 这个是@RequestMapping+POST方法的简写
    5. @RequestHeader: 请求Header参数
    6. @PathVariable: URL路径参数,比如/user/{id}中的id参数
    7. @RequestParam: URL请求参数,比如/user?id=1中的id参数
    8. @RequestBody: 请求Body参数

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

    API设计

    RESTful API具体设计如下:

    请求类型URL功能说明
    GET /users 查询用户列表
    POST /users 创建一个用户
    GET /users/{id} 根据id查询用户
    PUT /users/{id} 根据id更新用户
    DELTE /users/{id} 更加id删除用户

    RESTful架构有一些典型的设计误区,就是URI包含动词。因为”资源”表示一种实体,所以应该是名词,URI不应该有动词,动词应该放在HTTP协议中。 上面设计的API的URI中都是名词。

    实体定义

    1
    2
    3
    4
    5
    6
    public class User {
    private Long id;
    private String name;
    private Integer age;
    // 下面省略getter/setter
    }

    Controller实现

    接下来就可以编写RestController了,这里为了演示,会将数据保存到内存Map中,实际使用肯定是保存到数据库中。

    /**
    * 接口类
    */
    @RestController
    @RequestMapping(value = "/users")
    public class UserController {

    private static final Logger _logger = LoggerFactory.getLogger(UserController.class);

    // 创建线程安全的Map
    private static Map<Long, User> users = Collections.synchronizedMap(new HashMap<Long, User>());

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

    @RequestMapping(value = "/", method = RequestMethod.POST)
    public BaseResponse<String> postUser(@ModelAttribute User user) {
    // 处理"/users/"的POST请求,用来创建User
    // 除了@ModelAttribute绑定参数之外,还可以通过@RequestParam从页面中传递参数
    users.put(user.getId(), user);
    return new BaseResponse<>(true, "新增成功", "");
    }

    @RequestMapping(value = "/{id}", method = RequestMethod.GET)
    public BaseResponse<User> getUser(@PathVariable Long id) {
    // 处理"/users/{id}"的GET请求,用来获取url中id值的User信息
    // url中的id可通过@PathVariable绑定到函数的参数中
    return new BaseResponse<>(true, "查询成功", users.get(id));
    }

    @RequestMapping(value = "/{id}", method = RequestMethod.PUT)
    public BaseResponse<String> putUser(@PathVariable Long id, @ModelAttribute User user) {
    // 处理"/users/{id}"的PUT请求,用来更新User信息
    User u = users.get(id);
    u.setName(user.getName());
    u.setAge(user.getAge());
    users.put(id, u);
    return new BaseResponse<>(true, "更新成功", "");
    }

    @RequestMapping(value = "/{id}", method = RequestMethod.DELETE)
    public BaseResponse<String> deleteUser(@PathVariable Long id) {
    // 处理"/users/{id}"的DELETE请求,用来删除User
    users.remove(id);
    return new BaseResponse<>(true, "删除成功", "");
    }

    }

    测试

    接下来就是写一个测试来测一下,SpringMVC的内置测试支持非常方便。

    先写一个json和对象之间相互转化的工具类,使用Jackson库:

    public class JacksonUtil {
    private static ObjectMapper mapper = new ObjectMapper();

    public static String bean2Json(Object obj) {
    try {
    return mapper.writeValueAsString(obj);
    } catch (JsonProcessingException e) {
    e.printStackTrace();
    return null;
    }
    }

    public static <T> T json2Bean(String jsonStr, TypeReference<T> typeReference) {
    try {
    return mapper.readValue(jsonStr, typeReference);
    } catch (IOException e) {
    e.printStackTrace();
    return null;
    }
    }
    }

    然后再编写单元测试:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    @AutoConfigureMockMvc
    @RunWith(SpringRunner.class)
    @SpringBootTest(classes = Application.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
    public class ApplicationTests {
    @Autowired
    private MockMvc mvc;

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

    // 1、get查一下user列表,应该为空
    request = get("/users/");
    MvcResult result = mvc.perform(request)
    .andExpect(status().isOk())
    .andReturn();
    String content = result.getResponse().getContentAsString();
    BaseResponse<List<User>> response = JacksonUtil.json2Bean(content, new TypeReference<BaseResponse<List<User>>>() {});
    assertThat(response.isSuccess(), is(true));
    assertThat(response.getMsg(), is("查询列表成功"));
    assertThat(((List) response.getData()).size(), is(0));

    // 2、post提交一个user
    request = post("/users/")
    .param("id", "1")
    .param("name", "测试大师")
    .param("age", "20");
    result = mvc.perform(request)
    .andExpect(status().isOk())
    .andReturn();
    content = result.getResponse().getContentAsString();
    BaseResponse<String> response1 = JacksonUtil.json2Bean(content, new TypeReference<BaseResponse<String>>() {});
    assertThat(response1.isSuccess(), is(true));
    assertThat(response1.getMsg(), is("新增成功"));

    // 3、get获取user列表,应该有刚才插入的数据
    request = get("/users/");
    result = mvc.perform(request)
    .andExpect(status().isOk())
    .andReturn();
    content = result.getResponse().getContentAsString();
    BaseResponse<List<User>> response2 = JacksonUtil.json2Bean(content, new TypeReference<BaseResponse<List<User>>>() {});
    assertThat(response2.isSuccess(), is(true));
    assertThat(response2.getMsg(), is("查询列表成功"));
    assertThat((response2.getData()).size(), is(1));

    // 4、put修改id为1的user
    request = put("/users/1")
    .param("name", "测试终极大师")
    .param("age", "30");
    result = mvc.perform(request)
    .andExpect(status().isOk())
    .andReturn();
    content = result.getResponse().getContentAsString();
    BaseResponse<String> response3 = JacksonUtil.json2Bean(content, new TypeReference<BaseResponse<String>>() {});
    assertThat(response3.isSuccess(), is(true));
    assertThat(response3.getMsg(), is("更新成功"));

    // 5、get一个id为1的user
    request = get("/users/1");
    result = mvc.perform(request)
    .andExpect(status().isOk())
    .andReturn();
    content = result.getResponse().getContentAsString();
    BaseResponse<User> response4 = JacksonUtil.json2Bean(content, new TypeReference<BaseResponse<User>>() {});
    assertThat(response4.isSuccess(), is(true));
    assertThat(response4.getMsg(), is("查询成功"));
    User user = response4.getData();
    assertThat(user.getId(), is(1L));
    assertThat(user.getName(), is("测试终极大师"));

    // 6、del删除id为1的user
    request = delete("/users/1");
    result = mvc.perform(request)
    .andExpect(status().isOk())
    .andReturn();
    content = result.getResponse().getContentAsString();
    BaseResponse<String> response5 = JacksonUtil.json2Bean(content, new TypeReference<BaseResponse<String>>() {});
    assertThat(response5.isSuccess(), is(true));
    assertThat(response5.getMsg(), is("删除成功"));

    // 7、get查一下user列表,应该为空
    request = get("/users/");
    result = mvc.perform(request)
    .andExpect(status().isOk())
    .andReturn();
    content = result.getResponse().getContentAsString();
    BaseResponse<List<User>> response6 = JacksonUtil.json2Bean(content, new TypeReference<BaseResponse<List<User>>>() {});
    assertThat(response6.isSuccess(), is(true));
    assertThat(response6.getMsg(), is("查询列表成功"));
    assertThat((response6.getData()).size(), is(0));
    }

    }
  • 相关阅读:
    互联网协议入门
    C++解决约瑟夫环(史上最清晰)
    C# 最快的逐一打印斐波那契结果数列的算法
    二叉树的遍历(转载)
    C# 多线程join的用法,等待多个子线程结束后再执行主线程
    剖丁解牛式的快速排序分析
    用CTE结合排名函数rank()删除某列值重复的记录
    Http 头部属性详解
    C# 冒泡排序
    设计模式七大原则之依赖倒转原则
  • 原文地址:https://www.cnblogs.com/xiaohuizhenyoucai/p/14447215.html
Copyright © 2011-2022 走看看