首页IT科技filter过滤器js(day26-过滤器Filter)

filter过滤器js(day26-过滤器Filter)

时间2025-09-18 17:15:23分类IT科技浏览5192
导读:Filter过滤器 1.Filter过滤器说明...

Filter过滤器

1.Filter过滤器说明

为什么需要过滤器?

先来看一个例子:

我们在登录网站页面时                ,需要先进行登录验证               。

用户访问的正常的流程应该是:

用户先通过登录页面进行验证                       ,然后才可以访问各种页面                        。

为了防止用户绕过登录验证        ,我们需要在每个页面进行验证        , 获取session                       ,验证用户是否登录过        。

但是上述的方法又会产生下面的问题:

使用传统方法                ,每个页面都要进行登录验证 这将会造成代码的冗余        ,而且功能是重复的                       ,比较麻烦                ,维护起来也不方便

这时候就需要filter过滤器,它可以统一进行验证                       ,比如权限                       ,身份的验证,还可以进行日志记录                ,事务管理等...

过滤器介绍

Filter过滤器是JavaWeb的三大组件之一(Servlet程序                       ,Listener监听器        ,Filter过滤器) Filter过滤器是JavaEE规范                ,是接口 Filter过滤器的作用是:拦截请求                       ,过滤响应 应用场景: 权限检查 日志操作 事务管理

2.过滤器的基本原理

上述整个过程如下:

浏览器请求某个资源        ,Tomcat接收请求后        ,先判断是否需要使用过滤器               。 在web.xml文件中配置过滤器                       ,并指定过滤器的url-pattern(规则)                ,tomcat会根据你指定的规则来决定是否需要使用过滤器                        。 如果需要        ,就使用过滤器                       ,过滤器会根据你写的业务需要来进行验证        。如果验证成功                ,就可以继续访问;如果验证失败,就返回业务指定的地方       。 如果不需要过滤器                       ,就直接访问/返回资源                        。

3.过滤器快速入门

需求:在web工程下                       ,有后台管理目录manage,要求该目录下所有资源(html                ,图片                       ,jsp        ,servlet)等资源需要用户登录后才能访问                。

3.1思路分析

上述流程如下:

用户访问login.jsp页面填写数据                ,login.jsp将数据发送到loginCheckServlet验证       。 如果验证成功                       ,servlet创建用户浏览器关联的session并保存                       。 servlet转发到过滤器        ,验证还是不是真的登录过(有无session) 如果验证成功        ,就可以访问资源 如果验证失败                       ,就直接返回登录页面 如果用户直接访问资源                ,会先通过过滤器进行验证                。 如果没有登陆过        ,就打回登录页面                       ,不允许未经登录就直接访问资源 如果登录过                ,可以直接访问资源

3.2-1代码实现

首先创建项目,添加web支持                       ,添加需要的jar包

完成模块的整体流程

先完成一个正确完整的流程                       ,再加入其它的功能,完善功能。

总地来说就是先把框架搭建起来                ,再完善细节                       。

2.1 先完整一个正确的流程-看到一个效果->后面代码就可以验证

2.2 加入其它功能

2.3 完善功能

配置Tomcat

login.jsp:

<%-- Created by IntelliJ IDEA. User: li Date: 2022/11/28 Time: 17:03 Version: 1.0 --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>管理后台页面登录</title> </head> <body> <h1>管理后台页面登录</h1> <form action="<%=request.getContextPath()%>/loginCheckServlet" method="post"> u: <input type="text" name="username"/><br/><br/> p: <input type="password" name="password"/><br/><br/> <input type="submit" value="用户登录"/> </form> </body> </html>

LoginCheckServlet:

package com.servlet; import javax.servlet.*; import javax.servlet.http.*; import java.io.IOException; public class LoginCheckServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); } @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //获取到用户名和密码(这里应到数据库获取) // 这里假设密码是123456就可以通过 String username = request.getParameter("username"); String password = request.getParameter("password"); if ("123456".equals(password)) { //合法                       ,将用户名加入session request.getSession().setAttribute("username", username); //请求转发到admin.jsp //根据过滤器原理:请求转发的链接路径是不会被过滤器拦截的,而重定向会被过滤器拦截 request.getRequestDispatcher("/manage/admin.jsp").forward(request, response); } else { //非法 //返回登录页面 request.getRequestDispatcher("/login.jsp").forward(request, response); } } }

admin.jsp:

<%-- Created by IntelliJ IDEA. User: li Date: 2022/11/28 Time: 17:05 Version: 1.0 --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>admin</title> <%--指定浏览器解析的目录--%> <base href="" /> </body> </html>

ManageFilter:

