003.springboot web篇:快速构建较复杂的RESTful API与单元测试

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/sld880311/article/details/79460904

说明

通过实现订单的增删改查,初步了解web相关的构建和使用

REStful API规划

请求类型 URL 说明
GET /orders 查询所有订单
POST /orders/add 创建一个订单
GET /orders/id 查询一个订单
POST /orders/update/id 更新订单
DELETE /orders/delete/id 删除订单

常用注解说明

  1. @Controller:修饰class,用来创建处理http请求的对象
  2. @RestController:Spring4之后加入的注解,原来在@Controller中返回json需要@ResponseBody来配合,如果直接用@RestController替代@Controller就不需要再配置@ResponseBody,默认返回json格式。
  3. @RequestMapping:配置url映射
  4. @PathVariable:通过 @PathVariable 可以将 URL 中占位符参数绑定到控制器处理方法的入参中:URL 中的 {xxx} 占位符可以通过@PathVariable(“xxx“) 绑定到操作方法的入参中。
  5. @ModelAttribute:
    ①绑定请求参数到命令对象:放在功能处理方法的入参上时,用于将多个请求参数绑定到一个命令对象,从而简化绑定流程,而且自动暴露为模型数据用于视图页面展示时使用;
    ②暴露表单引用对象为模型数据:放在处理器的一般方法(非功能处理方法)上时,是为表单准备要展示的表单引用对象,如注册时需要选择的所在城市等,而且在执行功能处理方法(@RequestMapping注解的方法)之前,自动添加到模型对象中,用于视图页面展示时使用;
    ③暴露@RequestMapping方法返回值为模型数据:放在功能处理方法的返回值上时,是暴露功能处理方法的返回值为模型数据,用于视图页面展示时使用。
  6. @RequestParam:获取url中的参数,用于将请求参数区数据映射到功能处理方法的参数上。

代码参考

实体类order

package com.sunld.domain;

public class Order {

    /**
     * 订单id
     */
    private Integer id;
    /**
     * 订单名称
     */
    private String orderName;
    /**
     * 订单类型
     */
    private String orderType;

    /**
     * get、set方法
     */
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getOrderName() {
        return orderName;
    }
    public void setOrderName(String orderName) {
        this.orderName = orderName;
    }
    public String getOrderType() {
        return orderType;
    }
    public void setOrderType(String orderType) {
        this.orderType = orderType;
    }
    @Override
    public String toString() {
        return "Order [id=" + id + ", orderName=" + orderName + ", orderType=" + orderType + "]";
    }
}

Controller:OrderController

package com.sunld;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import com.sunld.domain.Order;

@RestController
//定义统一的入口,通过这里配置使下面的映射都在/orders下
@RequestMapping("/orders")
public class OrderController {

    //定义线程安全的map用来存储订单信息
    private static final Map<Integer , Order> staticOrderMap = 
            Collections.synchronizedMap(new HashMap<Integer, Order>());

    /**
     * 查询所有订单
     * url地址:http://127.0.0.1:8080/orders/
     * 还可以通过@RequestParam从页面中传递参数来进行查询条件或者翻页信息的传递
     * @return
     */
    @RequestMapping(value = "/" , method = RequestMethod.GET)
    public List<Order> getOrders(){
        List<Order> orderList = new ArrayList<Order>(staticOrderMap.values());
        return orderList;
    }

    /**
     * 添加订单
     * url地址:http://127.0.0.1:8080/orders/add
     * @ModelAttribute:用来接收form中的订单信息
     * 除了@ModelAttribute绑定参数之外,还可以通过@RequestParam从页面中传递参数
     * @param order
     * @return
     */
    @RequestMapping(value = "/add", method = RequestMethod.POST)
    public String addOrder(@ModelAttribute Order order) {
        if(order != null) {
            staticOrderMap.put(order.getId(), order);
            return "success";
        }
        return "failure";
    }

    /**
     * 根据订单id获取订单信息
     * url地址:http://127.0.0.1:8080/orders/1234
     * url中的id可通过@PathVariable绑定到函数的参数中
     * @return
     */
    @RequestMapping(value = "/{id}" , method = RequestMethod.GET)
    public Order getOrderById(@PathVariable Integer id) {
        return staticOrderMap.get(id);
    }
    /**
     * 根据订单id更新订单信息
     * url地址:http://127.0.0.1:8080/orders/update/1234
     * @param id
     * @param order
     * @return
     */
    @RequestMapping(value = "/update/{id}" , method = RequestMethod.POST)
    public String updateOrderById(@PathVariable Integer id, @ModelAttribute Order order) {
        Order o = staticOrderMap.get(id);
        if(o != null && order != null) {
            o.setOrderName(order.getOrderName());
            o.setOrderType(order.getOrderType());
            staticOrderMap.put(id, o);
            return "success";
        }else {
            return "failure";
        }
    }
    /**
     * 根据订单ID删除订单信息
     * url地址:http://127.0.0.1:8080/orders/delete/1234
     * @param id
     * @return
     */
    @RequestMapping(value="/delete/{id}", method=RequestMethod.DELETE) 
    public String deleteOrderById(@PathVariable Integer id) { 
        staticOrderMap.remove(id); 
        return "success"; 
    } 
}

测试类:OrderControllerTest

package com.sunld.controller;

import static org.hamcrest.CoreMatchers.equalTo;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.ResultActions;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.result.MockMvcResultHandlers;
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;

