Web之过滤器

今日内容

  1. 1、什么是过滤器
  2. 2、过滤器链
  3. 3、过滤器的优先级和参数
  4. 4、过滤器的典型应用

教学目标

  1. 1、熟悉什么是过滤器
  2. 2、掌握过滤器链
  3. 3、掌握过滤器的优先级和参数
  4. 4、掌握过滤器的典型应用

第一节 过滤器

1.1 什么是过滤器
  1. Filter也称之为过滤器,它是Servlet技术中最激动人心的技术,WEB开发人员通过Filter技术,对web服务器管理的所有web资源:例如Jsp, Servlet, 静态图片文件或静态 html 文件等进行拦截,从而实现一些特殊的功能。例如实现URL级别的权限访问控制、过滤敏感词汇、压缩响应信息等一些高级功能。
  2.   Servlet API中提供了一个Filter接口,开发web应用时,如果编写的Java类实现了这个接口,则把这个java类称之为过滤器Filter。通过Filter技术,开发人员可以实现用户在访问某个目标资源之前,对访问的请求和响应进行拦截。

1.2 如何编写过滤器
  1. 1、编写java类实现Filter接口
  2. 2、重写doFilter方法
  3. 3、设置拦截的url

入门案例:

  1. package com.qf.web.filter;
  2. import javax.servlet.*;
  3. import javax.servlet.annotation.WebFilter;
  4. import java.io.IOException;
  5. /**
  6. * @author wgy 2018/11/28 9:23
  7. * @version 1.0
  8. */
  9. @WebFilter("/myservlet1")//过滤路径
  10. public class MyFilter1 implements Filter {
  11. //初始化过滤器
  12. @Override
  13. public void init(FilterConfig filterConfig) throws ServletException {
  14. System.out.println("过滤器初始化了........init... "+filterConfig);
  15. }
  16. //执行过滤
  17. @Override
  18. public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
  19. System.out.println("过滤前........doFilter ");
  20. //放行
  21. chain.doFilter(request, response);
  22. System.out.println("过滤后.......doFilter");
  23. }
  24. //销毁
  25. @Override
  26. public void destroy() {
  27. System.out.println("销毁了.....destroy");
  28. }
  29. }

1.3 过滤器的配置

1.3.1 注解式配置

