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

版权声明: https://blog.csdn.net/weixin_42442713/article/details/84488418

Filter简介:

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

l特点:

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

过滤器的拦截是双向的

可以有多个过滤器。

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

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

过滤器的工作原理

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

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

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

过滤器Filter的实现和部署

(1)实现一个过滤器Filter

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

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

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

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

(2)部署一个过滤器Filter

web.xml配置文件中部署Filter

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

<filter-name>用来设定过滤器的名字

<filter-class >用来设定过滤器的类路径

<filter>
 	<filter-name>TestFilter</filter-name>
 	<filter-class>filter.TestFilter</filter-class>
 </filter>

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

<filter-name>用来设定过滤器的名字

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

<filter-mapping>
 	<filter-name>TestFilter</filter-name>
 	<url-pattern>/*.jsp</url-pattern>
 </filter-mapping>

实例:

过滤器类:

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配置:


	<!-- 配置过滤器   -->
	<!-- 配置过滤器的信息 -->
	<filter>
		<!-- 配置名字 -->
		<filter-name>FilterDemo1</filter-name>
		<!-- 包名+类名 -->
		<filter-class>cn.itcast.filter.FilterDemo1</filter-class>
	</filter>
	<!-- 配置过滤器的映射 -->
		<!-- 配置访问方式 -->
	<!-- 
	<filter-mapping>
		<filter-name>FilterDemo1</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>

Filter--- FilterChain

在一个web应用中,可以开发编写多个Filter,这些Filter组合起来称之为一个Filter链。

web服务器根据Filterweb.xml文件中的注册顺序<mapping>,决定先调用哪个Filter,当第一个FilterdoFilter方法被调用时,web服务器会创建一个代表Filter链的FilterChain对象传递给该方法。在doFilter方法中,开发人员如果调用了FilterChain对象的doFilter方法,则web服务器会检查FilterChain对象中是否还有filter,如果有,则调用第2filter,如果没有,则调用目标资源。

Filter链实验(查看filterChain API文档)

Filter是如何实现拦截的?

Filter接口中有一个doFilter方法,当开发人员编写好Filter,并配置对哪个web资源(拦截url)进行拦截后,WEB服务器每次在调用web资源之前,都会先调用一下filterdoFilter方法,因此,在该方法内编写代码可达到如下目的:

调用目标资源之前,让一段代码执行

是否调用目标资源(即是否让用户访问web资源)。

web服务器在调用doFilter方法时,会传递一个filterChain对象进来,filterChain对象是filter接口中最重要的一个对象,它也提供了一个doFilter方法,开发人员可以根据需求决定是否调用此方法,调用该方法,则web服务器就会调用web资源的service方法,即web资源就会被访问,否则web资源不会被访问。

调用目标资源之后,让一段代码执行

Filter的生命周期:

init(FilterConfig filterConfig)throws ServletException

和我们编写的Servlet程序一样,Filter的创建和销毁由WEB服务器负责web 应用程序启动时web 服务器将创建Filter 的实例对象,并调用其init方法进行初始化(注:filter对象只会创建一次,init方法也只会执行一次。示例 )

开发人员通过init方法的参数,可获得代表当前filter配置信息的FilterConfig对象。(filterConfig对象见下页PPT)

doFilter(ServletRequest,ServletResponse,FilterChain)

每次filter进行拦截都会执行

在实际开发中方法中参数requestresponse通常转换为HttpServletRequestHttpServletResponse类型进行操作

destroy()

Web容器卸载 Filter 对象之前被调用。

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;

/**
 * 过滤器的生命周期
 * @author Administrator
 *
 */
public class FilterDemo2 implements Filter{
	
	/**
	 * 初始化的操作
	 * 过滤器什么创建呢?	服务器启动的时候创建过滤器的实例。
	 * 调用几次?	调用一次	
	 */
	public void init(FilterConfig filterConfig) throws ServletException {
		System.out.println("init...");
	}
	
	/**
	 * 什么时候执行
	 * 每次请求的时候,过滤器配置满足过滤的条件,有一次请求就会执行一次。
	 */
	public void doFilter(ServletRequest request, ServletResponse response,
			FilterChain chain) throws IOException, ServletException {
		System.out.println("doFilter....");
		chain.doFilter(request, response);
	}

