# [Spring Boot] 請求與回應
[TOC]
|註釋|用途|使用|
|-|-|-|
|@Controller|將 Class 變成由 Spring 容器所管理的 Bean (Object),並且可以在內部使用 @RequestMapping。需搭配@ResponseBody,才能返回 Json 格式|class|
|@RestController|將 Class 變成由 Spring 容器所管理的 Bean (Object),並且可以在內部使用 @RequestMapping。可以直接返回 Json 格式|class|
|@RequestMapping|需搭配 @Controller 或 @RestController,將 url 路徑對應到方法上|class、方法|
|@ResponseBody|需搭配@Controller,才能返回 Json 格式|方法|
|@RequestParam|取得 url 裡面的參數|方法上的參數|
|@PathVariable|取得 url 路徑的值|方法上的參數|
|@RequestBody|取得 request body 的參數|方法上的參數|
|@RequestHeader|取得 request header 的 header|方法上的參數|
|@GetMapping|將 url 路徑對應到方法上,並限制前端只能夠使用 GET,來請求這個 url 路徑|方法|
|@PostMapping|將 url 路徑對應到方法上,並限制前端只能夠使用 POST,來請求這個 url 路徑|方法|
|@PutMapping|將 url 路徑對應到方法上,並限制前端只能夠使用 PUT,來請求這個 url 路徑|方法|
|@Validated|若@PathVariable、@RequestParam、@RequestHeader的參數上想要使用驗證,須加上此註解|class|
|@Valid|若@RequestBody的參數想要使用驗證,須加上此註解|方法上的參數|
|@NotNull|表示該參數不能為 null|方法上的參數、參數|
|@NotBlank|表示該參數不能為 null、且不能為空白的字串|方法上的參數、參數|
|@NotEmpty|表示該參數不能為 null、且 size 必須 > 0 (使用於List、Set、Map)|方法上的參數、參數|
## @Controller 與 @RestController 差異
@Controller 需要搭配 @ResponseBody,該方法才會傳送JSON格式的資料給Client
```=Java
@Controller
public class myController(){
@ResponseBody
@RequestMapping("/index")
public String hello(){
return "hello world!";
}
//不會使用JSON格式傳送資料給Client
@RequestMapping("/index")
public String hello(){
return "hello world!";
}
}
```
@RestController 不須在方法上加@ResponseBody,即可傳送JSON格式的資料給Client
```=Java
@RestController
public class myController(){
@RequestMapping("/index")
public String hello(){
return "hello world!";
}
}
```
## 取得請求參數
### @RequestParam
* name 指定 url 參數的名字
* required 表示此參數是否是必須的參數
* defaultValue 提前設定好參數的預設值,如果 url 裡面沒有該參數的話,就使用這個預設值
### @PathVariable
若要取得路徑為 http://localhost:8080/test/123 內的123
```Java
@RestController
public class myController(){
@RequestMapping("/test/{user}")
public String test(@PathVariable String user){
//
}
}
```
:::warning
**@RequestParam 與 @PathVariable 的差異**
@RequestParam 將參數置於路徑後: http://localhost:8080/test?id=123
@PathVariable 將參數置於路徑之中: http://localhost:8080/test/123
:::
### @RequestBody
可以將 request body 裡面的 Json 格式的參數 ,轉為 Spring Boot 中 自定義的 Java class
```Java
@RestController
public class myController(){
@RequestMapping("/test")
public String test(@RequestBody List userlist){ //userlist是取得的Json資料
//
}
}
```
註: 直接通過瀏覽器輸入url獲取不到Json物件,需要用後端或者ajax的方法請求,將Content-Type設定為application/json
### @RequestHeader
* name 指定 header 內參數的名字
若 request header 內有 Content-Type: application/json (Content-Type 是用來表示 request body 的格式)
```Java
@RestController
public class myController(){
@RequestMapping("/test")
public String test(@RequestHeader(name="Content-Type") String contentType){
//
}
}
```
* required 表示此 header 是否是必須的 header
* defaultValue 提前設定好 header 的預設值,如果 request header 裡面沒有該 header 的話,就使用這個預設值
## RESTful API
當你所設計的 API 符合 REST 風格時,你所設計的 API 就可以稱為是 RESTful API
RESTful API 主要包含三大條件
1. **使用 http method 表示動作**
http method 會對應到資料庫的 CRUD 操作
* GET-->Read
* POST-->Create
* PUT-->Update
* DELETE-->Delete
2. **使用 url 路徑描述資源之間的階層關係**,比如
* GET /users--> 取得所有 user
* GET /users/123--> 取得 user id 為 123 的 user
3. **response body 返回 json 或是 xml 格式**
註: GET 會將參數放在 url 的最後面來傳遞,POST 會將參數放在 request body 裡面來傳遞
## 驗證請求參數
### @Validated
若想要在加上「@PathVariable、@RequestParam、@RequestHeader」的參數上,使用 @NotNull... 這類的驗證請求參數的註解的話,則需要在這個 Class 上加上 @Validated
```Java
@RestController
@Validated
public class UserController {
@GetMapping("/users/{userId}")
public String read(@PathVariable @Min(100) Integer userId){
return "檢視使用者";
}
}
```
### @Valid
若想要在加上「@RequestBody」的 student 參數裡面,使用 @NotNull... 這類的驗證請求參數的註解的話,則需要在 User 參數前面加上 @Valid
```Java
@PostMapping("/users")
public String cearte(@RequestBody @Valid User user){
return "新增使用者";
}
```
以下是有使用驗證的Bean
```Java
public class User{
@NotNull
Integer id;
@NotBlank
String name;
//getter、setter
}
```
### 自定義回傳的 Http Response 狀態碼
可使用 `ResponseEntity<?>` 此方法返回 Http status 類型
```=Java!
@RequestMapping("/test")
public ResponseEntity<String> test(){
return ResponseEntity.status(HttpStatus.ACCEPTED);
}
```
## [補充] @Validated 無效
> 環境:
> spring boot 2.7.6 + apache maven
在Controller內的參數使用 @Min 及 @Max 沒有效果
```=java!
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
@GetMapping(value = "/{type}/products")
public ResponseEntity<ApiResponse<List<product>>> types(
@PathVariable @Min(1) @Max(10) int type
) {
List<product> result = productService.getAllByType(type);
var response = new ApiResponse<>(SUCCESS, message, result);
return ResponseEntity.ok().body(response);
}
```
原以為 validated 會包在 spring-boot-web 內,查詢後發現要另外引入 spring-boot-validated
> maven central repository
> https://central.sonatype.com/artifact/org.springframework.boot/spring-boot-starter-validation/2.7.6/overview
最後依專案選用 apache maven 2.7.6 的版本,在 pom.xml 加入下列程式碼即可使用 spring validated
```=xml!
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
<version>2.7.6</version>
</dependency>
```
## [補充] Json
全稱為 JavaScript Object Notation,是一種檔案格式,可將資料結構化,用於網頁呈現或傳輸數據。格式包含一個 key + 一個 value,key必須使用雙引號 `""` 包覆,value的值則有以下資料類型
* 整數
* 浮點數
* 字串
* Boolean
* 其他物件(如陣列)
---
參考資料
* [使用 JSON 資料](https://developer.mozilla.org/zh-TW/docs/Learn/JavaScript/Objects/JSON)
* [Day 6 Spring Boot -Controller(上)](https://ithelp.ithome.com.tw/articles/10193631)
* [17. Web MVC framework](https://docs.spring.io/spring-framework/docs/3.2.x/spring-framework-reference/html/mvc.html)