要用 Web 層包裝存儲庫,必須使用 Spring MVC。多虧了 Spring Boot,幾乎沒有基礎代碼可以編寫。相反,我們可以專注於操作:
nonrest/src/main/java/payroll/EmployeeController.java
package payroll;
import java.util.List;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
@RestController
class EmployeeController {
private final EmployeeRepository repository;
EmployeeController(EmployeeRepository repository) {
this.repository = repository;
}
// Aggregate root
@GetMapping("/employees")
List<Employee> all() {
return repository.findAll();
}
@PostMapping("/employees")
Employee newEmployee(@RequestBody Employee newEmployee) {
return repository.save(newEmployee);
}
// Single item
@GetMapping("/employees/{id}")
Employee one(@PathVariable Long id) {
return repository.findById(id)
.orElseThrow(() -> new EmployeeNotFoundException(id));
}
@PutMapping("/employees/{id}")
Employee replaceEmployee(@RequestBody Employee newEmployee, @PathVariable Long id) {
return repository.findById(id)
.map(employee -> {
employee.setName(newEmployee.getName());
employee.setRole(newEmployee.getRole());
return repository.save(employee);
})
.orElseGet(() -> {
newEmployee.setId(id);
return repository.save(newEmployee);
});
}
@DeleteMapping("/employees/{id}")
void deleteEmployee(@PathVariable Long id) {
repository.deleteById(id);
}
}
@RestController
表示每個方法返回的數據將直接寫入響應主體,而不是呈現模版;EmployeeRepository
由構造函數注入到控制器中;- 我們爲每個操作提供路由(
@GetMapping
、@PostMapping
、@PutMapping
和@DeleteMapping
,對應於 HTTP 的GET
、POST
、PUT
和DELETE
調用)。(注意:閱讀每種方法並瞭解他它們的作用非常有用。); EmployeeNotFoundException
是一個異常,用於指示何時查找員工但找不到員工。
nonrest/src/main/java/payroll/EmployeeNotFoundException.java
package payroll;
class EmployeeNotFoundException extends RuntimeException {
EmployeeNotFoundException(Long id) {
super("Could not find employee " + id);
}
}
當拋出 EmployeeNotFoundException
時,Spring MVC 配置的這個額外花絮用於呈現 HTTP 404:
nonrest/src/main/java/payroll/EmployeeNotFoundAdvice.java
package payroll;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
@ControllerAdvice
class EmployeeNotFoundAdvice {
@ResponseBody
@ExceptionHandler(EmployeeNotFoundException.class)
@ResponseStatus(HttpStatus.NOT_FOUND)
String employeeNotFoundHandler(EmployeeNotFoundException ex) {
return ex.getMessage();
}
}
@ResponseBody
表示該建議直接呈現到響應主體中;@ExceptionHandler
將建議配置爲僅在拋出EmployeeNotFoundException
時才響應;@ResponseStatus
說要發出HttpStatus.NOT_FOUND
,即 HTTP 404;- 建議的主題生成內容。在這種情況下,它會給出異常消息。
要啓動要用,請右鍵單機 PayRollApplication
中的 public static void main
,然後從 IDE 中選擇 Run,或者:
Spring Initializr 使用 Maven 包裝器,因此鍵入:
$ ./mvnw clean spring-boot:run
或者使用我們安裝的 Maven 版本鍵入以下命令:
$ mvn clean spring-boot:run
應用啓動後,我們可以立即對其進行查詢。
$ curl -v localhost:8080/employees
這將產生:
* Trying ::1...
* TCP_NODELAY set
* Connected to localhost (::1) port 8080 (#0)
> GET /employees HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.54.0
> Accept: */*
>
< HTTP/1.1 200
< Content-Type: application/json;charset=UTF-8
< Transfer-Encoding: chunked
< Date: Thu, 09 Aug 2018 17:58:00 GMT
<
* Connection #0 to host localhost left intact
[{"id":1,"name":"Bilbo Baggins","role":"burglar"},{"id":2,"name":"Frodo Baggins","role":"thief"}]
在這裏,我們可以查看壓縮格式的預加載數據。
如果我們嘗試查詢一個不存在的用戶…
$ curl -v localhost:8080/employees/99
我們將得到:
* Trying ::1...
* TCP_NODELAY set
* Connected to localhost (::1) port 8080 (#0)
> GET /employees/99 HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.54.0
> Accept: */*
>
< HTTP/1.1 404
< Content-Type: text/plain;charset=UTF-8
< Content-Length: 26
< Date: Thu, 09 Aug 2018 18:00:56 GMT
<
* Connection #0 to host localhost left intact
Could not find employee 99
該消息很好地顯示了 HTTP 404 錯誤和自定義消息找不到僱員 99。
顯示當前編碼的交互並不困難…
$ curl -X POST localhost:8080/employees -H 'Content-type:application/json' -d '{"name": "Samwise Gamgee", "role": "gardener"}'
創建一個新的 Employee
記錄,然後將內容發送回給我們:
{"id":3,"name":"Samwise Gamgee","role":"gardener"}
我們可以更改用戶:
$ curl -X PUT localhost:8080/employees/3 -H 'Content-type:application/json' -d '{"name": "Samwise Gamgee", "role": "ring bearer"}'
更新用戶:
{"id":3,"name":"Samwise Gamgee","role":"ring bearer"}
根據我們構建服務的方式,可能會產生重大影響。在這種情況下,替換比更新更好。例如,如果未提供名稱,則將其晴空。
我們可以刪除…
$ curl -X DELETE localhost:8080/employees/3
$ curl localhost:8080/employees/3
Could not find employee 3
這一切都很好,但是我們由 RESTful 服務嗎?(如果我們沒有受到提示,則答案爲否。)
缺少了什麼?