过滤器监视器应用

过滤器之编码

get方式的解码无法通过request设置。需要增强request。sun公司也知道我们可能对request对象的方法不满意,于是提供了HttpServletRequestWrapper类给我们实现(如果实现HttpServletRequest接口的话,要实现太多的方法了!

类似静态代理的增强request:

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.UnsupportedEncodingException;

public class MyRequest extends HttpServletRequestWrapper {
//    静态代理,用来增强HttpServletRequest
//    1.与被增强类实现共同的接口ServletRequest
//    2.代理类中声明一个变量记住被增强对象
//    3.代理类中创建构造方法用来接受被增强类
    HttpServletRequest httpServletRequest;
    public  MyRequest(HttpServletRequest httpServletRequest ){
        super(httpServletRequest);
        this.httpServletRequest=httpServletRequest;
    }

    @Override
    public String getParameter(String name) {
//        操作httpServletRequest,覆盖要增强的方法
       String strname=httpServletRequest.getParameter("name");
       if(strname == null)
           return null;
//       不是get请求,=按照原来方法执行
       if( httpServletRequest.getMethod() != "get")
           return  strname;
//       get方法  ISO8859-1为tomcat编码
        try {
            return new String(strname.getBytes("ISO8859-1"),httpServletRequest.getCharacterEncoding());
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return null;
    }
}

编写过滤器:

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebFilter(urlPatterns = "/fliter")
public class FilterEncode implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
//            get方法无法通过设置request.setCharacterEncoding();改变编码,
//              因此可以通过增强getParameter()方式来改变编码
//           静态代理类 MyRequest
        HttpServletRequest request=(HttpServletRequest) servletRequest;
        HttpServletResponse response=(HttpServletResponse) servletResponse;
        request.setCharacterEncoding("UTF-8");
        response.setContentType("text/html;charset=UTF-8");
//        增强request
        MyRequest myRequest = new MyRequest(request);
//        将增强的request放行
        filterChain.doFilter(myRequest,response);
    }

    @Override
    public void destroy() {

    }
}

动态代理设置过滤器:

  @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

        HttpServletResponse response=(HttpServletResponse) servletResponse;
        HttpServletRequest request=(HttpServletRequest) servletRequest;
        request.setCharacterEncoding("UTF-8");
        response.setContentType("text/html;charset=UTF-8");
        filterChain.doFilter((HttpServletRequest)Proxy.newProxyInstance(DynamicFilter.class.getClassLoader(), request.getClass().getInterfaces(), new InvocationHandler() {
            @Override
//            会拦截代理对象的任何方法 对request方法增强
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println("zhixinginvoke");
                  if( ! method.getName().equals("getParameter"))
                     return method.invoke(request,args);
                    if( ! request.getMethod().equalsIgnoreCase( "get"))
                        return method.invoke(request,args);
//                    执行到这只能是get方法

                      String name=(String) method.invoke(request,args);
              
                      if(name == null)
                          return null;
                      return new String(name.getBytes("ISO8859-1"),"UTF-8");


            }
        }),response);
        System.out.println("动态代理");
    }

过滤器之压缩

先介绍GZIPOutputStream的使用

# 将压缩的数据写入ByteArrayOutPutStream中
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        GZIPOutputStream gzipOutputStream = new GZIPOutputStream(byteArrayOutputStream);
        gzipOutputStream.write(bytes);
        gzipOutputStream.flush();
  • 通常情况下servlet中,一般使用getOutPutStream获取ServletOutputStream对象 ,或者通过getWriter获得Printwriter对象,在再过write()将数据写在浏览器。
  • 为了压缩数据,通过继承HttpServletResponseWrapper来增强getOutputStream(ServletOutputStream getOutputStream())和getWriter (PrintWriter getWriter())方法把数据写在ByteArrayOutputStream
  • 同时增强ServletOutputStream的write方法,因为PrintWriter 本身是包装类,本身就能实现将数据写在ByteArrayOutputStream

增强response:

public class MaxServletReposneWrapper extends HttpServletResponseWrapper {
//    增强response 相当于增强response将原本应该输入到浏览器的数据,输入到ByteArrayOutputStream
//    将数据写入ByteArrayOutputStream,并且提供接口,输出,以用来在过滤器中压缩数据
    ByteArrayOutputStream byteArrayOutputStream=new ByteArrayOutputStream();
    HttpServletResponse response ;
    PrintWriter printWriter;
    MaxServletReposneWrapper(HttpServletResponse response ){
        super(response);
        this.response=response;
    }
    @Override
    public ServletOutputStream getOutputStream() throws IOException {
        return new MaxServletOutPutStream(byteArrayOutputStream);
    }

