1. 过滤器概述

1.1. 什么是过滤器

Filter译为过滤器,是JavaWeb的三大组件之一,用于在Servlet之外对Request或者Response进行修改。对于Web应用程序来说,过滤器是一个驻留在服务器端的Web组件,它可以截取客户端和服务器端之间的请求与响应信息。

1.2. 发展历史

由于Servlet规范是开放的,借助于公众与开源社区的力量,Servlet规范越来越科学,功能也越来越强大。2000年,Sun公司在Servlet2.3规范中添加了Filter功能,并在Servlet2.4中对Filter进行了细节上的补充。目前主流版本为Servlet2.5的Filter。

1.3. 运行原理

Servlet是服务器端用于处理客户端的请求与响应的,而Filter就是介于客户端与服务器端拦截客户端的请求或服务器端的响应,并对其修改或过滤。具体实现流程如下:

当客户端向服务器端发送一个请求时,如果有对应的过滤器进行拦截,过滤器可以改变请求的内容、或者重新设置请求协议的相关信息等,然后再将请求发送给服务器端的Servlet进行处理。当Servlet对客户端做出响应时,过滤器同样可以进行拦截,将响应内容进行修改或者重新设置后,再响应给客户端浏览器。在上述过程中,客户端与服务器端并不需要知道过滤器的存在。

在一个Web应用程序中,可以部署多个过滤器进行拦截,这些过滤器组成了一个过滤器链。过滤器链中的每个过滤器负责特定的操作和任务,客户端的请求在这些过滤器之间传递,直到服务器端的Servlet。具体执行流程如下:

1.4. 第一个过滤器

在Servlet API中提供了一个Filter接口,实现过滤器只需要实现该接口即可。以下是Filter接口的API:

Method Summary

void

destroy() 
Called by the web container to indicate to a filter that it is being taken out of service.

void

doFilter(ServletRequest request, ServletResponse response, FilterChain chain) 
The doFilter method of the Filter is called by the container each time a request/response pair is passed through the chain due to a client request for a resource at the end of the chain.

void

init(FilterConfig filterConfig) 
Called by the web container to indicate to a filter that it is being placed into service.

实现过滤器的具体步骤如下:

  • 创建一个Java类,并实现Filter接口,重写该接口的方法。
public class MyFitler implements Filter {
/**
* init()方法用于Filter的初始化
*/
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("执行了Filter的init()方法...");
}
/**
* doFilter()方法用于Filter的拦截
*/
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
System.out.println("执行了Filter的doFilter()方法...");
}
/**
* destory()方法用于Filter的销毁
*/
public void destroy() {
System.out.println("执行了Filter的destroy()方法...");
}
}
  • 在Web工程的web.xml文件中配置过滤器。
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<!-- 配置过滤器 -->
<filter>
<!-- 配置过滤器的名称 -->
<filter-name>MyFitler</filter-name>
<!-- 配置对应过滤器类的完整路径 -->
<filter-class>app.java.fitler.MyFitler</filter-class>
</filter>
<!-- 配置过滤器的拦截路径 -->
<filter-mapping>
<!-- 配置过滤器的名称 -->
<filter-name>MyFitler</filter-name>
<!-- 配置过滤器的拦截的路径 -->
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
  • 创建Web动态资源Servlet。
public class HelloServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.println("<h1>Hello Servlet.</h1>");
out.flush();
out.close();
}
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
  • 在Web工程的web.xml文件中配置Servlet。
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<servlet>
<servlet-name>HelloServlet</servlet-name>
<servlet-class>app.java.servlet.HelloServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>HelloServlet</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
</web-app>
  • 创建Web工程的静态资源JSP页面。
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>hello.jsp</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
</head>
<body>
<h1>Hello JSP.</h1>
</body>
</html>
  • 发布Web工程并访问,无论是访问动态资源Servlet还是静态资源JSP,过滤器都会拦截,并执行过滤器的doFilter()方法。
  • 这时访问的Servlet或者JSP并没有被执行,原因是过滤器只进行了拦截,并没有将请求发送到对应的Servlet或者JSP。在过滤器的doFilter()方法中执行FilterChain对象的doFilter()方法将进行放行。
