javaWeb之过滤器(Filter)

Servlet技术规范 描述三种技术 : Servlet(服务器小程序) 、Filter(过滤器)、 Listener(监听器)
1 新建类 继承httpServlet
2 重写doGet 和 dopost方法
3 在web.xml中 注册和映射

  1. Filter简介
    Filter也称之为过滤器,它是Servlet技术中最实用的技术,
    例如Jsp, Servlet, 静态图片文件或静态 html 文件等进行拦截,
    从而实现一些特殊的功能。例如实现URL级别的权限访问控制、
    过滤敏感词汇、解决get和post乱码等一些高级功能。
    Servlet API中提供了一个Filter接口,开发web应用时,如果编写的Java类实现了这个接口,则把这个java类称之为过滤器Filter。
    通过Filter技术,开发人员可以实现用户在访问某个目标资源之前,
    对访问的请求和响应进行拦截,如下所示:
    javaWeb之过滤器(Filter)_第1张图片

2.Filter是如何实现拦截的?
Filter接口中有一个doFilter方法,当开发人员编写好Filter,并配置对哪个web资源(拦截url)进行拦截后,WEB服务器每次在调用web资源之前,都会先调用一下filter的doFilter方法,因此,在该方法内编写代码可达到如下目的:
调用目标资源之前,让一段代码执行
是否调用目标资源(即是否让用户访问web资源)。
web服务器在调用doFilter方法时,会传递一个filterChain对象进来,filterChain对象是filter接口中最重要的一个对象,它也提供了一个doFilter方法,开发人员可以根据需求决定是否调用此方法,调用该方法,则web服务器就会调用web资源的service方法,即web资源就会被访问,否则web资源不会被访问。
调用目标资源之后,让一段代码执行

javaWeb之过滤器(Filter)_第2张图片

Filter运行在服务器端,对服务器端web资源的访问 进行拦截,起到过滤的作用

Servlet API中 定义接口 Filter,用户只需要编写程序实现Filter接口,完成过滤器编写

  1. Filter快速入门
    3.1. 准备工作
    hello.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>




Insert title here


	

Hello,JSP

// HelloServlet
public class HelloServlet extends HttpServlet {
	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		response.getWriter().println("

Hello,Servlet

"); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }

3.2. 编写类 实现 Filter接口

/**
 * 编写为过滤器,过滤器作用 用来拦截web资源的访问
 * 
 * @author seawind
 * 
 */
public class Filter1 implements Filter {

	@Override
	public void destroy() {
	}
	@Override
	public void doFilter(ServletRequest request, ServletResponse response,
			FilterChain chain) throws IOException, ServletException {
		// 执行过滤
		System.out.println("执行Filter1 ");

		// 拦截后,如何让目标资源执行
		chain.doFilter(request, response);
	}

	@Override
	public void init(FilterConfig filterConfig) throws ServletException {
	}
}

3.3. 在服务器端注Filter(配置拦截哪个web资源----- web.xml

 
  
  	Filter1
  	cn.itcast.filter.Filter1
  	
  
  
  
  	Filter1
  	/hello.jsp
  	
	
    
    HelloServlet
  

3.4. 客户端访问被拦截目标资源之前,服务器调用Filter的doFilter方法 ,执行过滤

3.5. Filter的doFilter方法中传入 FilterChain, 如果调用FilterChain的doFilter 就会执行目标资源,否则目标资源不会执行

放行方法

问题1: 每次使用过滤器都需要 实现filter接口, 再去web.xml中配置, 是否很麻烦? 有没有更加简便的方法?
问题2: 如果配置两个过滤器谁先执行,谁后执行? 由什么决定的?
4. FilterChain

多个过滤器组成过滤器链,谁先执行,谁后执行?

在客户端访问服务器web资源时,服务器端为一个web资源,配置多个过滤器拦截 ,这多个过滤器,就会组成过滤器链 FilterChain, 调用FilterChain的doFilter 表示要执行过滤器链下一个资源,如果当前过滤器已经是链上最后一个过滤器,就会执行目标资源

  • web服务器根据Filter在web.xml文件中的注册顺序,决定先调用哪个Filter
  1. Filter生命周期
    我相信在北京大家都有乘坐地铁的经历, 为了安全期间, 我们必须安检部门的检查, 通过后才可以乘坐地铁.
    1 乘坐地铁服务 对应 服务器上资源服务
    2 安检部门 对应 过滤器

安检部门上岗前, 必须 发放安检设备
每次安检,都有严格的流程
结束安检, 需要回收安检设备

public class AnjianFilter implements Filter {
    public AnjianFilter() {
    	System.out.println("构造方法: 地铁安检部门成立----------------------");
    }
	public void init(FilterConfig fConfig) throws ServletException {
		System.out.println("init: 安检人员上岗前的准备工作----------------------");
	}

	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
		System.out.println("doFilter: 每次有人进入地铁必须进行安全检查----------------------" + new Date().toLocaleString());
		// 允许通过
		chain.doFilter(request, response);
	}
	
	public void destroy() {
		System.out.println("destroy: 收回安检设备----------------------");
	}
}

init(FilterConfig) doFilter(request,response,filterChain) destroy()
1、Filter对象在tomcat服务器启动时 创建,调用init方法 (只会创建一个对象,init方法执行一次)
2、doFilter 每次拦截目标资源时,执行
3、destroy 服务器关闭时执行

请思考:
安检部门 如果在非节假日客流量少时,5个手持安检设备就够了.
但是碰上节假日客流量多时,10个手持安检设备才够用,需要向上级申请.
节假日过后客流量少了,4个手持安检设备就够了,还需要再次向上级申请换回去…
如此频繁的申请,等待通过是否很麻烦,大家有没有好的主意?
6. FilterConfig对象
FilterConfig 作用和 ServletConfig 类似,用来在Filter初始化阶段,将参数传递给过滤器
1、通过 String getInitParameter(String name) 获得过滤器初始化参数

  • FilterConfig 提供参数,是Filter类私有参数,Filter2的初始化参数,不能在Filter1 中进行获取
  • 配置全局参数, 进行配置,通过ServletContext 获得
    javaWeb之过滤器(Filter)_第3张图片
    javaWeb之过滤器(Filter)_第4张图片
  1. 过滤器拦截配置

javaWeb之过滤器(Filter)_第5张图片

javaWeb之过滤器(Filter)_第6张图片

1、如果连接目标资源是一个Servlet,可以选择url和servlet名称两种配置方式


/hello

HelloServlet

2、url-pattern 和 Servlet中路径写法一样,有三种 : 完全匹配、目录匹配、扩展名匹配
3、指定过滤器所拦截的资源被 Servlet 容器调用的方式
容器调用服务器端资源 有四种方式
REQUEST、FORWARD、INCLUDE、ERROR

  1. Filter应用
    8.1. 案例1:解决post方式获取参数中文乱码的编码过滤器
    案例:编写jsp 输入用户名,在Servlet中获取用户名,将用户名输出到浏览器上
// 处理请求post乱码代码
request.setCharacterEncoding("utf-8");
// 设置响应编码集代码`这里写代码片`
response.setContentType("text/html;charset=utf-8");

经常会使用,而过滤器可以在目标资源之前执行,将很多程序中处理乱码公共代码,提取到过滤器中 ,以后程序中不需要处理编码问题

需求: 要求用户输入用户名,显示在页面上

8.1.1. input.jsp

请输入你的大名

8.1.2. Demo1Serlvet

public class Demo1Servlet extends HttpServlet {
	private static final long serialVersionUID = 1L;

	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		String username = request.getParameter("username");
		response.getWriter().println("幸会," + username);
	}
}

8.1.3. EncodingFilter

public class EncodingFilter implements Filter {
	public EncodingFilter() {
	}

