Web核心技术之Filter过滤器(2)

public void init(FilterConfig filterConfig) throws ServletException {

}

@Override

public void destroy() {

}

}

1.3 Filter执行流程

如上图是使用过滤器的流程,我们通过以下问题来研究过滤器的执行流程:

  • 放行后访问对应资源,资源访问完成后,还会回到Filter中吗?

从上图就可以看出肯定 会 回到Filter中

  • 如果回到Filter中,是重头执行还是执行放行后的逻辑呢?

如果是重头执行的话,就意味着 放行前逻辑 会被执行两次,肯定不会这样设计了;所以访问完资源后,会回到 放行后逻辑,执行该部分代码。

通过上述的说明,我们就可以总结Filter的执行流程如下:

接下来我们通过代码验证一下,在 doFilter() 方法前后都加上输出语句,如下

同时在 hello.jsp 页面加上输出语句,如下

执行访问该资源打印的顺序是按照我们标记的标号进行打印的话,说明我们上边总结出来的流程是没有问题的。启动服务器访问 hello.jsp 页面,在控制台打印的内容如下:

以后我们可以将对请求进行处理的代码放在放行之前进行处理,而如果请求完资源后还要对响应的数据进行处理时可以在放行后进行逻辑处理。

1.4 Filter拦截路径配置

拦截路径表示 Filter 会对请求的哪些资源进行拦截,使用 @WebFilter 注解进行配置。如:@WebFilter("拦截路径")

拦截路径有如下四种配置方式:

  • 拦截具体的资源:/index.jsp:只有访问index.jsp时才会被拦截

  • 目录拦截:/user/*:访问/user下的所有资源,都会被拦截

  • 后缀名拦截:*.jsp:访问后缀名为jsp的资源,都会被拦截

  • 拦截所有:/*:访问所有资源,都会被拦截

通过上面拦截路径的学习,大家会发现拦截路径的配置方式和 Servlet 的请求资源路径配置方式一样,但是表示的含义不同。

1.5 过滤器链

1.5.1 概述

过滤器链是指在一个Web应用,可以配置多个过滤器,这多个过滤器称为过滤器链。

如下图就是一个过滤器链,我们学习过滤器链主要是学习过滤器链执行的流程

上图中的过滤器链执行是按照以下流程执行:

  1. 执行 Filter1 的放行前逻辑代码

  2. 执行 Filter1 的放行代码

  3. 执行 Filter2 的放行前逻辑代码

  4. 执行 Filter2 的放行代码

  5. 访问到资源

  6. 执行 Filter2 的放行后逻辑代码

  7. 执行 Filter1 的放行后逻辑代码

以上流程串起来就像一条链子,故称之为过滤器链。

1.5.2 代码演示
  • 编写第一个过滤器 FilterDemo ,配置成拦截所有资源

@WebFilter(“/*”)

public class FilterDemo implements Filter {

@Override

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {

//1. 放行前,对 request数据进行处理

System.out.println(“1.FilterDemo…”);

//放行

chain.doFilter(request,response);

//2. 放行后,对Response 数据进行处理

System.out.println(“3.FilterDemo…”);

}

@Override

public void init(FilterConfig filterConfig) throws ServletException {

}

@Override

public void destroy() {

}

}

  • 编写第二个过滤器 FilterDemo2 ,配置炒年糕拦截所有资源

@WebFilter(“/*”)

public class FilterDemo2 implements Filter {

@Override

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {

//1. 放行前,对 request数据进行处理

System.out.println(“2.FilterDemo…”);

//放行

chain.doFilter(request,response);

//2. 放行后,对Response 数据进行处理

System.out.println(“4.FilterDemo…”);

}

@Override

public void init(FilterConfig filterConfig) throws ServletException {

}

@Override

public void destroy() {

}

}

  • 修改 hello.jsp 页面中脚本的输出语句

<%@ page contentType=“text/html;charset=UTF-8” language=“java” %>

Title

hello JSP~

<%

System.out.println(“3.hello jsp”);

%>

  • 启动服务器,在浏览器输入 http://localhost/filter-demo/hello.jsp 进行测试,在控制台打印内容如下

从结果可以看到确实是按照我们之前说的执行流程进行执行的。

1.5.3 问题

上面代码中为什么是先执行 FilterDemo ,后执行 FilterDemo2 呢?

我们现在使用的是注解配置Filter,而这种配置方式的优先级是按照过滤器类名(字符串)的自然排序。

比如有如下两个名称的过滤器 : BFilterDemoAFilterDemo 。那一定是 AFilterDemo 过滤器先执行。

1.6 案例

1.6.1 需求

访问服务器资源时,需要先进行登录验证,如果没有登录,则自动跳转到登录页面

1.6.2 分析

我们要实现该功能是在每一个资源里加入登陆状态校验的代码吗?显然是不需要的,只需要写一个 Filter ,在该过滤器中进行登陆状态校验即可。而在该 Filter 中逻辑如下:

1.6.3 代码实现
1.6.3.1 创建Filter

brand-demo 工程创建 com.itheima.web.filter 包,在该下创建名为 LoginFilter 的过滤器

@WebFilter(“/*”)

public class LoginFilter implements Filter {

@Override

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {

}

public void init(FilterConfig config) throws ServletException {

}

public void destroy() {

}

}

1.6.3.2 编写逻辑代码

doFilter() 方法中编写登陆状态校验的逻辑代码。

我们首先需要从 session 对象中获取用户信息,但是 ServletRequest 类型的 requset 对象没有获取 session 对象的方法,所以此时需要将 request对象强转成 HttpServletRequest 对象。

HttpServletRequest req = (HttpServletRequest) request;

然后完成以下逻辑

  • 获取Session对象

  • 从Session对象中获取名为 user 的数据

  • 判断获取到的数据是否是 null

  • 如果不是,说明已经登陆,放行

  • 如果是,说明尚未登陆,将提示信息存储到域对象中并跳转到登陆页面

代码如下:

@WebFilter(“/*”)

public class LoginFilter implements Filter {

@Override

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {

HttpServletRequest req = (HttpServletRequest) request;

//1. 判断session中是否有user

HttpSession session = req.getSession();

Object user = session.getAttribute(“user”);

//2. 判断user是否为null

if(user != null){

// 登录过了

//放行

chain.doFilter(request, response);

}else {

// 没有登陆,存储提示信息,跳转到登录页面

req.setAttribute(“login_msg”,“您尚未登陆!”);

req.getRequestDispatcher(“/login.jsp”).forward(req,response);

}

}

public void init(FilterConfig config) throws ServletException {

}

public void destroy() {

}

}

1.6.3.3 测试并抛出问题

在浏览器上输入 http://localhost:8080/brand-demo/ ,可以看到如下页面效果

从上面效果可以看出没有登陆确实是跳转到登陆页面了,但是登陆页面为什么展示成这种效果了呢?

1.6.3.4 问题分析及解决

因为登陆页面需要 css/login.css 这个文件进行样式的渲染,下图是登陆页面引入的css文件图解

而在请求这个css资源时被过滤器拦截,就相当于没有加载到样式文件导致的。解决这个问题,只需要对所以的登陆相关的资源进行放行即可。还有一种情况就是当我没有用户信息时需要进行注册,而注册时也希望被过滤器放行。

综上,我们需要在判断session中是否包含用户信息之前,应该加上对登陆及注册相关资源放行的逻辑处理

//判断访问资源路径是否和登录注册相关

//1,在数组中存储登陆和注册相关的资源路径

String[] urls = {“/login.jsp”,“/imgs/”,“/css/”,“/loginServlet”,“/register.jsp”,“/registerServlet”,“/checkCodeServlet”};

//2,获取当前访问的资源路径

String url = req.getRequestURL().toString();

//3,遍历数组,获取到每一个需要放行的资源路径

for (String u : urls) {

//4,判断当前访问的资源路径字符串是否包含要放行的的资源路径字符串

/*

比如当前访问的资源路径是 /brand-demo/login.jsp

而字符串 /brand-demo/login.jsp 包含了 字符串 /login.jsp ,所以这个字符串就需要放行

*/

