过滤器
过滤器是什么,为什么需要用过滤器
过滤器就是它的字面意思,它能够对任何非法请求进行拦截。举个例子来说,就是你去银行取钱不能够不登录账号就直接进入到取钱页面,这是为什么呢?原因是你直接访问取钱页面的请求被过滤器拦截了。
有人可能就问了,不就是个判断吗,直接在取钱页面直接加上就好了,效果是一样的。不可否认,说的很对,但是,如果我要是有100个不同的页面请求呢,咬咬牙也能加,要是有1万个呢,过滤器的创建方便以外,其实你想想每个页面都加,会增加多少代码量呢?为了减轻负担,活用我们四大特性之一抽象,我们就把它给取出来,也不用每个页面调用才能实现,会自动拦截,不符合要求的请求。
过滤器介绍
我们过滤器主要是采用继承(extend)Filter接口(Filter interface)来实现,既然是个接口就要重写方法,接下来就介绍下它的方法:
init(FilterConfig filter Config)
初始化方法,一般在服务器启动的时候就执行了,但是本人不才,能够详细了解到它的深层,我就给大家说一下我的发现吧,init方法中初始化是存在顺序的,且那个顺序一不是通过首字母顺序,二不是通过创建时间,三它的顺序是固定的,不是重写部署就出现一个版本的顺序,笔者认为是系统内部设置了顺序,但是平时可能不常见。doFilter(ServletRequest request,ServletResponse response, FilterChain chain)
这个叫做过滤器拦截的业务逻辑处理,主要就是存放一些放行判断的,就好比我把登录界面拦了下来,但是你不登陆我就不能让你通行,就陷入了逻辑闭环,先有鸡还是先有蛋呢,因此我们要在这里进行放行。放行的时候我们使用的是它后面那个参数chain
,这东西结合chain.doFilter(request,response)
就能够执行放行操作(访问servlet),但是chain
这个东西是链的意思,所以聪明的你已经看出来了,过滤器之间是如何避免你拦下我,我拦下你的冰雪蜜城行为了,对,doFilter
也存在一个顺序,那么它的顺序也和init一样让人捉摸不定吗?肯定不能,要不然每次还要猜测顺序,很麻烦,它的顺序是你创建Filter这个类文件文件名的首字母的顺序进行的。destroy()
有了创建有了应用,就肯定要有释放,要不然大家用完就扔在哪里,弱小无助的浏览器会吃不消的。
实战演示
说了很多的话,不如来一遍实践。事实胜于雄辩。
EncodingFilter.java 这个是用来将post请求的编码格式变成utf-8
的
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
@WebFilter(filterName = "encoding", urlPatterns = "/*")
public class EncodingFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("EncodingFilter.init");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("EncodingFilter.doFilter");
// servletRequest.setCharacterEncoding("utf-8"); 此行代码不能生效,需要使用HttpServletRequest进行编码
HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
String method = httpServletRequest.getMethod(); // 获取是get还是post
// 如果是post请求,我们就处理乱码问题
if (method.equalsIgnoreCase("post")){
httpServletRequest.setCharacterEncoding("UTF-8");
}
// 如果是post请求,解决乱码问题之后,继续往后执行,否则直接往下执行
filterChain.doFilter(servletRequest,servletResponse);
}
@Override
public void destroy() {
System.out.println("EncodingFilter.destroy");
}
}
LoginFilter
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
// /*表示能够将全部请求拦下来,进行筛选
@WebFilter(filterName = "Login", urlPatterns = "/*")
public class LoginFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("LoginFilter.init");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("LoginFilter.doFilter");
HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
HttpServletResponse httpServletResponse = (HttpServletResponse) servletResponse;
HttpSession session = httpServletRequest.getSession();
// 仅放行登录(如果还有用户的增删改查之类操作的话)
// 如果不放行登录,那么就会陷入死循环,登录被拦截,然后重定向到登录,然后在被拦截,进入循环
String method = httpServletRequest.getParameter("method");
String servletPath = httpServletRequest.getServletPath();
if (servletPath.equals("/login.jsp") // 这里放行登录页面,这是直接访问登录页面的形式
|| servletPath.equals("/user") && (method.equals("login")) // 这里放行登录页面(这是调用方法的形式)
|| servletPath.equals("/fail.html") // 这里放行登录错误页面
|| servletPath.endsWith(".js") // 这里放行前端的一些jQuery之类的
|| servletPath.endsWith(".css") // 这里放行bootStrap之类的
|| servletPath.equals("/code")) { // 这里放行的是生成验证码的
filterChain.doFilter(servletRequest, servletResponse);
return;
}
// 通过session里面存的数据,查看有没有一个叫做user的对象,如果有就是找到了,即登陆成功,只有登陆成功才能创建出一个user对象
User user = (User) session.getAttribute("user");
if (user == null) {
httpServletResponse.sendRedirect(httpServletRequest.getContextPath() + "/login.jsp");
return;
}
filterChain.doFilter(servletRequest, servletResponse);
}
@Override
public void destroy() {
System.out.println("LoginFilter.destroy");
}
}