Javaweb之filter详解
过滤器概述
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](https://www.cnblogs.com/aaron911/p/7988953.html#doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain))(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接口,重写该接口的方法。
[](javascript:void(0)😉
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()方法...");
}
}
[](javascript:void(0)😉
- 在Web工程的web.xml文件中配置过滤器。
[](javascript:void(0)😉
<?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>
[](javascript:void(0)😉
- 创建Web动态资源Servlet。
[](javascript:void(0)😉
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);
}
}
[](javascript:void(0)😉
- 在Web工程的web.xml文件中配置Servlet。
[](javascript:void(0)😉
<?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>
[](javascript:void(0)😉
- 创建Web工程的静态资源JSP页面。
[](javascript:void(0)😉
<%@ 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>
[](javascript:void(0)😉
-
发布Web工程并访问,无论是访问动态资源Servlet还是静态资源JSP,过滤器都会拦截,并执行过滤器的doFilter()方法。
-
这时访问的Servlet或者JSP并没有被执行,原因是过滤器只进行了拦截,并没有将请求发送到对应的Servlet或者JSP。在过滤器的doFilter()方法中执行FilterChain对象的doFilter()方法将进行放行。
[](javascript:void(0)😉
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()方法...");
}
}
[](javascript:void(0)😉
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接口,重写该接口的方法。
[](javascript:void(0)😉
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()方法...");
}
}
[](javascript:void(0)😉
- 再创建一个Java类,并实现Filter接口,重写该接口的方法。
[](javascript:void(0)😉
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()方法...");
}
}
[](javascript:void(0)😉
- 在Web工程的web.xml文件中配置过滤器。
[](javascript:void(0)😉
<?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>
[](javascript:void(0)😉
需要注意的是,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接口,重写该接口的方法。
[](javascript:void(0)😉
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()方法...");
}
}
[](javascript:void(0)😉
- 在Web工程的web.xml文件中配置过滤器,并且设置初始化参数内容。
[](javascript:void(0)😉
<?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>
[](javascript:void(0)😉
- 在过滤器的init()方法中获取配置文件的初始化参数。
[](javascript:void(0)😉
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()方法...");
}
}
[](javascript:void(0)😉
需要注意的是,通过getInitParameter()方法获取的初始化参数是私有参数。只有当前过滤器才能获取到,而其他过滤器并不能访问。如果配置全局初始化参数,可以使用来配置,并使用ServletContext对象获取。
2.4. Filter映射配置
过滤器需要配置在web.xml中才能生效。一个过滤器需要配置和标签,例如如下:
[](javascript:void(0)😉
<?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>
[](javascript:void(0)😉
配置过滤器的名称,实现类以及初始化参数。配置当前过滤器拦截的路径。中的标签用于配置当前过滤器拦截的路径,配置方式与Servlet的配置方式类似,共有三种方式:
- 完全匹配
- 目录匹配
- 扩展名匹配
如果需要拦截的是Servlet的话,有两种方式配置拦截路径:
- 使用标签:/hello
- 使用标签:HelloServlet
标签配置到达Servlet的方法,有四种取值:REQUEST、FORWARD、INCLUDE和ERROR。可以同时配置多个标签,如果没有配置标签,默认为REQUEST。这四种取值的区别如下:
- REQUEST:表示仅当直接请求Servlet时才生效。
- FORWARD:表示仅当某Servlet通过FORWARD到该Servlet时才生效。
- INCLUDE:JSP中可以通过jsp:include标签请求某Servlet或调用RequestDispatcher的include()方法请求某Servlet,仅这种情况下有效。
- ERROR:JSP中可以通过<%@ page errorPage=”error.jsp”>标签指定错误处理页面,仅这种情况下有效。
标签与标签的关系是“且”的关系。只有满足标签的条件,且满足标签的条件时,当前过滤器才能生效。
3. 过滤器案例
3.1. 全站乱码案例
中文乱码问题一直都是Web应用开发的问题,想要解决整个Web应用程序的中文乱码问题,可以如下操作:
- 创建一个Java类继承于HttpServletRequestWrapper类,用于重写HttpServletRequest,解决GET方式的中文乱码问题。
[](javascript:void(0)😉
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;
}
}
[](javascript:void(0)😉
- 创建一个过滤器用于解决整个Web应用程序的中文乱码问题。
[](javascript:void(0)😉
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() {}
}
[](javascript:void(0)😉
- 配置Web工程的web.xml文件。
[](javascript:void(0)😉
<?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>
[](javascript:void(0)😉
- 创建一个JSP页面用于中文乱码问题的测试。
[](javascript:void(0)😉
<%@ 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>
[](javascript:void(0)😉
- 创建一个Servlet用于测试中文乱码问题。
[](javascript:void(0)😉
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);
}
}
[](javascript:void(0)😉
- 配置Web工程的web.xml文件。
[](javascript:void(0)😉
<?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>
[](javascript:void(0)😉
3.2. 自动登录案例
所谓自动登录就是当用户第一次登录后,并且选择“自动登录”选项,用户从第二次访问开始,用户都无需再登录,完成直接登录的功能。具体实现步骤如下:
- 创建一个JSP页面用于用户登录功能。
[](javascript:void(0)😉
<%@ 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>
[](javascript:void(0)😉
- 创建一个JavaBean用于封装用户信息。
[](javascript:void(0)😉
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;
}
}
[](javascript:void(0)😉
- 创建一个Servlet用于处理用户登录逻辑。
[](javascript:void(0)😉
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;
}
}
}
[](javascript:void(0)😉
- 配置Web工程的web.xml文件。
[](javascript:void(0)😉
<?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>
[](javascript:void(0)😉
- 创建一个JSP页面用于显示主页面,显示用户登录信息。
[](javascript:void(0)😉
<%@ 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>
[](javascript:void(0)😉
- 创建一个过滤器用于完成自动登录功能。
[](javascript:void(0)😉
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() {}
}
[](javascript:void(0)😉
- 配置Web工程的web.xml文件。
[](javascript:void(0)😉
<?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>
[](javascript:void(0)😉
3.3. 权限控制案例
一般情况下,Web应用程序不能允许所有用户可以访问所有功能。换句话讲,不同的用户具有访问不同功能的权限。所以,需要完成权限控制功能,具体操作如下:
- 创建JavaBean用于封装用户信息(包含权限信息)。
[](javascript:void(0)😉
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;
}
}
[](javascript:void(0)😉
- 创建Web应用程序的主页面,用于用户功能的显示。
[](javascript:void(0)😉
<%@ 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>
[](javascript:void(0)😉
- 创建用户可以访问的功能列表页面。
[](javascript:void(0)😉
<%@ 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>
[](javascript:void(0)😉
- 创建管理员可以访问的功能列表页面。
[](javascript:void(0)😉
<%@ 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>
[](javascript:void(0)😉
- 创建一个过滤器用于完成权限控制功能。
[](javascript:void(0)😉
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() {}
}
[](javascript:void(0)😉
- 配置Web工程的web.xml文件。
[](javascript:void(0)😉
<?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>
[](javascript:void(0)😉
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接口,并重写所有方法。
[](javascript:void(0)😉
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() {}
}
[](javascript:void(0)😉
- 配置Web工程中的web.xml文件。
[](javascript:void(0)😉
<?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>
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() {}
}
[[外链图片转存中...(img-YQALfwSv-1644846104002)]](javascript:void(0);)
- 配置Web工程中的web.xml文件。
[[外链图片转存中...(img-k8ITAkPH-1644846104002)]](javascript:void(0);)
<?xml version="1.0" encoding="UTF-8"?>
NoCacheFilter
app.java.demo1.NoCacheFilter
NoCacheFilter
*.jsp
[![复制代码](https://img-blog.csdnimg.cn/img_convert/8a896be743d51bdff70c13beeef1ce59.gif)](javascript:void(0);)