Filter过滤器原理和登录实现
Filter过滤器API
Servlet过滤器API包含了3个接口,它们都在javax.servlet包中,分别是Filter接口、FilterChain接口和FilterConfig接口。
Filter接口(源码)
public interface Filter {
public void init(FilterConfig filterConfig) throws ServletException;
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException;
public void destroy();
}
所有的过滤器都必须实现Filter接口。该接口定义了init,doFilter0,destory()三个方法:
(1)init(FilterConfig filterConfig)
在web应用程序启动时,web服务器将根据 web.xml文件中的配置信息来创建每个注册的Filter实例对象,并将其保存在服务器的内存中。Web容器创建Filter对象实例后,将立即调用该Filter对象的init方法。Init方法在Filter生命周期中仅执行一次,web容器在调用init方法时,会传递一个包含Filter的配置和运行环境的FilterConfig对象(FilterConfig的用法和ServletConfig类似)。利用FilterConfig对象可以得到ServletContext对象,以及部署描述符中配置的过滤器的初始化参数。
(2)doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
doFilter()方法类似于Servlet接口的service()方法。当客户端请求目标资源的时候,容器就会调用与这个目标资源相关联的过滤器的 doFilter()方法。其中参数 request, response 为 web 容器或 Filter 链的上一个 Filter 传递过来的请求和相应对象;参数 chain 为代表当前 Filter 链的对象,在特定的操作完成后,可以在当前 Filter 对象的 doFilter 方法内部需要调用 FilterChain 对象的 chain.doFilter(request,response)方法才能把请求交付给 Filter 链中的下一个 Filter 或者目标 Servlet 程序去处理,也可以直接向客户端返回响应信息,或者利用RequestDispatcher的forward()和include()方法,以及 HttpServletResponse的sendRedirect()方法将请求转向到其他资源。这个方法的请求和响应参数的类型是 ServletRequest和ServletResponse,也就是说,过滤器的使用并不依赖于具体的协议。
(3)public void destroy()
在Web容器卸载 Filter 对象之前被调用。该方法在Filter的生命周期中仅执行一次。在这个方法中,可以释放过滤器使用的资源。
FilterChain接口(源码)
public interface FilterChain {
public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException;
}
(1)doFilter(ServletRequest request,ServletResponse response)
此方法是由Servlet容器提供给开发者的,用于对资源请求过滤链的依次调用,通过FilterChain调用过滤链中的下一个过滤 器,如果是最后一个过滤器,则下一个就调用目标资源。
FilterConfig接口(源码) FilterConfig接口检索过滤器名、初始化参数以及活动的Servlet上下文。
public interface FilterConfig {
//返回web.xml部署文件中定义的该过滤器的名称
public String getFilterName();
//返回调用者所处的servlet上下文
public ServletContext getServletContext();
//返回过滤器初始化参数值的字符串形式,当参数不存在时,返回nul1.name是初始化参数名
public String getInitParameter(String name);
//以Enumeration形式返回过滤器所有初始化参数值,如果没有初始化参数,返回为空
public Enumeration getInitParameterNames();
}
了解了Filter的基本概念和源码,下面具体使用下Filter过滤器来实现登录过滤。
需求:访问A页面(登录后才能访问的页面)-->未登录-->跳转到登录页面-->登陆成功后,跳转到A页面
自定义HttpFilter
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.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; /**
* HttpFilter
*/
public abstract class HttpFilter implements Filter{ //保存filterConfig对象
private FilterConfig filterConfig; /**
* 直接返回filterConfig对象
* @return
*/
public FilterConfig getFilterConfig() {
return filterConfig;
} /**
* 不建议子类直接覆盖,若直接失败,将可能导致filterConfig成员变量初始化失败
*/
@Override
public void init(FilterConfig filterConfig) throws ServletException {
this.filterConfig = filterConfig;
init();
} /**
* 供子类继承的初始化方法,刻通过getFilterConfig()方法获得filterConfig对象
*/
private void init() {} /**
* 原生的doFilter方法,在方法内部把ServletRequest和ServletResponse转化化为了HttpServletRequest和HttpServletResponse,
* 并调用了doFilter(HttpServletRequest request, HttpServletResponse response,FilterChain filterChain)方法
*/
@Override
public void doFilter(ServletRequest req, ServletResponse res,
FilterChain filterChain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res; doFilter(request, response, filterChain);
} /**
* 抽象方法,为http请求定制,必须实现的方法
* @param request
* @param response
* @param filterChain
* @throws IOException
* @throws ServletException
*/
public abstract void doFilter(HttpServletRequest request, HttpServletResponse response,
FilterChain filterChain) throws IOException, ServletException; @Override
public void destroy() {} }
web.xml配置CommonFilter
<filter>
<filter-name>commonFilter</filter-name>
<filter-class>com.gcx.emall.Filter.CommonFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>commonFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
登录过滤器CommonFilter
import java.io.IOException; import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory; public class CommonFilter extends HttpFilter { private final Logger log = LoggerFactory.getLogger(CommonFilter.class); @Override
public void doFilter(HttpServletRequest request,
HttpServletResponse response, FilterChain filterChain)
throws IOException, ServletException { log.info("==============拦截get请求================");
if ("GET".equalsIgnoreCase(request.getMethod())) {
RequestUtil.saveRequest(request);
}
String requestUri = request.getRequestURI();
String contextPath = request.getContextPath();
String url = requestUri.substring(contextPath.length());
if ("/login".equals(url)) {
filterChain.doFilter(request, response);
return;
} else {
String username = (String) request.getSession().getAttribute("user");
if (username == null) {
log.info("被拦截:跳转到login页面!");
request.getRequestDispatcher("/page/index1.jsp").forward(request, response);
} else
filterChain.doFilter(request, response);
}
}
}
RequestUtil 保存、获取request并加密请求页面
public class RequestUtil {
private static final Logger logger = LoggerFactory.getLogger(RequestUtil.class);
private static final Base64 base64 = new Base64(true);
public static final String LAST_PAGE = "lastPage";//未登录时访问的页面
public static final String REDIRECT_HOME = "/";//未登录时跳转到首页
public static final String LOGIN_HOME = "/index.jsp";//登录成功后进入的页面
/**
* 保存当前请求
*/
public static void saveRequest(HttpServletRequest request) {
request.getSession().setAttribute(LAST_PAGE, RequestUtil.hashRequestPage(request));
logger.debug("被拦截的url的sessionID:{}", request.getSession().getId());
logger.debug("save request for {}", request.getRequestURI());
}
/**
* 加密请求页面
* @param request
* @return
*/
public static String hashRequestPage(HttpServletRequest request) {
String reqUri = request.getRequestURI();
String query = request.getQueryString();
if (query != null) {
reqUri += "?" + query;
}
String targetPage = null;
try {
targetPage = base64.encodeAsString(reqUri.getBytes("UTF-8"));
} catch (UnsupportedEncodingException ex) {
//this does not happen
}
return targetPage;
}
/**
* 取出之前保存的请求
* @return
*/
public static String retrieveSavedRequest(HttpServletRequest request) {
HttpSession session = request.getSession();
if (session == null) {
return REDIRECT_HOME;
}
String HashedlastPage = (String) session.getAttribute(LAST_PAGE);
if (HashedlastPage == null) {
return LOGIN_HOME;
} else {
return retrieve(HashedlastPage);
}
}
/**
* 解密请求的页面
* @param targetPage
* @return
*/
public static String retrieve(String targetPage) {
byte[] decode = base64.decode(targetPage);
try {
String requestUri = new String(decode, "UTF-8");
int i = requestUri.indexOf("/", 1);
return requestUri.substring(i);
} catch (UnsupportedEncodingException ex) {
//this does not happen
return null;
}
}
}
LoginCOntroller
@RequestMapping(value = "/hello",method = RequestMethod.GET)
public String testHello( String test) {
log.info("执行了Hello方法!");
return "loginSuccess";
}
@RequestMapping(value = "/login",method = RequestMethod.POST)
public String login(HttpServletRequest request,String userName,String password){
log.info("执行了login方法!");
password = DigestUtils.md5Hex(password);
User user = userService.findUser(userName,password);
if(user!=null){
request.getSession().setAttribute("userId", user.getId());
request.getSession().setAttribute("user", userName); return "redirect:" + RequestUtil.retrieveSavedRequest(request);//跳转至访问页面
}else{
log.info("用户不存在");
request.getSession().setAttribute("message", "用户名不存在,请重新登录"); return "index";
}
}
最后需要几个jsp页面login.jsp,index.jsp(首页面,任何人都能访问的),loginSuccess.jsp,还需要在controller中加上一个测试testHello方法用于满足之前说的需求。
注意事项:我们过滤的是所有请求,但对于静态资源css,js,image我们应该不拦截,对其放行。我们可以在web.xml中进行指定
<!-- 不拦截静态文件 -->
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>/js/*</url-pattern>
<url-pattern>/css/*</url-pattern>
<url-pattern>/image/*</url-pattern>
<url-pattern>/fonts/*</url-pattern>
</servlet-mapping>
写在后面:本来想把Filter和SpringMVC的interceptor拦截器一起写总结了,但感觉篇幅有些长打算下篇在介绍。
Filter过滤器原理和登录实现的更多相关文章
- SpringBoot使用Filter过滤器处理是否登录的过滤时,用response.sendRedirect()转发报错
1.使用response.sendRedirect("/login")时报错,控制台报错如下: Cannot call sendError() after the response ...
- 布隆过滤器(Bloom Filter)的原理和实现
什么情况下需要布隆过滤器? 先来看几个比较常见的例子 字处理软件中,需要检查一个英语单词是否拼写正确 在 FBI,一个嫌疑人的名字是否已经在嫌疑名单上 在网络爬虫里,一个网址是否被访问过 yahoo, ...
- 过滤器(filter)实现用户登录拦截
过滤器(filter)实现用户登录拦截 >>>>>>>>>>>>>>>>>>>> ...
- 布隆过滤器(Bloom Filter)原理以及应用
应用场景 主要是解决大规模数据下不需要精确过滤的场景,如检查垃圾邮件地址,爬虫URL地址去重,解决缓存穿透问题等. 布隆过滤器(Bloom Filter)是1970年由布隆提出的.它实际上是一个很长的 ...
- 硬核 | Redis 布隆(Bloom Filter)过滤器原理与实战
在Redis 缓存击穿(失效).缓存穿透.缓存雪崩怎么解决?中我们说到可以使用布隆过滤器避免「缓存穿透」. 码哥,布隆过滤器还能在哪些场景使用呀? 比如我们使用「码哥跳动」开发的「明日头条」APP 看 ...
- Filter过滤器实现登录检查
主要利用filter过滤掉未经登录而直接跳转到非登录访问页面.代码而言的话并不难,只是有几点问题需要注意一下. 1.使用filter需要配置web.xml,如果是/*那么在拦截后的页面会连带jsp页面 ...
- 干货,一文带你超详细了解 Filter 的原理及应用
提出问题 1.我们在访问后台很多页面时都需要登录,只有登录的用户才能查看这些页面,我们需要 在每次请求的时候都检查用户是否登陆,这样做很麻烦,有没有一种方法可以在我们请求之 前就帮我们做这些事 ...
- javaweb之Filter过滤器详解
快速入门 1.新建一个类,实现Filter接口 2.实现doFilter()方法,打印一句话,来证明能够进行拦截 3.在web.xml中进行配置(参照Servlet配置) 4.访问一个页面,看看能不能 ...
- Filter过滤器的应用
Filter过滤器作用:在每次请求服务资源时做过滤处理. 原理:Filter接口中有一个doFilter方法,当开发人员编写好Filter类实现doFilter方法,并配置对哪个web资源进行拦截后, ...
随机推荐
- yii---where该如何使用
简单示例yii 的where使用方法: $where = ['post_id'=>$postId]; //$list = ForumThreadPost::find()->where($w ...
- Java工程师之SpringBoot系列教程前言&目录
前言 与时俱进是每一个程序员都应该有的意识,当一个Java程序员在当代步遍布的时候,你就行该想到我能多学点什么.可观的是后端的框架是稳定的,它们能够维持更久的时间在应用中,而不用担心技术的更新换代.但 ...
- Redis的启动过程
本文主要介绍Redis启动加载过程,总体上可以分为如下几步: 1. 初始化全局服务器配置 2. 加载配置文件(如果指定了配置文件,否则使用默认配置) 3. 初始化服务器 4. 加载数据库 5. 网络监 ...
- 解决VMware安装ubuntu16.04后无法全屏的问题
参考教程:http://www.jb51.net/os/Ubuntu/356462.html 双系统经常崩,故在windows10下装了个ubuntu的虚拟机,安装完成后无法全屏,进入系统设置调试显示 ...
- MySQL异步复制
准备:主备库版本一致,正常安装软件. 1.主库上设置一个复制使用的账户: mysql> grant replication slave on *.* to 'rep1'@'192.168.100 ...
- df and du
1.若有进程在占用某个文件,而其他进程把这文件删掉,只会删除其在磁盘中的标记,而不会释放其占用的磁盘空间:直到所有访问该文件的进程退出为止: 2.df 是从内核中获取磁盘占用情况数据的,而du是统计当 ...
- 【mlflow】执行import mlflow 报错:ImportError: No module named 'pkg_resources'
命令行运行 python -c “import mlflow” 的时候报错: ImportError: No module named 'pkg_resources' 结果发现是因为本地有一个文件夹叫 ...
- 【Pyton】【小甲鱼】爬虫
一.什么是爬虫? 可以理解为一只蜘蛛,在不同的网页上爬来爬去,获取我们需要的资源 二.Python如何访问互联网 urllib(一个包)=url(网页地址)+lib() 第一部分:protocol:/ ...
- numpy排序(sort、argsort、lexsort、partition、sorted)
1.sort numpy.sort(a, axis=1, kind='quicksort', order=None) a :所需排序的数组 axis:数组排序时的基准,axis=0按行排列:axis= ...
- mysql数据库环境配置中部分问题解决办法
注:原文地址:https://www.cnblogs.com/hezhuoheng/p/9366630.html 其中最重要的,是三个原则:命令按顺序输入.删除了ini(这个不是原则,是我解决问题的一 ...