<前文回顾>
<今日更新>
一、开篇整活儿
咱今儿个唠唠 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 中的一个注解,用于让方法异步执行。