	public void destroy() {
	}

	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
		// 解决获取参数出现中文乱码
		request.setCharacterEncoding("utf-8");
		// 解决浏览器出现中文乱码
		response.setContentType("text/html;charset=utf-8");
		// 放行
		chain.doFilter(request, response);
	}

	public void init(FilterConfig fConfig) throws ServletException {
	}
}

案例1缺点: 可以解决post方式的乱码, 但是解决get方式的乱码吗? 如果不可以请思考怎么做?
案例2:解决整个项目的乱码

昵称
城市
public class GenericEncodingFilter implements Filter {
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
		// 为了能够使用子类的方法,需要向下转型
		HttpServletRequest httpServletRequest = (HttpServletRequest)request;
		// 使用包装 对方法进行增强
		HttpServletRequest myRequest = new MyRequest(httpServletRequest);
		// 放行
		chain.doFilter(myRequest, response);
	}

	public void init(FilterConfig fConfig) throws ServletException {
	}

	@Override
	public void destroy() {
		
	}
	
	class MyRequest extends HttpServletRequestWrapper{
		private HttpServletRequest httpServletRequest;
		
		// 记录是否修改过
		private boolean isUpdate = false;
		
		public MyRequest(HttpServletRequest request) {
			super(request);
			this.httpServletRequest = request;
		}
		
		@Override
		public Map getParameterMap() {
			// 1 获取请求方式
			String method = httpServletRequest.getMethod();
			// 2 根据不同方式,做出对应的处理
			if("post".equalsIgnoreCase(method)) {
				// 设置请求编码集
				try {
					httpServletRequest.setCharacterEncoding("utf-8");
					return httpServletRequest.getParameterMap();
				} catch (UnsupportedEncodingException e) {
					e.printStackTrace();
				}
			}else if("get".equalsIgnoreCase(method)) {
				// 先编码,再解码
				Map parameterMap = httpServletRequest.getParameterMap();
				if(!isUpdate) {
					try {
						for(Entry entry : parameterMap.entrySet()){
							String[] valueArr = entry.getValue();
							for(int i=0; i parameterMap = this.getParameterMap();
			String[] valueArr = parameterMap.get(name);
			if(valueArr!=null) {
				return valueArr[0];
			}else {
				return null;
			}
		}
		@Override
		public String[] getParameterValues(String name) {
			return this.getParameterMap().get(name);
		}
	}
}

==================================================================================================================
过滤器
1、过滤器编写步骤
2、全局编码 过滤器
3、通用get/post乱码过滤器 ------------ 理解实现过程 ,保存起来会使用

你可能感兴趣的:(#,java,web)