Java二阶段 Filter and Listener

Filter(过滤器)也是在服务器,负责检查过滤,也可以执行任何request,response的操作。

过滤器是在服务器开启时,就已经创建了。而servlet是可以改变创建时机的。,能过滤服务器的一切资源。切记,能执行request,response的一切操作和修改request,response的操作。还能转向。

在这里插入图片描述
在这里插入图片描述

配置Filter(web.xml)

在这里插入图片描述

在web.xml中

 <filter>
        <filter-name>MyFilter</filter-name>
        <filter-class>com.qf.servlet.MyFilter</filter-class>
    </filter>
    //决定了拦截的顺序。先写的那个mapping,那个mapping就先执行
    <filter-mapping>
        <filter-name>MyFilter</filter-name>
<!--        拦截的路径-->
        <url-pattern>/hello.jsp</url-pattern>
    </filter-mapping>

Filter在服务器启动时,Filter就创建好了。执行顺寻与创建顺序无关。

注解(@webfilter)

在web.xml的顶部需要配置 metadata-complete=“false”,默认为false,如果改为true,不会去扫描注解,只会查看配置文件
采用注解的形式,过滤器的执行顺序与全限定名有关。会根据全限定名进行比较。
在这里插入图片描述

过滤器链

在这里插入图片描述

Filter的优先级 在这里插入图片描述

过滤器配置参数

在这里插入图片描述
web.xml

<filter>
    <filter-name>MyFilter</filter-name>
    <filter-class>com.qf.servlet.MyFilter</filter-class>
    <init-param>
        <param-name>username</param-name>
        <param-value>xiaoxuan</param-value>
    </init-param>
</filter>

客户端第一次请求资源,服务端会把资源发送给服务端,并把ETag和Last-Modified发送给客户端,当客户端再次请求时,会带着这个去请求服务端,如果和服务端的信息没差别,服务端就发送304,告诉客户端上自己的缓存里去找。
在这里插入图片描述

过滤器的应用

浏览器缓存

在这里插入图片描述
cache-cotrol:缓存存活时间,单位是秒,如果没有缓存,no-cache
expires:过期时间,单位是毫秒,没有缓存,0
pargma:控制缓存,没有缓存 nocache
在这里插入图片描述现在的大部分浏览器不会缓存动态页面,都会去请求服务端。

禁止缓存

现在浏览器已经没有问题了。

HttpServletResponse response = (HttpServletResponse)resp;
//设置无缓存
response.setHeader("cache-control", "no-cache");
//设置过期时间
response.setDateHeader("expires", 0);
response.setHeader("pragma", "no-cache");
chain.doFilter(req, resp);

允许缓存

HttpServletResponse response = (HttpServletResponse)resp;
//单位为秒,缓存的时间
response.setHeader("cache-control", "max-age=600");
//单位毫秒,记录过期的时间
response.setDateHeader("expires", System.currentTimeMillis()+600000);
chain.doFilter(req, resp);

这样就可以不需要访问服务器,浏览器自己去找自己的缓存。

自动登录

当成功登录之后,应该把自己的用户名和密码保存起来,下次能直接访问数据。
总的来说,就是在登录成功,检查是否选择自动登录按钮,如果选择了,就把账号和密码通过加密,存放到cookie,设置有效时间,当下次进入项目时,先检查当前用户是否在登录,如果没有,就把cookie中的数据解密,验证账号和密码是否正确,如果正确,就把数据存放到session中。

UserService userService = new UserServiceImpl();
HttpServletRequest request = (HttpServletRequest)req;
HttpServletResponse response = (HttpServletResponse)resp;
//判断当前是否登录
String username = (String) request.getSession().getAttribute("username");
if(username != null) {
    chain.doFilter(req,resp);
    return;
}
//获取cookie
Cookie[] cookies = request.getCookies();
if(cookies != null){
    for (Cookie cookie : cookies) {
        if(cookie.getName().equals("userInfo")){
            String value = cookie.getValue();
            //解密
            byte[] decode = Base64.getDecoder().decode(value);
            String info = new String(decode);
            String[] infos = info.split("#");
            User user = userService.queryByUserNameAndPassword(infos[0], infos[1]);
            if(user != null) {
                request.getSession().setAttribute("username", infos[0]);
            }else {
                Cookie cookie1 = new Cookie(infos[0],"");
                cookie1.setPath(request.getContextPath());
                cookie1.setMaxAge(0);
                response.addCookie(cookie1);
            }
        }
    }
}
chain.doFilter(req, resp);

