Javaweb:Servlet过滤器以及常见应用展示

Filter简介:

Javaweb:Servlet过滤器以及常见应用展示_第1张图片

Filter也称之为过滤器,它是Servlet技术中最实用的技术,WEB开发人员通过Filter技术,对web服务器管理的所有web资源:例如Jsp, Servlet, 静态图片文件或静态 html 文件等进行拦截,从而实现一些特殊的功能。

l特点:

过滤器不是目标资源,是在访问目标资源的前后执行的。

过滤器的拦截是双向的

可以有多个过滤器。

过滤器拦截是一堆目标资源。

Servlet API中提供了一个Filter接口,开发web应用时,如果编写的Java类实现了这个接口,则把这个java类称之为过滤器Filter。通过Filter技术,开发人员可以实现用户在访问某个目标资源之前,对访问的请求和响应进行拦截,如下所示:

Javaweb:Servlet过滤器以及常见应用展示_第2张图片

过滤器的工作原理

通过使用过滤器,可以拦截客户端的请求和响应,查看、提取或者以某种方式操作正在客户端和服务器之间进行交换的数据。

通过使用过滤器,可以对Web组件的前期处理和后期处理进行控制。

过滤器可以有多个,以构成一个过滤器链。Servlet容器会根据过滤器的配置情况来决定过滤器的调用次序。

过滤器Filter的实现和部署

(1)实现一个过滤器Filter

定义的过滤器类必须要实现接口javax.servlet.Filter,并且实现该接口中定义的3个方法:

vod init(…):用于初始化过滤器。

void destroy():用于销毁过滤器。

void doFilter(…):用于执行过滤操作。

(2)部署一个过滤器Filter

web.xml配置文件中部署Filter

元素定义过滤器,在 web.xml 文件中使用元素对编写的filter类进行注册,并设置它所能拦截的资源,元素有两个必要子元素:

用来设定过滤器的名字

用来设定过滤器的类路径


 	TestFilter
 	filter.TestFilter
 

配置过滤器的映射信息,有两个必要的子元素:

用来设定过滤器的名字

<url-pattern>用来设定被过滤的组件


 	TestFilter
 	/*.jsp
 

实例:

过滤器类:

package cn.itcast.filter;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

/**
 * 实现Filter接口,重写方法
 * 在web.xml进行配置
 * @author Administrator
 */
public class FilterDemo1 implements Filter{
	
	/**
	 * 初始化
	 */
	public void init(FilterConfig filterConfig) throws ServletException {
		
	}

	/**
	 * 每次请拦截的方式都执行(通过配置来决定)
	 * 由服务器调用doFilter() -- 进去到过滤器
	 * FilterChain服务器创建,把传入进来(过滤器的信息 )
	 */
	public void doFilter(ServletRequest request, ServletResponse response,
			FilterChain chain) throws IOException, ServletException {
		System.out.println("站住,打劫!!");
		
		
		// 放行
		// 放行 -- 执行下一个过滤器 -- 没有访问目标资源
		chain.doFilter(request, response);
		
		// 去访问Servlet
		
		// System.out.println("小伙,再来一次吧!!");
		
	}
	
	/**
	 * 销毁
	 */
	public void destroy() {
		
	}

}

web.xml配置:


	
	
	
		
		FilterDemo1
		
		cn.itcast.filter.FilterDemo1
	
	
		
	

 

映射Filter示例:


     testFilter
    /test.jsp





    testFilter
   /index.jsp
   REQUEST
   FORWARD

映射Filter的多种方式:

子元素可以设置的值及其意义:

REQUEST:当用户直接访问页面时,Web容器将会调用过滤器。如果目标资源是通过RequestDispatcherinclude()forward()方法访问时,那么该过滤器就不会被调用。

INCLUDE:如果目标资源是通过RequestDispatcherinclude()方法访问时,那么该过滤器将被调用。除此之外,该过滤器不会被调用。

FORWARD:如果目标资源是通过RequestDispatcherforward()方法访问时,那么该过滤器将被调用,除此之外,该过滤器不会被调用。

ERROR:如果目标资源是通过声明式异常处理机制调用时,那么该过滤器将被调用。除此之外,过滤器不会被调用。

Filter常见应用(1):

统一全站字符编码的过滤器

通过配置参数encoding指明使用何种字符编码,以处理Html Form请求参数的中文问题

过滤器类:

Javaweb:Servlet过滤器以及常见应用展示_第4张图片

web.xml配置文件: 

