Spring MVC 中文亂碼問(wèn)題
1. 前言
本節(jié)課程將向大家講解 Spring MVC 項(xiàng)目中如何處理中文信息。通過(guò)本節(jié)課程你也將學(xué)習(xí)到如何使用 JAVA 方式動(dòng)態(tài)配置過(guò)濾器。
中文亂碼的解決方式可以自定義過(guò)濾器,也可以使用 Spring MVC 自帶的過(guò)濾器。本章節(jié)的重點(diǎn)是掌握過(guò)濾器的使用。
2. 原生 API 解決方案
無(wú)論是基于原生 Servlet 、還是基于 Spring MVC 開(kāi)發(fā),中文亂碼總是一件讓人頭痛的事情。
當(dāng)用戶在網(wǎng)頁(yè)中輸入中文信息提交給服務(wù)器后,服務(wù)器端解析時(shí)得到可能是一個(gè)亂碼?;蛘弋?dāng)服務(wù)器發(fā)送中文數(shù)據(jù)給客戶端時(shí),瀏覽器中顯示出來(lái)的也可能是亂碼。
為什么會(huì)產(chǎn)生中文亂碼?
服務(wù)器端在解析客戶端數(shù)據(jù)時(shí),默認(rèn)情況下使用的并不是中文編碼。同理,在服務(wù)器端把數(shù)據(jù)放入響應(yīng)包中時(shí),使用的也不是中文編碼。
知道事情原因后,就好辦了,只需要在服務(wù)器端解析數(shù)據(jù)或向數(shù)據(jù)包中寫入數(shù)據(jù)時(shí)選擇正確的中文編碼就可以了。
在登錄頁(yè)面輸入用戶名和密碼時(shí),如下圖所示輸入中文:
在控制器中解析數(shù)據(jù)時(shí),得到的是亂碼,既然是亂碼,后面的邏輯想都不用想,肯定是通不過(guò)的。
瀏覽器封裝數(shù)據(jù)到請(qǐng)求包時(shí),使用的是支持中文的如 UTF-8 編碼。但是,在服務(wù)器解碼數(shù)據(jù)時(shí),使用的并不是 UTF-8 編碼。編碼與解碼的前后不一致,導(dǎo)致中文亂碼的出現(xiàn)。
知道原因后,問(wèn)題就不再是問(wèn)題。
無(wú)論 Spring MVC 顯得多么高級(jí),但解析數(shù)據(jù)還是由 HttpServletRequest 對(duì)象完成的,最直接的解決方案就是讓 Spring 注入原生的 HttpServletRequest 對(duì)象,再重設(shè)解析數(shù)據(jù)的編碼即可。
當(dāng)然,為了保證中文數(shù)據(jù)能正確的寫入響應(yīng)包,也需要注入 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";
}
}
再次在瀏覽器中發(fā)起中文登錄請(qǐng)求,控制器能正確解析中文,驗(yàn)證通過(guò),跳轉(zhuǎn)到 “index” 視圖。
問(wèn)題是得到了解決,但有種共產(chǎn)主義社會(huì)又回到原始社會(huì)的感覺(jué),Spring MVC 的優(yōu)勢(shì)蕩然無(wú)存。
這種方案只能說(shuō)是一種方案,而不能說(shuō)是一種企業(yè)級(jí)的快速解決方案。
3. 自定義過(guò)濾器
使用過(guò)濾器,當(dāng)然是絕佳的選擇方案,過(guò)濾器可以對(duì)來(lái)來(lái)往往的請(qǐng)求包、響應(yīng)包做統(tǒng)一處理。過(guò)濾器以組件獨(dú)立的方式運(yùn)行,不需要侵入目標(biāo)響應(yīng)控制器組件。完全符合 OOP 的高內(nèi)聚、低耦合要求。
自定義編寫一個(gè)簡(jiǎn)單的解決中文亂碼過(guò)濾器:
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() {
}
}
編寫完過(guò)濾器后,需要讓 Tomcat 知道它的存在,可以在 web.xml 中進(jìn)行配置。本章節(jié)使用純 JAVA 的配置方案。
打開(kāi) WebInitializer 類文件,重寫 onStartup()方法,使用 JAVA 方法注冊(cè)過(guò)濾器。
@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); 語(yǔ)句,必須重用父類中的代碼。
在此方法中還可以動(dòng)態(tài)配置 Servlet 、監(jiān)聽(tīng)器 。
重構(gòu)控制器代碼:
@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";
}
發(fā)布項(xiàng)目、重啟 tomcat ,打開(kāi)瀏覽器,進(jìn)入登錄頁(yè)面。發(fā)送中文登錄信息,中文亂碼得到解決。
4. Spring MVC 字符編碼過(guò)濾器
Spring MVC 提供有一個(gè)名為 CharacterEncodingFilter 過(guò)濾器組件,可以直接配置使用。
在 WebInitializer 類的 onStartup() 方法中使用 CharacterEncodingFilter 替代自己的過(guò)濾器。
@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, "/*");
}
同樣的在瀏覽器中發(fā)送中文登錄請(qǐng)求,經(jīng)過(guò)過(guò)濾器的過(guò)濾后,中文亂碼問(wèn)題得到了很好的解決。
CharacterEncodingFilter 很完美的解決了請(qǐng)求包的中文問(wèn)題,也解決了響應(yīng)瀏覽時(shí)的中文亂碼問(wèn)題。
5. 小結(jié)
本節(jié)課程和大家探討了中文亂碼的問(wèn)題,首先需要了解為什么會(huì)出現(xiàn)中文亂碼,知道原因后,解決的方案便會(huì)有很多。中文亂碼是一個(gè)共性問(wèn)題,Spring MVC 框架提供了一個(gè)字符過(guò)濾器,很完美地解決了這個(gè)問(wèn)題。
當(dāng)然,通過(guò)本節(jié)課程,你也了解到了如何使用 JAVA 方式動(dòng)態(tài)配置過(guò)濾器。