SpringMVC RESTful

1. RESTful CRUD实现流程

参数传递形式 RESTful风格
/getUser?id=1 GET /user/1
/updateUser?id=1 PUT /user/1
/deleteUser?id=1 DELETE /user/1
/saveUser POST /user/1

1.1. 编写HTML

页面只能发送GET/POST请求。为了实现RESTful,SpringMVC提供了一种机制:页面可以发送POST请求,通过”_method”参数设置实际要发送的请求类型,SpringMVC会根据”_method”的值转变为对应的请求进行处理

1
2
3
4
5
6
7
8
9
10
11
12
<a href="/user/1">查询</a>
<form action="/user" method="post">
<button type="submit">添加</button>
</form>
<form action="/user/1" method="post">
<input type="hidden" name="_method" value="delete">
<button type="submit">删除</button>
</form>
<form action="/user/1" method="post">
<input type="hidden" name="_method" value="put">
<button type="submit">更新</button>
</form>

1.2. 设置HiddenHttpMethodFilter(实现请求类型转变的原理)

浏览器 form 表单只支持 GET 与 POST 请求,而DELETE、PUT 等 method 并不支持,Spring3.0 添加了一个过滤器,可以将这些请求转换为标准的 http 方法,使得支持 GET、POST、PUT 与 DELETE 请求。

SpringMVC有一个内置的HiddenHttpMethodFilter,可以根据请求参数中的”_method”的值,转化为对应的请求方式,并进行处理

编辑web.xml,添加Filter

1
2
3
4
5
6
7
8
9
<filter>
<filter-name>HiddenHttpMethodFilter</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>HiddenHttpMethodFilter</filter-name>
<!-- 拦截所有请求 -->
<url-pattern>/*</url-pattern>
</filter-mapping>

1.3. 编写Controller

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@Controller
public class UserController {
@GetMapping("/user/{id}")
public void getUser(@PathVariable Integer id) {
System.out.println("查询id=" + id);
}

@PutMapping("/user/{id}")
public void updateUser(@PathVariable Integer id) {
System.out.println("更新id=" + id);
}

@DeleteMapping("/user/{id}")
public void deleteUser(@PathVariable Integer id) {
System.out.println("删除id=" + id);
}

@PostMapping("/user")
public void saveUser() {
System.out.println("添加");
}
}

2. HiddenHttpMethodFilter源码分析(5.1.5.RELEASE)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
public class HiddenHttpMethodFilter extends OncePerRequestFilter {
/** 允许的请求方法:PUT/DELETE/PATCH */
private static final List<String> ALLOWED_METHODS = Collections
.unmodifiableList(Arrays.asList(HttpMethod.PUT.name(), HttpMethod.DELETE.name(), HttpMethod.PATCH.name()));

/** 默认method参数的名称 Default method parameter: {@code _method}. */
public static final String DEFAULT_METHOD_PARAM = "_method";

private String methodParam = DEFAULT_METHOD_PARAM;

/**
* Set the parameter name to look for HTTP methods.
* @see #DEFAULT_METHOD_PARAM
*/
public void setMethodParam(String methodParam) {
Assert.hasText(methodParam, "'methodParam' must not be empty");
this.methodParam = methodParam;
}

@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {

HttpServletRequest requestToUse = request;

// 只处理POST请求,即只允许POST请求转化为其它类型的请求
if ("POST".equals(request.getMethod()) && request.getAttribute(WebUtils.ERROR_EXCEPTION_ATTRIBUTE) == null) {
// 获取"_method"值
String paramValue = request.getParameter(this.methodParam);
// 判断值是否为空,为空就不处理
if (StringUtils.hasLength(paramValue)) {
// 统一将值转换为大写,如put==>PUT, delete==>DELETE
String method = paramValue.toUpperCase(Locale.ENGLISH);
// 如果值是PUT/DELETE/PATCH,就将当前的HttpServletRequest转为HttpMethodRequestWrapper
// HttpMethodRequestWrapper就是写在下面的静态内部类
if (ALLOWED_METHODS.contains(method)) {
requestToUse = new HttpMethodRequestWrapper(request, method);
}
}
}
// 最后统一放行所有请求
filterChain.doFilter(requestToUse, response);
}

/**
* HttpMethodRequestWrapper 继承了HttpServletRequest
* 1、传入一个method参数,该值就是之前处理过的PUT/DELETE/PATH
* 2、重载了getMethod方法
*/
/**
* Simple {@link HttpServletRequest} wrapper that returns the supplied method for
* {@link HttpServletRequest#getMethod()}.
*/
private static class HttpMethodRequestWrapper extends HttpServletRequestWrapper {

private final String method;

public HttpMethodRequestWrapper(HttpServletRequest request, String method) {
super(request);
this.method = method;
}

@Override
public String getMethod() {
return this.method;
}
}

}
panchaoxin wechat
关注我的公众号
支持一下