    @Override
    public PrintWriter getWriter() throws IOException {
        System.out.println("pW______");
        printWriter=new PrintWriter(new OutputStreamWriter(byteArrayOutputStream,this.response.getCharacterEncoding()));
        return  printWriter;
    }
    byte[] getOutBytes(){
        try {

            //防止数据在缓存中,要刷新一下!
            if (printWriter != null) {
                printWriter.close();
            }
            if (byteArrayOutputStream != null) {
                System.out.println("bukong");
                byteArrayOutputStream.flush();
                return byteArrayOutputStream.toByteArray();
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;

    }
}

增强 ServletOutStream

public class MaxServletOutPutStream extends ServletOutputStream {
    ByteArrayOutputStream byteArrayOutputStream;
    MaxServletOutPutStream( ByteArrayOutputStream byteArrayOutputStream){
        this.byteArrayOutputStream=byteArrayOutputStream;
    }
    @Override
    public void write(int b) throws IOException {
        this.byteArrayOutputStream.write(b);//????? zhong
    }

过滤器:

public class ZipFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
    
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        MaxServletReposneWrapper myResponse = new MaxServletReposneWrapper(response);

        //把被增强的response对象传递进去,目标资源调用write()方法的时候就不会直接把数据写在浏览器上了
        filterChain.doFilter(request, myResponse);

        //得到目标资源想要返回给浏览器的数据
        byte[] bytes = myResponse.getOutBytes();

        //输出原来的大小
        System.out.println("压缩前:"+bytes.length);


        //使用GZIP来压缩资源,再返回给浏览器
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        GZIPOutputStream gzipOutputStream = new GZIPOutputStream(byteArrayOutputStream);
        gzipOutputStream.write(bytes);
        gzipOutputStream.flush();
        byteArrayOutputStream.flush();

        //得到压缩后的数据
        byte[] gzip = byteArrayOutputStream.toByteArray();

        System.out.println("压缩后:" + gzip.length);
        response.setHeader("Content-Disposition", "attachment; filename=chen.zip" );
        //还要设置头,告诉浏览器,这是压缩数据!
     response.setHeader("content-encoding", "gzip");
        response.setContentLength(gzip.length);
        response.getOutputStream().write(gzip);
        

    }

    @Override
    public void destroy() {

    }
}

测试:

protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.getWriter().write("fdshfidsuhfidusfhuidsfhuidshdsuifhsd" +
                "uifhsduifffffdshfidsuhfidusfhuidsfhuidshdsuif" +
                "hsduifhsduifffffdshfidsuhfidusfhuidsfhuidshd" +
                "suifhsduifhsduifffffdshfidsuhfidusfhuidsfhuidsh" +
                "dsuifhsduifhsduifffffdshfidsuhfidusfhuidsfhuids" +
                "hdsuifhsduifhsduifffffdshfidsuhfidusfhuidsfhuid" +
                "shdsuifhsduifhsduiffdshfidsuhfidusfhuidsfhuids" +
                "hdsuifhsduifhsduifffffdshfidsuhfidusfhuidsfhui" +
                "dshdsuifhsduifhsduifffffdshfidsuhfidusfhuidsfh" +
                "uidshdsuifhsduifhsduifffffdshfidsuhfidusfhuids" +
                "fhuidshdsuifhsduifhsduifffffdshfidsuhfidusfhuid" +
                "sfhuidshdsuifhsduifhsduifffffdshfidsuhfidusfhui" +
                "dsfhuidshdsuifhsduifhsduifffffdshfidsuhfidusfh" +
                "uidsfhuidshdsuifhsduifhsduifffffdshfidsuhfidusf" +
                "huidsfhuidshdsuifhsduifhsduifffffdshfidsuhfidus" +
                "fhuidsfhuidshdsuifhsduifhsduifffffdshfidsuhfid" +
                "usfhuidsfhuidshdsuifhsduifhsduifffffdshfidsuhf" +
                "idusfhuidsfhuidshdsuifhsduifhsd" +
                "uifffffdshfidsuhfidusfhuidsfhuidshdsuifhsduifhsduifffffff");

    }

过滤器之敏感词过滤

增强request:


    class MyDirtyRequest extends HttpServletRequestWrapper {
    
        HttpServletRequest request;
    
        //定义一堆敏感词汇
        private List<String> list = Arrays.asList("傻b", "尼玛", "操蛋");
    
        public MyDirtyRequest(HttpServletRequest request) {
            super(request);
            this.request = request;
        }
    
        @Override
        public String getParameter(String name) {
    
            String value = this.request.getParameter(name);
    
            if (value == null) {
                return null;
            }
    
            //遍历list集合,看看获取得到的数据有没有敏感词汇
            for (String s : list) {
    
                if (s.equals(value)) {
                    value = "*****";
                }
            }
    
            return value ;
        }
    }