过滤敏感词汇

一般我们都是将数据发送给服务器,服务器在响应回来,我们只要知道服务器用的什么方法,只要在过滤器中重载某些方法,并把自己创建的requset或者response传给目标资源,目标资源就调用的我们的重载的方法,依次达到不同的效果。
比如我们将评论提交给服务器,服务器需要把敏感词进行过滤。
在这里插入图片描述
这就是目标资源,它通过使用request.getParameter()方法得到数据。所以我们就在过滤器中把这个方法进行重载

@WebServlet(name = "CommentServlet", value = "/comment")
public class CommentServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("utf-8");
        response.setContentType("text/html;charset=utf-8");
        String comment = request.getParameter("comment");
        response.getWriter().write(comment);
    }

过滤器:

@WebFilter(filterName = "CleanDirtyFilter", value = "/comment")
public class CleanDirtyFilter implements Filter {
    public void destroy() {
    }

    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
        HttpServletRequest realRequest = (HttpServletRequest)req;
        //把req中的getParameter()方法进行重载,把自己创建的request传给下一个链或者目标资源
        MyRequest request = new MyRequest(realRequest);
        chain.doFilter(request, resp);
    }

    public void init(FilterConfig config) throws ServletException {

    }
    //HttpServletRequestWrapper只是包装了request,里面存了request的引用,里面的方法都是和request相同的,方法里面是调用的request的方法
    class MyRequest extends HttpServletRequestWrapper {
        //需要把脏词保存起来
        private List<String> dirtyWords;
        public MyRequest(HttpServletRequest request) {
            super(request);
            dirtyWords = new ArrayList<>();
            dirtyWords.add("笨猪");
            dirtyWords.add("好兄弟");
            dirtyWords.add("好朋友");
            dirtyWords.add("铁子");
        }

        @Override
        public String getParameter(String name) {
             String comment = super.getParameter(name);
            for (String dirtyWord : dirtyWords) {
                comment = comment.replaceAll(dirtyWord, "***");
            }
             return comment;
        }
    }
}

结果:
在这里插入图片描述

压缩

一般都是压缩文本,比如我们去访问一个新闻
在这里插入图片描述
显示为4669字节,数据太大,影响效率。所以我们需要进行压缩。
我们是用jsp显示的这条内容。

@WebFilter(filterName = "NewsFilter",value = "/news.jsp")
public class NewsFilter implements Filter {
    public void destroy() {
    }

    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
        //修改resp
        HttpServletResponse realResponse = (HttpServletResponse)resp;
        MyResponse response = new MyResponse(realResponse);
        chain.doFilter(req, response);
        //得到内存流
        ByteArrayOutputStream byteOut = response.getByteOut();
        //因为内存输出流的toByteArray(),toString就可以把缓冲区的数据给读出来,这个和普通的输出流是不一样的。
        //创建压缩流
        ByteArrayOutputStream newByteOut = new ByteArrayOutputStream();
        System.out.println("压缩之前的大小:"+byteOut.size());
        GZIPOutputStream gzip = new GZIPOutputStream(newByteOut);
        gzip.write(byteOut.toByteArray());
        gzip.finish();
        gzip.close();
        //告诉浏览器改内容已经被压缩
        response.setHeader("Content-Encoding", "gzip");
        System.out.println("压缩之后的内容:"+newByteOut.size());
        response.getOutputStream().write(newByteOut.toByteArray()   );
    }
    public void init(FilterConfig config) throws ServletException {

    }
    static class MyResponse extends HttpServletResponseWrapper{
        //打印流
        private PrintWriter pw;
        //内存输出操作流
        private ByteArrayOutputStream byteOut;
        public MyResponse(HttpServletResponse response) {
            super(response);
            try {
                byteOut = new ByteArrayOutputStream();
                //将打印流写入内存
                pw = new PrintWriter(new OutputStreamWriter(byteOut,"utf-8"));
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
        }
        //重载方法,让目标资源用我创建的打印流
        @Override
        public PrintWriter getWriter() throws IOException {
            //返回的是我创建的流
            return pw;
        }
        //等响应回来我们还需要从内存流里读出数据。所以我们还需要获取内存流
        public ByteArrayOutputStream getByteOut(){
            //不为空,需要刷新缓冲区
            if(pw != null) {
                pw.flush();
            }
            return byteOut;
        }
    }
}

