使用过滤器(Filter)解决请求参数中文乱码问题(复杂方式)_增加过滤器后中文变成了ascii-程序员宅基地

技术标签: 乱码问题  

前述:
     在写这篇笔记之前,对笔记中的设计模式进行介绍:
     本篇笔记中将要使用到的设计模式是:装饰(包装)设计模式
          (1)装饰(包装)设计模式口诀:
               ①定义一个类,实现被装饰对象的接口
               ②定义一个成员变量,记住被装饰对象的引用
               ③定义构造方法,传入被装饰对象的实例
               ④改写要修改的方法
               ⑤不需要改写的方法,调用被装饰对象的原来的方法
 
          (2)什么时候使用装饰设计模式
               当我们需要对一个类进行增强的时候,增强后的类不再当前类的范畴
                    例如:现在有一个     Animal类     Cat和Dog都属于动物类型,因此可以直接继承
                                                                      现在新来一个“电子狗 ”,不属于动物的范围,但是有需要用其中的方法,这时候我们选择使用装饰(包装)设计模式
 
一:需求:统一解决请求参数中文乱码
  
二:需求原因:
     在没有该需求之前,解决请求乱码问题:

          (1)POST:

  1. //第一种  
  2. //request.setCharacterEncoding(this.getServletContext().getInitParameter("charset"));  
  3. //备注:这种获取方式是因为在web.xml中进行了如下配置  
  4.      <!-- 设置编码 -->  
  5.       <context-param>  
  6.             <param-name>charset</param-name>  
  7.             <param-value>UTF-8</param-value>  
  8.       </context-param>  
  9.    
  10. //第二种  
  11. request.setCharacterEncoding("utf-8");  

分析:第一种方式的好处是,在context中配置后,项目后期如果需要修改获取方式,直接修改配置文件即可,不要对.java文件进行修改
 
         (2)GET:

  1. String value = request.getParameter("value");  
  2.       if(value == null || value.trim().equals("")){  
  3.           value="";  
  4.       }  
  5.       value = new String(value.getBytes("ISO-8859-1"),"utf-8");  


