开发者社区> loveincode> 正文

JavaWeb 后端 <十二> 之 过滤器 filter 乱码、不缓存、脏话、标记、自动登录、全站压缩过滤器

简介:
+关注继续查看

一、过滤器是什么?有什么?

1、过滤器属于Servlet规范,从2.3版本就开始有了。

2、过滤器就是对访问的内容进行筛选(拦截)。利用过滤器对请求和响应进行过滤

二、编写步骤和执行过程

1、编码步骤:

a、编写一个类:实现javax.servlet.Filter接口


public class FilterDemo1 implements Filter {
     
    public FilterDemo1(){
        System.out.println("调用了默认的构造方法");
    }
     
    //用户每次访问被过滤的资源,都会由服务器调用该方法实现过滤
    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {
        System.out.println("FilterDemo1执行过滤前");
        //对请求进行拦截,代码写在这
        chain.doFilter(request, response);//放行
        //对响应进行拦截,代码写在这
        System.out.println("FilterDemo1执行过滤后");
    }
 
    public void destroy() {
        System.out.println("调用了销毁方法");
    }
 
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("调用初始化方法");
    }
 
}

 b、配置web.xml,指定需要过滤的资源。(和Servlet的配置相当类似)

2、过滤器的执行过程(生命周期)

生命周期:

诞生:过滤器的实例是在应用被加载时就完成的实例化,并初始化的。

存活:和应用的生命周期一致的。在内存中是单例的。针对拦截范围内的资源访问,每次访问都会调用void doFIlter(request,response.chain)进行拦截。

死亡:应用被卸载。

 

三、串联过滤器

一个过滤器接着另外一个过滤器。执行的顺序  按照web.xml的先后顺序

随意 访问  会先直接FilterDemo2 的 再执行 FilterDemo3的

会输出 :

FilterDemo2前

FilterDemo3前

执行内容

FilterDemo3后

FilterDemo2后

四、案例:

1、解决请求参数(POST)和响应输出的乱码过滤器


//解决post方式请求参数和响应编码问题的过滤器
public class SetCharacterEncodingFilter implements Filter {
    private FilterConfig filterConfig;
    public void init(FilterConfig filterConfig) throws ServletException {
        this.filterConfig = filterConfig;
    }
 
    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {
         
        String encoding = filterConfig.getInitParameter("encoding");//用户可能忘记了配置该参数
        if(encoding==null){
            encoding = "UTF-8";//默认编码
        }
         
        request.setCharacterEncoding(encoding);//只能解决POST请求参数的中文问题
        response.setCharacterEncoding(encoding);//输出流编码
        response.setContentType("text/html;charset="+encoding);//输出流编码,通知了客户端应该使用的编码
        chain.doFilter(request, response);
    }
 
    public void destroy() {
 
    }
 
}

将 编码类型写在 Filter参数中

 

 

2、动态资源不要缓存的过滤器

Servlet/JSP:动态资源不要缓存。

 

这里 将 Servletrequest 和 ServletResponse 转换为 HttpServlet 的方法 避免发生错误


HttpServletRequest request = null;
HttpServletResponse response = null;
try{
  request  = (HttpServletRequest)req;
  response = (HttpServletResponse)resp;<br>}catch(Exception e){
  throw new RuntimeException("not-http request or response");
}

//控制动态资源不要缓存过滤器
public class NoCacheFilter implements Filter {
 
    public void init(FilterConfig filterConfig) throws ServletException {
 
    }
 
    public void doFilter(ServletRequest req, ServletResponse resp,
            FilterChain chain) throws IOException, ServletException {
         
//      HttpServletRequest request = (HttpServletRequest)req;
//      HttpServletResponse response = (HttpServletResponse)resp;   不使用该方法
         
        HttpServletRequest request = null;
        HttpServletResponse response = null;
        try{
            request  = (HttpServletRequest)req;
            response = (HttpServletResponse)resp;
        }catch(Exception e){
            throw new RuntimeException("not-http request or response");
        }
        response.setHeader("Expires", "-1");
        response.setHeader("Cache-Control", "no-cache");
        response.setHeader("Pragma", "no-cache");
        chain.doFilter(request, response);
    }
 
    public void destroy() {
 
    }
 
}

动态过滤掉 Servlet 和Jsp

3、静态资源控制缓存时间的过滤器