package com.filter; import javax.servlet.*; import java.io.IOException; public class ManageFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { //当Tomcat创建filter后        ,会调用该方法                ,进行初始化 System.out.println("ManageFilter init方法被调用..."); } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { //当每次调用该filter时                       ,doFilter方法就会被调用 System.out.println("ManageFilter doFilter被调用..."); } @Override public void destroy() { //当filter对像被销毁时        ,就会调用该方法 System.out.println("ManageFilter destroy被调用..."); } }

在web.xml配置Filter和Servlet:

<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0"> <!--filter一般写在其他servlet的前面--> <!-- 1.filter的配置和servlet非常相似        ,filter也是被Tomcat管理和维护的 (它的创建和销毁也是tomcat来处理的) 2.<url-pattern> 配置的是filter生效的规则                        。即当请求的url和其匹配的时候                       ,会触发调用该filter 3. /manage/* 里面第一个斜杠/                ,会解析成http://ip:port/工程路径 4. 完整的路径就是 http://ip:port/工程路径/manage/* 意为当请求的url资源满足该条件时        ,都会调用该filter --> <filter> <filter-name>ManageFilter</filter-name> <filter-class>com.filter.ManageFilter</filter-class> </filter> <filter-mapping> <filter-name>ManageFilter</filter-name> <url-pattern>/manage/*</url-pattern> </filter-mapping> <!--配置servlet--> <servlet> <servlet-name>LoginCheckServlet</servlet-name> <servlet-class>com.servlet.LoginCheckServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>LoginCheckServlet</servlet-name> <url-pattern>/loginCheckServlet</url-pattern> </servlet-mapping> </web-app>

redeployTomcat                       ,可以看到后台输出:

这说明filter对象是由Tomcat去创建的。我们先来看一下filter底层实现               。

3.3filter底层原理分析

filter的xml配置和servlet非常相似                ,filter也是被Tomcat管理和维护的                        。我们之前在学习servlet的时候知道了Tomcat是如何管理维护servlet的:

详见:手动实现Tomcat底层机制+自己设计servlet->day03-实现02->3.4容器设计

同理,我们也可以这样理解:Tomcat还维护了两个关于filter的容器        。一个容器filterURLMapping存放url-pattern和filter-name               。另一个容器filterMapping存放filter-name和filter实例                        。

一旦Tomcat启动以后:

把程序员配置的url和filter-name                       ,放到另一容器filterURLMapping<String,String>中        。 会将filter实例化                       ,把filter-name和filter实例,放到filterMapping<String,Filter>容器里面       。

Tomcat接收到请求时:获取请求中的url                ,和filterURLMapping容器中的url进行匹配                        。

如果匹配上了                       ,在容器filterURLMapping中根据配置的url找到对应的filter-name 再到另一容器filterMapping中根据filter-name        ,找到对应filter实例                ,并调用实例                       ,完成这个filter的doFilter方法                。

并且        ,有了filter机制后        ,在调用servlet前会先匹配filter       。

根据request对象封装的uri                       ,先到filterUrlMapping中匹配 如果匹配上了                ,就走上诉流程        ,最后调用相应filter对象的doFilter方法 如果没有匹配上                       ,就直接走我们后面的servlet/jsp/html等                       。(至于是servlet                ,又会走它那一套机制)

3.2-2代码实现

回到之前的程序,我们在浏览器中直接访问manage目录下的资源admin.jsp                       ,可以看到后台输出如下:

说明过滤器已经起作用了                。

如果没有显示doFilter被调用                       ,可能是因为浏览器缓存机制,建议在调试台点击禁用缓存。

现在来完善ManageFilter过滤器里面的业务代码:

既然请求manage目录下的资源首先要经过过滤器                ,那么我们可以在过滤器中获取session                       ,如果发现session中已经保存了用户信息(即登录过)        ,就放行;如果没有session信息                ,就返回登录页面                       。

package com.filter; import javax.servlet.*; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; import java.io.IOException; public class ManageFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { //当Tomcat创建filter后                       ,会调用该方法        ,进行初始化 System.out.println("ManageFilter init方法被调用..."); } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { //当每次调用该filter时        ,doFilter方法就会被调用 System.out.println("ManageFilter doFilter被调用..."); //如果这里没有调用继续请求的方法                       ,就会停止在这 // 如果继续访问目标资源-->等价于放行 // 在调用过滤器前                ,request对象已经被创建并封装起来了 // 所以我们这里就可以通过servletRequest获取很多信息        ,比如访问url                       ,session                ,比如访问的参数... // 同时可以做事务管理,数据获取                       ,日志管理等等 //获取session //用户浏览器向服务器发送带有jsessionid的cookie                       ,服务器根据该sid找到对应session //这样写后面还可以接续使用httpServletRequest的相关方法 HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest; HttpSession session = httpServletRequest.getSession(); //获取username session对象,后面还可以继续使用 Object username = session.getAttribute("username"); //如果在对应的session中                ,没有找到用户的用户名                       ,就说明没有登录过        ,否则就是登录过 if (username != null) { //用户登录成功过                ,直接放行 /** * filterChain.doFilter(servletRequest, servletResponse); * 1.doFilter代表继续访问目标资源 * 2.ServletRequest和 ServletResponse对象会传递给目标资源/文件 * 3.一定要理解filter传递的两个对象                       ,在一次http请求中        , * 和后面的servlet/jsp中的request        ,response是同一个对象 */ filterChain.doFilter(servletRequest, servletResponse); } else {//说明没有登录过                       ,令其返回登录页面 servletRequest.getRequestDispatcher("/login.jsp") .forward(servletRequest, servletResponse); } /** * 关于chain.doFilter()方法: * 在doFilter()方法中                ,在chain.doFilter()之前的代码        ,一般是对request执行的过滤操作; * 在chain.doFilter()后面的代码                       ,一般是对response执行的操作; * chain.doFiter()执行下一个过滤器或者业务处理器                        。 * 如果在doFilter()方法中                ,不写chain.doFilter(),业务无法继续往下处理。 */ } @Override public void destroy() { //当filter对像被销毁时                       ,就会调用该方法 System.out.println("ManageFilter destroy被调用..."); } }

3.4测试

redeployTomcat                       ,在浏览器访问login.jsp,因为login.jsp不在过滤器配置的url下                ,因此请求不会被拦截               。

在login.jsp输入正确的用户数据                       ,点击登录        ,可以看到后台成功转发到了manage目录下的admin.jsp                        。

整个过程为:

用户在login.jsp页面输入数据                ,login.jsp将表单数据提交到loginCheckServlet中检查

servlet发现数据合法                       ,于是给浏览器返回一个jsessionid        ,并在服务器内存中创建和此jsessionid关联的session        ,然后在此session中放入用户数据                       ,最后请求转发到/manage/admin.jsp        。

根据filter原理                ,请求转发不会经过过滤器               。但是在返回admin.jsp后        ,浏览器需要向服务器请求图片资源                       ,并且                ,我们的图片资源刚好匹配在filter配置的url                        。因此关于图片的请求,将会经过过滤器        。

一次请求只能返回一个资源                       ,想要获取图片资源                       ,因此浏览器发出了第二次请求,去获取图片资源       。

综上所述                ,在这次过程中                       ,只经过了一次过滤器        ,后台输出如下:

这时                ,打开浏览器新页面                       ,访问http://localhost:8080/filter/manage/admin.jsp        ,可以看到访问成功        ,因为之前已经登录过了                        。

3.5补充说明

3.5.1关于filterChain.doFilter()

https://www.jb51.net/article/229734.htm

filterChain.doFilter(servletRequest, servletResponse);

chain.doFilter将请求转发给过滤器链下一个filter , 如果没有filter那就是你请求的资源

在doFilter()方法中                       ,在chain.doFilter()之前的代码                ,一般是对request执行的过滤操作;在chain.doFilter()后面的代码        ,一般是对response执行的操作;chain.doFiter()执行下一个过滤器或者业务处理器                。如果在doFilter()方法中                       ,不写chain.doFilter()                ,业务无法继续往下处理;

doFilter代表继续访问目标资源,如servlet                       ,jsp                       ,或是下一个filter

ServletRequest和 ServletResponse对象会传递给目标资源/文件

在一次http请求中,filter传递的两个对象                ,和后面的servlet/jsp中的requestresponse是同一个对象

验证:filter传递的两个对象                       ,在一次http请求中        ,与其后面的servlet/jsp中的request/response是同一对象

在ManageFilter中:

在admin.jsp中:

想法:我们直接访问web应用下的/manage/admin.jsp                ,因为该资源在filter的url规则下                       ,因此当访问时        ,会调用过滤器        ,而过滤器中又将ServletRequest传递给admin.jsp       。

我们同时在filter和admin.jsp中输出request                       ,查看对象的hash值如何                       。

后台输出如下:两者的哈希值是一样的                。

这说明在一个请求里面                ,过滤器里面的ServletRequest        ,Servletresponse                       ,和后面目标资源拿到的request                ,response是同一个对象。是可以共用的                       。

3.5.2关于过滤器中的ServletRequest HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;

我们将过滤器中的ServletRequest转为HttpServletRequest类型,由于HttpServletRequest中有很多方法                       ,所以我们可以在过滤器中做一些日志记录                        。

创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!

展开全文READ MORE
编程格式化输出(printf 命令 – 格式化输出信息) 华为哪些机型有nfc功能(华为哪些手机有nfc功能)