解决全站字符乱码(POST和GET中文编码问题)

servlet:

l  POST:request.setCharacterEncoding(“utf-8”);

l  GET:

  • String username = request.getParameter(“username”);
  • username = new String(username.getBytes(“ISO-8859-1”), “utf-8”);
1 说明
乱码问题:

l  获取请求参数中的乱码问题;

  • POST请求:request.setCharacterEncoding(“utf-8”);
  • GET请求:new String(request.getParameter(“xxx”).getBytes(“iso-8859-1”), “utf-8”);

l  响应的乱码问题:response.setContextType(“text/html;charset=utf-8”)。

  基本上在每个Servlet中都要处理乱码问题,所以应该把这个工作放到过滤器中来完成。

2 分析
  其实全站乱码问题的难点就是处理GET请求参数的问题。

如果只是处理POST请求的编码问题,以及响应编码问题,那么这个过滤器就太!太!太简单的。

public class EncodingFilter extends HttpFilter {

public void doFilter(HttpServletRequest request,

HttpServletResponse response, FilterChain chain)

throws IOException, ServletException {

String charset = this.getInitParameter("charset");[崔1]

if(charset == null || charset.isEmpty()) {

charset = "UTF-8";

}[崔2]

request.setCharacterEncoding(charset);[崔3]  //调用request的函数

response.setContentType("text/html;charset=" + charset);[崔4]

chain.doFilter(request, response);

}

}

[崔1]获取配置文件中的初始化参数:charset

[崔2]如果没有给Filter配置charset参数,那么设置编码为UTF-8

[崔3]处理POST请求编码

[崔4]处理响应编码

如果是POST请求,当执行目标Servlet时,Servlet中调用request.getParameter()方法时,就会根据request.setCharacterEncoding()设置的编码来转码!这说明在过滤器中调用request.setCharacterEncoding()方法会影响在目标Servlet中的request.getParameter()方法的行为!

但是如果是GET请求,我们又如何能影响request.getParameter()方法的行为呢?这是不好做到的!我们不可能先调用request.getParameter()方法获取参数,然后手动转码后,再施加在到request中!因为request只有getParameter(),而没有setParameter()方法。

处理GET请求参数编码问题,需要在Filter中放行时,把request对象给“调包”了,也就是让目标Servlet使用我们“调包”之后的request对象。这说明我们需要保证“调包”之后的request对象中所有方法都要与“调包”之前一样可以使用,并且getParameter()方法还要有能力返回转码之后的参数。

这可能让你想起了“继承”,但是这里不能用继承,而是“装饰者模式(Decorator Pattern)”!

下面是三种对a对象进行增强的手段:

l  继承:AA类继承a对象的类型:A类,然后重写fun1()方法,其中重写的fun1()方法就是被增强的方法。但是,继承必须要知道a对象的真实类型,然后才能去继承。如果我们不知道a对象的确切类型,而只知道a对象是IA接口的实现类对象,那么就无法使用继承来增强a对象了;

l  装饰者模式:AA类去实现a对象相同的接口:IA接口,还需要给AA类传递a对象,然后在AA类中所有的方法实现都是通过代理a对象的相同方法完成的,只有fun1()方法在代理a对象相同方法的前后添加了一些内容,这就是对fun1()方法进行了增强;

l  动态代理:动态代理与装饰者模式比较相似,而且是通过反射来完成的。动态代理会在最后一天的基础加强中讲解,这里就不再废话了。

对request对象进行增强的条件,刚好符合装饰者模式的特点!因为我们不知道request对象的具体类型,但我们知道request是HttpServletRequest接口的实现类。这说明我们写一个类EncodingRequest,去实现HttpServletRequest接口,然后再把原来的request传递给EncodingRequest类!在EncodingRequest中对HttpServletRequest接口中的所有方法的实现都是通过代理原来的request对象来完成的,只有对getParameter()方法添加了增强代码!

JavaEE已经给我们提供了一个HttpServletRequestWrapper类,它就是HttpServletRequest的包装类,但它做任何的增强!你可能会说,写一个装饰类,但不做增强,其目的是什么呢?使用这个装饰类的对象,和使用原有的request有什么分别呢?