在这里插入图片描述

实现图片防盗链

在这里插入图片描述

只有本网站才能访问的资源(照片),如果别的网站访问这个照片,请求是别的网站的,这就是
盗取。这个也可以通过过滤器来过滤。

@WebFilter(filterName = "StealFilter", value = "*.png")
public class StealFilter implements Filter {
    public void destroy() {
    }
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
        HttpServletRequest request = (HttpServletRequest)req;
        //请求服务器的客户端的地址
        String referer = request.getHeader("referer");
        System.out.println(referer);
        //图片的地址
        String path = "http://localhost:8080"+request.getContextPath();
        //refer何时为空,在浏览器上面写上该地址去访问,refer就为null
        if(referer != null && referer.startsWith(path)){
            HttpServletResponse response = (HttpServletResponse)resp;
            //相同说明是正常访问
            chain.doFilter(req, resp);
            return;
        }
        //如果是非正常访问
        request.getRequestDispatcher("/upload/steal.jpg").forward(request,resp);
        System.out.println(request.getRequestURI());
        chain.doFilter(req,resp);
    }
    public void init(FilterConfig config) throws ServletException {

    }
}

监听器

在这里插入图片描述

监听器的类型

在这里插入图片描述
在这里插入图片描述

监听某个的对象放入session中或者移出

是对象要实现这个接口
监听的是这个对象
不需要注解或者配置web.xml文件

在这里插入图片描述

public class User implements HttpSessionBindingListener {
    private String name;
    private String color;

    public User() {
    }

    public User(String name, String color) {
        this.name = name;
        this.color = color;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }


    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", color='" + color + '\'' +
                '}';
    }

    @Override
    public void valueBound(HttpSessionBindingEvent event) {
        System.out.println("对象进入了session");
    }

    @Override
    public void valueUnbound(HttpSessionBindingEvent event) {
        System.out.println("对象移出了session");
    }
}

<%
    User user = new User("小红","绿色");
    session.setAttribute("user", user);
%>
<body>
    ${pageContext.session.removeAttribute("user")}
</body>

对象的钝化与活化

钝化:内存到硬盘
活化:硬盘到内存
还需要实现序列化接口

配置文件:

在这里插入图片描述

管理session

因为在服务器中创建的session默认是30分钟清除,也就是失效,但是我们可以自己设置有效时间。这就用到了监听器。

@WebListener
public class SessionManager implements ServletContextListener, HttpSessionListener {
    //容器,存放session
    private ConcurrentHashMap<String, HttpSession/> map;
    //定时器
    private Timer timer;
    @Override
    public void contextInitialized(ServletContextEvent sce) {
        //初始化
        map = new ConcurrentHashMap<>();
        timer = new Timer();
        //定时器开始
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                if(map.size()>0){
                    for (Map.Entry<String, HttpSession> entry : map.entrySet()) {
                        HttpSession value = entry.getValue();
                        //比较时间
                        if(System.currentTimeMillis()-value.getLastAccessedTime()>60000) {
                            //移出
                            map.remove(entry.getValue());
                            System.out.println("过期了"+value.hashCode());
                            //失效
                            value.invalidate();
                        }
                    }
                }
            }
        },0,10000);
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        map = null;
        timer.cancel();
    }

    @Override
    public void sessionCreated(HttpSessionEvent se) {
        System.out.println("创建了session"+se.getSource().hashCode());
        HttpSession session = (HttpSession)se.getSource();
        map.put(session.getId(),session);
    }

    @Override
    public void sessionDestroyed(HttpSessionEvent se) {
        System.out.println("session销毁了");
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值