使用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;
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> <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
类并设置好Encoding
和forceResponseEncoding
属性放入返回的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
,问题解决!