public class MyFitler implements Filter {
/**
* init()方法用于Filter的初始化
*/
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("执行了Filter的init()方法...");
}
/**
* doFilter()方法用于Filter的拦截
*/
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
System.out.println("执行了Filter的doFilter()方法...");
chain.doFilter(request, response);
}
/**
* destory()方法用于Filter的销毁
*/
public void destroy() {
System.out.println("执行了Filter的destroy()方法...");
}
}

2. 深入过滤器

2.1. 生命周期

Servlet API提供的Filter接口中含有三个方法,分别为init()、doFilter()和destroy()方法。该三个方式就是Filter的生命周期方法。

  • Filter的构造函数
  • 在Tomcat服务器启动时执行。
  • 在Filter的生命周期中只执行一次。
  • init(FilterConfig)方法
    • 在Tomcat服务器启动时执行。
    • 在Filter的生命周期中只执行一次。
    • 用于Filter的初始化工作。
  • doFilter(ServletRequest, ServletResponse, FilterChain)方法
    • 在每次拦截时执行。
    • 在Filter的生命周期中只执行多次。
    • 用于Filter的拦截处理工作。
  • destroy()方法
    • 在Tomcat服务器关闭时执行。
    • 在Filter的生命周期中只执行一次。
    • 用于Filter的销毁工作。

2.2. 过滤器链

在一个Web应用程序中,可以部署多个过滤器进行拦截,这些过滤器组成了一个过滤器链。完成过滤器链的功能,具体步骤如下:

  • 创建一个Java类,并实现Filter接口,重写该接口的方法。
public class MyFitler1 implements Filter {
/**
* init()方法用于Filter的初始化
*/
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("执行了Filter1的init()方法...");
}
/**
* doFilter()方法用于Filter的拦截
*/
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
System.out.println("执行了Filter1的doFilter()方法...");
}
/**
* destory()方法用于Filter的销毁
*/
public void destroy() {
System.out.println("执行了Filter1的destroy()方法...");
}
}
  • 再创建一个Java类,并实现Filter接口,重写该接口的方法。
public class MyFilter2 implements Filter {
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("执行了Filter2的init()方法...");
}
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
System.out.println("执行了Filter2的doFilter()方法...");
}
public void destroy() {
System.out.println("执行了Filter2的destroy()方法...");
}
}
  • 在Web工程的web.xml文件中配置过滤器。
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<!-- 配置过滤器 -->
<filter>
<!-- 配置过滤器的名称 -->
<filter-name>MyFitler</filter-name>
<!-- 配置对应过滤器类的完整路径 -->
<filter-class>app.java.fitler.MyFitler</filter-class>
</filter>
<!-- 配置过滤器的拦截路径 -->
<filter-mapping>
<!-- 配置过滤器的名称 -->
<filter-name>MyFitler</filter-name>
<!-- 配置过滤器的拦截的路径 -->
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter>
<filter-name>MyFitler2</filter-name>
<filter-class>app.java.fitler.MyFilter2</filter-class>
</filter>
<filter-mapping>
<filter-name>MyFitler2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>

需要注意的是,FilterChain的doFilter()方法执行时,如果只有一个过滤器的话,执行该方法会将请求发送给服务器端的动态或静态资源。如果是过滤器链的话,只有在执行过滤器链的最后一个过滤器的FilterChain的doFilter()方法时,才会将请求发送给服务器端的动态或静态资源。如果不是在过滤器链的最后一个过滤器的FilterChain的doFilter()方法时,将请求发送给下一个过滤器进行拦截。

在过滤器链中的过滤器执行的先后顺序是按照Web工程的web.xml文件配置过滤器的先后顺序被执行。

2.3. FilterConfig