在自定义的Filter类上使用注解@WebFilter(“/*”)

1.3.2 xml配置

在web.xml中进行过滤器的配置:

  1. <!--过滤器的xml配置 -->
  2. <filter>
  3. <!--名称-->
  4. <filter-name>sf</filter-name>
  5. <!--过滤器类全称-->
  6. <filter-class>com.qf.web.filter.SecondFilter</filter-class>
  7. </filter>
  8. <!--映射路径配置-->
  9. <filter-mapping>
  10. <!--名称-->
  11. <filter-name>sf</filter-name>
  12. <!--过滤的url匹配规则和Servlet的一模一样-->
  13. <url-pattern>/*</url-pattern>
  14. </filter-mapping>

1.4 过滤器链
  1. 通常客户端对服务器请求之后,服务器调用Servlet之前会执行一组过滤器(多个过滤器),那么这组过滤器就称为一条过滤器链。
  2. 每个过滤器实现某个特定的功能,一个过滤器检测多个Servlet。(匹配几个,检测几个)。
  3. 一组过滤器中的执行顺序与<filter-mapping>的配置顺序有关。
  4. 当第一个FilterdoFilter方法被调用时,web服务器会创建一个代表Filter链的FilterChain对象传递给该方法。在doFilter方法中,开发人员如果调用了FilterChain对象的doFilter方法,则web服务器会检查FilterChain对象中是否还有filter,如果有,则调用第2filter,如果没有,则调用目标资源

1.5 过滤器的优先级
  1. 在一个web应用中,可以开发编写多个Filter,这些Filter组合起来称之为一个Filter链。web服务器根据Filterweb.xml文件中的注册顺序,决定先调用哪个Filter。当第一个FilterdoFilter方法被调用时,web服务器会创建一个代表Filter链的FilterChain对象传递给该方法。在doFilter方法中,开发人员如果调用了FilterChain对象的doFilter方法,则web服务器会检查FilterChain对象中是否还有filter,如果有,则调用第2filter,如果没有,则调用目标资源
  2. 如果为注解的话,是按照类名的字符串顺序进行起作用的
  3. 如果web.xml,按照 filter-mapping注册顺序,从上往下
  4. web.xml配置高于注解方式
  5. 如果不同包、同名的filter,按照包名再排序

1.6 过滤器的初始化参数

在过滤器的创建的时候,可以传递初始化参数

第一种:基于注解的

  1. /**
  2. * Servlet Filter implementation class FirstFilter 创建过滤器
  3. */
  4. @WebFilter(value="/*",initParams= {@WebInitParam(name = "version", value = "1.0")})
  5. public class FirstFilter implements Filter {
  6. public FirstFilter() {
  7. }
  8. /**
  9. * @see Filter#destroy() 销毁
  10. */
  11. public void destroy() {
  12. // TODO Auto-generated method stub
  13. System.out.println("destroy销毁……");
  14. }
  15. /**
  16. * @see Filter#doFilter(ServletRequest, ServletResponse, FilterChain) 过滤
  17. */
  18. public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
  19. throws IOException, ServletException {
  20. System.out.println("doFilter……过滤");
  21. // 是否继续---访问下一个
  22. chain.doFilter(request, response);
  23. }
  24. /**
  25. * @see Filter#init(FilterConfig)
  26. * 初始化
  27. */
  28. public void init(FilterConfig fConfig) throws ServletException {
  29. System.out.println("init……初始化");
  30. System.out.println("初始化参数:版本号:"+fConfig.getInitParameter("version"));
  31. }
  32. }

第二种:基于xml配置

  1. /**
  2. * 创建过滤器
  3. */
  4. public class SecondFilter implements Filter {
  5. public SecondFilter() {
  6. // TODO Auto-generated constructor stub
  7. }
  8. public void destroy() {
  9. // TODO Auto-generated method stub
  10. }
  11. public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
  12. throws IOException, ServletException {
  13. // 是否继续---访问下一个
  14. chain.doFilter(request, response);
  15. }
  16. /**
  17. * @see Filter#init(FilterConfig)
  18. * 初始化
  19. */
  20. public void init(FilterConfig fConfig) throws ServletException {
  21. System.out.println("初始化参数:版本号:"+fConfig.getInitParameter("version"));
  22. }
  23. }

Web.xml实现配置:

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1">
  3. <display-name>Web_Day</display-name>
  4. <!--过滤器的xml配置 -->
  5. <filter>
  6. <filter-name>myfilter</filter-name>
  7. <filter-class>com.qf.web.filter.SecondFilter</filter-class>
  8. <!--过滤器的初始化参数 -->
  9. <init-param>
  10. <param-name>version</param-name>
  11. <param-value>1.0</param-value>
  12. </init-param>
  13. </filter>
  14. <filter-mapping>
  15. <filter-name>myfilter</filter-name>
  16. <url-pattern>/*</url-pattern>
  17. </filter-mapping>
  18. <welcome-file-list>
  19. <welcome-file>index.html</welcome-file>
  20. </welcome-file-list>
  21. </web-app>

1.7 过滤器的优点

可以实现 Web 应用程序中的预处理和后期处理逻辑

1.8 过滤器的典型应用

案例1 自动登录

创建数据库和用户表

DbHelper类:

  1. package com.qf.utils;
  2. import java.sql.SQLException;
  3. import javax.sql.DataSource;
  4. import org.apache.commons.dbutils.DbUtils;
  5. import org.apache.commons.dbutils.QueryRunner;
  6. import org.apache.commons.dbutils.handlers.BeanHandler;
  7. import com.mchange.v2.c3p0.ComboPooledDataSource;
  8. //数据库工具类
  9. public class DbHelper {
  10. private static DataSource ds;
  11. private static QueryRunner qr;
  12. static{
  13. ds=new ComboPooledDataSource();
  14. qr=new QueryRunner(ds);
  15. }
  16. //执行非查询语句,返回值受影响的行数
  17. public static int execute(String sql,Object... vs){
  18. try {
  19. return qr.execute(sql, vs);
  20. } catch (SQLException e) {
  21. // TODO Auto-generated catch block
  22. e.printStackTrace();
  23. }
  24. return 0;
  25. }
  26. //执行查询语句
  27. public static <T> T querySingle(String sql,Class<T> clz,Object... vs){
  28. try {
  29. return qr.query(sql, new BeanHandler<>(clz),vs);
  30. } catch (SQLException e) {
  31. // TODO Auto-generated catch block
  32. e.printStackTrace();
  33. }
  34. return null;
  35. }
  36. }

User类:

  1. public class User {
  2. private int id;
  3. private String username;
  4. private String pass;
  5. public int getId() {
  6. return id;
  7. }
  8. public void setId(int id) {
  9. this.id = id;
  10. }
  11. public String getUsername() {
  12. return username;
  13. }
  14. public void setUsername(String username) {
  15. this.username = username;
  16. }
  17. public String getPass() {
  18. return pass;
  19. }
  20. public void setPass(String pass) {
  21. this.pass = pass;
  22. }
  23. }

过滤器代码:

  1. /**
  2. * Servlet Filter implementation class AutoLoginFilter
  3. * 实现自动登录,只是拦截登录页面
  4. */
  5. @WebFilter(value="/login.html")
  6. public class AutoLoginFilter implements Filter {
  7. /**
  8. * Default constructor.
  9. */
  10. public AutoLoginFilter() {
  11. // TODO Auto-generated constructor stub
  12. }
  13. /**
  14. * @see Filter#destroy()
  15. */
  16. public void destroy() {
  17. // TODO Auto-generated method stub
  18. }
  19. /**
  20. * @see Filter#doFilter(ServletRequest, ServletResponse, FilterChain)
  21. */
  22. public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
  23. //强制转换为Http的请求和响应
  24. HttpServletRequest req=(HttpServletRequest) request;
  25. HttpServletResponse rep=(HttpServletResponse) response;
  26. //验证是否登录
  27. if(req.getSession().getAttribute("user")==null){
  28. //从Cookie获取上次保存的账号和密码
  29. Cookie[] cks=req.getCookies();
  30. User user=null;
  31. for(Cookie c:cks){
  32. if(c.getName().equals("user")){
  33. String[] us=c.getValue().split("@");
  34. user=new User();
  35. user.setUsername(us[0]);
  36. user.setPass(us[1]);
  37. break;
  38. }
  39. }
  40. //如果存储Cookie,那么就实现自动登录
  41. if(user!=null){//需要自动登录
  42. // 登录校验
  43. User user1 = DbHelper.querySingle("select * from tb_user where username=?", User.class, user.getUsername());
  44. boolean res=true;
  45. if (user1 != null) {
  46. if (user.getPass().equals(user1.getPass())) {
  47. req.getSession().setAttribute("user", user1);
  48. res=false;
  49. rep.sendRedirect(req.getServletContext().getContextPath()+"/success.jsp");
  50. }
  51. }
  52. if(res){//登录失败,之前的记录账号和密码错误
  53. Cookie ck=new Cookie("user","");
  54. ck.setPath("/");
  55. ck.setMaxAge(0);
  56. rep.addCookie(ck);
  57. rep.sendRedirect(req.getServletContext().getContextPath()+"/login.jsp");
  58. }
  59. }
  60. else{//直接登录页面
  61. chain.doFilter(request, response);
  62. }
  63. }
  64. else{//如果已经登录,那么就直接放行
  65. rep.sendRedirect("success.jsp");
  66. }
  67. }
  68. /**
  69. * @see Filter#init(FilterConfig)
  70. */
  71. public void init(FilterConfig fConfig) throws ServletException {
  72. // TODO Auto-generated method stub
  73. }
  74. }

