Java Servlet 过滤器用于拦截客户端请求并进行一些预处理。它还可以拦截响应并在在 Web 应用程序中发送给客户端之前进行后处理。
服务过滤器
在本文中,我们将关注Java中的Servlet过滤器,我们将研究Servlet过滤器的各种用途,我们如何创建过滤器,并通过简单的Web应用程序学习其使用。
Why do we have Servlet Filter?
In the last article, we learned how we can manage session in web application and if we want to make sure that a resource is accessible only when the user session is valid, we can achieve this using servlet session attributes. The approach is simple but if we have a lot of servlets and jsps, then it will become hard to maintain because of redundant code. If we want to change the attribute name in the future, we will have to change all the places where we have session authentication. That's why we have a servlet filter. Servlet Filters are pluggable java components that we can use to intercept and process requests before they are sent to servlets and response after servlet code is finished and before container sends the response back to the client. Some common tasks that we can do with servlet filters are:- Logging request parameters to log files.
- Authentication and autherization of request for resources.
- Formatting of request body or header before sending it to servlet.
- Compressing the response data sent to the client.
- Alter response by adding some cookies, header information etc.
As I mentioned earlier, servlet filters are pluggable and configured in deployment descriptor (web.xml) file. Servlets and filters both are unaware of each other and we can add or remove a servlet filter just by editing web.xml. We can have multiple filters for a single resource and we can create a chain of filters for a single resource in web.xml. We can create a Servlet Filter by implementing
javax.servlet.Filter
interface.
Servlet Filter interface
Servlet Filter interface is similar to Servlet interface and we need to implement it to create our own servlet filter. Servlet Filter interface contains lifecycle methods of a Filter and it's managed by servlet container. Servlet Filter interface lifecycle methods are:1. void init(FilterConfig paramFilterConfig) - When container initializes the Filter, this is the method that gets invoked. This method is called only once in the lifecycle of filter and we should initialize any resources in this method. FilterConfig is used by container to provide init parameters and servlet context object to the Filter. We can throw ServletException in this method. 2. doFilter(ServletRequest paramServletRequest, ServletResponse paramServletResponse, FilterChain paramFilterChain) - This is the method invoked every time by container when it has to apply filter to a resource. Container provides request and response object references to filter as argument. FilterChain is used to invoke the next filter in the chain. This is a great example of Chain of Responsibility Pattern. 3. void destroy() - When container offloads the Filter instance, it invokes the destroy() method. This is the method where we can close any resources opened by filter. This method is called only once in the lifetime of filter.
Servlet WebFilter annotation
javax.servlet.annotation.WebFilter
was introduced in Servlet 3.0 and we can use this annotation to declare a servlet filter. We can use this annotation to define init parameters, filter name and description, servlets, url patterns and dispatcher types to apply the filter. If you make frequent changes to the filter configurations, its better to use web.xml because that will not require you to recompile the filter class. Read: Java Annotations TutorialServlet Filter configuration in web.xml
We can declare a servlet filter in web.xml like below.
<filter> <filter-name>RequestLoggingFilter</filter-name> <!-- mandatory --> <filter-class>com.journaldev.servlet.filters.RequestLoggingFilter</filter-class> <!-- mandatory --> <init-param> <!-- optional --> <param-name>test</param-name> <param-value>testValue</param-value> </init-param> </filter>
We can map a Filter to servlet classes or url-patterns like below.```RequestLoggingFilter /* LoginServlet REQUEST Servlet Filter Example for Logging and session validation
In our servlet filter example, we will create filters to log request cookies and parameters and validate session to all the resources except static HTMLs and LoginServlet because it will not have a session. We will create a dynamic web project ServletFilterExample whose project structure will look like the below image.
login.html is the entry point of our application where the user will provide the login id and password for authentication. login.html code:```
Login Page ```LoginServlet is used to authenticate the request from the client for login.``` package com.journaldev.servlet.session;import java.io.IOException; import java.io.PrintWriter;
import javax.servlet.RequestDispatcher; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession;
/**
Servlet implementation class LoginServlet */ @WebServlet("/LoginServlet") public class LoginServlet extends HttpServlet { private static final long serialVersionUID = 1L; private final String userID = "admin"; private final String password = "password";
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// get request parameters for userID and password String user = request.getParameter("user"); String pwd = request.getParameter("pwd"); if(userID.equals(user) && password.equals(pwd)){ HttpSession session = request.getSession(); session.setAttribute("user", "Pankaj"); //setting session to expiry in 30 mins session.setMaxInactiveInterval(30*60); Cookie userName = new Cookie("user", user); userName.setMaxAge(30*60); response.addCookie(userName); response.sendRedirect("LoginSuccess.jsp"); }else{ RequestDispatcher rd = getServletContext().getRequestDispatcher("/login.html"); PrintWriter out= response.getWriter(); out.println("<font color=red>Either user name or password is wrong.</font>"); rd.include(request, response); }
}
}
When the client is authenticated, it's forwarded to LoginSuccess.jsp LoginSuccess.jsp code:
<%@ page language="java" contentType="text/html; charset=US-ASCII" pageEncoding="US-ASCII"%>Login Success Page <% //allow access only if session exists String user = (String) session.getAttribute("user"); String userName = null; String sessionID = null; Cookie[] cookies = request.getCookies(); if(cookies !=null){ for(Cookie cookie : cookies){ if(cookie.getName().equals("user")) userName = cookie.getValue(); if(cookie.getName().equals("JSESSIONID")) sessionID = cookie.getValue(); } } %>Hi <%=userName %>, Login successful. Your Session ID=<%=sessionID %>
User=<%=user %>
Checkout Page```Notice that there is no session validation logic in the above JSP. It contains a link to another JSP page, CheckoutPage.jsp. CheckoutPage.jsp code:``` <%@ page language="java" contentType="text/html; charset=US-ASCII" pageEncoding="US-ASCII"%>Login Success Page <% String userName = null; String sessionID = null; Cookie[] cookies = request.getCookies(); if(cookies !=null){ for(Cookie cookie : cookies){ if(cookie.getName().equals("user")) userName = cookie.getValue(); } } %>Hi <%=userName %>, do the checkout.
```LogoutServlet is invoked when a client clicks on the Logout button in any of the JSP pages.``` package com.journaldev.servlet.session;import java.io.IOException;
import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession;
/**
Servlet implementation class LogoutServlet */ @WebServlet("/LogoutServlet") public class LogoutServlet extends HttpServlet { private static final long serialVersionUID = 1L;
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html"); Cookie[] cookies = request.getCookies(); if(cookies != null){ for(Cookie cookie : cookies){ if(cookie.getName().equals("JSESSIONID")){ System.out.println("JSESSIONID="+cookie.getValue()); break; } } } //invalidate the session if exists HttpSession session = request.getSession(false); System.out.println("User="+session.getAttribute("user")); if(session != null){ session.invalidate(); } response.sendRedirect("login.html"); }
}
Now we will create logging and authentication servlet filter classes.
package com.journaldev.servlet.filters;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; import javax.servlet.annotation.WebFilter; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest;
/**
Servlet Filter implementation class RequestLoggingFilter */ @WebFilter("/RequestLoggingFilter") public class RequestLoggingFilter implements Filter {
private ServletContext context;
public void init(FilterConfig fConfig) throws ServletException { this.context = fConfig.getServletContext(); this.context.log("RequestLoggingFilter initialized"); }
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest req = (HttpServletRequest) request; Enumeration
params = req.getParameterNames(); while(params.hasMoreElements()){ String name = params.nextElement(); String value = request.getParameter(name); this.context.log(req.getRemoteAddr() + "::Request Params::{"+name+"="+value+"}"); } Cookie[] cookies = req.getCookies(); if(cookies != null){ for(Cookie cookie : cookies){ this.context.log(req.getRemoteAddr() + "::Cookie::{"+cookie.getName()+","+cookie.getValue()+"}"); } } // pass the request along the filter chain chain.doFilter(request, response);
}
public void destroy() { //we can close resources here }
}
1package com.journaldev.servlet.filters; 2 3import java.io.IOException; 4 5import javax.servlet.Filter; 6import javax.servlet.FilterChain; 7import javax.servlet.FilterConfig; 8import javax.servlet.ServletContext; 9import javax.servlet.ServletException; 10import javax.servlet.ServletRequest; 11import javax.servlet.ServletResponse; 12import javax.servlet.annotation.WebFilter; 13import javax.servlet.http.HttpServletRequest; 14import javax.servlet.http.HttpServletResponse; 15import javax.servlet.http.HttpSession; 16 17@WebFilter("/AuthenticationFilter") 18public class AuthenticationFilter implements Filter { 19 20 private ServletContext context; 21 22 public void init(FilterConfig fConfig) throws ServletException { 23 this.context = fConfig.getServletContext(); 24 this.context.log("AuthenticationFilter initialized"); 25 } 26 27 public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { 28 29 HttpServletRequest req = (HttpServletRequest) request; 30 HttpServletResponse res = (HttpServletResponse) response; 31 32 String uri = req.getRequestURI(); 33 this.context.log("Requested Resource::"+uri); 34 35 HttpSession session = req.getSession(false); 36 37 if(session == null && !(uri.endsWith("html") || uri.endsWith("LoginServlet"))){ 38 this.context.log("Unauthorized access request"); 39 res.sendRedirect("login.html"); 40 }else{ 41 // pass the request along the filter chain 42 chain.doFilter(request, response); 43 } 44 45 46 } 47 48 public void destroy() { 49 //close any resources here 50 } 51 52} 53```Notice that we are not authenticating any HTML page or LoginServlet. Now we will configure these filters mapping in the web.xml file.``` 54<?xml version="1.0" encoding="UTF-8"?> 55<web-app xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xmlns="https://java.sun.com/xml/ns/javaee" xsi:schemaLocation="https://java.sun.com/xml/ns/javaee https://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0"> 56 <display-name>ServletFilterExample</display-name> 57 <welcome-file-list> 58 <welcome-file>login.html</welcome-file> 59 </welcome-file-list> 60 61 <filter> 62 <filter-name>RequestLoggingFilter</filter-name> 63 <filter-class>com.journaldev.servlet.filters.RequestLoggingFilter</filter-class> 64 </filter> 65 <filter> 66 <filter-name>AuthenticationFilter</filter-name> 67 <filter-class>com.journaldev.servlet.filters.AuthenticationFilter</filter-class> 68 </filter> 69 70 <filter-mapping> 71 <filter-name>RequestLoggingFilter</filter-name> 72 <url-pattern>/*</url-pattern> 73 <dispatcher>REQUEST</dispatcher> 74 </filter-mapping> 75 <filter-mapping> 76 <filter-name>AuthenticationFilter</filter-name> 77 <url-pattern>/*</url-pattern> 78 </filter-mapping> 79</web-app> 80```Now when we will run our application, we will get response pages like below images. [](https://journaldev.nyc3.digitaloceanspaces.com/2013/08/Servlet-Filter-Login.png) [](https://journaldev.nyc3.digitaloceanspaces.com/2013/08/Servlet-Filter-Login-Success.png) [](https://journaldev.nyc3.digitaloceanspaces.com/2013/08/Servlet-Filter-Checkout.png) If you are not logged in and try to access any JSP page, you will be forwarded to the login page. In the server log file, you can see the logs written by servlet filters as well as servlets.``` 81Aug 13, 2013 1:06:07 AM org.apache.catalina.core.ApplicationContext log 82INFO: 0:0:0:0:0:0:0:1%0::Cookie::{JSESSIONID,B7275762B8D23121152B1270D6EB240A} 83Aug 13, 2013 1:06:07 AM org.apache.catalina.core.ApplicationContext log 84INFO: Requested Resource::/ServletFilterExample/ 85Aug 13, 2013 1:06:07 AM org.apache.catalina.core.ApplicationContext log 86INFO: Unauthorized access request 87Aug 13, 2013 1:06:07 AM org.apache.catalina.core.ApplicationContext log 88INFO: 0:0:0:0:0:0:0:1%0::Cookie::{JSESSIONID,B7275762B8D23121152B1270D6EB240A} 89Aug 13, 2013 1:06:07 AM org.apache.catalina.core.ApplicationContext log 90INFO: Requested Resource::/ServletFilterExample/login.html 91Aug 13, 2013 1:06:43 AM org.apache.catalina.core.ApplicationContext log 92INFO: 0:0:0:0:0:0:0:1%0::Request Params::{pwd=password} 93Aug 13, 2013 1:06:43 AM org.apache.catalina.core.ApplicationContext log 94INFO: 0:0:0:0:0:0:0:1%0::Request Params::{user=admin} 95Aug 13, 2013 1:06:43 AM org.apache.catalina.core.ApplicationContext log 96INFO: 0:0:0:0:0:0:0:1%0::Cookie::{JSESSIONID,B7275762B8D23121152B1270D6EB240A} 97Aug 13, 2013 1:06:43 AM org.apache.catalina.core.ApplicationContext log 98INFO: Requested Resource::/ServletFilterExample/LoginServlet 99Aug 13, 2013 1:06:43 AM org.apache.catalina.core.ApplicationContext log 100INFO: 0:0:0:0:0:0:0:1%0::Cookie::{JSESSIONID,8BDF777933194EDCAC1D8F1B73633C56} 101Aug 13, 2013 1:06:43 AM org.apache.catalina.core.ApplicationContext log 102INFO: 0:0:0:0:0:0:0:1%0::Cookie::{user,admin} 103Aug 13, 2013 1:06:43 AM org.apache.catalina.core.ApplicationContext log 104INFO: Requested Resource::/ServletFilterExample/LoginSuccess.jsp 105Aug 13, 2013 1:06:52 AM org.apache.catalina.core.ApplicationContext log 106INFO: 0:0:0:0:0:0:0:1%0::Cookie::{JSESSIONID,8BDF777933194EDCAC1D8F1B73633C56} 107Aug 13, 2013 1:06:52 AM org.apache.catalina.core.ApplicationContext log 108INFO: 0:0:0:0:0:0:0:1%0::Cookie::{user,admin} 109Aug 13, 2013 1:06:52 AM org.apache.catalina.core.ApplicationContext log 110INFO: Requested Resource::/ServletFilterExample/CheckoutPage.jsp 111Aug 13, 2013 1:07:00 AM org.apache.catalina.core.ApplicationContext log 112INFO: 0:0:0:0:0:0:0:1%0::Cookie::{JSESSIONID,8BDF777933194EDCAC1D8F1B73633C56} 113Aug 13, 2013 1:07:00 AM org.apache.catalina.core.ApplicationContext log 114INFO: 0:0:0:0:0:0:0:1%0::Cookie::{user,admin} 115Aug 13, 2013 1:07:00 AM org.apache.catalina.core.ApplicationContext log 116INFO: Requested Resource::/ServletFilterExample/LogoutServlet 117JSESSIONID=8BDF777933194EDCAC1D8F1B73633C56 118User=Pankaj 119Aug 13, 2013 1:07:00 AM org.apache.catalina.core.ApplicationContext log 120INFO: 0:0:0:0:0:0:0:1%0::Cookie::{JSESSIONID,8BDF777933194EDCAC1D8F1B73633C56} 121Aug 13, 2013 1:07:00 AM org.apache.catalina.core.ApplicationContext log 122INFO: 0:0:0:0:0:0:0:1%0::Cookie::{user,admin} 123Aug 13, 2013 1:07:00 AM org.apache.catalina.core.ApplicationContext log 124INFO: Requested Resource::/ServletFilterExample/login.html 125Aug 13, 2013 1:07:06 AM org.apache.catalina.core.ApplicationContext log 126INFO: 0:0:0:0:0:0:0:1%0::Cookie::{JSESSIONID,8BDF777933194EDCAC1D8F1B73633C56} 127Aug 13, 2013 1:07:07 AM org.apache.catalina.core.ApplicationContext log 128INFO: 0:0:0:0:0:0:0:1%0::Cookie::{user,admin} 129Aug 13, 2013 1:07:07 AM org.apache.catalina.core.ApplicationContext log 130INFO: Requested Resource::/ServletFilterExample/LoginSuccess.jsp 131Aug 13, 2013 1:07:07 AM org.apache.catalina.core.ApplicationContext log 132INFO: Unauthorized access request 133Aug 13, 2013 1:07:07 AM org.apache.catalina.core.ApplicationContext log 134INFO: 0:0:0:0:0:0:0:1%0::Cookie::{JSESSIONID,8BDF777933194EDCAC1D8F1B73633C56} 135Aug 13, 2013 1:07:07 AM org.apache.catalina.core.ApplicationContext log 136INFO: 0:0:0:0:0:0:0:1%0::Cookie::{user,admin} 137Aug 13, 2013 1:07:07 AM org.apache.catalina.core.ApplicationContext log 138INFO: Requested Resource::/ServletFilterExample/login.html 139```
它是Java EE网页应用程序的重要功能之一,我们应该使用它用于各种服务器执行的常见任务。在未来的帖子中,我们将看看服务器收听器和cookie。 更新:收到大量可下载项目的请求后,我已将其附加到帖子中,从下面链接下载。
请参阅关于 [Servlet Listener]系列的下一篇文章(/community/tutorials/servletcontextlistener-servlet-listener-example“Servlet Listener Example – ServletContextListener, HttpSessionListener and ServletRequestListener”)。 Update Struts 2使用Servlet Filter来拦截客户端请求并将其传送到适当的类行动,这些被称为Struts 2 Interceptors。