Filter, as the name suggests, is the process of filtering and preprocessing data. Why introduce filters? When you visit the website, sometimes you send some sensitive information. When it is displayed, you will replace the sensitive information with * and other characters, which is to process the information with a filter. This is just a simple example. Of course, the filter is so powerful that its function cannot be limited to this. It can not only preprocess data, but also preprocess all requests sent. At the same time, it can also preprocess the responses returned by the server, which greatly reduces the pressure on the server. For example, it implements some advanced functions such as URL level permission access control, filtering sensitive words, compressing response information and so on. Let's introduce the filter in detail.
1, Definition
To learn something, we must first understand its definition.
1. Concept
The filtering function is to filter the requests sent from the client to the server, and also process the responses returned by the server. It allows users to change a request and modify a response. Filter is not a servlet. It cannot generate a response, but it can preprocess a request before it reaches the servlet, or it can process the response when it leaves the servlet. In other words, the filter is actually a transmitter between the client and the servlet, and it can modify what is to be transmitted.
Note: the filter is used to intercept requests and responses and cannot generate responses, while the servlet is used to process requests and generate responses.
Purpose of the filter:
- Before the client requests to access back-end resources, intercept these requests for processing.
- The server processes the information and responses before sending them back to the client.
2. Applicable occasions
Implement URL level access control, filter sensitive words, compress response information, etc.
3. Type of filter:
name | English name |
---|---|
Copy validation filter | (Authentication Filters) |
Data compression filter | (Data compression Filters) |
Encryption filter | (Encryption Filters) |
Trigger resource access event filter | |
Image conversion filter | (Image Conversion Filters) |
Logging and audit filters | (Logging and Auditing Filters) |
MIME-TYPE chain filter | (MIME-TYPE Chain Filters) |
Tokenized filter | (Tokenizing Filters) |
XSL/T filter | (XSL/T Filters) to transform XML content |
4. How does the filter intercept
- After the client makes a request, the filter intercepts the client's HttpServletRequest before the HttpServletRequest reaches the Servlet.
- Check the HttpServletRequest as needed, or modify the HttpServletRequest header and data.
- The doFilter method is invoked in the filter to release the request. After the request reaches the Servlet, it processes the request and generates an HttpServletResponse to send to the client.
- The filter intercepts the HttpServletResponse before it reaches the client.
- Check the HttpServletResponse as needed, and modify the HttpServletResponse header and data.
- Finally, the HttpServletResponse arrives at the client.
5.Filter interface
The Servlet API provides a Filter interface, which must be implemented by the written Filter.
6.Filter life cycle
(1) There are three important methods in the Filter interface.
- init() method: initializes parameters and is called automatically when creating a Filter. When we need to set initialization parameters, we can write to this method.
- doFilter() method: when the request to be executed is intercepted, doFilter will execute. This describes our preprocessing of requests and responses.
- destroy() method: called automatically when destroying Filter.
(2) Filter lifecycle
The creation and destruction of filters are controlled by the web server.
- When the server starts, the web server creates an instance object of filter and calls its init method to complete the initialization of the object. The filter object is created only once, and the init method is executed only once.
- When the request is intercepted, the doFilter method is executed. Can be executed multiple times.
- When the server shuts down, the web server destroys the instance object of Filter.
7.Filter object - FilterConfig
When configuring the filter, users can use < init param > to configure some initialization parameters for the filter. When the web container instantiates the filter object and calls its init method, it will pass in the filterConfig object that encapsulates the filter initialization parameters. Therefore, when writing filter, developers can obtain the following information through the method of filterConfig object:
- String getFilterName(): get the name of the filter.
- String getInitParameter(String name): returns the value of the initialization parameter with the name specified in the deployment description. If it does not exist, null is returned
- Enumeration getInitParameterNames(): returns an enumeration collection of the names of all initialization parameters of the filter.
- public ServletContext getServletContext(): returns the reference of the Servlet context object.
8. Filter chain - FilterChain
A set of filters that intercept certain web resources is called a filter chain. The execution order of the filter is related to < filter mapping > (who executes first).
2, Development steps
Understand the related concepts of filter, and then develop an example.
1. Preparation steps
- Write a java class to implement the Filter interface and implement its doFilter method.
- Use the < Filter > and < filter mapping > elements in the web.xml file to register the written filter class and set the resources it can intercept.
2. Examples
(1) Simple Filter example
- Write the FilterDemo1 class
package com.oracle.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; public class FilterDemo1 implements Filter{ /* * A case of understanding the whole life cycle of Filter * matters needing attention: * 1.When implementing the Filter interface, the javax.servlet.Filter package is imported * 2.Methods are automatically called by the web server, and we don't need to call them manually * 3.init Initialization parameters are generally written in the method. They are not used here, and can be used in the following examples. * 4.destroy Methods generally do not need to write any code * 5.Rewriting the doFilter method can write our processing actions for intercepted requests and responses. * 6.After writing this class, configure the filter and configure it in web.xml. * @see javax.servlet.Filter#init(javax.servlet.FilterConfig) */ @Override public void init(FilterConfig filterConfig) throws ServletException { // TODO Auto-generated method stub System.out.println("FilterDemo1 of init Method called"); } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { // TODO Auto-generated method stub System.out.println("I am FilterDemo1,Client to Servlet The request was intercepted by me"); chain.doFilter(request, response); System.out.println("I am FilterDemo1,Servlet The response sent to the client was intercepted by me"); } @Override public void destroy() { // TODO Auto-generated method stub System.out.println("FilterDemo1 of destroy Method called"); } }
- Configure the filter and add the following code to the web.xml file
<filter> <filter-name>filterDemo1</filter-name> <filter-class>com.oracle.filter.FilterDemo1</filter-class> </filter> <filter-mapping> <filter-name>filterDemo1</filter-name> <url-pattern>/*</url-pattern> <!-- /*Is to intercept all files --> </filter-mapping>
- Console results
- Analysis: as can be seen from the above results, the init method is called when the server starts. When accessing the page, the filter intercepts the request to execute the doFilter method. In this method, the doFilter method is used. When the response is returned, continue to execute the remaining code, and pass the response to the client after execution. When the server is shut down, the server calls the destroy method.
(2) Filter chain example
- Write the FilterDemo1 class
package com.oracle.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; public class FilterDemo1 implements Filter{ /* * @see javax.servlet.Filter#init(javax.servlet.FilterConfig) */ @Override public void init(FilterConfig filterConfig) throws ServletException { // TODO Auto-generated method stub } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { // TODO Auto-generated method stub System.out.println("I am FilterDemo1,Client to Servlet The request was intercepted by me"); //Release the request and enter the next filter FilterDemo2 chain.doFilter(request, response); System.out.println("I am FilterDemo1,Servlet The response sent to the client was intercepted by me"); } @Override public void destroy() { // TODO Auto-generated method stub } }
- Write the FilterDemo2 class
package com.oracle.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; public class FilterDemo2 implements Filter{ @Override public void init(FilterConfig filterConfig) throws ServletException { // TODO Auto-generated method stub } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { // TODO Auto-generated method stub System.out.println("I am FilterDemo2,Client to Servlet The request was intercepted by me"); //Release the request and enter the Servlet chain.doFilter(request, response); System.out.println("I am FilterDemo2,Servlet The response sent to the client was intercepted by me"); } @Override public void destroy() { // TODO Auto-generated method stub } }
- Configure the filter and add the following code to the web.xml file
<filter> <filter-name>filterDemo1</filter-name> <filter-class>com.oracle.filter.FilterDemo1</filter-class> </filter> <filter> <filter-name>filterDemo2</filter-name> <filter-class>com.oracle.filter.FilterDemo2</filter-class> </filter> <filter-mapping> <filter-name>filterDemo1</filter-name> <url-pattern>/*</url-pattern> <!-- /*Is to intercept all files --> </filter-mapping> <filter-mapping> <filter-name>filterDemo2</filter-name> <url-pattern>/*</url-pattern> <!-- /*Is to intercept all files --> </filter-mapping>
- Console results
- Analysis: when multiple filters intercept the same request, according to the configuration order of < filter mapping > in the web.xml file, who is first, who executes first. When the first filter is successfully intercepted, the doFilter method will be executed. In this method, calling the chain.doFilter method will release the request to the next filter and execute it in turn until the last filter is executed. When the last filter calls the chain.doFilter method, the request will be released to Servlet, and when the Servlet process returns the response information, Go back to the last executed filter and continue to execute the remaining code of the filter. Return in turn until you return to the first filter and finally to the client.
(3) Disable cache filters for all dynamic pages
- Write the FilterDemo3 class
package com.oracle.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; import javax.servlet.http.HttpServletResponse; public class FilterDemo3 implements Filter{ @Override public void init(FilterConfig filterConfig) throws ServletException { // TODO Auto-generated method stub } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { // Set cache control, Pragma and Expires in the response header to cancel the cache 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 } }
(4) Filter for counting website visits by IP
- Write the FilterDemo4 class
package com.oracle.filter; 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 FilterDemo4 implements Filter{ private FilterConfig filterConfig; @Override public void init(FilterConfig filterConfig) throws ServletException { // TODO Auto-generated method stub //Initialization parameter, ipCount is used to store ip and access times ServletContext application = filterConfig.getServletContext(); Map<String,Integer> ipCount = new HashMap<String,Integer>(); application.setAttribute("ipCount",ipCount); this.filterConfig = filterConfig; } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { // TODO Auto-generated method stub ServletContext application = filterConfig.getServletContext(); Map<String,Integer> ipCount = (HashMap<String,Integer>)application.getAttribute("ipCount"); String ip = request.getRemoteAddr(); Integer count = ipCount.get(ip); if(count != null){ //The ip exists in the Map count = count + 1; }else{ count = 1; } ipCount.put(ip, count); application.setAttribute("ipCount",ipCount); chain.doFilter(request, response); } @Override public void destroy() { // TODO Auto-generated method stub } }
- Write the index.jsp page
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> <% String path = request.getContextPath(); String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <base href="<%=basePath%>"> <title>My JSP 'index.jsp' starting page</title> <meta http-equiv="pragma" content="no-cache"> <meta http-equiv="cache-control" content="no-cache"> <meta http-equiv="expires" content="0"> <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> <meta http-equiv="description" content="This is my page"> <!-- <link rel="stylesheet" type="text/css" href="styles.css"> --> </head> <body> <h1>branch IP Statistics of website views</h1> <table border="1" width="400"> <tr> <th>IP address</th> <th>Number of views</th> </tr> <c:forEach items="${ipCount}" var="m"> <tr> <td>${m.key}</td> <td>${m.value}</td> </tr> </c:forEach> </table> </body> </html>
- Configure the filter and add the following code to the web.xml file
<filter> <filter-name>filterDemo4</filter-name> <filter-class>com.oracle.filter.FilterDemo4</filter-class> </filter> <filter-mapping> <filter-name>filterDemo4</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
- Web results
(5) Automatic login
- Writing the AutoLoginFilter class
package com.oracle.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; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; import com.oracle.biz.UserInfoBiz; import com.oracle.biz.impl.UserInfoBizImpl; import com.oracle.entity.UserInfo; import com.oracle.util.CookieUtil; public class AutoLoginFilter implements Filter{ @Override public void init(FilterConfig filterConfig) throws ServletException { // TODO Auto-generated method stub } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { // TODO Auto-generated method stub //First, judge whether the session exists. If it exists, release it. If it does not exist, judge whether the user name and password exist in the cookie. If it exists, query the database for correctness. If it is correct, store it in the session and release it. If it is incorrect, release it HttpServletRequest req = (HttpServletRequest)request; HttpSession session = req.getSession(); UserInfo user = (UserInfo)session.getAttribute("user"); if(user != null){ chain.doFilter(req, response); }else{ //User does not exist in session Cookie[] cookies = req.getCookies(); Cookie cookie = CookieUtil.findCookie(cookies, "autoLogin"); if(cookie!=null){ //The user was found in the cookie UserInfoBiz ubiz = new UserInfoBizImpl(); String name = cookie.getValue().split("#oracle#")[0]; String pwd = cookie.getValue().split("#oracle#")[1]; String msg = ubiz.login(name, pwd); if("Login succeeded!".equals(msg)){ user = ubiz.getByName(name); session.setAttribute("user", user); chain.doFilter(req, response); }else{ chain.doFilter(req, response); } }else{ //The customer was not found chain.doFilter(req, response); } } } @Override public void destroy() { // TODO Auto-generated method stub } }
- Writing DoLoginServlet
package com.oracle.servlet; 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; import javax.servlet.http.HttpSession; import com.oracle.biz.UserInfoBiz; import com.oracle.biz.impl.UserInfoBizImpl; import com.oracle.entity.UserInfo; public class DoLoginServlet extends HttpServlet { /** * Constructor of the object. */ public DoLoginServlet() { super(); } /** * Destruction of the servlet. <br> */ public void destroy() { super.destroy(); // Just puts "destroy" string in log // Put your code here } /** * The doGet method of the servlet. <br> * * This method is called when a form has its tag value method equals to get. * * @param request the request send by the client to the server * @param response the response send by the server to the client * @throws ServletException if an error occurred * @throws IOException if an error occurred */ public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request,response); } /** * The doPost method of the servlet. <br> * * This method is called when a form has its tag value method equals to post. * * @param request the request send by the client to the server * @param response the response send by the server to the client * @throws ServletException if an error occurred * @throws IOException if an error occurred */ public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { HttpSession session = request.getSession(); request.setCharacterEncoding("UTF-8"); response.setCharacterEncoding("UTF-8"); String name = request.getParameter("myname"); String pwd = request.getParameter("pwd"); String autoLogin = request.getParameter("autoLogin"); UserInfoBiz ubiz = new UserInfoBizImpl(); //ubiz.login(name, pwd): judge whether the user logs in successfully and return a string. "Login succeeded!" is returned if successful, and the corresponding error prompt is returned if unsuccessful. String msg = ubiz.login(name, pwd); if("Login succeeded!".equals(msg)){ UserInfo user = ubiz.getByName(name); session.setAttribute("user", user); if("true".equals(autoLogin)){ //Use cookie s to remember user names and passwords Cookie cookie = new Cookie("autoLogin",user.getUserName()+"#oracle#"+user.getPassword()); //Set effective time cookie.setMaxAge(60*60*24); //Write cookie back to browser response.addCookie(cookie); } response.sendRedirect("success.jsp"); }else{ request.setAttribute("msg", msg); request.getRequestDispatcher("login.jsp").forward(request, response); } } /** * Initialization of the servlet. <br> * * @throws ServletException if an error occurs */ public void init() throws ServletException { // Put your code here } }
- Write CookieUtil
package com.oracle.util; import javax.servlet.http.Cookie; public class CookieUtil { public static 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; } } }
- Write login.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <% String path = request.getContextPath(); String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <base href="<%=basePath%>"> <title>My JSP 'login.jsp' starting page</title> <meta http-equiv="pragma" content="no-cache"> <meta http-equiv="cache-control" content="no-cache"> <meta http-equiv="expires" content="0"> <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> <meta http-equiv="description" content="This is my page"> <!-- <link rel="stylesheet" type="text/css" href="styles.css"> --> </head> <body> <form action="doLogin" method="post"> user name<input name="myname"><br/> password<input type="password" name="pwd"><br/> <input type="checkBox" name="autoLogin" value="true">automatic logon<br/> <input type="submit" value="land"> </form> </body> </html>
- Write success.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> <% String path = request.getContextPath(); String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <base href="<%=basePath%>"> <title>My JSP 'success.jsp' starting page</title> <meta http-equiv="pragma" content="no-cache"> <meta http-equiv="cache-control" content="no-cache"> <meta http-equiv="expires" content="0"> <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> <meta http-equiv="description" content="This is my page"> <!-- <link rel="stylesheet" type="text/css" href="styles.css"> --> </head> <body> <c:if test="${empty user}"> <h2>You haven't logged in yet, please go<a href="login.jsp">land</a></h2> </c:if> <c:if test="${not empty user}"> <h2>Welcome ${user.userName}</h2> </c:if> </body> </html>
(6) Processing the Get and Post requests of the website
- Idea: enhance the getParameter method of the request object. Write a class MyHttpServletRequest to implement HttpServletRequestWrapper, rewrite its getParameter method and other methods, and transcode the data submitted in different ways in these methods. In the filter, the request is forcibly converted to an object of type MyHttpServletRequest. In this way, when you use getParameter and other methods again, you actually call your rewritten getParameter method, that is, the processed data, so you don't have to worry about the problem of garbled code.
- MyHttpServletRequest class
package com.oracle.bookshop.filter; import java.io.UnsupportedEncodingException; import java.util.Map; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; public class MyHttpServletRequest extends HttpServletRequestWrapper { /* * This class overrides */ private HttpServletRequest request; private boolean hasEncode; public MyHttpServletRequest(HttpServletRequest request) { super(request);// super must write this.request = request; } // Override methods that need to be enhanced @Override public Map getParameterMap() { // Get request method first String method = request.getMethod(); if (method.equalsIgnoreCase("post")) { // post request try { // Handle post garbled code request.setCharacterEncoding("utf-8"); return request.getParameterMap(); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } } else if (method.equalsIgnoreCase("get")) { // get request Map<String, String[]> parameterMap = request.getParameterMap(); if (!hasEncode) { // Ensure that the get manual encoding logic runs only once for (String parameterName : parameterMap.keySet()) { String[] values = parameterMap.get(parameterName); if (values != null) { for (int i = 0; i < values.length; i++) { try { // Handle get garbled code values[i] = new String(values[i] .getBytes("ISO-8859-1"), "utf-8"); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } } } } hasEncode = true; } return parameterMap; } return super.getParameterMap(); } @Override public String getParameter(String name) { Map<String, String[]> parameterMap = getParameterMap(); String[] values = parameterMap.get(name); if (values == null) { return null; } return values[0]; // Retrieve the first value of the parameter } @Override public String[] getParameterValues(String name) { Map<String, String[]> parameterMap = getParameterMap(); String[] values = parameterMap.get(name); return values; } }
- Write CharacterEnodingFilter
package com.oracle.bookshop.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; import javax.servlet.http.HttpServletRequest; public class CharacterEnodingFilter implements Filter{ @Override public void destroy() { // TODO Auto-generated method stub } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { // TODO Auto-generated method stub HttpServletRequest req = (HttpServletRequest)request; MyHttpServletRequest myreq = new MyHttpServletRequest(req); chain.doFilter(myreq, response); } @Override public void init(FilterConfig arg0) throws ServletException { // TODO Auto-generated method stub } }
--------
Reference information: