Spring MVC 中文乱码问题

1. 前言

本节课程将向大家讲解 Spring MVC 项目中如何处理中文信息。通过本节课程你也将学习到如何使用 JAVA 方式动态配置过滤器。

中文乱码的解决方式可以自定义过滤器,也可以使用 Spring MVC 自带的过滤器。本章节的重点是掌握过滤器的使用。

2. 原生 API 解决方案

无论是基于原生 Servlet 、还是基于 Spring MVC 开发,中文乱码总是一件让人头痛的事情。

当用户在网页中输入中文信息提交给服务器后,服务器端解析时得到可能是一个乱码。或者当服务器发送中文数据给客户端时,浏览器中显示出来的也可能是乱码。

为什么会产生中文乱码?

服务器端在解析客户端数据时,默认情况下使用的并不是中文编码。同理,在服务器端把数据放入响应包中时,使用的也不是中文编码。

知道事情原因后,就好办了,只需要在服务器端解析数据或向数据包中写入数据时选择正确的中文编码就可以了。

在登录页面输入用户名和密码时,如下图所示输入中文:

图片描述

在控制器中解析数据时,得到的是乱码,既然是乱码,后面的逻辑想都不用想,肯定是通不过的。

浏览器封装数据到请求包时,使用的是支持中文的如 UTF-8 编码。但是,在服务器解码数据时,使用的并不是 UTF-8 编码。编码与解码的前后不一致,导致中文乱码的出现。

知道原因后,问题就不再是问题。

无论 Spring MVC 显得多么高级,但解析数据还是由 HttpServletRequest 对象完成的,最直接的解决方案就是让 Spring 注入原生的 HttpServletRequest 对象,再重设解析数据的编码即可。

当然,为了保证中文数据能正确的写入响应包,也需要注入 HttpServletResponse 。

@RequestMapping(value="/login")	
public String login01(HttpServletRequest request,HttpServletResponse response) throws UnsupportedEncodingException {
	request.setCharacterEncoding("utf-8");
	response.setContentType("text/html;charset=utf-8");
	String userName=request.getParameter("userName");
	String userPassword=request.getParameter("userPassword");

	if("慕课".equals(userName) && "123".equals(userPassword)) {
		return "index";
	}
		return "fail";
	}
}

再次在浏览器中发起中文登录请求,控制器能正确解析中文,验证通过,跳转到 “index” 视图。

问题是得到了解决,但有种共产主义社会又回到原始社会的感觉,Spring MVC 的优势荡然无存。

这种方案只能说是一种方案,而不能说是一种企业级的快速解决方案。

3. 自定义过滤器

使用过滤器,当然是绝佳的选择方案,过滤器可以对来来往往的请求包、响应包做统一处理。过滤器以组件独立的方式运行,不需要侵入目标响应控制器组件。完全符合 OOP 的高内聚、低耦合要求。

自定义编写一个简单的解决中文乱码过滤器:

public class EncodingFilter implements Filter {
	@Override
	public void init(FilterConfig filterConfig) throws ServletException {
	}
    @Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
			throws IOException, ServletException {
		HttpServletRequest req = (HttpServletRequest) request;
		HttpServletResponse res = (HttpServletResponse) response;
		req.setCharacterEncoding("utf-8");
		res.setContentType("text/html;charset=UTF-8");
		chain.doFilter(req, res);
	}
    @Override
	public void destroy() {
	}
}

编写完过滤器后,需要让 Tomcat 知道它的存在,可以在 web.xml 中进行配置。本章节使用纯 JAVA 的配置方案。

打开 WebInitializer 类文件,重写 onStartup()方法,使用 JAVA 方法注册过滤器。

@Override
public void onStartup(ServletContext servletContext) throws ServletException {
	super.onStartup(servletContext);
	EncodingFilter encodingFilter=new EncodingFilter();
	FilterRegistration.Dynamic register= servletContext.addFilter("encdoing", encodingFilter);
	register.addMappingForUrlPatterns(
			EnumSet.of(DispatcherType.REQUEST, DispatcherType.FORWARD, DispatcherType.INCLUDE), false, "/*");
}

Tips: 一定要加上 super.onStartup (servletContext); 语句,必须重用父类中的代码。

在此方法中还可以动态配置 Servlet 、监听器 。

重构控制器代码:

@RequestMapping(value="/login")	
public String login01(User user) throws UnsupportedEncodingException {	
	System.out.println(user.getUserName());
	if("慕课".equals(user.getUserName()) && "123".equals(user.getUserPassword())) {
		return "index";
	}
	return "fail";
}

发布项目、重启 tomcat ,打开浏览器,进入登录页面。发送中文登录信息,中文乱码得到解决。

4. Spring MVC 字符编码过滤器

Spring MVC 提供有一个名为 CharacterEncodingFilter 过滤器组件,可以直接配置使用。

WebInitializer 类的 onStartup() 方法中使用 CharacterEncodingFilter 替代自己的过滤器。

@Override
public void onStartup(ServletContext servletContext) throws ServletException {
	super.onStartup(servletContext);
	CharacterEncodingFilter charEncodingFilter=new CharacterEncodingFilter();
	charEncodingFilter.setEncoding("utf-8");
	FilterRegistration.Dynamic register= servletContext.addFilter("encdoing", charEncodingFilter);
	register.addMappingForUrlPatterns(
			EnumSet.of(DispatcherType.REQUEST, DispatcherType.FORWARD, DispatcherType.INCLUDE), false, "/*");		
}

同样的在浏览器中发送中文登录请求,经过过滤器的过滤后,中文乱码问题得到了很好的解决。

CharacterEncodingFilter 很完美的解决了请求包的中文问题,也解决了响应浏览时的中文乱码问题。

5. 小结

本节课程和大家探讨了中文乱码的问题,首先需要了解为什么会出现中文乱码,知道原因后,解决的方案便会有很多。中文乱码是一个共性问题,Spring MVC 框架提供了一个字符过滤器,很完美地解决了这个问题。

当然,通过本节课程,你也了解到了如何使用 JAVA 方式动态配置过滤器。