在过滤器接口的init()方法中提供了FilterConfig参数,通过该参数可以获取web.xml配置过滤器的参数内容,或者获取ServletContext对象等。FilterConfig API内容如下:

Method Summary

String

getFilterName() 
Returns the filter-name of this filter as defined in the deployment descriptor.

String

getInitParameter(String name) 
Returns a String containing the value of the named initialization parameter, or null if the parameter does not exist.

Enumeration

getInitParameterNames() 
Returns the names of the filter's initialization parameters as an Enumeration of String objects, or an empty Enumeration if the filter has no initialization parameters.

ServletContext

getServletContext() 
Returns a reference to the ServletContext in which the caller is executing.

具体使用方式如下:

  • 创建一个Java类,并实现Filter接口,重写该接口的方法。
public class MyFitler implements Filter {
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("执行了Filter的init()方法...");
}
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
System.out.println("执行了Filter的doFilter()方法...");
}
public void destroy() {
System.out.println("执行了Filter的destroy()方法...");
}
}
  • 在Web工程的web.xml文件中配置过滤器,并且设置初始化参数内容。
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<filter>
<filter-name>MyFitler</filter-name>
<filter-class>app.java.fitler.MyFitler</filter-class>
<init-param>
<param-name>longestory</param-name>
<param-value>http://www.baidu.com.com</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>MyFitler</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
  • 在过滤器的init()方法中获取配置文件的初始化参数。
public class MyFitler implements Filter {
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("执行了Filter的init()方法...");
System.out.println(filterConfig.getInitParameter("longestory"));
}
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
System.out.println("执行了Filter的doFilter()方法...");
}
public void destroy() {
System.out.println("执行了Filter的destroy()方法...");
}
}

需要注意的是,通过getInitParameter()方法获取的初始化参数是私有参数。只有当前过滤器才能获取到,而其他过滤器并不能访问。如果配置全局初始化参数,可以使用<context-param>来配置,并使用ServletContext对象获取。

2.4. Filter映射配置

过滤器需要配置在web.xml中才能生效。一个过滤器需要配置<filter>和<filter-mapping>标签,例如如下:

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<!-- 配置过滤器 -->
<filter>
<!-- 配置过滤器的名称 -->
<filter-name>MyFitler</filter-name>
<!-- 配置对应过滤器类的完整路径 -->
<filter-class>app.java.fitler.MyFitler</filter-class>
</filter>
<!-- 配置过滤器的拦截路径 -->
<filter-mapping>
<!-- 配置过滤器的名称 -->
<filter-name>MyFitler</filter-name>
<!-- 配置过滤器的拦截的路径 -->
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>

<filter>配置过滤器的名称,实现类以及初始化参数。<filter-mapping>配置当前过滤器拦截的路径。<filter-mapping>中的<url-pattern>标签用于配置当前过滤器拦截的路径,配置方式与Servlet的<url-pattern>配置方式类似,共有三种方式:

  • 完全匹配
  • 目录匹配
  • 扩展名匹配

如果需要拦截的是Servlet的话,有两种方式配置拦截路径:

  • 使用<url-pattern>标签:<url-pattern>/hello</url-pattern>
  • 使用<servlet-name>标签:<servlet-name>HelloServlet</servlet-name>

<dispatcher>标签配置到达Servlet的方法,有四种取值:REQUEST、FORWARD、INCLUDE和ERROR。可以同时配置多个<dispatcher>标签,如果没有配置<dispatcher>标签,默认为REQUEST。这四种取值的区别如下:

  • REQUEST:表示仅当直接请求Servlet时才生效。
  • FORWARD:表示仅当某Servlet通过FORWARD到该Servlet时才生效。
  • INCLUDE:JSP中可以通过<jsp:include>标签请求某Servlet或调用RequestDispatcher的include()方法请求某Servlet,仅这种情况下有效。
  • ERROR:JSP中可以通过<%@ page errorPage=”error.jsp”>标签指定错误处理页面,仅这种情况下有效。