	/**
	 * 过滤器什么时候销毁  服务器关闭,移除项目
	 * 调用几次 一次。
	 */
	public void destroy() {
		System.out.println("destroy....");
	}

}

 FilterConfig接口:

用户在配置filter时,可以使用<init-param>filter配置一些初始化参数,当web容器实例化Filter对象,调用其init方法时,会把封装了filter初始化参数的filterConfig对象传递进来。因此开发人员在编写filter时,通过filterConfig对象的方法,就可获得:

String getFilterName():得到filter的名称。

String getInitParameter(String name): 返回在部署描述中指定名称的初始化参数的值。如果不存在返回null.

Enumeration getInitParameterNames():返回过滤器的所有初始化参数的名字的枚举集合。

public ServletContext getServletContext():返回Servlet上下文对象的引用。

Filter的配置之<filter>(和上面有雷同)

<filter>
 	     <filter-name>testFitler</filter-name>
	     <filter-class>org.test.TestFiter</filter-class>
	     <init-param>
		 <param-name>word_file</param-name>	
		 <param-value>/WEB-INF/word.txt</param-value>
	     </init-param>
</filter>



<filter-name>用于为过滤器指定一个名字,该元素的内容不能为空。
<filter-class>元素用于指定过滤器的完整的限定类名。
<init-param>元素用于为过滤器指定初始化参数,它的子元素<param-name>指定参数的名字,<param-value>指定参数的值。在过滤器中,可以使用FilterConfig接口对象来访问初始化参数。

 Filter的配置之<filter-mapping>:

<filter-mapping>元素用于设置一个 Filter 所负责拦截的资源。一个Filter拦截的资源可通过两种方式来指定:Servlet 名称和资源访问的请求路径

<filter-name>子元素用于设置filter的注册名称。该值必须是在<filter>元素中声明过的过滤器的名字

<url-pattern>设置 filter 所拦截的请求路径(过滤器关联的URL样式)

<servlet-name>指定过滤器所拦截的Servlet名称。

<dispatcher>指定过滤器所拦截的资源被 Servlet 容器调用的方式,可以是REQUEST,INCLUDE,FORWARDERROR之一,默认REQUEST。用户可以设置多个<dispatcher> 子元素用来指定 Filter 对资源的多种调用方式进行拦截。

package cn.itcast.filter;

