消除全站字符乱码,修改request请求参数

ca88会员登录中心

  修改request参数的整体流程就是:会定义一个拦截器,在请求刚进入项目的时候,拦截住request,处理之后再将其放回。

乱码问题:

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中都要处理乱码问题,所以应该把这个工作放到过滤器中来完成。 

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

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

如果只是处理POST请求的编码问题,以及响应编码问题,这个就很好解决了response.setContentType(“text/html;charset=utf-8”);和request.setCharacterEncoding(“utf-8”);就可以解决的

 

好了,这里主要的就是解决GET请求参数的问题,我使用的方式是用过滤器(拦截器)Filter来解决,

我的思路是:

首先定义一过滤器allDecodingFilter的过滤器,这个过滤器是过滤全站的所有文件(<url-pattern>/*</url-pattern>),

1.要解决GET请求参数的问题,我们首先定义一个装饰类(这里涉及到了装饰者模式),装饰类通俗一点的说法就是把原有的类的方法或属性进行再改造。我就定义一个名为DecodingRequest的装饰类,这个类必须继承HttpServletRequestWrapper类,因为这个类继承了HttpServletRequest接口,并实现HttpServletRequest接口的所有方法,那么只要我继承了HttpServletRequestWrapper类就可以对该类里面的方法再重写了(有兴趣的话可以去看看j2ee源码)。这里主要就是重写getParameter(String
name)方法。

2.回到过滤器中,我就可以把我自己定义的DecodingRequest类传递给Servlet的doget()和dopost()方法,那么当需要获取参数调用getParameter(String
name)时,其实就是调用自己定义的getParameter(String
name)方法,那么就不会出现乱码了。口述的可能不好,我还是通过代码来说话吧

 

过滤器allDecodingFilter:

public class allDecodingFilter implements Filter {

    public void destroy() {
    }

    /**
     * @see Filter#doFilter(ServletRequest, ServletResponse, FilterChain)
     */
    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) request;

        //处理响应编码
        HttpServletResponse reps = (HttpServletResponse) response;
        response.setContentType("text/html;charset=utf-8");


        // 处理post请求参数的乱码
        request.setCharacterEncoding("utf-8");

        // 若是Get请求方式就使用装饰类的获取的参数的方法
        if (req.getMethod().equals("GET")) {

            HttpServletRequest newReq = new DecodingRequest(req);//这个类下一步会陈述
            /*
             * 调包request 1. 自己定义的request的装饰类 2. 在拦截通过时,使用我们自己定义request 3.
             * 在Servlet中
             * ,只有你调用request.getParameter(name)方法本质就是执行自己定义的request.getParameter
             * (name)方法
             */
            chain.doFilter(newReq, response);
        } else {
            // 若是post方式就不使用装饰类
            chain.doFilter(request, response);
        }
    }

    public void init(FilterConfig fConfig) throws ServletException {
    }

}

  装饰类DecodingRequest

/**
 *装饰类(这是装饰者模式)
 *HttpServletRequestWrapper:这个类帮我们实现了HttpServletRequest接口所有的方法,
 *那么我们就可以根据自己的需求对其里面的方法再进行实现
 */
public class DecodingRequest extends HttpServletRequestWrapper {
    private HttpServletRequest req;
    public DecodingRequest(HttpServletRequest request) {
        super(request);
        this.req=request;
    }
    /**
     * 获取到参数进而修改编码方式,当用户获取参数的时候就是执行了这个方法了
     */
    @Override
    public String getParameter(String name) {
        try {
            //修改字符编码方式
            name=new String(req.getParameter(name).getBytes("iso-8859-1"),"utf-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return name;
    }

}

  Servlet测试类

public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        //这里实质调用的是DecodingRequest类中的request.getParameter("uname");方法
        String name = request.getParameter("uname");
        System.out.println(name);
        response.getWriter().print(name);
    }

    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        String name = request.getParameter("uname");
        System.out.println(name);
        response.getWriter().print(name);
    }

  

其实全站乱码问题的难点就是处理GET请求参数的问题。
如果只是处理POST请求的…

//@WebFilter(filterName = "paramFilter", urlPatterns = "/*")//拦截器拦截所有请求
//@Order(100)//括号中的数字越大,在多个拦截器的执行顺序越靠前
public class ParamFilter extends OncePerRequestFilter{

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {

        HttpServletRequest wrapper = new RequestWrapper(request);//定义一个新的request(名称是wrapper),
        filterChain.doFilter(wrapper, response);//将修改过的request(wrapper)放回
    }

    private static class RequestWrapper extends HttpServletRequestWrapper {//这里用的是内部类,也可以不用

        private Map<String, String[]> params = new HashMap<String, String[]>();//将request对象中的参数修改后,放在这个集合里,随后项目取的所有Parameter都是从这个集合中取数

        public RequestWrapper(HttpServletRequest request) {//定义构造函数
            super(request);//将request交给父类

            //先通过request原生的方法,遍历获取到的参数
            Enumeration enu=request.getParameterNames(); 
            while (enu.hasMoreElements()) {
                String paraName=(String)enu.nextElement();

                Map<String, Object> paraObj = (Map<String, Object>)JSONUtils.parse(paraName);//因为我前台传过来的是json格式的参数
                Set<Entry<String, Object>> entrySet = paraObj.entrySet();
                for (Entry<String, Object> entry : entrySet) {
                    String key = entry.getKey();
                    Object value = entry.getValue();
                    params.put(key, value);//
                }
            }
            //在这里修改params中的数据,不管是添加、修改
            ......

            //将修改好的params重新放入RequestWrapper对象中
            addParameters(request,params);
        }
        public void addAllParameters(Map<String , Object>otherParams) {//增加多个参数
            for(Map.Entry<String , Object>entry : otherParams.entrySet()) {
                addParameter(entry.getKey() , entry.getValue());
            }
        }
        @Override
        public String getParameter(String name) {
             String[]values = params.get(name);
             if(values == null || values.length == 0) {
                 return null;
             }
             return StringEscapeUtils.escapeHtml4(values[0]);
        }
        @Override
        public Enumeration<String> getParameterNames() {
            Vector<String> v = new Vector<String>();
            Set<Entry<String, String[]>> entrySet = params.entrySet();
            for (Entry<String, String[]> entry : entrySet) {
                v.add(entry.getKey());
            }
            Enumeration<String> en =  v.elements();

            return v.elements();
        }

        @Override
        public String[] getParameterValues(String name) {
            return params.get(name);
        }
    }
}
2 分析

案例如下:

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对象了!

 

解决全站字符乱码(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”);

  本质上来讲,request请求当中的参数是无法更改的,也不能添加或者删除;
  但在后台程序中,一般对request的参数的操作,都是通过request的getParameter、getParameterNames、getParameterValues等方法执行的;所以我们要是能重写这些方法,就从侧面改变了request的请求参数。恰好,servlet就提供了一个HttpServletRequestWrapper类来供大家去继承(该类是HttpServletRequest的封装类,public
class HttpServletRequestWrapper extends ServletRequestWrapper
implements
  HttpServletRequest{}),重写request相关方法。

  其实全站乱码问题的难点就是处理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对象进行增强的手段:


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


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


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

 

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

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

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

 

1 说明

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图