<url-pattern>标签与<dispatcher>标签的关系是“且”的关系。只有满足<url-pattern>标签的条件,且满足<dispatcher>标签的条件时,当前过滤器才能生效。

3. 过滤器案例

3.1. 全站乱码案例

中文乱码问题一直都是Web应用开发的问题,想要解决整个Web应用程序的中文乱码问题,可以如下操作:

  • 创建一个Java类继承于HttpServletRequestWrapper类,用于重写HttpServletRequest,解决GET方式的中文乱码问题。
public class MyRequest extends HttpServletRequestWrapper {
public MyRequest(HttpServletRequest request) {
super(request);
}
@Override
public String getParameter(String name) {
String value = super.getParameter(name);
if (getMethod().equalsIgnoreCase("GET")) {
try {
value = new String(value.getBytes("ISO-8859-1"),"utf-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
return value;
}
}
  • 创建一个过滤器用于解决整个Web应用程序的中文乱码问题。
public class EncodingFilter implements Filter {
public void init(FilterConfig filterConfig) throws ServletException {}
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
MyRequest req = new MyRequest((HttpServletRequest)request);
chain.doFilter(req, response);
}
public void destroy() {}
}
  • 配置Web工程的web.xml文件。
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<filter>
<filter-name>EncodingFilter</filter-name>
<filter-class>app.java.demo4.EncodingFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>EncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
  • 创建一个JSP页面用于中文乱码问题的测试。
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>My JSP 'login.jsp' starting page</title>
</head>
<body>
<form id="userinfo" action="encoding" method="post">
用户名:<input type="text" name="username"><br>
密码:<input type="password" name="password"><br>
<input type="submit" value="登录">
</form>
<a href="/encoding?username=张无忌">GET方式的中文乱码问题</a>
</body>
</html>
  • 创建一个Servlet用于测试中文乱码问题。
public class EncodingServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String username = request.getParameter("username");
response.getWriter().println("<h1>username : "+username+"</h1>");
}
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
  • 配置Web工程的web.xml文件。
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<servlet>
<servlet-name>EncodingServlet</servlet-name>
<servlet-class>app.java.servlet.EncodingServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>EncodingServlet</servlet-name>
<url-pattern>/encoding</url-pattern>
</servlet-mapping>
</web-app>

3.2. 自动登录案例

所谓自动登录就是当用户第一次登录后,并且选择“自动登录”选项,用户从第二次访问开始,用户都无需再登录,完成直接登录的功能。具体实现步骤如下:

  • 创建一个JSP页面用于用户登录功能。
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>My JSP 'login.jsp' starting page</title>
</head>
<body>
<h3 style="color:red;">${msg }</h3>
<form id="userinfo" action="login" method="post">
用户名:<input type="text" name="username"><br>
密码:<input type="password" name="password"><br>
<input type="checkbox" name="autologin" value="true">自动登录<br>
<input type="submit" value="登录">
</form>
</body>
</html>
  • 创建一个JavaBean用于封装用户信息。
public class User {
private String username;
private String password;
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;
}
}
  • 创建一个Servlet用于处理用户登录逻辑。
public class LoginServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String username = request.getParameter("username");
String password = request.getParameter("password");
if("admin".equals(username)&&"admin".equals(password)){
User user = new User();
user.setUsername(username);
user.setPassword(password); HttpSession session = request.getSession();
session.setAttribute("user", user); if("true".equals(request.getParameter("autologin"))){
Cookie cookie = new Cookie("autologin", username+"#"+password);
cookie.setPath("/");
cookie.setMaxAge(60 * 60 * 24 * 90);
response.addCookie(cookie);
}
response.sendRedirect("index.jsp");
return;
}else{
request.setAttribute("msg", "用户名或密码错误,请重新输入.");
request.getRequestDispatcher("login.jsp").forward(request, response);
return;
}
}
}
  • 配置Web工程的web.xml文件。
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<servlet>
<servlet-name>LoginServlet</servlet-name>
<servlet-class>app.java.servlet.LoginServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>LoginServlet</servlet-name>
<url-pattern>/login</url-pattern>
</servlet-mapping>
</web-app>
  • 创建一个JSP页面用于显示主页面,显示用户登录信息。
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>My JSP 'index.jsp' starting page</title>
</head>
<body>
<c:if test="${empty user }">
<h1>您还未登录,请去<a href="login.jsp">登录</a></h1>
</c:if>
<c:if test="${not empty user }">
<h1>欢迎您,${user.username }</h1>
</c:if>
</body>
</html>
  • 创建一个过滤器用于完成自动登录功能。