监听器之检测上线人数

  • 通过监听session的创建和销毁来,检测上线人数,因此实现HttpSessionListener
  • 不用自己创建session和销毁session,因为服务器会自动创建一个session,以及jESSIONID的cookie
  • 此cookie的MaxAge为-1,即浏览器关闭后,cookie消失,但是session依然还在服务器,只是无法通过jessionid找出来,因此可以设置session的存活时间,来模拟session的销毁

监听器:

httpSessionEvent.getSession().getServletContext()

public class LSession implements HttpSessionListener {
    @Override
    public void sessionCreated(HttpSessionEvent httpSessionEvent) {
        ServletContext servletContext=httpSessionEvent.getSession().getServletContext();
        Integer num=(Integer) servletContext.getAttribute("num");
        if(num == null){
            servletContext.setAttribute("num",1);
        }else{
            num++;
            servletContext.setAttribute("num",num);
        }
    }

    @Override
    public void sessionDestroyed(HttpSessionEvent httpSessionEvent) {
        ServletContext servletContext=httpSessionEvent.getSession().getServletContext();
        Integer num =(Integer) servletContext.getAttribute("num");
        if(num == null){
            servletContext.setAttribute("num",0);
        }else{
            num--;
            servletContext.setAttribute("num",num);
        }
    }
}

web.xmlj配置监听器和session存活时间

 <session-config>
        <session-timeout>1</session-timeout>
    </session-config>
    <listener>
        <listener-class>ListenerSession.LSession</listener-class>
    </listener>

jsp测试:

 在线人数:${num}

新打开浏览器会增加在线人数,关闭不会销毁session,过了session存活时间才会销毁。

关闭在打开,增加人数。

监听器之session扫描器

  • 定时扫描session,移除未使用的session

  • 因为要移除session【使用invalidate方法】,所以使用容器,保存session

  • 定时扫描session,所以要用到Timer

    #Timer的使用
    # 1.创建Timer
    # 2.使用timer.schedule(TimerTask,time)
    # 3.编写自己的TimerTask
    
  • 容器添加session和定时扫描容器中所有的session,这两个动作要做好并发控制,可以设置一个全局的变量lock进行并发控制

  • 因为定时器应该在服务器一启动的时候,就应该被创建了。因此还需要监听ServletContext

定时器任务代码:

public class myTask extends TimerTask {
//    此处如果要使用监听器中的list 和 lock 可以通过构造方法引入 因为对象是引用类型,所以相当于操作监听器中的对象
    List<HttpSession> list;
    Object lock;
    myTask(List<HttpSession> list,Object lock){
        this.list=list;
        this.lock=lock;

    }
    @Override
    public void run() {
        synchronized (lock) {
            for (HttpSession session : list) {
//            为了测试,session未使用时间写成1min
                if (System.currentTimeMillis() - session.getLastAccessedTime() > 60 * 1000) {
                    session.invalidate();
                    list.remove(session);
                }
            }
        }
    }
}

监听器:


public class LContextSession implements HttpSessionListener, ServletContextListener {
    //   服务器已启动就创建容器     因为要频繁的增删改查所以用linkedlist 容器也应该是线程安全的。
    List<HttpSession> list= Collections.synchronizedList(new LinkedList<HttpSession>());
    private  Object lock=1;
    @Override
    public void contextInitialized(ServletContextEvent servletContextEvent) {
//        web引用已启动就添加定时器
        Timer timer=new Timer();
//        延迟为0,间隔60秒扫描一次
        timer.schedule(new myTask(list,lock),0,60*1000);
    }

    @Override
    public void contextDestroyed(ServletContextEvent servletContextEvent) {

    }

    @Override
    public void sessionCreated(HttpSessionEvent httpSessionEvent) {
        synchronized (lock){
            list.add(httpSessionEvent.getSession());
        }
        System.out.println("session创建了");
    }

    @Override
    public void sessionDestroyed(HttpSessionEvent httpSessionEvent) {
        System.out.println("session 销毁了");
    }
}

监听器之踢人小案例

  • 要监听哪个方法,就在哪个方法里写操作代码

  • 监听session属性的变化。在attributeAdded(HttpSessionBindingEvent sbe) 方法中写操作

  • 在此方法中,创建Map,存在ServletContext中,(如果map已存在,直接获取即可),并且把session放到Map中,以用来在servlet中踢人。

       //得到Session属性的值
    	Object o = sbe.getValue();
    
            //判断属性的内容是否是User对象
            if (o instanceof User) {
                User user = (User) o;
                map.put(user.getUsername(), sbe.getSession());
            }
    //解释:session只有在属性值为User的时候加入map中一次,如果此session再次添加其他类型的属性值,不会再把该session加入到map中
    
  • 写创建session的servlet

  • 视图层列出map中的所有session

  • 写踢人的servlet:从ServletContext中获取map,从视图层传入,要踢的人的key,从map中移除,并使session无效

https://segmentfault.com/a/1190000013252595

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值