HttpServletRequestWrapper类虽然是HttpServletRequest的装饰类,但它不是用来直接使用的,而是用来让我们去继承的!当我们想写一个装饰类时,还要对所有不需要增强的方法做一次实现是很心烦的事情,但如果你去继承HttpServletRequestWrapper类,那么就只需要重写需要增强的方法即可了。

3 代码

EncodingRequest

public class EncodingRequest extends HttpServletRequestWrapper [崔5] {

private String charset;

public EncodingRequest[崔6] (HttpServletRequest request, String charset) {

super(request);

this.charset = charset;

}

public String getParameter[崔7] (String name) {

HttpServletRequest request [崔8] = (HttpServletRequest) getRequest();

String method = request.getMethod()[崔9] ;

if(method.equalsIgnoreCase("post[崔10] ")) {

try {

request.setCharacterEncoding(charset);[崔11]

} catch (UnsupportedEncodingException e) {}

} else if(method.equalsIgnoreCase("get[崔12] ")) {

String value = request.getParameter(name);[崔13]

try {

value = new String(name.getBytes("ISO-8859-1"), charset);[崔14]

} catch (UnsupportedEncodingException e) {

}

return value[崔15] ;

}

return request.getParameter(name);

}

}

EncodingFilter

public class EncodingFilter extends HttpFilter {

public void doFilter(HttpServletRequest request,

HttpServletResponse response, FilterChain chain)

throws IOException, ServletException {

String charset = this.getInitParameter("charset");[崔16]

if(charset == null || charset.isEmpty()) {

charset = "UTF-8";

}[崔17]

response.setCharacterEncoding(charset);

response.setContentType("text/html;charset=" + charset);

EncodingRequest res = new EncodingRequest(request, charset);[崔18]

chain.doFilter(res, response);[崔19]

}

}

web.xml

<filter>

<filter-name>EncodingFilter</filter-name>

<filter-class>cn.itcast.filter.EncodingFilter</filter-class>

<init-param>

<param-name>charset</param-name>

<param-value>UTF-8</param-value>

</init-param>

</filter>

<filter-mapping>

<filter-name>EncodingFilter</filter-name>