//控制静态资源的缓存时间
public class StaticResourcesNeedCacheFilter implements Filter {
    private FilterConfig filterConfig;
    public void init(FilterConfig filterConfig) throws ServletException {
        this.filterConfig = filterConfig;
    }
 
    public void doFilter(ServletRequest req, ServletResponse resp,
            FilterChain chain) throws IOException, ServletException {
        HttpServletRequest request = null;
        HttpServletResponse response = null;
        try{
            request  = (HttpServletRequest)req;
            response = (HttpServletResponse)resp;
        }catch(Exception e){
            throw new RuntimeException("not-http request or response");
        }
        long time = 0;//缓存的时间
         
        //根据用户请求的uri地址的后缀:/day19_00_filter/1.html
        String uri  = request.getRequestURI();
        String exName = uri.substring(uri.lastIndexOf(".")+1);
        if("html".equals(exName)){
            String value = filterConfig.getInitParameter("html");//小时
            time = Long.parseLong(value)*60*60*1000;
        }
        if("css".equals(exName)){
            String value = filterConfig.getInitParameter("css");//小时
            time = Long.parseLong(value)*60*60*1000;
        }
        if("js".equals(exName)){
            String value = filterConfig.getInitParameter("js");//小时
            time = Long.parseLong(value)*60*60*1000;
        }
         
        response.setDateHeader("Expires", System.currentTimeMillis()+time);  //Expires 控制时间
        chain.doFilter(request, response);
    }
 
    public void destroy() {
 
    }
 
}

 

4、//*用户自动登录过滤器:

使用了Md5 加密

Base64编码:很重要

编写


//自动登录过滤器
public class AutoLoginFilter implements Filter {
    private  BusinessService s = new BusinessServiceImpl();
    public void init(FilterConfig filterConfig) throws ServletException {
 
    }
 
    public void doFilter(ServletRequest req, ServletResponse resp,
            FilterChain chain) throws IOException, ServletException {
         
        HttpServletRequest request = null;
        HttpServletResponse response = null;
        try{
            request  = (HttpServletRequest)req;
            response = (HttpServletResponse)resp;
        }catch(Exception e){
            throw new RuntimeException("not-http request or response");
        }
        HttpSession session = request.getSession();
        //判断用户有没有登录:只管没有登录的
        User sUser = (User)session.getAttribute("user");
        if(sUser==null){
            //找loginInfo的cookie:只管找到的
            Cookie cs[] = request.getCookies();
            for(int i=0;cs!=null&&i<cs.length;i++){
                if("loginInfo".equals(cs[i].getName())){
                    //解出用户名(Base64)和密码(MD5)
                    String usernamePassword = cs[i].getValue();
                    String username = usernamePassword.split("_")[0];//base64编码后的
                    String password = usernamePassword.split("_")[1];//MD5加密后的
                    //调用Service再次验证正确性
                    User user = s.login(SecurityUtil.base64decode(username), password);
                    //通过:登录。在HttpSession中设置登录标记
                    if(user!=null){
                        session.setAttribute("user", user);
                    }
                }
            }
        }
        chain.doFilter(request, response);
    }
 
    public void destroy() {
 
    }
 
}

五、过滤器配置的细节

 

六、巩固装饰设计模式

一、装饰

1、编写一个类,实现与被包装类(数据库驱动对Connection的实现)相同的接口。(使这个类和数据库的驱动实现有着相同的行为)

2、定义一个变量,引用被包装类的实例。

3、定义构造方法,传入被包装类的实例。

4、对于要改写的方法,编写自己的代码即可。

5、对于不需要改写的方法,调用原有对象的对应方法。

二、装饰变体(BufferedReader本身就是包装类,对Reader的包装。LineNumberReader,对BufferedReader的包装,还是他的子类)

1、编写一个类,继承已经是包装类的类。

2、定义一个变量,引用被包装类的实例。

3、定义构造方法,传入被包装类的实例。

4、覆盖掉需要改写的方法

七、案例:

1、解决全站中文乱码过滤器

之前解决了 post 的乱码 问题 这里 添加 get的 解决问题

1.定义一个类 EncodingHttpServletRequest 继承 HttpServletRequestWrapper  前对 后 的 包装 得到自己想要的 方法

2.重写  HttpServletRequestWrapper 的 getParameter 方法 。

