servlet过滤器
来源:互联网 发布:如何使用网络代理 编辑:程序博客网 时间:2024/05/18 00:16
一、概念:
Filter也称之为过滤器,它是Servlet技术中比较激动人心的技术,WEB开发人员通过Filter技术,对web服务器管理的所有web资源:例如Jsp, Servlet, 静态图片文件或静态 html 文件等进行拦截,从而实现一些特殊的功能。例如实现URL级别的权限访问控制、过滤敏感词汇、压缩响应信息等一些高级功能。
二、Filter简介
Servlet API中提供了一个Filter接口,开发web应用时,如果编写的Java类实现了这个接口,则把这个java类称之为过滤器Filter。通过Filter技术,开发人员可以实现用户在访问某个目标资源之前,对访问的请求和响应进行拦截。简单说,就是可以实现web容器对某资源的访问前截获进行相关的处理,还可以在某资源向web容器返回响应前进行截获进行处理。
三、快速入门
1、新建一个类,实现Filter接口
2、实现doFilter()方法,打印一句话,来证明能够进行拦截
3、在web.xml中进行配置(参照Servlet配置)
4、访问一个页面,看看能不能拦截
在web.xml中进行配置
四、Filter的应用场景
通过对filter过滤器的了解,可以得知在以下三种情况下可以做些处理:
1> 通过控制对chain.doFilter的方法的调用,来决定是否需要访问目标资源。
比如,可以在用户权限验证等等。判断用户是否有访问某些资源的权限,有权限放行,没权限不执行chain.doFilter方法。
2> 通过在调用chain.doFilter方法之前,做些处理来达到某些目的。
比如,解决中文乱码的问题等等。可以在doFilter方法前,执行设置请求编码与响应的编码。甚至可以对request接口进行封装装饰来处理get请求方式的中文乱码问题(重写相应的request.getParameter方法)。
3> 通过在调用chain.doFilter方法之后,做些处理来达到某些目的。
比如对整个web网站进行压缩。在调用chain.doFilter方法之前用类A对response对象进行封装装饰,重写getOutputStream和重写getWriter方法。在类A内部中,将输出内容缓存进ByteArrayOutputStream流中,然后在chain.doFilter方法执行后,获取类A中ByteArrayOutputStream流缓存数据,用GZIPOutputStream流进行压缩下。
五、Filter实现拦截的原理
Filter接口中有一个doFilter方法,当开发人员编写好Filter类实现doFilter方法,并配置对哪个web资源进行拦截后,WEB服务器每次在调用web资源的service方法之前(服务器内部对资源的访问机制决定的),都会先调用一下filter的doFilter方法。
六、Filter生命周期
和Servlet一样Filter的创建和销毁也是由WEB服务器负责。不过与Servlet区别的是,它是1>在应用启动的时候就进行装载Filter类(与Servlet的load-on-startup配置效果相同)。2>容器创建好Filter对象实例后,调用init()方法。接着被Web容器保存进应用级的集合容器中去了等待着,用户访问资源。3>当用户访问的资源正好被Filter的url-pattern拦截时,容器会取出Filter类调用doFilter方法,下次或多次访问被拦截的资源时,Web容器会直接取出指定Filter对象实例调用doFilter方法(Filter对象常驻留Web容器了)。4>当应用服务被停止或重新装载了,则会执行Filter的destroy方法,Filter对象销毁。
注意:init方法与destroy方法只会直接一次。
七、Filter部署应用注意事项
1> filter-mapping标签中servlet-name与url-pattern。
Filter不仅可以通过url-pattern来指定拦截哪些url匹配的资源。而且还可以通过servlet-name来指定拦截哪个指定的servlet(专门为某个servlet服务了,servlet-name对应Servlet的相关配置)。
2> filter-mapping标签中dispatcher。
指定过滤器所拦截的资源被 Servlet 容器调用的方式,可以是REQUEST,INCLUDE,FORWARD和ERROR之一,默认REQUEST。用户可以设置多个<dispatcher> 子元素用来指定 Filter 对资源的多种调用方式进行拦截。
REQUEST:
当用户直接访问页面时,Web容器将会调用过滤器。如果目标资源是通过RequestDispatcher的include()或forward()方法访问或ERROR情况时,那么该过滤器就不会被调用。
INCLUDE:
如果目标资源是通过RequestDispatcher的include()方法访问时,那么该过滤器将被调用。除此之外,该过滤器不会被调用。
FORWARD:
如果目标资源是通过RequestDispatcher的forward()方法访问时,那么该过滤器将被调用,除此之外,该过滤器不会被调用。
ERROR:
如若在A.jsp页面page指令中指定了error属性=examError.jsp,那么A.jsp中若出现了异常,会跳转到examError.jsp中处理。而在跳转到examError.jsp时,若过滤器配置了ERROR的dispather那么则会拦截,否则不会拦截。
总结:
一个filter 包括:
1. 在servlet被调用之前截获;
2. 在servlet被调用之前检查servlet request;
3. 根据需要修改request头和request数据;
4. 根据需要修改response头和response数据;
5. 在servlet被调用之后截获.
你能够配置一个filter 到一个或多个servlet;单个servlet或servlet组能够被多个filter 使用.几个实用的filter 包括:用户辨认filter,日志filter,审核filter,加密filter,符号filter,能改变xml内容的XSLT filter等.
filter作用及原理上面其实已经讲得差不多(要我写还写不出来这么高大上的东西),那么我附上一个简单而实用的代码,
- <!-- 自定义的过滤器 -->
- <filter>
- <filter-name>authorityFilter</filter-name> <span style="font-family: Arial, Helvetica, sans-serif;"> </span>
- <filter-class>cn.thinknet.filter.AuthorityFilter</filter-class><span style="font-family: Arial, Helvetica, sans-serif;"><!-- 自定义过滤器的位置 --></span>
- <init-param>
- <param-name>allowAuthorityURL</param-name><!-- 不需要过滤的地址 -->
- <param-value>login.jsp,register.jsp,login.action,sendMail.action,register.action,getbackPwdOne.jsp,getbackPwdTwo.jsp,getbackPwdThree.jsp,getbackOne.action,getbackTwo.action,getbackThree.action,forget_pwd.action,getHomePageResult.action,index.jsp,index.html,userAuthen.action</param-value>
- </init-param>
- <init-param>
- <param-name>authorityURL</param-name><!-- 只对指定过滤参数后缀进行过滤 -->
- <param-value>.action,.jsp,.do</param-value>
- </init-param>
- <init-param>
- <param-name>redirectPath</param-name><!-- 未通过跳转到登录界面 -->
- <param-value>/wrtPlatformVt/wrt/login.jsp</param-value>
- </init-param>
- <init-param>
- <param-name>disableFilter</param-name><!-- Y:过滤无效 -->
- <param-value>N</param-value>
- </init-param>
- </filter>
- <filter-mapping> <!-- 拦截所有的请求信息 如想通过扩展名匹配拦截。 如:.action后缀的请求 配置则为 *.action-->
- <!-- 精确匹配 顾名思义精确到单个请求 如:/manage/login.action 配置则为/manage/login.action -->
- <!-- 路劲匹配 通过*配符的方式进行相对匹配,如下的/* 则表示拦截所有信息 -->
- <filter-name>authorityFilter</filter-name>
- <url-pattern>/*</url-pattern>
- </filter-mapping>
<init-param> 标签对应的是参数名和值,可以用于在init()时通过FilterConfig的对象 filterConfig.getInitParameter("参数名")获取。
自定义过滤器代码:
- package cn.thinknet.filter;
- import java.io.IOException;
- import java.io.PrintWriter;
- import javax.servlet.Filter;
- import javax.servlet.FilterChain;
- import javax.servlet.FilterConfig;
- import javax.servlet.ServletException;
- import javax.servlet.ServletRequest;
- import javax.servlet.ServletResponse;
- import javax.servlet.http.Cookie;
- import javax.servlet.http.HttpServlet;
- import javax.servlet.http.HttpServletRequest;
- import org.apache.commons.lang3.ArrayUtils;
- import org.apache.commons.lang3.StringUtils;
- import cn.thinknet.utils.others.AKKeysUtil;
- /**
- * 过滤器
- *
- *
- *
- */
- public class AuthorityFilter extends HttpServlet implements Filter
- {
- /**
- *
- */
- private static final long serialVersionUID = 4504557649329493897L;
- public String[] allowAuthorityURLs;
- public String[] authorityURLs;
- public FilterConfig config;
- /**
- * 过滤不能访问的地址
- */
- @Override
- public void doFilter(ServletRequest request, ServletResponse response,
- FilterChain filterChain) throws IOException, ServletException
- {
- // 未登录需要跳转的地址
- String redirectPath = config
- .getInitParameter(AKKeysUtil.WEB_CONTEXT_REDIRECT_PATH);
- // 过滤是否启用
- boolean isEnable = true; // 过滤器可用
- String disableStr = config
- .getInitParameter(AKKeysUtil.WEB_CONTEXT_DISABLE_FILTER);
- if (StringUtils.isNotEmpty(disableStr))
- {
- isEnable = disableStr.equals("N");
- }
- HttpServletRequest req = (HttpServletRequest) request;
- // 判断过滤器是否启用
- if (!isEnable)
- {
- filterChain.doFilter(request, response);
- return;
- }
- // 需要过滤的后缀
- String authorityURL = config
- .getInitParameter(AKKeysUtil.WEB_CONTEXT_AUTHORITY_URL);
- if (StringUtils.isNotEmpty(authorityURL))
- {
- authorityURLs = authorityURL.split(",");
- }
- // 判断当前的请求地址中是否存在需要过滤的后缀
- if (authorityURL(req))
- {
- // 不需要过滤的地址
- String allowAuthorityURL = config
- .getInitParameter(AKKeysUtil.WEB_CONTEXT_ALLOW_AUTHORITY_URL);
- if (StringUtils.isNotEmpty(allowAuthorityURL))
- {
- allowAuthorityURLs = allowAuthorityURL.split(",");
- }
- // 过滤不拦截的url
- if (allowAuthorityURL(req))
- {
- filterChain.doFilter(request, response);
- return;
- } else
- {
- // 判断当前用户是否登录,没有登录直接跳转到登录页面
- if (!relogin(redirectPath, response, req))
- {
- return;
- }
- }
- // 最后对action与jsp进行权限校验
- // if (authorityRequestAddress(req))
- // {
- // 【暂时不实现纵向越权控制】
- filterChain.doFilter(request, response);
- // }
- // else
- // {
- // 没有权限时
- // noAuthority();
- // }
- } else
- {
- // 例如js,image,css等文件不列入权限控制范围内
- filterChain.doFilter(request, response);
- }
- }
- @Override
- public void init(FilterConfig filterConfig) throws ServletException
- {
- config = filterConfig;
- // WebApplicationContext ctx = WebApplicationContextUtils
- // .getWebApplicationContext(this.getServletContext());
- // menuService = (MenuService) ctx.getBean("menuService");
- }
- /**
- * 在未登陆的情况下允许访问的URL
- *
- * @return Boolean
- */
- private boolean allowAuthorityURL(HttpServletRequest request)
- {
- boolean isAllow = false;
- // 获得当前访问的地址
- String current_url = request.getRequestURI();
- if (ArrayUtils.isNotEmpty(allowAuthorityURLs))
- {
- for (String allowUrl : allowAuthorityURLs)
- {
- if (StringUtils.containsIgnoreCase(current_url, allowUrl))
- {
- isAllow = true;
- break;
- }
- }
- }
- return isAllow;
- }
- /**
- * 需要过滤的后缀
- *
- * @return Boolean
- */
- private boolean authorityURL(HttpServletRequest request)
- {
- boolean isFilter = false;
- if (ArrayUtils.isNotEmpty(authorityURLs))
- {
- for (String suffix : authorityURLs)
- {
- if (request.getRequestURI().indexOf(suffix) != -1)
- {
- isFilter = true;
- break;
- }
- }
- }
- return isFilter;
- }
- /**
- * 判断员工回话是否失效
- *
- * @param redirectPath
- * 需要跳转的页面
- * @param response
- * 请求响应
- *
- * @param request
- * 请求
- *
- * @throws IOException
- *
- * @return boolean 假:代表重新登录,真:代表session存在
- */
- private boolean relogin(String redirectPath, ServletResponse response,
- HttpServletRequest request) throws IOException
- {
- response.setContentType("text/html;charset=UTF-8");
- response.setCharacterEncoding("UTF-8");
- PrintWriter out = response.getWriter();
- // 判断该用户是否存在session中,如果有直接进入当前action
- if (null == request.getSession(true).getAttribute(
- AKKeysUtil.USER_EMPLOY_SESSION_KEY))
- {
- // 跳转到登录界面
- out.print("<script language='javascript'>alert('身份验证失效,请重新登录!');window.parent.location.href='"
- + redirectPath + "';</script>");
- return false;
- }
- // 如果用户禁用掉cookie,则跳转到登录界面,提示用户启用cookie
- Cookie[] cookies = request.getCookies();
- if (null == cookies)
- {
- // 1.可能用户清除过cookie 2.可能是由于用户禁用了cookie 此时都会跳转到登录界面
- // 跳转到登录界面
- out.print("<script language='javascript'>alert('Cookie被清理或是已禁用,请尝试重新登录!');window.parent.location.href='"
- + redirectPath + "';</script>");
- return false;
- }
- return true;
- }
- }
注意,AKKeysUtil这个是封装好的一个工具类,所有使用到的地方对应的均是 <init-param>标签的参数名,自行对应更改即可。
- servlet 过滤器
- Servlet 过滤器
- servlet过滤器
- Servlet过滤器
- Servlet过滤器
- Servlet过滤器
- Servlet过滤器
- Servlet过滤器
- Servlet过滤器
- Servlet过滤器
- Servlet过滤器
- Servlet过滤器
- Servlet过滤器
- Servlet过滤器
- Servlet过滤器
- Servlet过滤器
- Servlet过滤器
- Servlet 过滤器
- 小波的秘密5_多分辨率分析和连续小波变换2
- 解压文件
- 报错Installtion failed with message INSTALL_FAILED_USER_RESTARICTED.解决方案
- 遍历XML文件添加到TreeView递归调用
- Java——第四章(数组和字符串)--字符串
- servlet过滤器
- WebView 加载HttpS 的地址,
- ubuntu1604Caffe安装经历
- VS使用时候的一个问题
- 文章标题
- 让KVM虚拟机支持console功能
- html5第二天笔记(上)
- Codeforces 350C - Bombs
- c++大数类