案例2 过滤脏词
  1. public class DirtyFilter implements Filter {
  2. @Override
  3. public void init(FilterConfig filterConfig) throws ServletException {
  4. // TODO Auto-generated method stub
  5. }
  6. @Override
  7. public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
  8. throws IOException, ServletException {
  9. chain.doFilter(new DirtyHttpServletRequest((HttpServletRequest)request), response);
  10. }
  11. @Override
  12. public void destroy() {
  13. // TODO Auto-generated method stub
  14. }
  15. static class DirtyHttpServletRequest extends HttpServletRequestWrapper{
  16. private List<String> dirtywords=new ArrayList<String>();
  17. public DirtyHttpServletRequest(HttpServletRequest request) {
  18. super(request);
  19. dirtywords.add("sb");
  20. dirtywords.add("狗蛋");
  21. dirtywords.add("扯淡");
  22. }
  23. @Override
  24. public String getParameter(String name) {
  25. String v=super.getParameter(name);
  26. for (String s : dirtywords) {
  27. v=v.replaceAll(s, "***");
  28. }
  29. return v;
  30. }
  31. }
  32. }

案例3 过滤器解决编码
  1. public class CharacterEncodingFilter implements Filter {
  2. //filter配置
  3. private FilterConfig config;
  4. //默认编码
  5. private String defaultcharset="utf-8";
  6. @Override
  7. public void init(FilterConfig filterConfig) throws ServletException {
  8. this.config=filterConfig;
  9. }
  10. @Override
  11. public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
  12. throws IOException, ServletException {
  13. String charset=config.getInitParameter("charset");
  14. if(charset==null){
  15. charset=defaultcharset;
  16. }
  17. //1设置请求和响应的编码
  18. request.setCharacterEncoding(charset);
  19. response.setContentType("text/html;charset="+charset);
  20. //2放行
  21. chain.doFilter(request, response);
  22. System.out.println("xxxxxxxxxxxxxxxx");
  23. }
  24. @Override
  25. public void destroy() {
  26. }
  27. }

案例4

登录、自动登录、查询所有、权限验证(普通-查看、删除)

总结

过滤器

  1. Filter

作业题

  1. 1、使用过滤器实现未登录拦截

面试题

  1. 1、过滤器有哪些作用和用法?