1、Filter过滤器

Servlet是控制器,Filter是过滤器,Listener是监听器,合为Web的三大组件
用于登录验证,统一编码处理,敏感字符过滤

过滤器类的编写:

  1. @WebFilter("/index.jsp") //注解方式指定要过滤的资源
  2. public class FilterA implements Filter {
  3. public void destroy() {
  4. //过滤器销毁时执行
  5. }
  6. public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
  7. System.out.println("FilterA执行了。。。");
  8. chain.doFilter(req, resp); //放行操作,
  9. System.out.println("FilterA响应了。。。");
  10. }
  11. public void init(FilterConfig config) throws ServletException {
  12. //服务器启动时执行
  13. }
  14. }

关于多个过滤器对同一个资源进行过滤:
1、先执行的后响应,后执行的先响应
2、注解方式是按照类名对应的ANSC码表大小顺序执行
xml编写:过滤器从上到下依次执行

  1. <!--注册filter-->
  2. <filter>
  3. <filter-name>FilterA</filter-name>
  4. <filter-class>com.yunhe.filter.FilterA</filter-class>
  5. </filter>
  6. <!--配置filter拦截路径-->
  7. <filter-mapping>
  8. <filter-name>FilterA</filter-name>
  9. <url-pattern>/index.jsp</url-pattern>
  10. </filter-mapping>

2、Filter过滤器细节

生命周期:

init方法:服务器启动时,加载项目,创建filter对象时执行,只执行一次
doFilter方法:用户范文被拦截目标资源时,可执行多次
destroy方法:服务器关闭前,Filter对象被销毁,如果服务器正常关闭,只执行一次

拦截路径:

精准匹配:指定目标的资源路径(如:”/index.jsp”)
目录匹配:指定目标的资源的目录路径(如:”user/“)
后缀匹配:指定目标的资源的后缀名称(如:”.html”)
匹配所有:指定该网站所有的资源(”/
“)

拦截方式:

  1. request:
  2. 默认的拦截方式,浏览器直接发送请求
  3. forward:
  4. 资源A转发到资源B时拦截,(如:ForwardServlet,index.jsp)
  5. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  6. xml方式:
  7. <filter>
  8. <filter-name>ForwardServlet</filter-name>
  9. <filter-class>com.yunhe.filter.ForwardServlet</filter-class>
  10. </filter>
  11. <filter-mapping>
  12. <filter-name>ForwardServlet</filter-name>
  13. <url-pattern>/index.jsp</url-pattern>
  14. <dispatcher>REQUEST</dispatcher>
  15. <dispatcher>FORWARD</dispatcher>
  16. </filter-mapping>
  17. 注解方式:
  18. @WebFilter(urlPatterns = "/index.jsp",dispatcherTypes = {DispatcherType.REQUEST,DispatcherType.FORWARD})
  19. 加上拦截方式的话,就不能省略urlPatterns了

过滤器链:

  1. 过滤器链执行顺序 (先进后出)
  2. 1.用户发送请求
  3. 2.FilterA拦截,放行
  4. 3.FilterB拦截,放行
  5. 4.执行目标资源 index.jsp
  6. 5.FilterB增强响应
  7. 6.FilterA增强响应
  8. 7.封装响应消息格式,返回到浏览器
  9. xml文件格式:
  10. 谁先声明,谁先执行

3、Listener监听器

某一个被关注的对象,在对象发生变化时需要执行操作,什么时候变化需要监听器去关注该对象的变化情况,比如网站的访问次数,在线人数,系统启动时的初始化配置
监听器的内容:

  1. 监听作用域对象的创建和销毁:
  2. *SevletRequestListener:监听请求对象的创建和销毁
  3. *HttpSessionListener:监听会话对象(session)的创建和销毁
  4. *ServletContextListener:监听应用的创建和销毁
  5. 监听作用域对象的属性和添加,删除,替换

监听器的web.xml配置:

  1. <listener>
  2. <listener-class>监听器全类名</listener-class>
  3. </listener>

4、Filter&Listener案例

前端JSP代码:bbs.jsp

  1. <%@ page contentType="text/html;charset=UTF-8" language="java" %>
  2. <html>
  3. <head>
  4. <title>bbs</title>
  5. </head>
  6. <body>
  7. 在线人数: ${sessionCount}
  8. <br>
  9. <a href="/delSessionServlet">退出系统</a>
  10. <h3>LPL季后赛观看留言板</h3>
  11. <hr>
  12. <form action="${pageContext.request.contextPath}/wordsServlet" method="post">
  13. <textarea name="content" id="" cols="206" rows="20" style="resize: none;"></textarea><br><br>
  14. <input type="submit" value="请留言">
  15. </form>
  16. </body>
  17. </html>