3.将get传入的值使用 该 super.getCharacterEncoding()的编码 方式返回

如果 使用 get方法 就可以 得到 应有的编码方式


public class SetCharacterEncodingFilter implements Filter {
    private FilterConfig filterConfig;
    public void init(FilterConfig filterConfig) throws ServletException {
        this.filterConfig = filterConfig;
    }
 
    public void doFilter(ServletRequest req, ServletResponse resp,
            FilterChain chain) throws IOException, ServletException {
         
        HttpServletRequest request;
        HttpServletResponse response;
        try{
            request = (HttpServletRequest)req;
            response = (HttpServletResponse)resp;
        }catch(Exception e){
            throw new RuntimeException("non-http request or response");
        }
         
        String encoding = filterConfig.getInitParameter("encoding");//用户可能忘记了配置该参数
        if(encoding==null){
            encoding = "UTF-8";//默认编码
        }
         
        request.setCharacterEncoding(encoding);//只能解决POST请求参数的中文问题
        response.setCharacterEncoding(encoding);//输出流编码
        response.setContentType("text/html;charset="+encoding);//输出流编码,通知了客户端应该使用的编码
         
        EncodingHttpServletRequest erequest = new EncodingHttpServletRequest(request);
         
        chain.doFilter(erequest, response);
    }
 
    public void destroy() {
 
    }
 
}
class EncodingHttpServletRequest extends HttpServletRequestWrapper{
    public EncodingHttpServletRequest(HttpServletRequest request){
        super(request);
    }
 
    public String getParameter(String name) {
        String value = super.getParameter(name);
        if(value==null)
            return value;
        //只管get方式
        if("get".equalsIgnoreCase(super.getMethod())){
            try {
                value = new String(value.getBytes("ISO-8859-1"),super.getCharacterEncoding());
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
        }
        return value;
    }
     
}

2、过滤脏话过滤器

1.新建 DWHttpServletRequest 类 继承  HttpServletRequestWrapper ,

2.包装 getParameter 发方法  过滤 脏话

3.执行 内容  时 得到的是  DWHttpServletRequest 的 request 所以使用的方法是 DWHttpServletRequest的 getParameter。


public class DirtyWordsFilter implements Filter {
 
    public void init(FilterConfig filterConfig) throws ServletException {
    }
 
    public void doFilter(ServletRequest req, ServletResponse resp,
            FilterChain chain) throws IOException, ServletException {
         
        HttpServletRequest request;
        HttpServletResponse response;
        try{
            request = (HttpServletRequest)req;
            response = (HttpServletResponse)resp;
        }catch(Exception e){
            throw new RuntimeException("non-http request or response");
        }
        DWHttpServletRequest dwrequest = new DWHttpServletRequest(request);
        chain.doFilter(dwrequest, response);
 
    }
 
    public void destroy() {
    }
 
}
class DWHttpServletRequest extends HttpServletRequestWrapper{
    private String[] strs = {"禽兽","畜生","傻B","张新鹏"};
    public DWHttpServletRequest(HttpServletRequest request){
        super(request);
    }
 
    public String getParameter(String name) {
        String value = super.getParameter(name);
        if(value==null)
            return value;
         
        for(String s:strs){
            value = value.replace(s, "**");
        }
        return value;
    }
}

3、html标记过滤器

方法和前2种类似


public class HtmlFilter implements Filter {
 
    public void init(FilterConfig filterConfig) throws ServletException {
    }
 
    public void doFilter(ServletRequest req, ServletResponse resp,
            FilterChain chain) throws IOException, ServletException {
         
        HttpServletRequest request;
        HttpServletResponse response;
        try{
            request = (HttpServletRequest)req;
            response = (HttpServletResponse)resp;
        }catch(Exception e){
            throw new RuntimeException("non-http request or response");
        }
        HtmlHttpServletRequest hrequest = new HtmlHttpServletRequest(request);
        chain.doFilter(hrequest, response);
 
    }
 
    public void destroy() {
    }
 
}
class HtmlHttpServletRequest extends HttpServletRequestWrapper{
    public HtmlHttpServletRequest(HttpServletRequest request){
        super(request);
    }
 
    public String getParameter(String name) {
        String value = super.getParameter(name);
        if(value==null)
            return value;
         
        value = htmlFilter(value);//转义字符
        return value;
    }
 