import com.sunld.OrderController;

@RunWith(SpringRunner.class)
@SpringBootTest
public class OrderControllerTest {
    private MockMvc mvc; 

    @Before 
    public void setUp() throws Exception { 
        mvc = MockMvcBuilders.standaloneSetup(new OrderController()).build(); 
    } 

    @Test
    public void testOrderController() throws Exception {
        //1.创建查询所有订单,结果返回为空
        System.out.println("=====================初次查询所有订单信息start=====================");
        getOrders()
           .andExpect(MockMvcResultMatchers.content().string(equalTo("[]")))
           .andReturn();
        System.out.println("=====================初次查询所有订单信息end=======================");
        System.out.println("=====================第一次添加订单start=========================");
        // 2、post提交一个订单
        mvc.perform(MockMvcRequestBuilders.post("/orders/add")
                        .param("id", "1234")
                        .param("orderName", "购买平板电脑")
                        .param("orderType", "在线付款")
                        .accept(MediaType.APPLICATION_JSON))
            .andExpect(MockMvcResultMatchers.status().isOk())
            .andDo(MockMvcResultHandlers.print())
            .andExpect(MockMvcResultMatchers.content().string(equalTo("success")))
            .andReturn();
        //2.1、查询所有订单
        /**
         * 结果应该为"[{\"id\":1234,\"orderName\":\"购买平板电脑\",\"orderType\":\"在线付款\"}]"
         */
        getOrders()
           .andExpect(MockMvcResultMatchers.content().string(equalTo("[{\"id\":1234,\"orderName\":\"购买平板电脑\",\"orderType\":\"在线付款\"}]")))
           .andReturn();
        System.out.println("=====================第一次添加订单end===========================");
        System.out.println("=====================再次添加订单start===========================");
        //3、再添加一个订单
        mvc.perform(MockMvcRequestBuilders.post("/orders/add")
                .param("id", "3456")
                .param("orderName", "购买奶粉")
                .param("orderType", "货到付款")
                .accept(MediaType.APPLICATION_JSON))
           .andExpect(MockMvcResultMatchers.status().isOk())
           .andDo(MockMvcResultHandlers.print())
           .andExpect(MockMvcResultMatchers.content().string(equalTo("success")))
           .andReturn();
        //3.1、查看所有订单信息
        /**
         * 订单信息:
         * [{"id":3456,"orderName":"购买奶粉","orderType":"货到付款"},{"id":1234,"orderName":"购买平板电脑","orderType":"在线付款"}]
         */
        getOrders();
        System.out.println("=====================再次添加订单end=============================");
        System.out.println("=====================修改存在编号的订单start============================");
        //4、修改编号为1234的订单:该订单存在
        mvc.perform(MockMvcRequestBuilders.post("/orders/update/1234")
                .param("orderName", "订单名称由【购买平板电脑】修改为【再次购买平板电脑】")
                .param("orderType", "在线付款")
                .accept(MediaType.APPLICATION_JSON))
           .andExpect(MockMvcResultMatchers.status().isOk())
           .andDo(MockMvcResultHandlers.print())
           .andReturn();
        //4.1查询订单1234
        getOrdersById("1234");
        System.out.println("=====================修改存在编号的订单end==============================");
        System.out.println("=====================修改订单编号不存在的订单start==============================");
        //5、修改编号为1的订单、该订单不存在,直接返回failure
        mvc.perform(MockMvcRequestBuilders.post("/orders/update/1")
                .param("orderName", "订单名称由【购买平板电脑】修改为【再次购买平板电脑】")
                .param("orderType", "在线付款")
                .accept(MediaType.APPLICATION_JSON))
           .andExpect(MockMvcResultMatchers.status().isOk())
           .andDo(MockMvcResultHandlers.print())
           .andExpect(MockMvcResultMatchers.content().string(equalTo("failure")))
           .andReturn();
        System.out.println("=====================修改订单编号不存在的订单end==============================");
        //6、删除订单1234
        mvc.perform(MockMvcRequestBuilders.delete("/orders/delete/1234").accept(MediaType.APPLICATION_JSON))
           .andExpect(MockMvcResultMatchers.status().isOk())
           .andDo(MockMvcResultHandlers.print())
           .andExpect(MockMvcResultMatchers.content().string(equalTo("success")))
           .andReturn();
        //61查看所有订单
        getOrders();
    }

    private ResultActions getOrders() throws Exception {
        return mvc.perform(MockMvcRequestBuilders.get("/orders/").accept(MediaType.APPLICATION_JSON))
                  .andExpect(MockMvcResultMatchers.status().isOk())
                  .andDo(MockMvcResultHandlers.print());
//                .andReturn();
    }

    private ResultActions getOrdersById(String id) throws Exception {
        return mvc.perform(MockMvcRequestBuilders.get("/orders/" + id).accept(MediaType.APPLICATION_JSON))
                  .andExpect(MockMvcResultMatchers.status().isOk())
                  .andDo(MockMvcResultHandlers.print());
//                .andReturn();
    }
}

总结

参考

spring学习之@ModelAttribute运用详解
@RequestParam详解
Spring Boot构建RESTful API与单元测试

代码

https://github.com/sld880311/springboot-learning/tree/master/springboot_simpleweb

猜你喜欢

转载自blog.csdn.net/sld880311/article/details/79460904