后端编码过滤器代码:EncodeFilter

  1. package com.yunhe.filter;
  2. import javax.servlet.*;
  3. import javax.servlet.annotation.WebFilter;
  4. import javax.servlet.http.HttpServletRequest;
  5. import javax.servlet.http.HttpServletResponse;
  6. import java.io.IOException;
  7. //@WebFilter("/*")
  8. public class EncodeFilter implements Filter {
  9. //编码问题
  10. private String encode ;
  11. public void init(FilterConfig config) throws ServletException {
  12. encode = config.getInitParameter("encode");//服务器初始化时获取配置文件定义的编码类型
  13. }
  14. public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
  15. HttpServletRequest request = (HttpServletRequest)req;
  16. HttpServletResponse response = (HttpServletResponse)resp;
  17. //如果是post请求,设置编码
  18. if (request.getMethod().equalsIgnoreCase("post")) {
  19. request.setCharacterEncoding(encode);
  20. }
  21. response.setContentType("text/html;charset="+encode); // 这个操作不太推荐.... 因为把所有响应类型给成了 html
  22. chain.doFilter(req, resp);//放行
  23. }
  24. public void destroy() {
  25. }
  26. }

后端敏感过滤器代码:WordsFilter

  1. package com.yunhe.filter;
  2. import javax.servlet.*;
  3. import javax.servlet.annotation.WebFilter;
  4. import javax.servlet.http.HttpServletRequest;
  5. import javax.servlet.http.HttpServletResponse;
  6. import java.io.*;
  7. import java.util.Arrays;
  8. import java.util.List;
  9. import java.util.ResourceBundle;
  10. @WebFilter("/wordsServlet") //只有执行该类后才执行该类
  11. public class WordsFilter implements Filter {
  12. //敏感字问题
  13. //存储敏感字库中取出来的数据
  14. private List<String> wordList;
  15. public void destroy() {
  16. }
  17. public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
  18. // 向下转型
  19. HttpServletRequest request = (HttpServletRequest) req;
  20. HttpServletResponse response = (HttpServletResponse) resp;
  21. /*
  22. //获取用户输入的数据
  23. String content = request.getParameter("content");
  24. //判断是否含有敏感字内容
  25. for (String word : wordList){ //遍历从敏感字库中取出的数据
  26. System.out.println("content:"+content+"--->"+"word:"+word);
  27. if (content.contains(word)){//判断content内容中是否含有word的内容
  28. response.getWriter().write("你输入的词汇敏感,拦截了。。。");
  29. return;
  30. }
  31. }
  32. chain.doFilter(req, resp);//放行
  33. */
  34. //判断是否含有敏感字内容,并替换
  35. MyRequest requestPro = new MyRequest(request, wordList);
  36. chain.doFilter(requestPro, response);//放行
  37. }
  38. public void init(FilterConfig config) throws ServletException {
  39. //服务器初始化就做的事
  40. // 1.读取words.properties文件中的内容
  41. //ResourceBundle方法可读取properties类型文件内的数据
  42. ResourceBundle words = ResourceBundle.getBundle("words");
  43. // 2.读取keyword关键字内容
  44. // String keyword = words.getString("keyword");
  45. String keyword = null;
  46. try {
  47. keyword = new String(words.getString("keyword").getBytes("ISO-8859-1"),"utf-8");
  48. } catch (UnsupportedEncodingException e) {
  49. e.printStackTrace();
  50. }
  51. // 3.split切割,转为list集合
  52. wordList = Arrays.asList(keyword.split(",")) ; //数组转list集合
  53. System.out.println("加载非法词库:"+wordList);
  54. }
  55. }

重写方法(增强该方法,使该方法具有过滤敏感字的功能):MyRequest 这里用到设计模式(装饰器模式)
装饰器模式:

  1. 1. 包装类和被包装类实现同一个接口(或者继承同一个抽象类)
  2. 2. 包装类要有被包装类的对象引用
  3. 3. 对需要增强的方法重写
  4. 4. 对不需要增强的方法,执行原有的逻辑
  1. package com.yunhe.filter;
  2. import javax.servlet.http.HttpServletRequest;
  3. import javax.servlet.http.HttpServletRequestWrapper;
  4. import java.util.List;
  5. public class MyRequest extends HttpServletRequestWrapper {
  6. // 非法词库
  7. private List<String> wordList;
  8. public MyRequest(HttpServletRequest request, List<String> wordList) {
  9. super(request);
  10. this.wordList= wordList;
  11. }
  12. //重写getParameter方法,实现非法字段过滤
  13. @Override
  14. public String getParameter(String name) {
  15. //调用原有的方法获取用户输入的值
  16. String parameter = super.getParameter(name);
  17. //对非法字符过滤
  18. for (String word : wordList) {
  19. if (parameter.contains(word)){ //判断前端传过来的句子中是否含有word数据内容。
  20. //替换句子中的非法字符为***
  21. parameter = parameter.replaceAll(word,"***");
  22. }
  23. }
  24. return parameter;
  25. }
  26. }