import java.io.IOException;
import java.util.Enumeration;

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 FilterDemo3 implements Filter{

	/**
	 * 使用FilterConfig来获取一些信息
	 */
	public void init(FilterConfig config) throws ServletException {
		// 获取filter配置的名称<filter-name>
		String filterName = config.getFilterName();
		System.out.println("过滤器的配置名称:"+filterName);
		// 获取初始化参数
		String username = config.getInitParameter("username");
		String password = config.getInitParameter("password");
		System.out.println(username+" : "+password);
		
		Enumeration<String> e = config.getInitParameterNames();
		while(e.hasMoreElements()){
			// username和password
			String name = e.nextElement();
			// 获取username的值
			String value = config.getInitParameter(name);
			System.out.println(name+" : "+value);
		}
		
		// 获取ServeltContext对象
		ServletContext c = config.getServletContext();
		
	}
	
	public void doFilter(ServletRequest request, ServletResponse response,
			FilterChain chain) throws IOException, ServletException {
		System.out.println("我是demo3...");
		chain.doFilter(request, response);
		System.out.println("我是回来的demo3...");
	}

	public void destroy() {
		
	}

}
 <filter>
	 	<filter-name>FilterDemo3</filter-name>
	 	<filter-class>cn.itcast.filter.FilterDemo3</filter-class>
	 	<init-param>
	 		<param-name>username</param-name>
	 		<param-value>root</param-value>
	 	</init-param>
	 	<init-param>
	 		<param-name>password</param-name>
	 		<param-value>123</param-value>
	 	</init-param>
	 </filter>
	  <filter-mapping>
	 	<filter-name>FilterDemo3</filter-name>
	 	<url-pattern>/*</url-pattern>
	 	<dispatcher>ERROR</dispatcher>
	 </filter-mapping>
	 -->

映射Filter示例:

<filter-mapping>
     <filter-name>testFilter</filter-name>
    <url-pattern>/test.jsp</url-pattern>
</filter-mapping>



<filter-mapping>
    <filter-name>testFilter</filter-name>
   <url-pattern>/index.jsp</url-pattern>
   <dispatcher>REQUEST</dispatcher>
   <dispatcher>FORWARD</dispatcher>
</filter-mapping>

映射Filter的多种方式:

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

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

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

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

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

Filter常见应用(1):

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

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

过滤器类:

web.xml配置文件: 

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
		
	}

}
 <filter>
	 	<filter-name>TimeFilter</filter-name>
	 	<filter-class>cn.itcast.demo2.TimeFilter</filter-class>
	 </filter>
	 <filter-mapping>
	 	<filter-name>TimeFilter</filter-name>
	 	<url-pattern>*.jsp</url-pattern>
	 </filter-mapping>
</filter>

Filter常见应用(3):

分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<String, Integer> countMap = new HashMap<String, Integer>();
		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<String, Integer> countMap = (Map<String, Integer>) 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
		
	}

}
 <filter>
	 	<filter-name>CountFilter</filter-name>
	 	<filter-class>cn.itcast.demo3.CountFilter</filter-class>
	 </filter>
	 <filter-mapping>
	 	<filter-name>CountFilter</filter-name>
	 	<url-pattern>/*</url-pattern>
	 </filter-mapping>

Filter常见应用(4):

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

什么是自动登录?

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

在用户登陆成功后,以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>(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() {
		
	}

}

<filter>
	 	<filter-name>AutoLoginFilter</filter-name>
	 	<filter-class>cn.itcast.demo4.AutoLoginFilter</filter-class>
	 </filter>
	 <filter-mapping>
	 	<filter-name>AutoLoginFilter</filter-name>
	 	<url-pattern>/*</url-pattern>
	 </filter-mapping>

前台程序:

login.jsp:
 

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>

<h3>登陆页面</h3>
<form action="${ pageContext.request.contextPath }/login" method="post">
	用户名:<input type="text"  name="username" /><br/>
	密码:<input type="password"  name="password" /><br/>
	<input type="checkbox" name="autologin" value="auto_ok" />自动登陆<br/> 
	<input type="submit" value="登陆 " />
</form>

</body>
</html>

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" %>
    
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>

<c:if test="${ empty existUser }">
	<h3><a href="${ pageContext.request.contextPath }/demo4/login.jsp">亲,请登陆!</a></h3>
</c:if>

<c:if test="${ not empty existUser }">
	<h3>亲!欢迎访问:${ existUser.nickname },角色是:${ existUser.type }</h3>
	
	<h3>
		<a href="${ pageContext.request.contextPath }/admin/add.jsp">添加商品</a>
		<a href="${ pageContext.request.contextPath }/admin/update.jsp">修改商品</a>
		<a href="${ pageContext.request.contextPath }/admin/delete.jsp">删除商品</a>
		<a href="${ pageContext.request.contextPath }/user/show.jsp">查看商品</a>
	</h3>
	
</c:if>

</body>
</html>

Filter常见应用(5):

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<String, String> urlMap = new HashMap<String, String>();
		// 获取初始化参数,把参数的内容保存到urlMap中
		Enumeration<String> e = config.getInitParameterNames();
		while(e.hasMoreElements()){
			// 获取到<param-name>的值
			String paramName = e.nextElement();
			// 获取到的是<param-value>的值
			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<String, String> urlMap = (Map<String, String>) context.getAttribute("urlMap");
		
		// 做对比 set的key值 /admin  /user
		Set<String> 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("<h3>亲,您权限不够!!</h3>");
						return;
					}
				}
			}
		}
		
		chain.doFilter(req, response);
		
	}

	public void destroy() {
		
	}

}

web.xml配置文件: 

<filter>
	 	<filter-name>CheckUserUrlFilter</filter-name>
	 	<filter-class>cn.itcast.demo5.CheckUserUrlFilter</filter-class>
	 	<init-param>
	 		<param-name>/admin</param-name>
	 		<param-value>admin</param-value>
	 	</init-param>
	 	<init-param>
	 		<param-name>/user</param-name>
	 		<param-value>user</param-value>
	 	</init-param>
	 </filter>
	 <filter-mapping>
	 	<filter-name>CheckUserUrlFilter</filter-name>
	 	<url-pattern>/*</url-pattern>
	 </filter-mapping>

Filter高级开发:

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

Decorator设计模式的实现

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

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

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

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

request对象的增强:

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

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

猜你喜欢

转载自blog.csdn.net/weixin_42442713/article/details/84488418
今日推荐