【简记】Java Web 内幕——Filter
来源:互联网 发布:速拓软件手机 编辑:程序博客网 时间:2024/04/27 23:26
本文内容:
- 过滤器介绍
- 过滤器的生成过程,执行顺序
- 案例(利用过滤器对字符编码进行处理)
为什么需要过滤器
项目开发中,经常会涉及到重复代码的实现!
如何解决:
1. 抽取重复代码,封装
2. 每个用到重复代码的地方,手动地调用!
过滤器,设计执行流程:
1. 用户访问服务器
2. 过滤器: 对Servlet请求进行拦截
3. 先进入过滤器, 过滤器处理
4. 过滤器处理完后, 再放行, 此时,请求到达Servlet/JSP
5. Servlet处理
6. Servlet处理完后,再回到过滤器, 最后在由tomcat服务器相应用户
实现一些特殊的功能。例如实现URL级别的权限访问控制、过滤敏感词汇、压缩响应信息等一些高级功能
Filter简介
Servlet API中提供了一个Filter接口,开发web应用时,如果编写的Java类实现了这个接口,则把这个java类称之为过滤器Filter。通过Filter技术,开发人员可以实现用户在访问某个目标资源之前,对访问的请求和响应进行拦截。
过滤器相关Api:
|– interface Filter 过滤器核心接口
void init(filterConfig);
初始化方法,在服务器启动时候执行;
void doFilter(request,response,filterChain);
在每个用户的请求进来时这个方法都会被调用,并在Servlet 的service 方法之前被调用。
void destroy();
销毁过滤器实例时候调用
|– interface FilterConfig
获取初始化参数信息;FilterConfig 与ServletConfig 也类似, 除了都能取到容器的环境类ServletContext 对象之外,还能获取在< filter >下配置的< init-param>参数值。
|– interface FilterChain
过滤器链参数;一个个过滤器形成一个执行链;
FilterChain 就代表当前的整个请求链,所以通过调用FilterChain . doFilter 可以将请求继续传递下去。如果想拦截这个请求, 可以不调用FilterChain.doFilter , 那么这个请求就直接返回了。所以Filter 是一种责任链设计模式。
void doFilter(ServletRequest request, ServletResponse response) ;
与Servlet的不同之处
- 在tomcat服务器启动时就会调用filter的构造函数来创建实例(Servlet默认是当调用时才会创建实例)
filterDemo:
public class HelloFilter implements Filter{ // 创建实例 public HelloFilter(){ System.out.println("1. 创建过滤器实例"); } @Override public void init(FilterConfig filterConfig) throws ServletException { System.out.println("2. 执行过滤器初始化方法"); // 获取过滤器在web.xml中配置的初始化参数 String encoding = filterConfig.getInitParameter("encoding"); System.out.println(encoding); // 获取过滤器在web.xml中配置的初始化参数 的名称 Enumeration<String> enums = filterConfig.getInitParameterNames(); while (enums.hasMoreElements()){ // 获取所有参数名称:encoding、path String name = enums.nextElement(); // 获取名称对应的值 String value = filterConfig.getInitParameter(name); System.out.println(name + "\t" + value); } } // 过滤器业务处理方法: 在请求到达servlet之前先进入此方法处理公用的业务逻辑操作 @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { System.out.println("3. 执行过滤器业务处理方法"); // 放行 (去到Servlet) // 如果有下一个过滤器,进入下一个过滤器,否则就执行访问servlet chain.doFilter(request, response); System.out.println("5. Servlet处理完成,又回到过滤器"); } @Override public void destroy() { System.out.println("6. 销毁过滤器实例"); }}
web.XML中的配置
<!-- 过滤器配置 --> <filter> <!--配置初始化参数--> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> <filter-name>hello_filter</filter-name> <filter-class>day21.a_filter_hello.HelloFilter</filter-class> </filter> <filter-mapping> <filter-name>hello_filter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
过滤器执行流程
对指定的请求拦截
<!-- 配置第二个过滤器 --> <!-- 演示: 拦截指定的请求 --> <filter> <filter-name>hello_filter2</filter-name> <filter-class>cn.itcast.a_filter_hello.HelloFilter2</filter-class> </filter> <filter-mapping> <filter-name>hello_filter2</filter-name> <!-- 1. 拦截所有 <url-pattern>/*</url-pattern> --> <!-- 2. 拦截指定的jsp <url-pattern>/index.jsp</url-pattern> <url-pattern>/list.jsp</url-pattern> --> <!-- 拦截所有的jsp <url-pattern>*.jsp</url-pattern> --> <!-- 3. 根据servlet的内部名称拦截 <servlet-name>IndexServlet</servlet-name> --> <!-- 拦截指定的servlet <url-pattern>/index</url-pattern> --> <!-- 4. 指定拦截指定的类型 --> <url-pattern>/*</url-pattern> < dispatcher >REQUEST</ dispatcher > < dispatcher >FORWARD</ dispatcher > </filter-mapping>
默认拦截的类型:(直接访问或者重定向)<dispatcher>REQUEST</dispatcher>拦截转发: <dispatcher>FORWARD</dispatcher>拦截包含的页面(RequestDispatcher.include(/page.jsp); 对page.jsp也执行拦截) <dispatcher>INCLUDE</dispatcher>拦截声明式异常信息: <dispatcher>ERROR</dispatcher>
在web.xml中可以配置指定的error页
案例一:过滤器处理编码实例
几乎每一个Servlet都要涉及编码处理:处理请求数据中文问题!
【GET/POST】
每个servlet都要做这些操作,把公用的代码抽取-过滤器实现!
网页代码:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html> <head> <title>My JSP 'index.jsp' starting page</title> <meta http-equiv="pragma" content="no-cache"> <meta http-equiv="cache-control" content="no-cache"> <meta http-equiv="expires" content="0"> </head> <body> <form name="frmLogin" action="${pageContext.request.contextPath }/login" method="post"> 用户名: <input type="text" name="userName"><br/> <input type="submit" value="POST提交" > </form> <hr/> <form name="frmLogin" action="${pageContext.request.contextPath }/login" method="get"> 用户名: <input type="text" name="userName"><br/> <input type="submit" value="GET提交" > </form> </body></html>
处理表单的Servlet:
public class LoginServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 获取请求数据 String name = request.getParameter("userName"); System.out.println("用户:" + name); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doGet(request, response); }}
过滤器:
(1)仅对post方法有效
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { System.out.println("3. 执行过滤器业务处理方法"); // 转型 final HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) res; // 一、处理公用业务 request.setCharacterEncoding("UTF-8"); // POST提交有效 response.setContentType("text/html;charset=UTF-8"); chain.doFilter(proxy, response); System.out.println("5. Servlet处理完成,又回到过滤器"); }
(2)使用代理
HttpServletRequest proxy = (HttpServletRequest) Proxy.newProxyInstance( request.getClass().getClassLoader(), // 指定当前使用的类加载器 new Class[]{HttpServletRequest.class}, // 对目标对象实现的接口类型 new InvocationHandler() { // 事件处理器 @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // 定义方法返回值 Object returnValue = null; // 获取方法名 String methodName = method.getName(); // 判断:对getParameter方法进行GET提交中文处理 if ("getParameter".equals(methodName)) { // 获取请求数据值【 <input type="text" name="userName">】 String value = request.getParameter(args[0].toString()); // 调用目标对象的方法 System.out.println(getEncoding(value)); // 获取提交方式 String methodSubmit = request.getMethod(); // 直接调用目标对象的方法 // 判断如果是POST提交 if ("POST".equals(methodSubmit)) { if (value != null && !"".equals(value.trim())) { // 处理GET中文 value = new String(value.getBytes("ISO-8859-1"), "UTF-8"); } } return value; } else { // 执行request对象的其他方法 returnValue = method.invoke(request, args); } return returnValue; } });
- 【简记】Java Web 内幕——Filter
- 【简记】Java Web 内幕——Listener
- 【简记】Java Web 内幕——CDN简介
- 【简记】Java Web 内幕——NIO例程
- 【简记】Java Web 内幕——AOP源码
- 【简记】Java Web 内幕——jdbc基础
- 【简记】Java Web 内幕——Servlet介绍,编程
- 【简记】Java Web 内幕——编码问题
- 【简记】Java Web 内幕——Mybatis框架小结
- 【简记】Java Web 内幕——一次完整的HTTP事务是怎样一个过程?
- 【简记】Java Web 内幕——NIO,IO调优,IO设计模式
- 【简记】Java Web 内幕——Spring基本概念+基本配置操作
- 【简记】Java Web 内幕——Spring中AOP的实现
- 【简记】Java Web 内幕——Spring源码(组件分析,BeanFactory源码,Bean创建之前)
- 【简记】Java Web 内幕——Spring中Bean的创建(源码摘录)
- 【简记】Java Web 内幕——Spring中的事务操作和底层源码
- 【简记】Java Web 内幕——XML介绍,解析XML,DOM和SAX解析
- 【简记】Java Web 内幕——类加载机制,类与类加载器
- Hadoop2.7.3 mapreduce(五)详解
- fork()
- String a=new String("abc")创建了几个对象
- TCP中几种RST的情况
- 一致性哈希
- 【简记】Java Web 内幕——Filter
- POJ 3436 ACM Computer Factory(Dinic)
- 动态内存管理
- HDU 2023
- HDU 6045 Is Derek lying?
- HDU2689 Sort it (树状数组|水题)
- Matlab函数bwmorph、bwperim
- matlab连接摄像头读取视频部…
- Oracle 一个用户将表权限赋给另一个用户