Javaweb:Servlet过滤器以及常见应用展示_第5张图片

 

package cn.itcast.demo1;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

/**
 * 解决全局的编码的问题
 * @author Administrator
 *
 */
public class EncodingFilter implements Filter{

	
	private FilterConfig filterConfig;

	public void init(FilterConfig filterConfig) throws ServletException {
		this.filterConfig = filterConfig;
	}

	/**
	 * 设置编码的问题
	 */
	public void doFilter(ServletRequest request, ServletResponse response,
			FilterChain chain) throws IOException, ServletException {
		
		String encoding = filterConfig.getInitParameter("encoding");
		// 解决POST乱码的问题
		request.setCharacterEncoding(encoding);
		// 响应
		response.setContentType("text/html;charset="+encoding);
		// 放行
		chain.doFilter(request, response);
	}

	@Override
	public void destroy() {
		// TODO Auto-generated method stub
		
	}

}

Filter常见应用(2)

禁止浏览器缓存所有动态页面的过滤器:

3 HTTP 响应头字段都可以禁止浏览器缓存当前页面,它们在 Servlet 中的示例代码如下:

response.setDateHeader("Expires",-1);

response.setHeader("Cache-Control","no-cache"); 

response.setHeader("Pragma","no-cache"); 

并不是所有的浏览器都能完全支持上面的三个响应头,因此最好是同时使用上面的三个响应头。

Expires数据头:值为GMT时间值,为-1指浏览器不要缓存页面

Cache-Control响应头有两个常用值:

no-cache指浏览器不要缓存当前页面。

max-age:xxx指浏览器缓存页面xxx秒。

package cn.itcast.demo2;

import java.io.IOException;

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.HttpServletResponse;

public class TimeFilter implements Filter{

	@Override
	public void init(FilterConfig filterConfig) throws ServletException {
		// TODO Auto-generated method stub
		
	}

	public void doFilter(ServletRequest request, ServletResponse response,
			FilterChain chain) throws IOException, ServletException {
		// 设置三个头信息
		HttpServletResponse resp = (HttpServletResponse) response;
		resp.setHeader("Cache-Control", "no-cache");
		resp.setHeader("Pragma", "no-cache");
		resp.setDateHeader("Expires", -1);
		
		chain.doFilter(request, resp);
	}

	@Override
	public void destroy() {
		// TODO Auto-generated method stub
		
	}

}
 
	 	TimeFilter
	 	cn.itcast.demo2.TimeFilter
	 
	 
	 	TimeFilter
	 	*.jsp
	 

 

Filter常见应用(3):

Javaweb:Servlet过滤器以及常见应用展示_第6张图片

分ip统计访问次数

因为一个网站可能有多个页面,无论哪个页面被访问,都要统计访问次数,所以使用过滤器最为方便。

因为需要分IP统计,所以可以在过滤器中创建一个Map,使用IP为key,访问次数为value。当有用户访问时,获取请求的IP,如果IP在Map中存在,说明以前访问过,那么在访问次数上加1,即可;IP在Map中不存在,那么设置次数为1。

把这个Map存放到ServletContext中!

package cn.itcast.demo3;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

public class CountFilter implements Filter{

	private FilterConfig config;

	/**
	 * 进行初始化的操作
	 * 在ServletContext域中存入map
	 */
	public void init(FilterConfig config) throws ServletException {
		// 先有一个MAP
		Map countMap = new HashMap();
		ServletContext context = config.getServletContext();
		// 存
		context.setAttribute("countMap", countMap);
		this.config = config;
	}
	
	/**
	 * 该方法执行了
	 */
	public void doFilter(ServletRequest request, ServletResponse response,
			FilterChain chain) throws IOException, ServletException {
		/**
		 * 1.获取map
		 * 2.获取ip
		 * 3.在map中和ip就对比
		 * 	* 如果map中有ip,获取count,+1
		 * 	* 如果map中没有ip,把ip和count=1存入到map中
		 * 4.把map存入到ServletContext中
		 * 5.放行
		 */
		ServletContext context = config.getServletContext();
		// 获取map
		Map countMap = (Map) context.getAttribute("countMap");
		// 获取你的ip
		String ip = request.getRemoteAddr();
		// 判断map中是否存在该ip
		Integer count = countMap.get(ip);
		// 判断count为null
		if(count == null){
			// 第一次来
			count = 1;
		}else{
			// 来过很多次了
			count++;
		}
		// 把ip和count存入到Map中
		countMap.put(ip, count);
		// 向域中存入map
		context.setAttribute("countMap", countMap);
		// 放行
		chain.doFilter(request, response);
	}

