过滤器的基础
- 过滤器
- 过滤器怎么构造?
- filter是有优先级的,当存在多个filter的时候。
- Filter的生命周期
- Filter设计模式:责任链设计模式
- 怎么让任何项目都得通过filter验证呢,url里面设置为 /*
- 过滤器功能代码
- 什么情况下不能拦截 ?
过滤器
过滤器怎么构造?
package com.sj.www;
import jakarta.servlet.*;
import jakarta.servlet.annotation.WebFilter;
import java.io.IOException;
/**
* "*.do"这种写法不用以/开头
* 这种写法属于模糊匹配中的拓展匹配,以星号开始就不要以斜杠开头
* 还一种写法是/dept/*
* 星号表示任意,所以上面那种写法是匹配所有以/dept/开头的路径
*/
@WebFilter("*.do")
public class Filter1 implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("Filter的init方法被执行了");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("doFiterl方法被执行了");
/*执行下一个过滤器,如果没有过滤器,那么就按请求路径执行Java程序*/
filterChain.doFilter(servletRequest,servletResponse);
}
@Override
public void destroy() {
System.out.println("过滤器被销毁了");
}
}
- 注意: Filter的优先级,天生的就比Servlet优先级高。
- /a.do对应一个Filter, 也对应一个Servlet。
那么一定是先执行Filter,然后再执行Servlet。| - 目标Servlet是否执行, 取决于两个条件: .
第一:在过滤器当中是否编写了: chain.doFilter(request, response);代码。
第二:用户发送的请求路径是否和Servlet的请求路径- 致。
chain.doilter(request, response);这行代码的作用:执行下一个过滤器,如果下面没有过滤器了,执行最终的Servlet.
filter是有优先级的,当存在多个filter的时候。
- 使用xml:filter-mapping的顺序决定了谁先执行,越靠上优先级越高。
- 使用注解:按照类的名字在字典中的顺序执行。
- 并且是最先执行的那个filter最后才结束doFilter方法。
Filter的生命周期
- 和servlet对象声明周期一致
- 唯一不同就是filter在服务器启动阶段 实例化,servlet不会
- /a 对应了一个servlet和一个filter,它一定会先执行filter,在考虑执行servlet
Filter设计模式:责任链设计模式
- 先执行过滤器1的代码,然后跳到过滤器2,在跳到过滤器3…过滤器n,最后没有过滤器了跳到指定路径的Java中执行完Java程序,在回到过滤器n的doFilter方法中,执行完剩下的程序,然后过滤器n执行完,回到过滤器n-1执行完剩下的程序…就是这个意思。
- 在编译阶段就确定了调用关系,如果你想改变他们的调用顺序,必须修改Java代码顺序,显然是违背了开闭原则的,但是过滤器是可以在xml里面通过改变mapping的顺序来调整执行的顺序,不需要改源代码,属于是改善了这种设计模式。
- Filter虽然是接口,但是我们可以不重写init和desico方法,因为他们带default(默认)标记,可以不重写。
怎么让任何项目都得通过filter验证呢,url里面设置为 /*
<filter>
<filter-name>filter</filter-name>
<filter-class>com.sj.www.LoginCheckFilter</filter-class>
</filter>
<!--只要你访问的路径是/下面的,你都要走我过滤器-->
<filter-mapping>
<filter-name>filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
过滤器功能代码
package com.sj.www;
import jakarta.servlet.*;
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import java.io.IOException;
public class LoginCheckFilter implements Filter {
/*测试使用count*/
int count=0;
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request=(HttpServletRequest) servletRequest;
HttpServletResponse response=(HttpServletResponse) servletResponse;
HttpSession session = request.getSession(false);
boolean flag=false;
Cookie[] cookies = request.getCookies();
if (cookies !=null){
for (Cookie cookie : cookies) {
if (cookie.getName().equals("loginuser")){
flag=true;
}
}
}
/*
* 请求的是哪个页面不能拦截
* 1、用户进入网站的welcome页面不能过滤掉,不能让客户一进你网站,就让人家登录
* 2、过滤器的else一定不要拦截,否则就等于自己拦截自己,无限循环导致重定向过多
* 3、index.jsp也不能过滤掉,因为你/Welcome没登陆的没cookie的时候跳转的就是这个index.jsp页面,给别人展示一些
* 内容的外加登录功能,你不能用户想看你首页,你得登录,显然是不合适得
* 总结有些页面你不想让用户,直接就进去的,就写在if条件里,只有满足这个条件才能进
* 如果是index和login好的你可以直接进,如果你想进的是/oa/list不好意思,验证是否登录,登录过了就通过
*
* 一些不需要登录的,可以写在if里,一些登录的验证可以写在if条件里
* */
String servletPath = request.getServletPath();
if ("/Welcome".equals(servletPath)||"/index.jsp".equals(servletPath)||"/login.jsp".equals(servletPath)||session != null && session.getAttribute("username") != null||flag) {
filterChain.doFilter(request,response);
}else{
/*
* 没有通过上面的条件,就被过滤掉了,就走下面
*
/*否则就跳到登录页面*/
System.out.println("过滤器被调用"+(++count)+"次");
response.sendRedirect(request.getContextPath()+"/login.jsp");
}
}
}
什么情况下不能拦截 ?
过滤器if里面写的:1、你网站的首页index2、如果你的首页是个Java程序(在Java程序执行一段程序后(跳转到首页)那么这个路径和index都要放在里面3、else里跳转的页面也要放到if里(否则浏览器会循环到里面导致重定向过多次))
目前写的路径是: /*表示所有的请求均拦截。
1、用户访问index. jsp的时候不能拦截(因为欢迎页跳转到的是这里,而且index一般都不拦截)
2、用户已经登录了,这个需要放行,不能拦截。
3、用户要去登录,这个也不能拦截。
4、WelcomeServlet也不能拦截,因为这是欢迎页。