public class AutoLoginFilter implements Filter {
public void init(FilterConfig filterConfig) throws ServletException {}
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest)request;
// 判断用户是否选择手动登录
if(req.getSession().getAttribute("user") != null){
// 已经登录
chain.doFilter(request, response);
return;
}else{
// 没有登录,查找是否含有自动登录Cookie
Cookie autoLoginCookie = findCookie(req.getCookies(), "autologin");
if (autoLoginCookie == null){
// 没有自动登录信息
chain.doFilter(request, response);
return;
}else{
// 存在自动登录信息
String username = autoLoginCookie.getValue().split("#")[0];
String password = autoLoginCookie.getValue().split("#")[1];
if (!"admin".equals(username)||!"admin".equals(password)) {
// 自动登录信息有问题
chain.doFilter(request, response);
}else{
// 完成自动登录功能
User user = new User();
user.setUsername(username);
user.setPassword(password);
req.getSession().setAttribute("user", user);
chain.doFilter(request, response);
return;
}
}
}
}
public Cookie findCookie(Cookie[] cookies, String name) {
if (cookies == null) {
return null;
} else {
for (Cookie cookie : cookies) {
if (cookie.getName().equals(name)) {
return cookie;
}
}
return null;
}
}
public void destroy() {}
}
  • 配置Web工程的web.xml文件。
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<filter>
<filter-name>AutoLoginFilter</filter-name>
<filter-class>app.java.demo2.AutoLoginFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>AutoLoginFilter</filter-name>
<url-pattern>/index.jsp</url-pattern>
</filter-mapping>
</web-app>

3.3. 权限控制案例

一般情况下,Web应用程序不能允许所有用户可以访问所有功能。换句话讲,不同的用户具有访问不同功能的权限。所以,需要完成权限控制功能,具体操作如下:

  • 创建JavaBean用于封装用户信息(包含权限信息)。
public class User {
private String username;
private String password;
private String role;
public String getRole() {
return role;
}
public void setRole(String role) {
this.role = role;
}
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;
}
}
  • 创建Web应用程序的主页面,用于用户功能的显示。
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>My JSP 'index.jsp' starting page</title>
</head>
<body>
<c:if test="${empty user }">
<h1>您还未登录,请去<a href="login.jsp">登录</a></h1>
</c:if>
<c:if test="${not empty user }">
<h1>欢迎您,${user.username }</h1>
<h1><a href="user/userlist.jsp">用户操作功能列表</a></h1>
<h1><a href="admin/adminlist.jsp">管理员操作功能列表</a></h1>
</c:if>
</body>
</html>
  • 创建用户可以访问的功能列表页面。
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>My JSP 'userlist.jsp' starting page</title>
</head>
<body>
<h1>这里是用户操作的功能列表!</h1>
</body>
</html>
  • 创建管理员可以访问的功能列表页面。
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>My JSP 'adminlist.jsp' starting page</title>
</head>
<body>
<h1>这里是管理员操作的功能列表!</h1>
</body>
</html>
  • 创建一个过滤器用于完成权限控制功能。