三、优化思路:
     使用一个过滤器,在请求到达servlet之前,先对request对象设置编码
     要求所有的请求都要进行设置编码,因此所有的request都要拦截,进行增强,那么:

  1. <span style="white-space:pre">  </span><filter>  
  2.             <filter-name>EncodingFilter</filter-name>  
  3.             <filter-class>com.cqy.filter.EncodingFilter</filter-class>  
  4.       </filter>  
  5.    
  6.       <filter-mapping>  
  7.             <filter-name>EncodingFilter</filter-name>  
  8.             <url-pattern>/*</url-pattern>  
  9.       </filter-mapping>  


四:代码实现:
     1、过滤器代码
  1. package com.cqy.filter;  
  2.    
  3. import java.io.IOException;  
  4.    
  5. import javax.servlet.Filter;  
  6. import javax.servlet.FilterChain;  
  7. import javax.servlet.FilterConfig;  
  8. import javax.servlet.ServletException;  
  9. import javax.servlet.ServletRequest;  
  10. import javax.servlet.ServletResponse;  
  11. import javax.servlet.http.HttpServletRequest;  
  12. import javax.servlet.http.HttpServletResponse;  
  13.    
  14. import com.cqy.domain.MyRequest;  
  15.    
  16. public class EncodingFilter implements Filter {  
  17.    
  18.       @Override  
  19.       public void destroy() {  
  20.    
  21.       }  
  22.    
  23.       @Override  
  24.       public void doFilter(ServletRequest req, ServletResponse res,  
  25.                   FilterChain chain) throws IOException, ServletException {  
  26.             // 将请求和响应强制转换成Http形式  
  27.             HttpServletRequest request = (HttpServletRequest) req;  
  28.             HttpServletResponse response = (HttpServletResponse) res;  
  29.    
  30.             // 处理响应乱码  
  31.             response.setContentType("text/html;charset=utf-8");  
  32.    
  33.             // 自定义一个request对象:MyRequest,对服务器原来的requset进行增强,使用装饰设计模式  
  34.             // 要增强原来的request对象,必须先获取到原来的request对象  
  35.             MyRequest myRequest = new MyRequest(request);  
  36.    
  37.             // 注意:放行的时候应该传入增强后的request对象  
  38.             chain.doFilter(myRequest, response);  
  39.       }  
  40.    
  41.       @Override  
  42.       public void init(FilterConfig arg0) throws ServletException {  
  43.    
  44.       }  
  45.    
  46. }  


2、自定义增强类(MyRequest )

  1. package com.domain;  
  2.    
  3. import java.io.UnsupportedEncodingException;  
  4. import java.util.Map;  
  5. import java.util.Set;  
  6.    
  7. import javax.servlet.http.HttpServletRequest;  
  8. import javax.servlet.http.HttpServletRequestWrapper;  
  9.    
  10. /**  
  11.  * @author  继承HttpServletRequestWrapper相当于实现了HttpServletRequest  
  12.  *         HttpServletRequestWrapper类,它本身实现了所有HttpServletRequest的方法  
  13.  *         继承它之后,需要修改的方法MyRequest可以自己定义,不需要修改的方法,直接使用父类的方法  
  14.  *  
  15.  *         第一步:总结:继承HttpServletRequestWrapper,为了偷懒,  
  16.  *         不用自己去实现所有HttpServletRequest的方法 第二步:使用构造函数将原来的request对象保存到当前自定义对象中  
  17.  *         第三步:针对要修改的方法,进行增强 第四步:定义一个flag标记,防止编码重复执行  
  18.  */  
  19. public class MyRequest extends HttpServletRequestWrapper {  
  20.    
  21.     // 定义了一个成员变量,用来保存构造函数传入的requset对象  
  22.     private HttpServletRequest request = null;  
  23.    
  24.     // 定义一个标记,用来标注:当前requset中,请求参数,是否已经编码过了  
  25.     private boolean flag = false;  
  26.    
  27.     public MyRequest(HttpServletRequest request) {  
  28.         super(request);  
  29.         this.request = request;  
  30.    
  31.     }  
  32.    
  33.     // 总需求:对request对象的获取数据的方法,进行增强(统一编码)  
  34.    
  35.     @Override  
  36.     public Map<String, String[]> getParameterMap() {  
  37.         // 获得请求方式request.getMethod()方法  
  38.         String method = this.request.getMethod();  
  39.         // post请求  
  40.         if ("post".equalsIgnoreCase(method)) {  
  41.             // 设置编码格式  
  42.             try {  
  43.                 request.setCharacterEncoding("utf-8");  
  44.             } catch (UnsupportedEncodingException e) {  
  45.                 e.printStackTrace();  
  46.             }  
  47.             Map<String, String[]> map = this.request.getParameterMap();  
  48.             return map;  
  49.    
  50.         } else if ("get".equalsIgnoreCase(method)) {  
  51.             // get请求  
  52.             // 分析:get请求需要对每一个参数都进行转换,因此需要对map中的每个元素进行遍历  
  53.             // 首先获得map集合  
  54.             Map<String, String[]> map = this.request.getParameterMap();  
  55.    
  56.             //第一次获取请求参数,flag==false,执行后面的额乱码处理动作  
  57.             //第二次获取请求参数的时候,flag==true,不执行后面的处理,直接返回已经编码过的map集合  
  58.             if (flag) {  
  59.                 return map;  
  60.             }  
  61.             if (map == null) {  
  62.                 return super.getParameterMap();  
  63.             } else {  
  64.                 // 然后获得map集合的key  
  65.                 Set<String> key = map.keySet();  
  66.                 // 通过key将map中的元素取出来  
  67.                 for (String string : key) {  
  68.                     String[] value = map.get(string);  
  69.                     // 接下来需要将String中的每一个都进行遍历,转换参数  
  70.                     for (int i = 0; i < value.length; i++) {  
  71.                         try {  
  72.                             String string2 = new String(  
  73.                                     value[i].getBytes("iso-8859-1"), "utf-8");  
  74.                             value[i] = string2;  
  75.                         } catch (UnsupportedEncodingException e) {  
  76.                             e.printStackTrace();  
  77.                         }  
  78.                     }  
  79.                 }  
  80.                 flag = true;  
  81.                 return map;  
  82.             }  
  83.         } else {  
  84.             //位置请求方式,自定义对象处理不了,使用父类的方法处理  
  85.             return super.getParameterMap();  
  86.         }  
  87.     }  
  88.    
  89.     @Override  
  90.     public String[] getParameterValues(String name) {  
  91.         // 通过map集合获取参数  
  92.         Map<String, String[]> map = this.getParameterMap();  
  93.         if (map == null) {  
  94.             return super.getParameterValues(name);  
  95.         } else {  
  96.             String[] strings = map.get(name);  
  97.             return strings;  
  98.         }  
  99.     }  
  100.    
  101.     @Override  
  102.     public String getParameter(String name) {  
  103.         // 通过values获取参数  
  104.         String[] values = this.getParameterValues(name);  
  105.         if (values == null) {  
  106.             return super.getParameter(name);  
  107.         } else {  
  108.             return values[0];  
  109.         }  
  110.     }  
  111.    
  112. }  


版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_40950778/article/details/78539916

智能推荐

无责任Windows Azure SDK .NET开发入门篇三[使用Azure AD 管理用户信息--3.1 Index用户列表]...-程序员宅基地

