1. 程式人生 > >003.springboot web篇:快速構建較複雜的RESTful API與單元測試

003.springboot web篇:快速構建較複雜的RESTful API與單元測試

說明

通過實現訂單的增刪改查,初步瞭解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();
    }
}

總結

參考

程式碼

相關推薦

003.springboot web快速構建複雜RESTful API單元測試

說明 通過實現訂單的增刪改查,初步瞭解web相關的構建和使用 REStful API規劃 請求型別 URL 說明 GET /orders

Spring Boot 入門 (二) Spring Boot構建RESTful API單元測試

http://blog.didispace.com/springbootrestfulapi/ 首先,回顧並詳細說明一下在快速入門中使用的@Controller、@RestController、@RequestMapping註解。如果您對Spring MVC不熟悉並且還沒有嘗試過快速入門案例,建

Spring Boot 2.x基礎教程構建RESTful API單元測試

首先,回顧並詳細說明一下在快速入門中使用的@Controller、@RestController、@RequestMapping註

Spring Boot構建RESTful API單元測試實戰

一 點睛 1 相關注解 @Controller:修飾class,用來建立處理http請求的物件 @RestController:Spring4之後加入的註解,原來在@Controller中返回json需要@ResponseBody來配合,如果直接用@

Spring Boot構建RESTful API單元測試

@Controller:修飾class,用來建立處理http請求的物件@RestController:Spring4之後加入的註解,原來在@Controller中返回json需要@ResponseBody來配合,如果直接用@RestController替代@Controlle

(轉)第十一springboot集成swagger2,構建優雅的Restful API

html 風格 lan round amt select() hash 指定 model   聲明:本部分內容均轉自於方誌明博友的博客,因為本人很喜歡他的博客,所以一直在學習,轉載僅是記錄和分享,若也有喜歡的人的話,可以去他的博客首頁看:http://blog.csdn.n

004.SpringBoot web靜態資源管理

預設靜態資源管理 在web開發中,靜態資源的訪問是必不可少的,如:圖片、js、css 等資源的訪問。spring Boot 對靜態資源訪問提供了很好的支援,基本使用預設配置就能滿足開發需求。 SpringBoot預設為我們提供了靜態資源處理,使用We

springboot集成swagger2,構建優雅的Restful API

測試 sele ase 我們 conf start orien ket 過程 swagger,中文“拽”的意思。它是一個功能強大的api框架,它的集成非常簡單,不僅提供了在線文檔的查閱,而且還提供了在線文檔的測試。另外swagger很容易構建restful風格的api,簡單

企業級 SpringBoot 教程 (十一)springboot集成swagger2,構建優雅的Restful API

group require pip 掃描 pan itl 信息 elm 框架 swagger,中文“拽”的意思。它是一個功能強大的api框架,它的集成非常簡單,不僅提供了在線文檔的查閱,而且還提供了在線文檔的測試。另外swagger很容易構建restful風格的api,簡單

JAVA springboot微服務b2b2c電子商務系統-springboot集成swagger2,構建優雅的Restful API(十一)

利用 swagger itl ecif b2b 測試 功能 mod rem swagger,中文“拽”的意思。它是一個功能強大的api框架,它的集成非常簡單,不僅提供了在線文檔的查閱,而且還提供了在線文檔的測試。另外swagger很容易構建restful風格的api,簡單優

springboot(基礎快速構建一個springboot專案

前言: springboot作為springcloud的基礎,學會springboot是必不可少的技能,所以這個系列教程一是記錄自己的學習過程,二是作為一份分享教程,幫助新手

SpringBoot第二web(基於Thymeleaf模板)

接著第一篇,繼續配置web專案。 1、在pom檔案中加入: <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-sta

一起來學SpringBoot | 第一構建第一個SpringBoot工程

文章目錄 1. 設計的目標 2. 前提 3. 建立專案 3.1. 目錄結果 3.2. pom.xml 依賴 3.3. 主函式入口 3.4. 初窺配置檔案 3.5. 測試 4. 拓展知識 4.1. 自定義Banner 5. 總結 6. 說點什麼

轉載SpringBoot非官方教程 | 第十一springboot整合swagger2,構建優雅的Restful API

swagger,中文“拽”的意思。它是一個功能強大的api框架,它的整合非常簡單,不僅提供了線上文件的查閱,而且還提供了線上文件的測試。另外swagger很容易構建restful風格的api,簡單優雅帥氣,正如它的名字。 一、引入依賴 <depend

SpringBoot2.X (三)快速構建SpringBoot 專案的兩種方式

上篇通過maven 專案手動構建的方式稍微有點麻煩,我們這裡有兩種快速構建的方式: 一、 通過 http://start.spring.io/ 線上構建 二、 通過IntelliJ IDEA 快速構建 let’s go ----> 選擇group,

SpringBoot第十五swagger構建優雅文件

作者:追夢1819 原文:https://www.cnblogs.com/yanfei1819/p/11007470.html 版權宣告:本文為博主原創文章,轉載請附上博文連結! 引言   前面的十四篇文介紹了 SpringBoot 的一些基本和常用的功能。後面,我們將介紹 SpringBoot 的高階的功

JAVAEE——SpringBoot日誌日誌框架SLF4j、日誌配置、日誌使用、切換日誌框架

<appender name="stdout" class="ch.qos.logback.core.ConsoleAppender"> <!-- 日誌輸出格式: %d表示日期時間, %thread表示執行緒名

自學Springboot第一快速入門)

SpringBoot的核心入口類和@SpringBootApplication Spring Boot的專案一般都會有*Application的入口類,入口類中會有main方法,這是一個標準的Java應用程式的入口方法。 @SpringBootApplication 註解

Spring Boot基礎教程 ( 一 ) 基礎專案構建,引入web模組,完成一個簡單的RESTful API

簡介 在您第1次接觸和學習Spring框架的時候,是否因為其繁雜的配置而退卻了?在你第n次使用Spring框架的時候,是否覺得一堆反覆黏貼的配置有一些厭煩?那麼您就不妨來試試使用Spring Boot來讓你更易上手,更簡單快捷地構建Spring應用! Spring Boot

一起來學SpringBoot | 第二SpringBoot配置詳解

文章目錄 自定義屬性配置 自定義檔案配置 多環境化配置 外部命令引導 總結 說點什麼 SpringBoot 是為了簡化 Spring 應用的建立、執行、除錯、部署等一系列問題而誕生的產物,自動裝配的特性讓我們可以更好的關注業務本身而不是外部的XML配