SpingMVC编码问题
WuCheng

使用Post提交的UTF-8编码问题

记录一下最近学习Spring MVC遇到的编码问题

当使用post提交请求的时候(因为Tomcat中本身就在配置文件中设置过编码,所以在Get请求中不会出现乱码),UTF-8编码几乎是所有人都会遇到的一个比较糟心的问题,通常在Java web阶段的解决方式都是直接在BaseServlet设置request的编码,顺带设置了response的编码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public abstract class BaseServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("UTF-8");
resp.setCharacterEncoding("UTF-8");

String action = req.getParameter("action");
try {
Method method = this.getClass().getDeclaredMethod(action, HttpServletRequest.class, HttpServletResponse.class);

method.invoke(this,req,resp);

} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}

然而在Spring MVC中,所有的请求都是交给DispatcherServlet管理,如果在RequestMapping中直接拿到RequestServlet再进行设置很显然不是一个好办法,并且在拿到request请求域中的Parameter参数的时候就再进行更改就无效了。

那么我们应该在获取到Request域中参数之前就要进行设置,并且要保证所有的请求都会经过这个方法,那么很显然就是在Filter中设置了

在Spring MVC中提供了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
public class CharacterEncodingFilter extends OncePerRequestFilter {
@Nullable
private String encoding;
private boolean forceRequestEncoding;
private boolean forceResponseEncoding;

//中间省去构造和get set方法

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

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

protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
String encoding = this.getEncoding();
if (encoding != null) {
if (this.isForceRequestEncoding() || request.getCharacterEncoding() == null) {
request.setCharacterEncoding(encoding);
}

if (this.isForceResponseEncoding()) {
response.setCharacterEncoding(encoding);
}
}

filterChain.doFilter(request, response);
}
}

从代码中可以看到,传入的编码参数为encoding,所以需要设置encoding值为UTF-8,以及顺便更改Response编码也需要设置forceResponseEncoding属性为true

而Request编码因为request.getCharacterEncoding() == null满足条件,当encoding有值则会直接设置,所以不需要设置forceRequestEncoding为true

在web.xml配置CharacterEncodingFilter方式

那么在web.xml中配置文件如下

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>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<!--设置开启Response编码的修改-->
<init-param>
<param-name>forceResponseEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>

<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

Annotation配置类创建对象返回方式

当使用注解配置的时候就比使用web.xml方便一点,在配置代替web.xml的配置类中继承AbstractAnnotationConfigDispatcherServletInitializer接口中,重写getServletFilter()将创建的CharacterEncodingFilter类并设置好EncodingforceResponseEncoding属性放入返回的Filter数组中即可

1
2
3
4
5
6
7
8
9
public class WebInit extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Filter[] getServletFilters() {
CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter();
characterEncodingFilter.setEncoding("UTF-8");
characterEncodingFilter.setForceResponseEncoding(true);
return new Filter[]{characterEncodingFilter};
}
}

其他一些问题

然而在我正确设置后,在控制台测试输出仍然不能正确显示中文!

在多次修改部署后,终于发现了问题所在……

原因是Tomcat控制台输出的编码有问题,仅仅设置好了程序的编码是没有效果的,没有想到控制台本身也有编码问题,真的很坑人……

然后在Tomcat配置VM options中填入-Dfile.encoding=UTF-8,问题解决!

  • 本文标题:SpingMVC编码问题
  • 本文作者:WuCheng
  • 创建时间:2022-11-03 23:33:37
  • 本文链接:https://www.wucheng.work/2022/11/03/SpingMVC编码问题/
  • 版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!