文章浏览阅读79次。3.1 Index用户列表 或许当前域下的用户列表 [Authorize]public async Task<ActionResult> Index(){ var userList = new List<IUser>(); try { var client = AuthenticationHelper.G..._azure sdk .net 用法 登录azure

__attribute__ 总结___attribute__((warn_unused_result))-程序员宅基地

文章浏览阅读425次。&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; attribute是GNU C特色之一,在iOS用的比较广泛.系统中有许多地方使用到. attribute可以设置函数属性(Function Attribute )、变量属性(Variable Attrib___attribute__((warn_unused_result))

spring security oauth2之refresh token_spring security refresh token-程序员宅基地

文章浏览阅读9.6k次。oAuth2.0认证服务器生成的Access_token是有有效期限制的默认为12个小时,refresh_token默认为三十天。如果Access_token提示过期,可以根据refresh_token获取新的Access_token下面介绍如何生成refresh_token,并根据refresh_token获取新的Access_token:authorizedGrantTypesoa..._spring security refresh token

Python 玩出花儿了!一文教你用 Python 制作吃豆人游戏! | 附代码-程序员宅基地

文章浏览阅读7.2k次,点赞19次,收藏70次。作者 | 李秋键责编 | Carol封图 | CSDN 下载自视觉中国近几年来Python语言得到了快速发展,而Pygame作为Python开发应用和游戏必备的库更是展现了Python的..._python吃豆人实验原理

炸弹人(枚举解决)-程序员宅基地

文章浏览阅读327次。题目描述:现有关卡:游戏者只有一枚炸弹,且炸弹可以杀死杀伤范围内所有敌人。请问炸弹放在哪个位置,可以消灭最多的敌人。题目的抽象化墙用#表示,敌人用G表示,空地用.表示上代码#include<bits/stdc++.h>using namespace std;int main(){ char a[20][21];//建立一个二维字符数组,表示x行y列 i...

PhpStorm中如何使用database工具_phpstorm database显示字段备注-程序员宅基地

文章浏览阅读529次。http://blog.csdn.net/knight_quan/article/details/519830291.简介:PhpStorm是一个轻量级且便捷的PHP IDE,其提供的智能代码补全,快速导航以及即时错误检查等功能大大提高了编码效率。它以其独特的开发便利性,短时间内赢得了大量PHPer的青睐。MySQL是一个关系_phpstorm database显示字段备注

随便推点

51按键外部中断控制流水灯_case 0xfe: return 0; case 0xfd: return 1; case 0xf-程序员宅基地

文章浏览阅读2.1w次,点赞28次,收藏218次。实验二 外部按键输入一、实验目的1、了解单片机检测口方法2、了解单片机外部中断原理3、了解按键输入原理二、实验内容1、完成按键扫描控制流水灯2、完成按键外部中断控制流水灯三、实验原理四、实验电路与程序1、软件实验一:按键扫描控制流水灯1)实验要求:读取四个按键的输入,检测到按下后控制灯流动一段时间,然后继续读取按键输入。2)实验目的:1. 掌握按键消抖方法;2. 掌握单片机端口检测方法3)实验说明:通过本实验,可以了解单片机读取IO口电平的方法,同时也可以了解单片机编程,调试方_case 0xfe: return 0; case 0xfd: return 1; case 0xfb: return 2; case 0xf7

Android画文字自动换行实现技巧-程序员宅基地

文章浏览阅读609次。package com.dcs.tools;import java.util.Vector;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;import android.graphics.Paint.FontMetrics;import android.view.K..._android drawtext 换行

小程序中遇见文件过大的话就需要分包-程序员宅基地

文章浏览阅读331次。{ "pages": [ "pages/index/index", ], "subPackages": [   { "root": "A/", "pages": [ "pages/kaisuo/kaisuo" ] },    {..._分包引入组件

Android studio 打包apk release版本 安装闪退_andriod打包闪退-程序员宅基地

文章浏览阅读2.8k次,点赞3次,收藏7次。使用gradle配置signconfigrelease 中minifyEnabled true这一行导致输出的apk安装后运行失败 资源未找到改成:minifyEnabled false 正常运行 特此记录_andriod打包闪退

react父组件调用子组件方法_razor父组件调用子组件方法更新没有反应-程序员宅基地

文章浏览阅读4.2k次。把子组件的参数回传到父组件中,并且赋值给子组件的一个实例方法.参考React中文网: http://www.css88.com/react/docs/refs-and-the-dom.htmlimport React, {Component} from 'react';export default class Parent extends Component { render() {..._razor父组件调用子组件方法更新没有反应

cad细等线体不显示_CAD字体显示问号或全部不显示,处理方法-程序员宅基地

文章浏览阅读3k次。引言:CAD一搬使用仿宋字体,用这字体的好处:1、笔画粗细均匀,有长、方、扁三体;2、“仿宋_GB2312”字体(即CAD仿宋0.7字体)是印刷字体的一种,适用于各类打印、印刷工作;[]注:电脑自带的“仿宋”字体不是“仿宋_GB2312”字体,要带GB2312字样后缀才是CAD常用的字体],这个要分清整;3、该字体具有安装方便、特点鲜明的优势。电脑没有“仿宋_GB2312”字体,就上百度搜一下,如..._cad细等线体显示不出来

推荐文章

热门文章

相关标签