<url-pattern>/*</url-pattern>

</filter-mapping>


[崔5]包含HttpServletRequst

[崔6]创建本类对象时,需要提供底层request,以及字符集

[崔7]重写getParameter()方法

[崔8]把底层对象转换成HttpServletRequest

[崔9]获取请求方法

[崔10]如果是post请求

[崔11]设置编码,OK!

[崔12]如果是GET请求

[崔13]通过底层对象获取参数

[崔14]把参数转码

[崔15]返回转码后的参数值

[崔16]获取初始化参数

[崔17]如果没有配置初始化参数,那么把字符集设置为utf-8

[崔18]创建EncodingRequest对象,使用request为底层对象

[崔19]放行!这时用户获取到的request就是EncodingRequest对象了!

Java_Web学习笔记_过滤器应用案例(解决全站字符乱码)的更多相关文章

  1. 学习笔记_过滤器详细(过滤器JavaWeb三大组件之一)

    过滤器详细 1 过滤器的生命周期 我们已经学习过Servlet的生命周期,那么Filter的生命周期也就没有什么难度了! (l)  init(FilterConfig):在服务器启动时会创建Filte ...

  2. 学习笔记_过滤器应用_1(分ip统计网站的访问次数)

    分ip统计网站的访问次数 ip count 192.168.1.111 2 192.168.1.112 59 统计工作需要在所有资源之前都执行,那么就可以放到Filter中了. 我们这个过滤器不打算做 ...

  3. 学习笔记_过滤器详细_2(过滤器JavaWeb三大组件之一)

    过滤器详细 5 四种拦截方式 我们来做个测试,写一个过滤器,指定过滤的资源为b.jsp,然后我们在浏览器中直接访问b.jsp,你会发现过滤器执行了! 但是,当我们在a.jsp中request.getR ...

  4. 学习笔记_过滤器概述(过滤器JavaWeb三大组件之一)

    过滤器Filter Filter和Lister是Servlet规范里的两个高级特性.不同于Servlet,它们不用于处理客户端请求,只用于对request.response进行修改或者对context ...

  5. 学习笔记_过滤器应用(粗粒度权限控制(拦截是否登录、拦截用户名admin权限))

    RBAC ->基于角色的权限控制 l  tb_user l  tb_role l  tb_userrole l  tb_menu(增.删.改.查) l  tb_rolemenu 1 说明 我们给 ...

  6. 解决全站字符乱码(POST和GET中文编码问题)

    1 说明 乱码问题: 获取请求参数中的乱码问题: POST请求:request.setCharacterEncoding(“utf-8”): GET请求:new String(request.getP ...

  7. ArcGIS案例学习笔记3_1_地理配准案例_目视找点

    ArcGIS案例学习笔记3_1_地理配准案例_目视找点 计划时间:第3天上午 方法:地理配准/添加链接点/左键/右键/输入坐标 数据:江苏省.zip 矢量:省界,市界,GPS WGS84 地理坐标系 ...

  8. ArcGIS案例学习笔记3_1_地理配准案例_图面控制点

    ArcGIS案例学习笔记3_1_地理配准案例_图面控制点 计划时间:第3天上午 目的:地形图控制点配准 数据:地形图drg 无坐标: 步骤 1.查看地图标注 2. 地理配准,添加控制点 3.结果: 联 ...

  9. jQuery源代码学习笔记_工具函数_noop/error/now/trim

    jQuery源代码学习笔记_工具函数_noop/error/now/trim jquery提供了一系列的工具函数,用于支持其运行,今天主要分析noop/error/now/trim这4个函数: 1.n ...

随机推荐

  1. 揭开嵌入式c面试题背后的玄机

    今天老大让我针对一个面试者出些嵌入式方面的面试题,主要是想对他的技术深度进一步了解.我就出了下面这些问题,每个问题背后都是考察一个嵌入式程序员应该具备的相关技能.当然这些只是我的个人理解,不一定正确. ...

  2. TCA9546A

    The TCA9546A is a 4-channel, bidirectional translating switch for I 2 C buses that supports Standard ...

  3. C++中构造函数和析构函数调用的时机

    今天看书忽然对这个地方有点模糊,尤其是析构函数在调用默认的析构函数和用户自己覆写的析构函数的时候有点意识模糊呢.写段代码总结下 #include <iostream> using name ...

  4. HW1.6

    public class Solution { public static void main(String[] args) { System.out.println("1 + 2 + 3 ...

  5. 巧用TAG属性保存对象的指针

    指针的数据类型是整型,一个指针就是一个整型的数值. 所以凡整型的变量(这个整型的变量可以是声明在INI文件中,也可以是声明在函数中的)也好,对象的整型的属性也好,都可以用来存储一个指针. 但对象往往没 ...

  6. C++:private继承与public继承

    1 private, public, protected 访问标号的访问范围 private:只能由1.该类中的函数.2.其友元函数访问. 不能被任何其他访问,该类的对象也不能访问. protecte ...

  7. Selenium 进行web自动化测试

    1.安装火狐版本时注意,如果无法正常安装,应该点击右键---以管理员身份运行 2.安装成功后,选择工具--选项--高级--更新,停止其自动化更新 3.maven里面加载应有的selenium的组件

  8. 史上最全的ASP.NET MVC路由配置,以后RouteConfig再弄不懂神仙都难救你啦~

    继续延续坑爹标题系列.其实只是把apress.pro.asp.net.mvc.4.framework里的CHAPTER 13翻译过来罢了,当做自己总结吧.内容看看就好,排版就不要吐槽了,反正我知道你也 ...

  9. JavaWeb国际化

    软件的国际化: 软件在不同的地方,适应不同的风格: 中国: 显示中文,以及服务符合中国习惯的文本字符串! 美国: 显示英文,以及服务符合他国习惯的文本字符串! 这种软件,就叫国际化的软件! 如何做到国 ...

  10. Oracle数据库编程:PL/SQL编程基础

    2.PL/SQL编程基础: PL/SQL块:        declare        定义部分        begin        执行部分        exception        异 ...