    private String htmlFilter(String message) {
        if (message == null)
            return (null);
 
        char content[] = new char[message.length()];
        message.getChars(0, message.length(), content, 0);
        StringBuffer result = new StringBuffer(content.length + 50);
        for (int i = 0; i < content.length; i++) {
            switch (content[i]) {
            case '<':
                result.append("<");
                break;
            case '>':
                result.append(">");
                break;
            case '&':
                result.append("&");
                break;
            case '"':
                result.append(""");
                break;
            default:
                result.append(content[i]);
            }
        }
        return (result.toString());
    }
}

4、//*全站压缩过滤器(有难度)


public class GzipFilter implements Filter {
 
    public void init(FilterConfig filterConfig) throws ServletException {
 
    }
 
    public void doFilter(ServletRequest req, ServletResponse resp,
            FilterChain chain) throws IOException, ServletException {
        HttpServletRequest request;
        HttpServletResponse response;
        try{
            request = (HttpServletRequest)req;
            response = (HttpServletResponse)resp;
        }catch(Exception e){
            throw new RuntimeException("non-http request or response");
        }
        GzipHttpServletResponse gresponse = new GzipHttpServletResponse(response);
        chain.doFilter(request, gresponse);
        //目标资源执行完毕后执行:要压缩
        byte b[] = gresponse.getBytes();//得到原始的数据为编码的关键点
        System.out.println("压缩前大小:"+b.length);
        //判断客户是否支持gzip压缩
        String acceptEncoding = request.getHeader("Accept-Encoding");
        if(acceptEncoding!=null&&acceptEncoding.contains("gzip")){
            //支持
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            GZIPOutputStream gout = new GZIPOutputStream(out);
            gout.write(b);
            gout.close();
             
            b = out.toByteArray();//压缩后的数据
            System.out.println("压缩后大小:"+b.length);
            //告知浏览器压缩方式
            response.setHeader("Content-Encoding", "gzip");
            response.setContentLength(b.length);//告知客户端,正文的长度
        }
        response.getOutputStream().write(b);
    }
 
    public void destroy() {
 
    }
 
}
class GzipHttpServletResponse extends HttpServletResponseWrapper{
    private ByteArrayOutputStream baos = new ByteArrayOutputStream();//存放截获的数据
     
    private PrintWriter pw = null;
    public GzipHttpServletResponse(HttpServletResponse response){
        super(response);
    }
    //截获输出的数据:放到baos中
    public ServletOutputStream getOutputStream() throws IOException {
        return new MyServletOutputStream(baos);
    }
     
    //字符流:截获放到baos中
    public PrintWriter getWriter() throws IOException {
        pw = new PrintWriter(new OutputStreamWriter(baos, super.getCharacterEncoding()));
        return pw;
    }
    //获取截获的数据
    public byte[] getBytes(){
        try {
            if(pw!=null){
                pw.close();
            }
            baos.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return baos.toByteArray();
    }
}
class MyServletOutputStream extends ServletOutputStream{
    private ByteArrayOutputStream baos;
    public MyServletOutputStream(ByteArrayOutputStream baos){
        this.baos = baos;
    }
    public void write(int b) throws IOException {
        baos.write(b);
    }
     
}

 

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
从2开始,在Go语言后端业务系统中引入缓存
从2开始,在Go语言后端业务系统中引入缓存
63 0
【JavaWeb】【JSP】JSP传值到Servlet后端为NULL的问题
【JavaWeb】【JSP】JSP传值到Servlet后端为NULL的问题
48 0
后端缓存的23个关键关注点(3)
后端缓存的23个关键关注点(3)
93 0
后端缓存的23个关键关注点(2)
后端缓存的23个关键关注点(2)
68 0
后端缓存的23个关键关注点(1)
后端缓存的23个关键关注点(1)
61 0
高可用后端架构设计实战-利用request cache请求缓存优化批量查询接口
高可用后端架构设计实战-利用request cache请求缓存优化批量查询接口
86 0
+关注
loveincode
勤奋上进
文章
问答
文章排行榜
最热
最新
相关电子书
更多
机器学习在互联网后端技术中的应用
立即下载
十分钟上线-使用函数计算构建支付宝小程序服务
立即下载
机器学习在互联网后端技术中的应用
立即下载