public class AuthoFilter implements Filter {
private FilterConfig config;
private Map<String, String> map = new HashMap<String, String>();
public void init(FilterConfig filterConfig) throws ServletException {
this.config = filterConfig;
}
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
Enumeration names = config.getInitParameterNames();
while (names.hasMoreElements()) {
String name = (String) names.nextElement();
String value = config.getInitParameter(name);
map.put(value, name);
}
HttpServletRequest req = (HttpServletRequest) request;
String path = req.getRequestURI().substring(req.getContextPath().length());
for (String needPath : map.keySet()) {
if (path.startsWith(needPath)) {
String needRole = map.get(needPath);
User user = (User) req.getSession().getAttribute("user");
if (user == null) {
req.getRequestDispatcher("login.jsp").forward(request, response);
return;
}else {
String role = user.getRole();
if (needRole.equals(role)) {
chain.doFilter(request, response);
return;
}else {
throw new RuntimeException("权限不足,无法访问!");
}
}
}
}
chain.doFilter(request, response);
}
public void destroy() {}
}
  • 配置Web工程的web.xml文件。
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<filter>
<filter-name>AuthoFilter</filter-name>
<filter-class>app.java.demo3.AuthoFilter</filter-class>
<init-param>
<param-name>user</param-name>
<param-value>/user</param-value>
</init-param>
<init-param>
<param-name>admin</param-name>
<param-value>/admin</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>AuthoFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>

3.4. 禁用缓存案例

之前完成过禁止浏览器缓存功能,使用的是响应协议头中的三个内容,如下:

Expires: -1

禁用浏览器缓存(考虑不同浏览器兼容性,存在三个字段)

Cache-Control: no-cache

Pragma: no-cache

在服务器端Servlet代码如下:

//设置响应头信息,禁止浏览器缓存.
response.setHeader("Cache-Control", "no-cache");
response.setHeader("Pragma", "no-cache");
response.setDateHeader("Expires", -1);

但这种方式只能适用于一个JSP页面,而一个Web应用程序中可能包含多个JSP页面。如果想要整个Web应用程序的所有JSP页面都禁止缓存,需要使用过滤器功能来完成,具体操作如下:

  • 创建一个过滤器类,实现Filter接口,并重写所有方法。
public class NoCacheFilter implements Filter {
public void init(FilterConfig filterConfig) throws ServletException {}
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
//1 将ServletResponse强转为HttpServletResponse
HttpServletResponse res = (HttpServletResponse)response;
//2 禁止浏览器缓存功能
res.setHeader("Cache-Control", "no-cache");
res.setHeader("Pragma", "no-cache");
res.setDateHeader("Expires", -1);
//3 过滤器放行
chain.doFilter(request, response);
}
public void destroy() {}
}
  • 配置Web工程中的web.xml文件。
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<filter>
<filter-name>NoCacheFilter</filter-name>
<filter-class>app.java.demo1.NoCacheFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>NoCacheFilter</filter-name>
<url-pattern>*.jsp</url-pattern>
</filter-mapping>
</web-app>

JavaWeb Filter的更多相关文章

  1. JavaWeb——Filter

    一.基本概念 之前我们用一篇博文介绍了Servlet相关的知识,有了那篇博文的知识积淀,今天我们学习Filter将会非常轻松,因为Filter有很多地方和Servlet类似,下面在讲Filter的时候 ...

  2. JAVAWEB Filter使用

    Filter学习 1Filter是什么:是过滤器简称 2Filter有什么作用:在filter中可以得到代表用户请求和响应的request.response对象,因此在编程中可以使用Decorator ...

  3. JavaWeb——Filter过滤器

    1.Filter的目的 Filter用于在Servlet之前检测和修改请求和响应,它可以拒绝.重定向或转发请求.常见的有这几种: 日志过滤器 使用过滤器记录请求,提供请求日志记录,还可以添加追踪信息用 ...

  4. JavaWeb—过滤器Filter

    1.Filter简介 Filter称之为过滤器,是用来做一些拦截的任务.比如客户端请求服务器的某个资源时(可以是Servlet.JSP.HTML等等),我们可以拦截.当服务器返回资源给客户端的时候,我 ...

  5. Filter、Listener 学习总结

    今天我们来介绍 Filter.Listener 这两个模块一些简单的知识和应用,接下来我们开始我们的正题 ! 1. Filter(过滤器) 1.1 对 Servlet 容器调用 Servlet 的过程 ...

  6. filter和listener的生命周期

    filter(过滤器)和listener(监听器)的生命周期 老实说 生命周期要是说成作用的时间范围我会理解的更好 filter package com.javaweb.filter; import ...

  7. Filter的常见应用

    1.字符编码过滤器 实现功能,在a.jsp中填写用户名提交到b.jsp,在b.jsp中读取参数名. a.jsp <body> <form action="encoding/ ...

  8. Filter内容

    1.利用Filter来过滤的时候大都是Http请求和Http响应,在doFilter()方法中,参数类是ServletRequest和ServletResponse  ,使用的时候一般需要强制转换为H ...

  9. jsp版ueditor图片在线管理返回绝对路径

    引用:http://zhengyunfei.iteye.com/blog/2149979 如果你有富文本编辑器的功能需要开发,我推荐你用百度的ueditor.本文将与你分享jsp版ueditor开发中 ...

