26、请求处理-【源码分析】-Rest映射及源码解析
26、请求处理-【源码分析】-Rest映射及源码解析
# 请求处理 - Rest映射及源码解析
## 一、什么是Restful风格
Restful是一种软件架构风格,它强调使用HTTP协议对资源进行操作,通过不同的HTTP请求方法(如GET、POST、PUT、DELETE等)来表示对资源的不同操作:
- **GET**:获取资源
- **POST**:创建新资源
- **PUT**:更新资源(整体更新)
- **DELETE**:删除资源
相比传统的URL风格,Restful风格更加简洁、清晰,例如:
- 传统风格:
- `/getUser?id=1`:获取用户信息
- `/deleteUser?id=1`:删除用户
- Restful风格:
- `/users/1`:GET表示获取用户信息,DELETE表示删除用户
## 二、Spring Boot中的Rest映射实现
在Spring Boot中,支持Restful风格的请求映射主要依赖于`HiddenHttpMethodFilter`过滤器。
### 1. 原理概述
由于HTML表单仅支持GET和POST请求,为了实现PUT和DELETE等请求,需要采用以下方式:
1. **表单使用POST方法**
2. **添加隐藏域**
- 在表单中添加一个名为`_method`的隐藏域,其值为实际的请求方法(如PUT、DELETE)。
- 示例:
```html
<form action="/users/1" method="post">
<input type="hidden" name="_method" value="PUT">
<!-- 其他表单内容 -->
<input type="submit" value="更新用户">
</form>
```
3. **过滤器处理**
- `HiddenHttpMethodFilter`拦截所有POST请求。
- 检查请求中是否存在名为`_method`的参数。
- 如果存在,将请求方法替换为`_method`的值,从而将POST请求转换为PUT或DELETE等请求。
### 2. 源码分析
#### (1)`HiddenHttpMethodFilter`的作用
`HiddenHttpMethodFilter`的核心代码如下:
```java
public class HiddenHttpMethodFilter extends OncePerRequestFilter {
// ...省略部分代码...
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
HttpServletRequest wrappedRequest = request;
// 判断请求是否为POST,且存在_method参数
if ("POST".equals(request.getMethod()) && request.getAttribute(WebUtils.ERROR_EXCEPTION_ATTRIBUTE) == null) {
String paramValue = request.getParameter(this.methodParam);
if (StringUtils.hasLength(paramValue)) {
// 将请求包装为新的HttpServletRequest对象,重写getMethod方法
wrappedRequest = new HttpMethodRequestWrapper(request, paramValue);
}
}
// 继续执行过滤器链
filterChain.doFilter(wrappedRequest, response);
}
// ...省略部分代码...
}
```
#### (2)Spring Boot的自动配置
在`WebMvcAutoConfiguration`类中,Spring Boot自动配置了`HiddenHttpMethodFilter`:
```java
@Configuration(proxyBeanMethods = false)
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
@AutoConfigureAfter({ DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class,
ValidationAutoConfiguration.class })
public class WebMvcAutoConfiguration {
// ...省略部分代码...
@Bean
@ConditionalOnMissingBean(HiddenHttpMethodFilter.class)
@ConditionalOnProperty(prefix = "spring.mvc.hiddenmethod.filter", name = "enabled", matchIfMissing = true)
public OrderedHiddenHttpMethodFilter hiddenHttpMethodFilter() {
return new OrderedHiddenHttpMethodFilter();
}
// ...省略部分代码...
}
```
- **条件配置**:
- `@ConditionalOnMissingBean(HiddenHttpMethodFilter.class)`:当容器中不存在`HiddenHttpMethodFilter`时才自动配置。
- `@ConditionalOnProperty(prefix = "spring.mvc.hiddenmethod.filter", name = "enabled", matchIfMissing = true)`:默认开启,可以通过`spring.mvc.hiddenmethod.filter.enabled`配置项关闭。
## 三、使用示例
### 1. 控制器方法
```java
@RestController
@RequestMapping("/users")
public class UserController {
@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) {
// 删除用户
}
}
```
### 2. 表单示例
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Restful Form</title>
</head>
<body>
<form action="/users/1" method="post">
<input type="hidden" name="_method" value="PUT">
<!-- 更新用户信息 -->
<input type="submit" value="更新用户">
</form>
<form action="/users/1" method="post">
<input type="hidden" name="_method" value="DELETE">
<!-- 删除用户 -->
<input type="submit" value="删除用户">
</form>
</body>
</html>
```
## 四、总结
通过`HiddenHttpMethodFilter`,Spring Boot实现了对Restful风格请求的支持,使得在表单中也能发送PUT、DELETE等请求。理解其原理和配置方式,有助于在实际开发中更好地应用Restful API设计。