	@Override
	public void destroy() {
		// TODO Auto-generated method stub
		
	}

}
 
	 	CountFilter
	 	cn.itcast.demo3.CountFilter
	 
	 
	 	CountFilter
	 	/*
	 

Filter常见应用(4):

实现用户自动登陆的过滤器

什么是自动登录?

自动登录就是必须先登录,并且选择自动登录的按钮,关闭浏览器,再次打开浏览器访问原来的登录页面的时候,会直接进入,不行再次登录。

Javaweb:Servlet过滤器以及常见应用展示_第7张图片

 

在用户登陆成功后,以cookis形式发送用户名、密码给客户端

编写一个过滤器,filter方法中检查cookie中是否带有用户名、密码信息,如果存在则调用业务层登陆方法,登陆成功后则向session中存入user对象(即用户登陆标记),以实现程序完成自动登陆。

保证环境配置准备完毕,还需要在MySQL中创建表信息,与User封装类的字段相同。

后台程序:

MyjdbcUtil.java: 操作数据库的工具类,独立放在util工具包中:

package cn.itcast.utils;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import javax.sql.DataSource;

import com.mchange.v2.c3p0.ComboPooledDataSource;

/**
 * 操作JDBC
 * @author Administrator
 */
public class MyJdbcUtil {
	
	public static ComboPooledDataSource dataSource = new ComboPooledDataSource();
	
	/**
	 * 获取链接
	 * @return
	 * @throws SQLException 
	 */
	public static Connection getConnection() throws SQLException{
		return dataSource.getConnection();
	}
	
	/**
	 * 获取连接池
	 * @return
	 */
	public static DataSource getDataSource(){
		return dataSource;
	}
	
