(6) Web Starter開發API - Controller
本篇內容的程式碼於 Spring_4_UsingWebStarter
在上一篇文章內已經可以順利的執行一個 Spring Boot 的專案,現在我們要使用 spring-boot-starter-web 這個 Starter 開始建立後端API。
spring-boot-starter-web
Web Starter 的主要目的在於搭建一個 Web 的系統,其中包含:
- RESTful API
- Spring MVC (捨棄那些繁瑣的 xml 配置以自動配置取代)
- 內建預設的 Tomcat 容器 (可以直接執行服務而不需使用其他容器)
為了使用 web starter,因此必須於 pom.xml 內加入相關的 dependency,而因為先前已經繼承過 spring-boot-starter-parent,所以不加上版號資訊也沒有關係:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
同時,在 Web Starter 中就已經有包含幾個 dependency:
- spring-boot-starter
- jackson
- spring-core
- spring-mvc
- spring-boot-starter-tomcat
因此在上一篇文章中,一開始加入的 spring-boot-starter 的 dependency 就可以移除。
Spring MVC
雖然 Spring Boot 已經將 Spring MVC 優化為自動配置,不過在開始之前,還是需要對 Spring MVC 具備一些基本的概念。
- M,Model,對傳遞的數據進行封裝
- V,View,生成呈現資料相關的頁面給客戶端
- C,Controller,處理Request並回傳相關頁面或數據給客戶端
在早期開發 Java Web,通常 View 的部分是使用 jsp 來進行頁面的開發,但在前後端分離的時代,View 的部分已經漸漸的被 html、css、javascript 或者三大框架 Angular、React、Vue 取代。
對於後端來說,View 的部分就相對地不著墨許多(不過還是有其他板模可以提供View,例如 Thymeleaf ),更多的注意力就專注於開發API、處理邏輯層面、造訪資料庫等等相關的業務邏輯處理。
- Controller:API的部分,也就是處理 Request 的部分
- Service:處理業務邏輯的部分
- Repository:造訪資料庫,對資料庫進行取得資料等相關動作
- Model:與資料庫交換資料時對資料的封裝層
在 Spring MVC 的框架中,是可以使用「標註 (Annotation)」的方式配置這些內容,因此接著就來認識這些 Annotation 的使用方式與相關內容吧!
Controller 的建立
Controller 是處理 API 接口的部分,因此有一些 Annotation 來專門標記哪些 class 是作為API接口的類別。
常見的有以下幾種:
- @Controller:可以透過一些板模(Ex: Thymeleaf)回傳一個頁面,或者組合使用 @ResponseBody 的標記來回傳資料(RESTful API)。
- @RestController:同等於 @Controller + @ResponseBody 的組合
而若開發 RESTful API 時,必須指定每個 API 的方法與路徑,比較常見的方法有 GET、POST、PUT、DELETE 等 RESTful 的方法。對應的 Annotation 如下:
- @GetMapping()
- @PostMapping()
- @PutMapping()
- @DeleteMapping()
如果想要自訂或修改 Request URL 的請求路徑,則可以透過 @RequestMapping() 來指定請求的映射路徑。
例如要開發一個取得列表的 RESTful API:
@Controller
@RequestMapping("/api")
public class Controller {
@ResponseBody
@GetMapping("/items")
public List<Object> getItems() { ... };
}
同等於:
@RestController
@RequestMapping("/api")
public class Controller {
@GetMapping("/items")
public List<Object> getItems() { ... };
}
那麼你就可以透過如下 URL 取得 Items 的列表:
http://{ip}:{port}/api/items
API 的傳入參數
當使用 API 時勢必得可以傳入參數,可是傳入參數的方法有好幾種情況,因此接著來繼續介紹比較常用傳入參數的方法有哪些。
1. 將參數放在 URL 後面
[GET] http://.../items?id=12&name=apple
像這種情況,在開發 API 時就可以這樣寫:
@GetMapping("/items")
public void getItems(Long id, String name) {...}
不過在這種情形下,URL 後面不一定要加上參數也可以使用 API,只是在function中所傳入的參數會是null。
如果要使某一項參數為「必要參數」,則可以透過 @RequestParam 標註,指定哪些參數為必要參數:
@GetMapping("/items")
public void getItems(@RequestParam Long id, String name) {...}
如此,若在 URL 中沒有加上指定參數時,則會回傳 400 Bad Request。
2. 將參數放在 URL 裡面
[GET] http://.../items/12/apple
像這種情況,在開發 API 時就可以這樣寫:
@GetMapping("/items/{id}/{name}")
public void getItems(
@PathVariable Long id,
@PathVariable String name
) {...}
這裡就是將變數帶入 URL 的路徑上,並且透過 @PathVariable 指定參數的位置與名稱。
3. 將參數放在 Body 裡面
[GET] http://.../items
[BODY]
{
"id":12,
"name":"apple"
}
如果要將參數放在 Body 中,最常用的方式就是使用 JSON 的格式來傳送資料。像這種情況,在開發 API 時就可以這樣寫:
@GetMapping("/items")
public void getItems(@RequestBody Item item) {
item.getId();
item.getName();
...
}
也就是透過 @RequestBody 來傳入一個固定格式的內容,通常用這種方式是已經在後端將傳入的資料定義好,並以 POJO 的方式定義之。
4. HttpServletRequest 取得參數
也可以使用原本 Servlet 的方法來取得參數,例如:
public void getItems(HttpServletRequest request) {
String param = request.getParameter("param");
String[] values = request.getParameterValues("param");
}
更多使用 HttpServletRequest 的方法可以參考如下網址:
https://docs.oracle.com/javaee/6/api/javax/servlet/ServletRequest.html
API 的回傳結果
大部分呼叫 API,期望就是可以得到資料的回覆,因此接著就來看看有那些比較常見的回傳結果的方法吧!
1. 什麼都不回傳
@GetMapping("/items")
public void getItems(Long id) { ... }
2. 直接設定回傳的資料型別
@GetMapping("/items")
public Integer getItems(Long id) {
Integer result;
...
return result;
}
或者你要回傳一個物件:
@GetMapping("/items")
public Item getItems(@RequestBody Item item) {
item.setName("banana");
return item;
}
3. 使用 ResponseEntity 封裝
這是 Spring 提供的一個對於 Response 的封裝,允許我們設定 HTTP 的 Response Code、Response Header、Response Body。
他有兩種實作方式,一種是 new ResponseEntity 物件:
@GetMapping("/items")
public ResponseEntity<Item> getItems(@RequestBody Item item) {
item.setName("banana");
return new ResponseEntity<>(item, HttpStatus.OK);
}@GetMapping("/items")
public ResponseEntity<Item> getItems(@RequestBody Item item) {
item.setName("banana");
HttpHeaders headers = new HttpHeaders();
headers.add("total-item-count", "20");
return new ResponseEntity<>(item, headers, HttpStatus.OK);
}
另一種是直接使用 ResponseEntity 的 static 靜態方法:
@GetMapping("/items")
public ResponseEntity<Item> getItems(@RequestBody Item item) {
item.setName("banana");
return ResponseEntity.status(HttpStatus.OK).body(item);
}@GetMapping("/items")
public ResponseEntity<Item> getItems(@RequestBody Item item) {
item.setName("banana");
return ResponseEntity
.status(HttpStatus.OK)
.header("total-item-count", "20")
.body(item);
}
4. HttpServletResponse 回傳結果
這也是原本 Servlet 在處理 Response 的常用方法,他一樣可以設定 Response 的 Header、Status、Body。例如:
@GetMapping("/items")
public void getItems(
HttpServletResponse response,
@RequestBody Item item
) {
item.setName("banana");
response.setStatus(HttpServletResponse.SC_OK);
response.setContentType("application/json;charset=UTF-8");
response.setHeader("total-item-count", "20");
response.getWriter().print(item.toString());
}
更多說明可以參考如下網址:
https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/http/ResponseEntity.htmlhttps://tomcat.apache.org/tomcat-5.5-doc/servletapi/javax/servlet/http/HttpServletResponse.htmlhttps://www.baeldung.com/spring-response-entity
實際練習
你可以在 這裡 找到我已經事先建立好的專案,這裡的資料夾結構會以如下方式建立:
management-system
\---src
\---main
\---java
\---com
\---albert
\---management
| ManagementApplication.java
|
+---controller
| ProductController.java
|
\---dto
ProductDTO.java
- Controller 的資料夾底下是存放 Request Mapping 類的 java 檔
- dto 的資料夾底下是存放資料在傳遞時所封裝的 POJO 類的 java 檔
在這裡我定義了一個 ProductDTO.java 以作為「Product資訊」的數據封裝,其包含幾個參數:
private Long id; // 產品的ID
private String name; // 產品的名稱
private Integer remain; // 產品的剩餘數量
而 ProductController.java 是對於 Product 的 Request Mapping 類別,也就是開發 API 接口的部分。在這部分中,實作了上述 API 參數的輸入以及數據的輸出的一些應用。
如果你將這個專案下載下來後,你就可以在 management-system 資料夾的位置,透過 cmd 執行專案:
$ .\mvnw clean spring-boot:run
測試 API
當我們在開發 API 的時候,我們會需要測試 API 的行為,以方便開發與驗證 API 的正確性。目前測試 API 最常用的工具就是 Postman。
例如在這裡所建立的專案中,其中有兩隻API,可以依照圖片中的方式進行測試:
- [GET] http://localhost:8080/products/list1
- [POST] http://localhost:8080/products/create
文末
這篇文章一開始先介紹了 Spring MVC 的基本架構,並介紹了一些 Controller 的使用說明,其他例如 Service、Repository 的部分會在之後的文章再繼續說明。
最後我們使用 Postman 來協助開發 API,不過也許你覺得要安裝 Postman 很麻煩,或者覺得還要透過 Postman 來協助開發很討厭。
所以在下一篇文章中會介紹一個開發 API 的輔助神器,Swagger,那麼就接著看下去吧!