Filter 过滤器
1.基本使用
- 使用的实现接口在javax.servlet包下的接口Filter
@WebFilter("/*")
public class DemoFilter1 implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("init执行");
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
System.out.println("doFilter执行");
}
@Override
public void destroy() {
System.out.println("destroy执行");
}
}
注意实现javax.servlet包下的接口
-
实现的三个类
- init
- destory
- doFilter
-
filter配置两种方式
方式一:配文件
<?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> <filter-name>filter</filter-name> <filter-class>com.liu.filter.DemoFilter1</filter-class> </filter> <filter-mapping> <filter-name>filter</filter-name> <url-pattern>/DemoController</url-pattern> </filter-mapping> <filter> <filter-name>filter2</filter-name> <filter-class>com.liu.filter.DemoFilter2</filter-class> </filter> <filter-mapping> <filter-name>filter2</filter-name> <url-pattern>/DemoController</url-pattern> </filter-mapping> </web-app>
方式二:注解配置
2.servlet与filter区别
servlet与filter 相似点:
- 符合特定标准之后,通过url出发java类中执行特定的方法
- 配置方式:都可以使用注解和配置文件
- 接口中的方法相似
- init
- destory
- doFilter
filter的不同点:
-
声明周期不同:
- filter在服务器启动时,创建实例是全局变量,application的作用域;
- servlet:创建服务器对象(application)的时候才被实例化
-
请求地址是否可以重复:
- filter中,配置的请求地址可以重复,
- servlet:配置的请求地址不可以重复,
- filter配置的请求地址与servlet的配置的请求地址重复,是先进入filter在进入servlet
-
filter过滤器
-
实现Filter接口的类中有**FilterChain 过滤器链**(作用可以在行代码之前作出判断,是否进入下面代码)
-
FilterChain 的作用:让进来的代码继续执行
@Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { System.out.println("doFilter执行"); chain.doFilter(request,response);//过滤器链执行该行代码,才能向下执行,否则不会向下执行 }
-
在servlet中可以使用重定向实现不同servlet容器的相互跳转
-
-
filter可以配置多层过滤器,进入顺序有类型加载顺序决定的
- 注解:按照包中的类名的排列顺序执行
- wei.xml配置文件:按照配置文件读取的上下的顺序
-
filter中,通常来配置通用的功能(公共的功能),通常使用*****,来实现扩大请求的进入范围
应用:
-
servlet用来实现单个的功能
-
filter用来配置通用的功能
- 在doFilter中设置utf-8请求字符编码格式
- 设置跨域访问
- 访问控制
- 以前在每一个servlet中都要判断用户是否登陆成功,这样重复重复性代码太多,
- 使用filter实现访问控制,通过if判断来用户是否登陆
注意:
- 进入静态资源,也进入过滤器
3.filter配置方式
1.精准定位
执行顺序:先走DemoFilter1,再走Demoservlet1
2./*
//servlet容器
@WebServlet("/myService/DemoController1")//DemoController1
@WebFilter("/myService/DemoController2")//DemoController2
//Filter过滤器
@WebFilter("/myService/DemoController2")//DemoFilter1
@WebFilter("/myService/*")//DemoFilter2
//url访问
//访问 /myService/DemoController1 会走DemoFilter2和DemoController1
//访问 /myService/DemoController2 会走 DemoFilter1,DemoFilter2和DemoController2
应用:过滤器的基本配置
使用过滤器的基本配置,配置请求字符集编码utf-8,跨域设置
@WebFilter("/*")
public class MyFilter1 implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
//使用过滤器的基本配置,配置请求字符集编码utf-8,跨域设置
HttpServletRequest req=(HttpServletRequest)request;
HttpServletResponse resp=(HttpServletResponse)response;
//1.配置请求字符集编码utf-8
req.setCharacterEncoding("utf-8");
//2.跨域设置
/* 允许跨域的主机地址 */
resp.setHeader("Access-Control-Allow-Origin", "http://localhost:5173");
/* 允许跨域的请求⽅法GET, POST, HEAD 等 */
resp.setHeader("Access-Control-Allow-Methods", "*");
/* 重新预检验跨域的缓存时间 (s) */
resp.setHeader("Access-Control-Max-Age", "3600");
/* 允许跨域的请求头 */
resp.setHeader("Access-Control-Allow-Headers", "*");
/* 是否携带cookie */
resp.setHeader("Access-Control-Allow-Credentials", "true");
chain.doFilter(req,resp);
}
@Override
public void destroy() {
}
}
MyFilter2:
访问权限控制:
方式一:通过注解上面的请求路径实现权限控制
- 代码:
@WebFilter("/mysevice/*")
public class MyFilter2 implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
//使用过滤器的基本配置,配置请求字符集编码utf-8,跨域设置
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse resp = (HttpServletResponse) response;
//访问权限控制
HttpSession session = req.getSession();
PnAdminUser paUser = (PnAdminUser) session.getAttribute("paUser");
if (paUser != null) {
chain.doFilter(req, resp);
} else {
System.out.println("没有登录");
ReturnEntity re = new ReturnEntity();
re.setReturnCode(ReturnCodeEnum.NO_LOGIN.getCode());
re.setReturnMsg(ReturnCodeEnum.NO_LOGIN.getMsg());
resp.setContentType("application/json;charset=utf-8");
PrintWriter writer = resp.getWriter();
writer.print(JSON.toJSONString(re));
writer.close();
}
}
@Override
public void destroy() {
}
}
- 请求路径
//菜单请求路径
@WebServlet("/mysevice/menus/*")
//过滤器
@WebFilter("/mysevice/*")
//登录请求路径
@WebServlet("/login")
- 流程图
方式二:通过请求地址判断配合前端push跳转
登录访问权限
描述:
前端作出请求,在过滤器中对所有的请求作出判断,不是login的给前端作出反馈,然后让前端根据响应码作出相应的跳转
@WebFilter("/*")
public class MyFilter2 implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
//使用过滤器的基本配置,配置请求字符集编码utf-8,跨域设置
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse resp = (HttpServletResponse) response;
//访问权限控制
HttpSession session = req.getSession();
PnAdminUser paUser = (PnAdminUser) session.getAttribute("paUser");
//通过白名单和黑名单设置访问权限
String requestURI = req.getRequestURI();//获取当前请求路径: /day16/menus/query 有项目的servlet的项目名,有/*
String contextPath = req.getServletPath();//获取servlet的项目配置路径: /login 没有项目的servlet的项目名,没有/*
System.out.println(requestURI);
System.out.println(contextPath);
if ("/login".equals(contextPath)) {
chain.doFilter(req, resp);
} else {
if (paUser != null) {
chain.doFilter(req, resp);
} else {
System.out.println("没有登录");
ReturnEntity re = new ReturnEntity();
re.setReturnCode(ReturnCodeEnum.NO_LOGIN.getCode());
re.setReturnMsg(ReturnCodeEnum.NO_LOGIN.getMsg());
resp.setContentType("application/json;charset=utf-8");
PrintWriter writer = resp.getWriter();
writer.print(JSON.toJSONString(re));
writer.close();
}
}
}
}
侧边栏菜单模块控制权限控制
为了登录用户在main主页面中,通过url访问不属于自己的权限模块作出控制,
在登录用户的时候,通过不同用户的menu_id的访问权限查询菜单表中的url的路径存到list中,每次到了该过滤器都要遍历该用户的访问权限的url,
/**
* @description: 对登录用户访问侧边栏菜单权限控制
*/
@WebFilter("/*")
public class MyFilter3 implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse resp = (HttpServletResponse) response;
//访问权限控制
HttpSession session = req.getSession();
PnAdminUser paUser = (PnAdminUser) session.getAttribute("paUser");
List<String> userMenuId = (List<String>) session.getAttribute("userMenuId");
String requestURI = req.getRequestURI();//获取当前请求路径: /day16/menus/query 有项目的servlet的项目名,有/*
String servletPath = req.getServletPath();//获取servlet的项目配置路径: /login 没有项目的servlet的项目名,没有/*
System.out.println(requestURI);
System.out.println(servletPath);
//系统中存在的功能URL,但是在数据库中不存在,每个用户可以登录,登出,访问侧边栏
if ("/login".equals(servletPath)||"/loginOut".equals(servletPath)||"/PnAdminMenu".equals(servletPath)) {
chain.doFilter(req, resp);
} else {
//如果用户登录成功进入主菜单,在url列表中有,表示有此模块权限,可以访问
// 在url列表中没有,表示没有此模块全新啊,不可以访问
if (userMenuId.contains(servletPath)) {
chain.doFilter(req, resp);
} else {
System.out.println("没有权限");
ReturnEntity re = new ReturnEntity();
re.setReturnCode(ReturnCodeEnum.NO_PERMISSION.getCode());
re.setReturnMsg(ReturnCodeEnum.NO_PERMISSION.getMsg());
resp.setContentType("application/json;charset=utf-8");
PrintWriter writer = resp.getWriter();
writer.print(JSON.toJSONString(re));
writer.close();
}
}
}
}
粒度