	/**
	 * 释放资源
	 * @param rs
	 * @param stmt
	 * @param conn
	 */
	public static void release(ResultSet rs,Statement stmt,Connection conn){
		if(rs != null){
			try {
				rs.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
			rs = null;
		}
		if(stmt != null){
			try {
				stmt.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
			stmt = null;
		}
		if(conn != null){
			try {
				conn.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
			conn = null;
		}
	}
	
	/**
	 * 释放资源的方法
	 * @param stmt
	 * @param conn
	 */
	public static void release(Statement stmt,Connection conn){
		if(stmt != null){
			try {
				stmt.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
			stmt = null;
		}
		if(conn != null){
			try {
				// 归还的方法
				conn.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
			conn = null;
		}
	}
	
}

LoginServlet.java:

package cn.itcast.demo4;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 登陆的功能
 * @author Administrator
 *
 */
public class LoginServlet extends HttpServlet {

	private static final long serialVersionUID = -8579027867816374707L;

	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		
		request.setCharacterEncoding("UTF-8");
		// 获取参数
		String username = request.getParameter("username");
		String password = request.getParameter("password");
		
		UserDao dao = new UserDao();
		User existUser = dao.findUser(username, password);
		if(existUser == null){
			// 给提示
			request.getRequestDispatcher("/demo4/login.jsp").forward(request, response);
		}else{
			
			// 把用户名和密码保存到cookie中,回写到浏览器。
			String autologin = request.getParameter("autologin");
			// 下一次自动登陆,把你的用户名和密码保存起来
			if("auto_ok".equals(autologin)){
				// 创建cookie,回写
				Cookie cookie = new Cookie("autologin",username+"#itcast#"+password);
				// 设置有效时间
				cookie.setMaxAge(60*60);
				// 回写
				response.addCookie(cookie);
			}
			// 把用户的信息保存到session中
			request.getSession().setAttribute("existUser", existUser);
			response.sendRedirect(request.getContextPath()+"/demo4/suc.jsp");
		}
		
	}

	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		doGet(request, response);
	}

}


User.java:

package cn.itcast.demo4;

public class User {
	
	private int id;
	private String username;
	private String password;
	private String nickname;
	private String type;
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getUsername() {
		return username;
	}
	public void setUsername(String username) {
		this.username = username;
	}
	public String getPassword() {
		return password;
	}
	public void setPassword(String password) {
		this.password = password;
	}
	public String getNickname() {
		return nickname;
	}
	public void setNickname(String nickname) {
		this.nickname = nickname;
	}
	public String getType() {
		return type;
	}
	public void setType(String type) {
		this.type = type;
	}
}

UserDao.java:

package cn.itcast.demo4;

import java.sql.SQLException;

import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;

import cn.itcast.utils.MyJdbcUtil;

public class UserDao {
	
	/**
	 * 通过用户名和密码查询单个用户
	 * @param username
	 * @param password
	 * @return
	 */
	public User findUser(String username,String password){
		QueryRunner runner = new QueryRunner(MyJdbcUtil.getDataSource());
		try {
			return runner.query("select * from t_user where username = ? and password = ?", new BeanHandler(User.class), username,password);
		} catch (SQLException e) {
			e.printStackTrace();
			throw new RuntimeException(e);
		}
	}

}

 AutoLoginFilter.java:            过滤器实现自动登录功能

package cn.itcast.demo4;

import java.io.IOException;

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.HttpServletRequest;
import javax.servlet.http.HttpSession;

/**
 * 自动登陆的功能
 * @author Administrator
 *
 */
public class AutoLoginFilter implements Filter{

	public void init(FilterConfig filterConfig) throws ServletException {
		
	}
	
	
	public void doFilter(ServletRequest request, ServletResponse response,
			FilterChain chain) throws IOException, ServletException {
		/**
		 * * 在过滤器中可以直接获取session中的用户信息,如果user不为空,说明浏览器没关。放行。
			* 从session中获取不到user的信息
		  * 先获取cookie,获取指定名称的cookie,
		  * 如果cookie为空,放行。
		  * 如果cookie不为空,获取用户名和密码。去数据库查询。
		  * 如果查询不到,cookie的信息不正确,放行(没有存入session中)。
		  * 如果查询到了,cookie中的信息是正确,把用户的信息保存到session中。放行。
		 */
		// 从session中获取用户的信息
		HttpServletRequest req = (HttpServletRequest) request;
		HttpSession session = req.getSession();
		// 从session获取用户的信息
		User user = (User) session.getAttribute("existUser");
		// 如果浏览器没关闭,session中的用户信息不为null的
		if(user != null){
			chain.doFilter(req, response);
		}else{
			// session中没有用户的信息
			// 获取指定名称的cookie
			Cookie [] cookies = req.getCookies();
			// 获取到cookie,就可以进行判断了
			Cookie cookie = getCookieByName(cookies,"autologin");
			// 如果cookie为null
			// 在你的浏览器中,根本就没有autologin的cookie
			if(cookie == null){
				// 直接放行	自己访问suc.jsp(因为suc.jsp已经做过处理了,没有session默认让你去登陆)了。
				chain.doFilter(req, response);
			}else{
				// 从cookie中获取用户名和密码,去数据中查询
				String username = cookie.getValue().split("#itcast#")[0];
				String password = cookie.getValue().split("#itcast#")[1];
				// 你需要去数据库中进行查询
				UserDao dao = new UserDao();
				// 去数据库中查询指定名称和密码的用户
				User existUser = dao.findUser(username, password);
				// 查询出的用户为null
				if(existUser == null){
					// 放行
					chain.doFilter(req, response);
				}else{
					// 存入到session中
					session.setAttribute("existUser", existUser);
					// 放行
					chain.doFilter(req, response);
				}
			}
		}
	}
	
	
	public Cookie getCookieByName(Cookie [] cookies,String cookieName){
		if(cookies == null){
			return null;
		}else{
			for (Cookie cookie : cookies) {
				// 判断
				if(cookie.getName().equals(cookieName)){
					return cookie;
				}
			}
			return null;
		}
	}
	

	public void destroy() {
		
	}

}


	 	AutoLoginFilter
	 	cn.itcast.demo4.AutoLoginFilter
	 
	 
	 	AutoLoginFilter
	 	/*
	 

 

前台程序:

login.jsp:
 

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>




Insert title here



登陆页面

用户名:
密码:
自动登陆

suc.jsp:
 

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
    
    <%@ taglib prefix="c"  uri="http://java.sun.com/jsp/jstl/core" %>
    




Insert title here




	

亲,请登陆!

亲!欢迎访问:${ existUser.nickname },角色是:${ existUser.type }

添加商品 修改商品 删除商品 查看商品

Filter常见应用(5):

Javaweb:Servlet过滤器以及常见应用展示_第8张图片

AuthorityFilter 权限过滤器

在一个系统中通常有多个权限的用户。不同权限用户的可以浏览不同的页面。使用Filter进行判断不仅省下了代码量,而且如果要更改的话只需要在Filter文件里动下就可以。

过滤器类:

package cn.itcast.demo5;

import java.io.IOException;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;

import cn.itcast.demo4.User;

/**
 * URL级别全选验证
 * @author Administrator
 *
 */
public class CheckUserUrlFilter implements Filter{

	private FilterConfig config;

	/**
	 * 初始化的操作,获取初始化参数,读取到Map集合中。存入ServletContext中。
	 */
	public void init(FilterConfig config) throws ServletException {
		// 创建Map保存信息
		Map urlMap = new HashMap();
		// 获取初始化参数,把参数的内容保存到urlMap中
		Enumeration e = config.getInitParameterNames();
		while(e.hasMoreElements()){
			// 获取到的值
			String paramName = e.nextElement();
			// 获取到的是的值
			String paramValue = config.getInitParameter(paramName);
			// 存入Map集合中 	{/admin:admin}	{/user:user}
			urlMap.put(paramName, paramValue);
		}
		// 存入到ServletContext中
		config.getServletContext().setAttribute("urlMap", urlMap);
		this.config = config;
	}

	/**
	 * 权限的验证
	 * 	* 从请求的链接中拿到链接和urlMap中的链接和type类型做对比
	 */
	public void doFilter(ServletRequest request, ServletResponse response,
			FilterChain chain) throws IOException, ServletException {
		// 先获取请求的链接		请求:/admin/add.jsp		map {/admin:admin}	{/user:user}
		
		HttpServletRequest req = (HttpServletRequest) request;
		// /day21/admin/add.jsp
		// String uri = req.getRequestURI();
		// System.out.println(uri);
		// 
		// 获取请求的链接
		String sPath = req.getServletPath();
		// System.out.println(sPath);
		// 和Map来进行对比
		ServletContext context = config.getServletContext();
		// 获取Map的集合了
		Map urlMap = (Map) context.getAttribute("urlMap");
		
		// 做对比 set的key值 /admin  /user
		Set set = urlMap.keySet();
		// 循环 /admin
		for (String paramName : set) {
			// /admin/add.jsp从/admin开始的
			if(sPath.startsWith(paramName)){
				// 去获取session的用户信息,从用户的信息中获取type属性的值,和Map中的value的值进行对比。
				User user = (User) req.getSession().getAttribute("existUser");
				// 如果user为null
				if(user == null){
					// 转发到登陆的页面上
					req.getRequestDispatcher("/demo4/login.jsp").forward(req, response);
					return;
				}else{
					// 去判断用户的type的值和我Map中的value的值做对比
					String userType = user.getType();
					
					// 还有一个Map中存了一个值  {/admin  admin} {/user  user}
					String paramValue = urlMap.get(paramName);
					
					if(userType.equals(paramValue)){
						// 匹配成功了	/admin/add.jsp  做过一次判断了,已/admin开头的,
						// 从用户的信息中获取type 的值和Map的值做了对比
						chain.doFilter(req, response);
						return;
					}else{
						// 向用户提示
						response.setContentType("text/html;charset=UTF-8");
						response.getWriter().write("

亲,您权限不够!!

"); return; } } } } chain.doFilter(req, response); } public void destroy() { } }

 

web.xml配置文件: 


	 	CheckUserUrlFilter
	 	cn.itcast.demo5.CheckUserUrlFilter
	 	
	 		/admin
	 		admin
	 	
	 	
	 		/user
	 		user
	 	
	 
	 
	 	CheckUserUrlFilter
	 	/*
	 

 

Filter高级开发:

由于开发人员在filter中可以得到代表用户请求和响应的requestresponse对象,因此在编程中可以使用Decorator(装饰器)模式对requestresponse对象进行包装,再把包装对象传给目标资源,从而实现一些特殊需求。

Decorator设计模式的实现

1.首先看需要被增强对象继承了什么接口或父类,编写一个类也去继承这些接口或父类。

2.在类中定义一个变量,变量类型即需增强对象的类型。

3.在类中定义一个构造函数,接收需增强的对象。

4.覆盖需增强的方法,编写增强的代码。

request对象的增强:

Servlet API 中提供了一个request对象的Decorator设计模式的默认实现类HttpServletRequestWrapper , (HttpServletRequestWrapper 类实现了request 接口中的所有方法,但这些方法的内部实现都是仅仅调用了一下所包装的的 request 对象的对应方法)以避免用户在对request对象进行增强时需要实现request接口中的所有方法。

使用Decorator模式包装request对象,完全解决getpost请求方式下的乱码问题

 

你可能感兴趣的:(J2EE)