if(url.contains(u)){

//找到了,放行

chain.doFilter(request, response);

//break;

return;

}

}

1.6.3.5 过滤器完整代码

-@WebFilter(“/*”)

public class LoginFilter implements Filter {

@Override

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {

HttpServletRequest req = (HttpServletRequest) request;

//判断访问资源路径是否和登录注册相关

//1,在数组中存储登陆和注册相关的资源路径

String[] urls = {“/login.jsp”,“/imgs/”,“/css/”,“/loginServlet”,“/register.jsp”,“/registerServlet”,“/checkCodeServlet”};

//2,获取当前访问的资源路径

String url = req.getRequestURL().toString();

//3,遍历数组,获取到每一个需要放行的资源路径

for (String u : urls) {

//4,判断当前访问的资源路径字符串是否包含要放行的的资源路径字符串

/*

比如当前访问的资源路径是 /brand-demo/login.jsp

而字符串 /brand-demo/login.jsp 包含了 字符串 /login.jsp ,所以这个字符串就需要放行

*/

if(url.contains(u)){

//找到了,放行

chain.doFilter(request, response);

//break;

return;

}

}

//1. 判断session中是否有user

HttpSession session = req.getSession();

Object user = session.getAttribute(“user”);

//2. 判断user是否为null

if(user != null){

// 登录过了

//放行

chain.doFilter(request, response);

}else {
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:前端)

最后

文章到这里就结束了,如果觉得对你有帮助可以点个赞哦,如果有需要前端校招面试题PDF完整版的朋友可以点击这里即可获取,包括答案解析。

能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!**

因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

[外链图片转存中…(img-68wJnNVk-1712549328745)]

[外链图片转存中…(img-2eALyKp0-1712549328746)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!

[外链图片转存中…(img-ifuuGfBU-1712549328746)]

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:前端)

最后

文章到这里就结束了,如果觉得对你有帮助可以点个赞哦,如果有需要前端校招面试题PDF完整版的朋友可以点击这里即可获取,包括答案解析。

[外链图片转存中…(img-tloy111x-1712549328746)]

  • 13
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值