?<前文回顧>
<今日更新>
一、開篇整活兒
咱今兒個嘮嘮 Spring Boot 里頭咋整 RESTful API。這玩意兒吧,說難不難,說簡單也不簡單,整好了是 API,整不好就是 AP(挨批)。你要是剛入門,那可得悠著點兒,別一上來就整得自己“骨折”了。
二、Spring MVC 和 RESTful API 是啥關系?
Spring MVC 是 Spring 里頭用來搞 Web 開發的框架,RESTful API 呢,就是一種設計風格,講究用 HTTP 協議里頭的 GET、POST、PUT、DELETE 這些方法來操作資源。Spring MVC 里頭有個叫?@Controller?的注解,專門用來處理 HTTP 請求,跟 RESTful API 那是天造地設的一對兒。
1. Controller 是咋回事?
Controller 就是 Spring MVC 里頭的一個組件,專門負責處理請求和返回響應。你可以把它想象成一個“接線員”,客戶端的請求來了,它得接電話,然后根據請求的內容,決定該干啥。
Java Code |
@RestController @RequestMapping("/api") public class MyController { ????@GetMapping("/hello") ????public String sayHello() { ????????return "Hello, World!"; ????} } |
這段代碼里頭,@RestController?是?@Controller?和?@ResponseBody?的結合體,意思就是這個類里頭的方法返回的都是直接寫給客戶端的數據,不用再整啥視圖解析了。@RequestMapping?是用來映射 URL 的,/api?就是根路徑,/hello?就是子路徑。
2. RESTful 風格的 URL 設計
RESTful 風格的 URL 講究的是“資源”和“操作”。比如說,你要操作一個用戶資源,那 URL 就得設計成?/users,然后根據不同的 HTTP 方法來做不同的操作:
- GET?/users:獲取所有用戶
- GET?/users/{id}:獲取某個用戶
- POST?/users:創建一個用戶
- PUT?/users/{id}:更新某個用戶
- DELETE?/users/{id}:刪除某個用戶
Java Code |
@RestController @RequestMapping("/users") public class UserController { ????@GetMapping ????public List<User> getUsers() { ????????// 返回所有用戶 ????} ????@GetMapping("/{id}") ????public User getUser(@PathVariable Long id) { ????????// 返回某個用戶 ????} ????@PostMapping ????public User createUser(@RequestBody User user) { ????????// 創建用戶 ????} ????@PutMapping("/{id}") ????public User updateUser(@PathVariable Long id, @RequestBody User user) { ????????// 更新用戶 ????} ????@DeleteMapping("/{id}") ????public void deleteUser(@PathVariable Long id) { ????????// 刪除用戶 ????} } |
這段代碼里頭,@PathVariable?是用來從 URL 里頭提取參數的,@RequestBody?是用來接收客戶端傳過來的 JSON 數據的。
三、Filter 是咋過濾 RESTful 請求的?
Filter 是 Java Web 開發里頭的一個玩意兒,用來在請求到達 Controller 之前或者響應返回客戶端之前,做一些預處理或者后處理。比如說,你可以用 Filter 來過濾掉一些不合法的請求,或者給請求加上一些額外的信息。
1. 實現一個簡單的 Filter
Java Code |
@Component public class MyFilter implements Filter { ????@Override ????public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) ????????????throws IOException, ServletException { ????????HttpServletRequest httpRequest = (HttpServletRequest) request; ????????String method = httpRequest.getMethod(); ????????if ("GET".equals(method)) { ????????????// 處理 GET 請求 ????????} else if ("POST".equals(method)) { ????????????// 處理 POST 請求 ????????} ????????chain.doFilter(request, response); ????} } |
這段代碼里頭,doFilter?方法是 Filter 的核心方法,所有的請求都會經過這個方法。chain.doFilter?是讓請求繼續往下走,如果不調用這個方法,那請求就被攔截了。
2. Filter 的應用場景
Filter 可以用來干很多事兒,比如說:
- 權限校驗:看看用戶有沒有權限訪問某個資源
- 日志記錄:記錄每個請求的詳細信息
- 請求參數處理:對請求參數做一些預處理,比如說去掉空格啥的
Java Code |
@Component public class AuthFilter implements Filter { ????@Override ????public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) ????????????throws IOException, ServletException { ????????HttpServletRequest httpRequest = (HttpServletRequest) request; ????????String token = httpRequest.getHeader("Authorization"); ????????if (token == null || !isValidToken(token)) { ????????????HttpServletResponse httpResponse = (HttpServletResponse) response; ????????????httpResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED); ????????????return; ????????} ????????chain.doFilter(request, response); ????} ????private boolean isValidToken(String token) { ????????// 校驗 token 是否有效 ????????return true; ????} } |
這段代碼里頭,AuthFilter?是用來做權限校驗的,如果請求里頭沒有帶?Authorization?頭,或者 token 無效,那就返回 401 狀態碼,表示未授權。
四、Spring Boot 里頭的 RESTful API 設計小技巧
1. 使用?@ExceptionHandler?處理異常
RESTful API 里頭,異常處理是個大事兒。Spring Boot 里頭有個?@ExceptionHandler?注解,專門用來處理 Controller 里頭的異常。
Java Code |
@RestControllerAdvice public class GlobalExceptionHandler { ????@ExceptionHandler(Exception.class) ????public ResponseEntity<String> handleException(Exception e) { ????????return new ResponseEntity<>("出錯了:" + e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR); ????} } |
這段代碼里頭,@RestControllerAdvice?是用來定義一個全局的異常處理類,@ExceptionHandler?是用來處理特定類型的異常的。ResponseEntity?是用來返回 HTTP 響應的,里頭可以帶上狀態碼和響應體。
2. 使用?@Valid?做參數校驗
RESTful API 里頭,參數校驗也是個大事兒。Spring Boot 里頭有個?@Valid?注解,專門用來做參數校驗。
Java Code |
@PostMapping("/users") public User createUser(@Valid @RequestBody User user) { ????// 創建用戶 } |
這段代碼里頭,@Valid?是用來校驗?User?對象的,如果?User?對象里頭的字段不符合要求,那就會拋出?MethodArgumentNotValidException?異常。
3. 使用?@ConfigurationProperties?做配置綁定
Spring Boot 里頭有個?@ConfigurationProperties?注解,專門用來把配置文件里頭的屬性綁定到 Java 對象里頭。
Java Code |
@ConfigurationProperties(prefix = "myapp") public class MyAppProperties { ????private String name; ????private String version; ????// getters and setters } |
這段代碼里頭,@ConfigurationProperties?是用來把?application.properties?里頭以?myapp?開頭的屬性綁定到?MyAppProperties?對象里頭的。
五、Spring Boot 里頭的 RESTful API 設計坑點
1. 路徑沖突
Spring Boot 里頭,路徑設計得不好,就容易出現沖突。比如說,你有兩個方法,一個映射到?/users/{id},另一個映射到?/users/new,那 Spring Boot 就不知道該調用哪個方法了。
Java Code |
@GetMapping("/users/{id}") public User getUser(@PathVariable Long id) { ????// 返回某個用戶 } @GetMapping("/users/new") public User newUser() { ????// 返回一個新用戶 } |
這段代碼里頭,/users/{id}?和?/users/new?就沖突了,因為?new?會被當成?id?來處理。
2. 跨域問題
RESTful API 里頭,跨域是個常見問題。Spring Boot 里頭可以用?@CrossOrigin?注解來解決跨域問題。
Java Code |
@CrossOrigin(origins = "http://example.com") @RestController @RequestMapping("/api") public class MyController { ????// ... } |
這段代碼里頭,@CrossOrigin?是用來允許?http://example.com?這個域名跨域訪問的。
專有名詞解釋
- Spring MVC:Spring 框架中的一個模塊,用于構建 Web 應用程序,基于 Model-View-Controller 設計模式。
- RESTful API:一種基于 HTTP 協議的 API 設計風格,強調資源的操作和狀態轉移。
- Controller:Spring MVC 中的一個組件,負責處理 HTTP 請求并返回響應。
- Filter:Java Web 開發中的一個組件,用于在請求到達 Controller 之前或響應返回客戶端之前進行預處理或后處理。
- RestController:Spring MVC 中的一個注解,結合了?Controller?和?ResponseBody,用于返回直接寫給客戶端的數據。
- RequestMapping:Spring MVC 中的一個注解,用于映射 URL 路徑到 Controller 方法。
- PathVariable:Spring MVC 中的一個注解,用于從 URL 路徑中提取參數。
- RequestBody:Spring MVC 中的一個注解,用于接收客戶端傳過來的 JSON 數據。
- ExceptionHandler:Spring MVC 中的一個注解,用于處理 Controller 中的異常。
- Valid:Spring MVC 中的一個注解,用于做參數校驗。
- ConfigurationProperties:Spring Boot 中的一個注解,用于將配置文件中的屬性綁定到 Java 對象中。
- CrossOrigin:Spring Boot 中的一個注解,用于解決跨域問題。
- Async:Spring Boot 中的一個注解,用于讓方法異步執行。