退出网站监听器代码:delSessionServlet

  1. package com.yunhe.listener;
  2. import javax.servlet.ServletException;
  3. import javax.servlet.annotation.WebServlet;
  4. import javax.servlet.http.HttpServlet;
  5. import javax.servlet.http.HttpServletRequest;
  6. import javax.servlet.http.HttpServletResponse;
  7. import java.io.IOException;
  8. @WebServlet("/delSessionServlet")
  9. public class DelSessionServlet extends HttpServlet {
  10. @Override
  11. protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  12. request.setCharacterEncoding("utf-8");// 处理post请求乱码问题
  13. response.setContentType("text/html;charset=UTF-8"); // 响应参数乱码解决方法
  14. //退出网站,销毁session
  15. request.getSession().invalidate();
  16. }
  17. @Override
  18. protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  19. this.doPost(request, response);
  20. }
  21. }

服务器启动初始化参数:SessionIntListener

  1. package com.yunhe.listener;
  2. import javax.servlet.ServletContext;
  3. import javax.servlet.ServletContextEvent;
  4. import javax.servlet.ServletContextListener;
  5. import javax.servlet.annotation.WebListener;
  6. @WebListener
  7. public class SessionIntListener implements ServletContextListener {
  8. //服务器启动时执行,在ServletContext域中初始化用于存储Session的容器
  9. @Override
  10. public void contextInitialized(ServletContextEvent servletContextEvent) {
  11. System.out.println("sessionCreated被访问,存储session的容器初始化完成。。。");
  12. //获取ServletContext域对象
  13. ServletContext servletContext = servletContextEvent.getServletContext();
  14. //在ServletContext域中初始化用于存储Session的容器
  15. servletContext.setAttribute("sessionCount", 0);
  16. }
  17. @Override
  18. public void contextDestroyed(ServletContextEvent servletContextEvent) {
  19. }
  20. }

网站受到访问时统计在线人数:SessionCountListener

  1. package com.yunhe.listener;
  2. import javax.servlet.annotation.WebListener;
  3. import javax.servlet.http.HttpSessionEvent;
  4. import javax.servlet.http.HttpSessionListener;
  5. @WebListener
  6. public class SessionCountListener implements HttpSessionListener {
  7. @Override
  8. public void sessionCreated(HttpSessionEvent httpSessionEvent) {
  9. System.out.println("session被创建了。。。。。");
  10. //创建session时,执行该方法、
  11. //获取用于记录Session的计数器sessionCount
  12. int sessionCount = (int) httpSessionEvent.getSession().getServletContext().getAttribute("sessionCount");
  13. //Session发生变化,哎,来一个用户,Session的数量就加一
  14. int num = sessionCount+1;
  15. httpSessionEvent.getSession().getServletContext().setAttribute("sessionCount",num);
  16. System.out.println("当前网站用户:"+num);
  17. }
  18. @Override
  19. public void sessionDestroyed(HttpSessionEvent httpSessionEvent) {
  20. System.out.println("session被销毁了。。。。。");
  21. //销毁session时,执行该方法
  22. int sessionCount = (int) httpSessionEvent.getSession().getServletContext().getAttribute("sessionCount");
  23. int num = sessionCount-1;
  24. httpSessionEvent.getSession().getServletContext().setAttribute("sessionCount",num);
  25. System.out.println("当前网站用户:"+num);
  26. }
  27. }

用户发表评论需要跳转的资源:WordsServlet

  1. package com.yunhe.servlet;
  2. import javax.servlet.ServletException;
  3. import javax.servlet.annotation.WebServlet;
  4. import javax.servlet.http.HttpServlet;
  5. import javax.servlet.http.HttpServletRequest;
  6. import javax.servlet.http.HttpServletResponse;
  7. import java.io.IOException;
  8. @WebServlet("/wordsServlet")
  9. public class WordsServlet extends HttpServlet {
  10. @Override
  11. protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  12. // 1.接收请求参数 content
  13. String content = request.getParameter("content");
  14. // 2.将结果响应到 浏览器
  15. response.getWriter().write(content);
  16. }
  17. @Override
  18. protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  19. this.doPost(request, response);
  20. }
  21. }

储存敏感字的配置文件:words.properties

  1. keyword = 敏感字1, 敏感字2, 敏感字3, ...

web.xml配置文件:

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
  5. version="3.1">
  6. <!--注册过滤器EncodeFilter-->
  7. <filter>
  8. <filter-name>EncodeFilter</filter-name>
  9. <filter-class>com.yunhe.filter.EncodeFilter</filter-class>
  10. <init-param>
  11. <!--用于动态获取编码类型-->
  12. <param-name>encode</param-name>
  13. <param-value>utf-8</param-value>
  14. </init-param>
  15. </filter>
  16. <!--EncodeFilter的映射-->
  17. <filter-mapping>
  18. <filter-name>EncodeFilter</filter-name>
  19. <url-pattern>/*</url-pattern>
  20. </filter-mapping>
  21. </web-app>