过滤器是啥
Filter表示过滤器,是JavaWeb三大组件(Servlet、Filter、Listener)之一。
过滤器可以把对资源的请求拦截下来,从而实现一些特殊的功能。
用户登录功能,如果登录成功就跳转欢迎页面,如果没有登录成功,就跳转到登录页面让用户重新登录。要实现这个效果需要在每一个资源中都写上这段逻辑,而这种操作可以在过滤器中实现。这个就是权限控制,过滤器还可以做日志记录、统一编码处理、敏感词过滤。
过滤器快速入门
1.定义类,实现Filter接口,并重写其所有方法
//过滤器的初始化
public void init(FilterConfig fConfig) throws ServletException{
//对请求和响应进行处理,实现过滤器的功能
public void doFilter(ServletRequest request,ServletReponse response,FilterChain chain)
//Web容器销毁过滤器时调用该方法
public void destroy()
2.配置Filter拦截资源的路径:在类上定义@WebFilter注解。而注解的value属性值/*:表示拦截所有的资源
@WebFilter("/*")
public class MyFilter implements Filter
3.在doFilter方法中输出一句话,并放行
public void doFilter(ServletRequest request,ServletResponse response,FilterChain chain){
System.out.println("run at MyFilter->doFilter");
//放行
chain.doFilter(request,response);
}
演示代码
1.创建一个项目,项目下有一个hello.jsp页面和一个Filter文件
hello.jsp代码
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h1 align="center">欢迎</h1>
</body>
</html>
MyFilter.java代码
package com.servlet;
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.annotation.WebFilter;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Servlet implementation class HellowFilter
*/
@WebFilter("/*")
public class MyFilter implements Filter{
//过滤器的初始化
public void init(FilterConfig fConfig) throws ServletException{
System.out.println("run at MyFilter ->init");
}
//对请求和响应进行处理,实现过滤器的功能
public void doFilter(ServletRequest request,ServletResponse response,FilterChain chain) throws IOException,ServletException{
System.out.println("Run at MyFilter->doFilter");
}
}
启动服务器后,访问hello.jsp,网页会白屏,但是控制台会输出run at MyFilter ->init和Run at MyFilter->doFilter。 为什么网页会空白,因为Filter拦截器拦截了请求。网页的请求被拦住了不会往下走。想要让网页显示,就得加一行
chain.doFilter(request,response);
//放行
不放行=请求中断
改善代码
package com.servlet;
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.annotation.WebFilter;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Servlet implementation class HellowFilter
*/
@WebFilter("/*")
public class MyFilter implements Filter{
//过滤器的初始化
public void init(FilterConfig fConfig) throws ServletException{
System.out.println("run at MyFilter ->init");
}
//对请求和响应进行处理,实现过滤器的功能
public void doFilter(ServletRequest request,ServletResponse response,FilterChain chain) throws IOException,ServletException{
System.out.println("Run at MyFilter->doFilter");
// 必须加这一行!让请求继续往下走
chain.doFilter(request, response);
}
// 过滤器销毁
@Override
public void destroy() {
}
}
Filter执行流程
浏览器--请求-->Filter放行前逻辑->服务器
浏览器<--响应--Filter放行后逻辑<-服务器
Filter部分执行流程:
执行前逻辑->放行->访问资源->执行放行后逻辑
Filter拦截路径配置
拦截路径表示Filter会对请求的哪些资源进行拦截,使用@WebFilter注解进行配置@WebFilter("拦截路径")
拦截路径有如下四种配置方法:
- 拦截具体的资源
/index.jsp之访问index.jsp时才会被拦截 - 拦截目录
/user/*访问/user目录下的所有资源,都会被拦截 - 后缀名拦截
*.jsp,访问后缀名为.jsp的资源,都会被拦截 - 拦截所有
/*访问所有的资源,就会被拦截
过滤器链
过滤器链是指在一个Web应用,可以配置多个过滤器,这多个过滤器称为过滤器链。
浏览器--请求-->Filter1放行前逻辑->Filter2放行前逻辑->服务器
浏览器<--响应--Filter1放行后逻辑<-Filter2放行后逻辑<-服务器
演示代码
第一个MyFilter代码
package com.servlet;
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.annotation.WebFilter;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Servlet implementation class HellowFilter
*/
@WebFilter("/*")
public class MyFilter implements Filter{
//过滤器的初始化
public void init(FilterConfig fConfig) throws ServletException{
System.out.println("run at MyFilter ->init");
}
//对请求和响应进行处理,实现过滤器的功能
public void doFilter(ServletRequest request,ServletResponse response,FilterChain chain) throws IOException,ServletException{
System.out.println("Run at MyFilter->doFilter");
//放行前,对request接收的数据进行处理...
System.out.println("MyFilter-放行前,对request接收的数据进行处理..");
// 必须加这一行!让请求继续往下走
chain.doFilter(request, response);
//放行后,对response数据进行处理
System.out.println("MyFilter-放行后,对response数据进行处理..");
}
// 过滤器销毁
@Override
public void destroy() {
}
}
第二个MyFilter2代码
package com.servlet;
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.annotation.WebFilter;
import javax.servlet.http.HttpFilter;
/**
* Servlet Filter implementation class MyFilter2
*/
@WebFilter("/*")//拦截所有文件
public class MyFilter2 implements Filter {
public void init(FilterConfig fConfig) throws ServletException {
// TODO Auto-generated method stub
System.out.println("run at MyFilter2->init");
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
//放行前,对request接受的数据进行处理...
System.out.println("MyFilter2-放行前,对request接受的数据进行处理..");
//放行
chain.doFilter(request, response);
//放行后,对response数据进行处理
System.out.println("MyFilter2-放行后,对request接受的数据进行处理..");
}
public void destroy() {
// TODO Auto-generated method stub
}
}
重写hello.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<%
System.out.println("run at hello.jsp");
%>
</head>
<body>
<h1 align="center">欢迎</h1>
</body>
</html>
过滤器执行顺序
我们现在使用的是注解配置Filter,而这种配置方式的优先级是按照过滤器类名(字符串)的自然排序
比如有两个过滤器BFilter和AFilter。那一定是AFilter过滤器先执行。
实例
online.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>登录</title>
</head>
<body>
<div>
<form align="center" action="LoginServlet" method="post">
用户名:<input type="text" name="user_name"><br/>
密码:<input type="password" name="pwd"><br/>
<input type="checkbox">记住<br/>
<input type="submit"><br/>
</form>
</div>
</body>
</html>
LoginServlet.java
package om.servlet;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
@WebServlet("/LoginServlet")
public class LoginServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 1. 获取用户名密码
String userName = request.getParameter("user_name");
String pwd = request.getParameter("pwd");
// 2. 简单验证(你可以改成数据库校验)
if("admin".equals(userName) && "123456".equals(pwd)) {
HttpSession session = request.getSession();
session.setAttribute("loginer", userName); // 存入登录标记
response.sendRedirect("welcome.jsp"); // 登录成功跳欢迎页
}else {
// 登录失败回登录页
response.sendRedirect("online.jsp");
}
}
}
Online_Filter.java
package om.Filter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
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.annotation.WebFilter;
import javax.servlet.http.HttpFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
/**
* Servlet Filter implementation class Online_Filter
*/
@WebFilter("/*")//拦截所有文件
public class Online_Filter implements Filter {
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
// 将request对象强转成HttpServletRequest对象,以便获取session对象
HttpServletRequest req=(HttpServletRequest)request;
HttpServletResponse resp = (HttpServletResponse) response;
//判断访问资源路径是否允许匿名访问
//1.在容器中存储允许匿名访问的资源
List<String> anoList=new ArrayList<>();
anoList.add("/online.jsp");//登录页
anoList.add("/LoginServlet");//servlet得放行
anoList.add("/welcome.jsp");
// anoList.add(".regist.jsp");//登录处理的servlet
// anoList.add("/register");//注册页处理的Servlet
// anoList.add("/css");//静态资源
// anoList.add(".images");//静态资源
// anoList.add("/iconfont");//静态资源
// anoList.add("/js");//静态资源
// anoList.add("/...");//静态资源
//2.获取当前访问的资源路径
String url=req.getRequestURI().toString();
System.out.println("访问路径是:"+url);
boolean allowAnno=false;//是否允许匿名访问
//3. 判断当前访问的资源路径字符串是否包含要放行的的资源路径字符串
//比如当前访问的资源路径是http://localhost:8080/eshop/online.jsp
//而字符串http://localhost:8080/eshop/online.jsp, 包含了 字符串
//online.jsp ,所以url就需要放行
for(String annoUrl : anoList) {
if(url.contains(annoUrl)) {
allowAnno=true;
break;
}
}
//如果允许匿名访问,直接放行
if(allowAnno) {
System.out.println("----允许匿名访问,放行----");
chain.doFilter(request, response);
}else {
//不允许匿名访问,则判断用户是否已经登录过
HttpSession session =req.getSession();
//获取登录人信息
Object loginer=session.getAttribute("user_name");
//如果登录人信息为空
if(loginer==null) {
System.out.println("---拒绝同行---");
//跳转到online.jsp
resp.sendRedirect(req.getContextPath()+"/online.jsp");
}else {
//已经登录,放行
System.out.println("---已经登录,放行---");
chain.doFilter(request, response);
}
}
}
// public void destroy() {
//
// }
// public void init(FilterConfig fConfig) throws ServletException {
//
// }
}
welcome.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>欢迎</title>
</head>
<body>
<h1 align="center">欢迎</h1>
</body>
</html>
当用户输入账号:"admin"密码:”123456“时,跳转到欢迎界面。