SpringMVC 乱码解决

1. GET请求乱码

1.1. 终极解决方案:修改server.xml的URIEncoding

如果使用tomcat插件,在<configuration>标签中设置<uriEncoding>属性即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<build>
<plugins>
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
<configuration>
<port>8080</port>
<path>/</path>
<!-- 设置uriEncoding -->
<uriEncoding>UTF-8</uriEncoding>
</configuration>
</plugin>
</plugins>
</build>

如果是tomcat服务器,则修改conf/server.xml

1
2
3
4
5
<!-- 找到设置port="8080"的那个标签,添加URIEncoding="UTF-8"即可 -->
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443"
URIEncoding="UTF-8" />

2. POST请求乱码

2.1. 方式1:原生API

1
2
3
4
5
6
7
@GetMapping("/test")
public void haha(HttpServletRequest request) throws Exception {
// 在第1次获取请求参数之前设置
request.setCharacterEncoding("UTF-8");
// 再获取参数,就不会乱码了
String username = request.getParameter("username");
}

2.2. 方式2:CharacterEncodingFilter

使用原生API,每一个POST方法都要写一遍
request.setCharacterEncoding("UTF-8"),太麻烦。干脆统一写一个Filter,所有的请求先统一执行一遍该方法,保证编码能被解析。

这个Filter不用我们亲自写,SpringMVC内置了CharacterEncodingFilter,这个过滤器不仅能设置POST请求的编码,还能设置响应的编码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<filter>
<filter-name>characterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<!-- 设置请求数据的编码为UTF-8 -->
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<!-- 设置响应数据的编码为UTF-8(该编码取决于上面设置的encoding属性) -->
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<!-- 拦截所有请求 -->
<filter-name>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

3. CharacterEncodingFilter的设置顺序最好放在首位

CharacterEncodingFilter会设置POST请求的编码

1
request.setCharacterEncoding(encoding)

设置POST请求的编码,这条语句应该要写在获取参数之前,这样才能保证读取的参数编码格式是正确的

1
2
3
4
// 先设置编码
request.setCharacterEncoding(encoding)
// 再获取参数
request.getParameter("username");

有的过滤器,如HiddenHttpMethodFilter,查看源码可知有通过request.getParameter()获取参数。如果HiddenHttpMethodFilter配置顺序在CharacterEncodingFilter之前,就会出现先获取参数,再设置POST请求编码的情况。所以为了避免这种情况发生,在web.xml中,CharacterEncodingFilter应该配置在其它Filter之前

4. CharacterEncodingFilter源码分析

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
70
71
72
73
74
75
76
77
78
79
80
81
public class CharacterEncodingFilter extends OncePerRequestFilter {
/** 在web.xml中配置encoding,就会设置该值 */
@Nullable
private String encoding;

/**
* 在web.xml中设置forceEncoding的值,会同时设置forceRequestEncoding/forceResponseEncoding
*/

/** request是否强制使用encoding编码 */
private boolean forceRequestEncoding = false;

/** response是否强制使用encoding编码 */
private boolean forceResponseEncoding = false;

public CharacterEncodingFilter() {
}

public CharacterEncodingFilter(String encoding) {
this(encoding, false);
}

public CharacterEncodingFilter(String encoding, boolean forceEncoding) {
this(encoding, forceEncoding, forceEncoding);
}

public CharacterEncodingFilter(String encoding, boolean forceRequestEncoding, boolean forceResponseEncoding) {
Assert.hasLength(encoding, "Encoding must not be empty");
this.encoding = encoding;
this.forceRequestEncoding = forceRequestEncoding;
this.forceResponseEncoding = forceResponseEncoding;
}

public void setEncoding(@Nullable String encoding) {
this.encoding = encoding;
}

@Nullable
public String getEncoding() {
return this.encoding;
}

public void setForceEncoding(boolean forceEncoding) {
this.forceRequestEncoding = forceEncoding;
this.forceResponseEncoding = forceEncoding;
}

public void setForceRequestEncoding(boolean forceRequestEncoding) {
this.forceRequestEncoding = forceRequestEncoding;
}

public boolean isForceRequestEncoding() {
return this.forceRequestEncoding;
}

public void setForceResponseEncoding(boolean forceResponseEncoding) {
this.forceResponseEncoding = forceResponseEncoding;
}

public boolean isForceResponseEncoding() {
return this.forceResponseEncoding;
}

@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
String encoding = getEncoding();
if (encoding != null) {
if (isForceRequestEncoding() || request.getCharacterEncoding() == null) {
// 设置POST请求的编码
request.setCharacterEncoding(encoding);
}
if (isForceResponseEncoding()) {
// 设置响应编码
response.setCharacterEncoding(encoding);
}
}
// 放行所有请求
filterChain.doFilter(request, response);
}
}
panchaoxin wechat
关注我的公众号
支持一下