今天遇到一个很奇怪的问题,所以花时间研究了下!
csdn的文章编辑确实有点体验不太好,自己截的图明明是大图,发表文章后就变成了小图,小图就看不太清除了,大家凑合着看吧!截图在下面!
首先,大家先看下效果吧,先知道我要做什么?我项目中有一个jsp页面中,jsp页面中有个form表单,这个表单主要是用来收集数据的,然后提交(post提交)到服务器端上的一个servlet类处理,表单的文本框中会输入中文,所以为了处理中文乱码的问题,我专门写了一个处理中文乱码的过滤器,在中文乱码过滤器类中设置了编码格式是utf-8,web.xml文件中配置了这个中文乱码过滤器!web.xml文件中还配置了request监听器对象和request的Attribute属性的监听器对象。大家都知道,过滤器类中有一个init方法,在web容器启动的时候,比如tomcat启动的时候,过滤器类中的init方法就会执行,而request监听器对象也有一个方法,叫requestInitialized方法,但是requestInitialized方法不会在tomcat启动的时候执行,而是会在request对象创建的时候执行requestInitialized方法。
代码如下:
RequestListener类
package com.jiongmeng.listener;
import java.util.Enumeration;
import javax.servlet.ServletRequest;
import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;
/**
* @Description: (request对象在创建和消亡的监听器)
* @author 囧囧 E-mail:666888999@qq.com
* jerry
* @date: 2017年11月8日 下午1:06:49
* <p>Copyright: Copyright (c) 2005-2017版权归囧萌软件科技公司所有</p>
* @version 创建时间:2017年11月8日 下午1:06:49
*/
public class RequestListener implements ServletRequestListener{
@Override
public void requestDestroyed(ServletRequestEvent requestEvent) {
System.out.println("************request对象消亡************");
}
@Override
public void requestInitialized(ServletRequestEvent requestEvent) {
System.out.println("************request对象创建************");
// ServletRequest request = requestEvent.getServletRequest();
// String hobby = request.getParameter("hobby");
// System.out.println("页面传递的参数hobby(爱好) = " + hobby);
// Enumeration<String> parameterNames = request.getParameterNames();
// while (parameterNames.hasMoreElements()) {
// String parameterName = parameterNames.nextElement();
// System.out.println("参数名 = " + parameterName + " 参数值 = " + request.getParameter(parameterName));
// }
}
}
RequestAttributeListener类
package com.jiongmeng.listener;
import javax.servlet.ServletRequestAttributeEvent;
import javax.servlet.ServletRequestAttributeListener;
/**
* @Description: (request对象在attribute时的监听器)
* @author 囧囧 E-mail:666888999@qq.com
* jerry
* @date: 2017年11月8日 下午1:12:47
* <p>Copyright: Copyright (c) 2005-2017版权归囧萌软件科技公司所有</p>
* @version 创建时间:2017年11月8日 下午1:12:47
*/
public class RequestAttributeListener implements ServletRequestAttributeListener{
@Override
public void attributeAdded(ServletRequestAttributeEvent requestAttributeEvent) {
System.out.println("我是request对象的attributeAdded方法");
System.out.println("request对象中添加属性,名 = " + requestAttributeEvent.getName() + " 值 = " + requestAttributeEvent.getValue());
//System.out.println("请求参数hobby的值 = " + requestAttributeEvent.getServletRequest().getParameter("hobby"));
}
@Override
public void attributeRemoved(ServletRequestAttributeEvent requestAttributeEvent) {
System.out.println("我是request对象的attributeRemoved方法");
//打印的是删除前的值
System.out.println("request对象中删除属性,名 = " + requestAttributeEvent.getName() + " 值 = " + requestAttributeEvent.getValue());
// System.out.println("请求参数hobby的值 = " + requestAttributeEvent.getServletRequest().getParameter("hobby"));
}
@Override
public void attributeReplaced(ServletRequestAttributeEvent requestAttributeEvent) {
System.out.println("我是request对象的attributeReplaced方法");
//打印的是修改前的值
System.out.println("request对象中修改属性,名 = " + requestAttributeEvent.getName() + " 值 = " + requestAttributeEvent.getValue());
System.out.println("请求参数hobby的值 = " + requestAttributeEvent.getServletRequest().getParameter("hobby"));
}
}
ChineseMessyCodeFilter类
package com.jiongmeng.filter;
import java.io.IOException;
import java.util.Enumeration;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
/**
*
* 中文乱码过滤器(请求前过滤器)
* @author czh
* @time 2017年10月12日 下午10:48:17
*/
public class ChineseMessyCodeFilter implements Filter{
private String characterEncoding = "utf-8";
@Override
public void destroy() {
System.out.println("*******************中文乱码过滤器destroy()*******************");
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
throws IOException, ServletException {
request.setCharacterEncoding(characterEncoding);
System.out.println("*********************脱衣服洗澡!(请求前过滤)*********************"); //前过滤
// System.out.println("请求servlet资源路径 = " + ((HttpServletRequest)request).getServletPath());
// System.out.println("请求方式(get / post) = " + ((HttpServletRequest)request).getMethod());
filterChain.doFilter(request, response);
System.out.println(response.getClass());
System.out.println("*********************穿衣服准备出门!(请求后过滤)*********************");//后过滤
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("filterName = " + filterConfig.getFilterName());
characterEncoding = filterConfig.getInitParameter("characterEncoding");
Enumeration<String> names = filterConfig.getInitParameterNames();
while (names.hasMoreElements()) {
String name = (String) names.nextElement();
System.out.println(name + " = " + filterConfig.getInitParameter(name));
}
System.out.println("*******************中文乱码过滤器init()*******************");
}
}
web.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
<display-name>javaWeb</display-name>
<error-page>
<exception-type>java.lang.ArithmeticException</exception-type>
<location>/arithmeticError.jsp</location>
</error-page>
<error-page>
<error-code>500</error-code>
<location>/error500.jsp</location>
</error-page>
<error-page>
<error-code>404</error-code>
<location>/error404.jsp</location>
</error-page>
<servlet>
<servlet-name>SystemInit</servlet-name>
<servlet-class>com.jiongmeng.system.SystemInit</servlet-class>
<load-on-startup>0</load-on-startup>
</servlet>
<listener>
<listener-class>com.jiongmeng.listener.ApplicationListener</listener-class>
</listener>
<listener>
<listener-class>com.jiongmeng.listener.ApplicationAttributeListener</listener-class>
</listener>
<listener>
<listener-class>com.jiongmeng.listener.SessionListenerImpl</listener-class>
</listener>
<listener>
<listener-class>com.jiongmeng.listener.SessionAttributeListener</listener-class>
</listener>
<!--
注意:
Request对象监听器 和Request对象的Attribute属性对象监听器中的request.getParameter()方
法和一些相关的方法会导致chineseMessyCodeFilter中文乱码过滤器失效或不起作用
-->
<listener>
<listener-class>com.jiongmeng.listener.RequestListener</listener-class>
</listener>
<listener>
<listener-class>com.jiongmeng.listener.RequestAttributeListener</listener-class>
</listener>
<context-param>
<param-name>springConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext.xml</param-value>
</context-param>
<context-param>
<param-name>city</param-name>
<param-value>jiangxiyudu</param-value>
</context-param>
<!--
配置多个过滤器时,各个过滤器的init()函数的执行顺序我还没发现什么规律,好像是随机的,有待
验证,以后有时间再研究,这里先放一放
-->
<!--
配置多个过滤器时,各个过滤器的doFilter()函数的执行顺序是按照filter-mapping的顺序
-->
<!--
检测客户端浏览器的类型的过滤器,检测是移动端浏览器还是PC端浏览器
-->
<!--
<filter>
<filter-name>checkBrowserTypeFilter</filter-name>
<filter-class>com.jiongmeng.filter.CheckBrowserTypeFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>checkBrowserTypeFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
-->
<!-- 限制IP地址过滤器 -->
<!--
<filter>
<filter-name>iPAddressFilter</filter-name>
<filter-class>com.jiongmeng.filter.IPAddressFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>iPAddressFilter</filter-name>
<url-pattern>*.jsp</url-pattern>
</filter-mapping>
-->
<!--
logoFilter过滤器造成了forwardB.jsp页面在转发到forwardC.jsp的时候,将2个jsp页面合并的问题!
-->
<!-- 替换logo和替换响应内容的过滤器 -->
<!--
<filter>
<filter-name>logoFilter</filter-name>
<filter-class>com.jiongmeng.filter.LogoFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>logoFilter</filter-name>
<url-pattern>*.jsp</url-pattern>
<url-pattern>/loginServlet</url-pattern>
</filter-mapping>
-->
<!-- 检测是否登录的过滤器 -->
<!--
<filter>
<filter-name>loginFilter</filter-name>
<filter-class>com.jiongmeng.filter.LoginFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>loginFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
-->
<!--
<filter>
<filter-name>clothesFilter</filter-name>
<filter-class>com.jiongmeng.filter.ClothesFilter</filter-class>
</filter>
<filter>
<filter-name>shoesFilter</filter-name>
<filter-class>com.jiongmeng.filter.ShoesFilter</filter-class>
</filter>
<filter>
<filter-name>hatFilter</filter-name>
<filter-class>com.jiongmeng.filter.HatFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>clothesFilter</filter-name>
<url-pattern>/thermaServlet</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>shoesFilter</filter-name>
<url-pattern>/thermaServlet</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>hatFilter</filter-name>
<url-pattern>/thermaServlet</url-pattern>
</filter-mapping>
-->
<!-- 中文乱码过滤器 -->
<filter>
<filter-name>chineseMessyCodeFilter</filter-name>
<filter-class>com.jiongmeng.filter.ChineseMessyCodeFilter</filter-class>
<init-param>
<param-name>characterEncoding</param-name>
<param-value>utf-8</param-value>
</init-param>
<init-param>
<param-name>logType</param-name>
<param-value>log4j</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>chineseMessyCodeFilter</filter-name>
<url-pattern>/thermaServlet</url-pattern>
<url-pattern>/hello</url-pattern>
<url-pattern>/*</url-pattern>
</filter-mapping>
<session-config>
<session-timeout>15</session-timeout>
</session-config>
<welcome-file-list>
<welcome-file>testRequestGetParameter</welcome-file>
<welcome-file>testIncludeAction.jsp</welcome-file>
<welcome-file>tomcatKnowledge.jsp</welcome-file>
</welcome-file-list>
<servlet>
<servlet-name>myJspHideObject</servlet-name>
<jsp-file>/9jspHideObject.jsp</jsp-file>
<init-param>
<param-name>userName</param-name>
<param-value>令狐冲</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>myJspHideObject</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>firstServlet</servlet-name>
<servlet-class>com.jiongmeng.FirstServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>firstServlet</servlet-name>
<url-pattern>/firstServlet</url-pattern>
<url-pattern>/myfirstServlet</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>bookInfo</servlet-name>
<servlet-class>com.jiongmeng.BookInfo</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>bookInfo</servlet-name>
<url-pattern>/bookInfo/*</url-pattern>
<url-pattern>/bookInfo/save</url-pattern>
<url-pattern>/bookInfo/update</url-pattern>
<url-pattern>/bookInfo/findAll</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>testServlet</servlet-name>
<servlet-class>com.jiongmeng.TestServlet</servlet-class>
<init-param>
<param-name>color</param-name>
<param-value>blue</param-value>
</init-param>
<init-param>
<param-name>color</param-name>
<param-value>red</param-value>
</init-param>
<init-param>
<param-name>userName</param-name>
<param-value>jiongjiong</param-value>
</init-param>
<load-on-startup>0</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>testServlet</servlet-name>
<url-pattern>/testServlet</url-pattern>
</servlet-mapping>
</web-app>
在浏览器地址栏中输入jsp地址,就会执行request监听器对象的requestInitialized方法和request的Attribute属性的监听器对象的attributeReplaced方法。等jsp加载完了,就会执行request监听器对象的requestDestroyed方法,当然这些都不是我们的重点!
点击submit按钮提及到服务器端,发现表单中的中文提交到服务器端的时候,服务器端拿到的中文数据是中文乱码,这就很奇怪了,我明明是写了处理中文乱码的过滤器的嘛!
于是我debug了一下,看看执行的流程和顺序是怎么回事!
debug后,第1步执行的是request监听器对象的requestInitialized方法,所以监听器是优先于过滤器执行的,看下图
第2步执行的是RequestAttributeListener类中的attributeReplaced方法,看下图
第3步执行的是ChineseMessyCodeFilter类(中文乱码过滤器类)中的doFilter方法,看下面的截图
这个时候小伙伴应该明白了为什么我们写了中文乱码过滤器还是会乱码!
没错,就是在执行ChineseMessyCodeFilter类(中文乱码过滤器类)中的doFilter方法之前,我们的程序先执行了request监听器对象的requestInitialized方法和request的Attribute属性的监听器对象的attributeReplaced方法,而这2个方法中又使用了request.getParameter()方法,我们都知道在request.setCharacterEncoding("utf-8");这句话之前,不能使用request.getParameter()方法,这样会导致服务器端获取到的还是中文乱码,所以必须是request.getParameter()这句话只能放在request.setCharacterEncoding("utf-8");这句话之后,才能解决中文乱码的问题,所以知道原因了的话,我们只要把RequestAttributeListener类中的attributeReplaced方法中的getServletRequest().getParameter()这句话注释掉,把RequestListener类中requestInitialized方法中的request.getParameter()注释掉,就可以解决中文乱码过滤器失效的问题,所以大家记住,javaweb开发中监听器中的一些语句会导致过滤器失效,就像这个例子一样,request监听器对象中的一些语句导致了中文乱码过滤器失效!
注释掉后,jsp表单提交,服务器端拿表单数据的时候就不会是中文乱码了!,看下图