随机推荐

  1. Laravel5.1 搭建博客 --展示简单的首页

    今天起开始搭建博客,把之前学的东西运用下. 1 创建 配置项目 1.1 创建项目 composer create-project laravel/laravel blog 5.1.1 1.2 配置数据 ...

  2. 第十五篇:流迭代器 + 算法灵活控制IO流

    前言 标准算法配合迭代器使用太美妙了,使我们对容器(数据)的处理更加得心应手.那么,能不能对IO流也使用标准算法呢?有人认为不能,他们说因为IO流不是容器,没有迭代器,故无法使用标准算法.他们错了,错 ...

  3. golang build 编译规则

    文章来源: http://blog.csdn.net/varding/article/details/12675971 讲述了golang中的条件编译,摘要如下: 第一种条件编译的方法:编译标签 编译 ...

  4. sql server 作业没跑、开启sql 代理服务、新建作业

    sql server 数据库中设置了晚上跑的作业,以前没注意,后来换了服务器建了新的虚拟机后第二天发现作业没跑. 主动执行作业可以实现目的,但是他不会自动执行,那么问题来了,为啥呢? 没有开启SQL ...

  5. iOS 计算某个月的天数 计算某天的星期

    // 某年某月的天数 - (NSInteger)dayCount:(NSInteger)years { NSInteger count = ; ; i <= ; i++) { == i) { = ...

  6. 七牛wordpress

    当你看到柯南君的时候说明:我的七牛云图加速已经生效了. 准备工作: ①申请一个七牛账号并新增空间 ②到wordpress后台搜索qiniu并安装插件 在七牛后台找到AK和SK,配置wp后台七牛镜像存储 ...

  7. 【Linux】命令学习笔记和总结

    莫名的想学习一下Linux了,因为对这方面的知识储备为0.对于命令行界面始终是零接触零了解,对一个程序员来说这几乎是致命的,所以简单了解一下. 一.教程参考 参考菜鸟教程即可: Linux 教程 | ...

  8. Office word中去掉首页的页眉

    1.首先将光标位置移动到第二页的开始,然后点击页面布局命令. 2.页面布局里面找到分隔符,找到下一页的分隔符.(分页符分页) 3.双击第二页的页眉,打开页眉编辑菜单.将连接到前一条页眉的命令去掉. 4 ...

  9. 名义人均GDP的背后,中国真实的人均GDP是1.2万美元!(中国GDP含金量较高)

    来源:天涯社区 根据IMF(国际货币基金组织)在今年4月的报告,2014年份中国人均GDP为7600美元,在185个国家当中排行第78位. 然而,根据楼主在国外行走多年的经验,巴西.墨西哥.马来西亚. ...

  10. C++ 常见字符处理 收录

    1.string字符串删除 字符串中 指定字符 std::string& HTTPRequestHandlerImpl::replace_all_distinct(std::string&am ...