Filter 是java下的一种过滤器 ,能实现对java web程序 客户端和服务器端消息的过滤,也就是在服务器段接受request之前,可以预先对request进行处理,或在客户端接受response之前,对response进行处理。开发人员能够通过这种技术,对一些资源进行管控,能够对网页请求,文件等进行拦截,是一种保证系统安全的技术。
服务器在接收到来自浏览器的请求之后,在servlet处理请求之前,要先经过层层Filter的过滤。这样能够保证它request到达servlet之前预处理request等。
在web项目中,Filter是一个接口,我们所实现这个接口之后,会有三个需要重写的方法。
(1)init(FilterConfig filterConfig) throws ServletException
Web 容器调用 init(FilterConfig) 来初始化过滤器。容器在调用该方法时,向过滤器传递 FilterConfig 对象,利用 FilterConfig 对象可以得到 ServletContext 对象,以及在 web.xml 中配置的过滤器的初始化参数。在这个方法中,可以抛出 ServletException 异常,通知容器该过滤器不能正常工作。此时的 Web 容器启动失败,整个应用程序不能够被访问。 实例化和初始化的操作只会在容器启动时执行,而且只会执行一次。
(2)doFilter(ServletRequest,ServletResponse,FilterChain)
doFilter 方法类似于 Servlet 接口的 service 方法。当客户端请求目标资源的时候,容器会筛选出符合 filter-mapping
中的 url-pattern
的 filter,并按照声明 filter-mapping
的顺序依次调用这些 filter 的 doFilter 方法。在这个链式调用过程中,可以调用 chain.doFilter(ServletRequest, ServletResponse)
将请求传给下一个过滤器(或目标资源),也可以直接向客户端返回响应信息,或者利用 RequestDispatcher 的 forward 和 include 方法,以及 HttpServletResponse 的 sendRedirect 方法将请求转向到其它资源。需要注意的是,这个方法的请求和响应参数的类型是 ServletRequest 和 ServletResponse,也就是说,过滤器的使用并不依赖于具体的协议。
(3)destroy()
destroy 方法指示过滤器的生命周期结束。在这个方法中,可以释放过滤器使用的资源。
长时间打开一个网页不进行操作会出现登录失效的情况,此时要是没有拦截功能,那么会出现在未登录的情况下还能进行操作。
我们先创建登录成功后要访问的Servlet,也就是login.jsp中给出认证之后要访问的页面。
success: function(msg){
if("vcodeError" == msg){
....
} else if("loginError" == msg){
....
} else if("admin" == msg){
window.location.href = "SystemServlet?method=toAdminView";
} else if("student" == msg){
window.location.href = "SystemServlet?method=toStudentView";
} else if("teacher" == msg){
window.location.href = "SystemServlet?method=toTeacherView";
}
}
浏览器就可以根据这个消息跳转到管理员登录成功之后应该去的页面。
public class SystemServlet extends HttpServlet {
private static final long serialVersionUID = -7258264317769166483L;
public void doGet(HttpServletRequest req,HttpServletResponse res) throws IOException{
doPost(req,res);
}
public void doPost(HttpServletRequest req,HttpServletResponse res) throws IOException{
res.getWriter().write("hello");
}
}
从上面的代码中可以看出来,登录成功后会跳转到SystemServlet。
同样,我们仍然要在web.xml进行配置,建立SystemServlet到访问路径的映射。
<servlet>
<description>登录后的主界面显示description>
<servlet-name>SystemServletservlet-name>
<servlet-class>com.ischoolbar.programmer.servlet.SystemServletservlet-class>
servlet>
<servlet-mapping>
<servlet-name>SystemServletservlet-name>
<url-pattern>/SystemServleturl-pattern>
servlet-mapping>
这样配置之后,我们登录成功之后,浏览器会给我们响应,并且打印出“hello”于浏览器页面中。
完成了Servlet和xml,接下来就可以创建对登录的拦截功能了。我们的需求是,用户在登录失效的情况下,重新定向到登录页面,登录之后再继续对系统进行操作。
我们新建一个package,取名为filter,再在此包下创建一个名为LoginFilter的java文件。
public class LoginFilter implements Filter {
@Override
public void destroy() {
// TODO Auto-generated method stub
}
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
// TODO Auto-generated method stub
HttpServletRequest request = (HttpServletRequest)req;
HttpServletResponse response = (HttpServletResponse)res;
Object user = request.getSession().getAttribute("user");
if(user == null){
//未登录
response.sendRedirect("index.jsp");
return;
}else{
chain.doFilter(request, response);
}
}
@Override
public void init(FilterConfig arg0) throws ServletException {
// TODO Auto-generated method stub
}
}
上面的程序中,显示对ServletRequest和ServletRequest进行强转。
在这里我的理解是:ServletRequest和HttpServletRequest ,ServletRequest和HttpServletResponse 都是接口。而后者又是前者的子接口,子接口中实现的方法是父接口所没有的,我们想要从Session中获取信息,父接口没有其实现的方法,只能向下转型使用子接口实现的方法。
另外,如果没有将用户信息从Session中拿出来,这说明用户是未登录的状态,就重新定向到了登录页面。
我们来验证一下:
从结果来看,过滤器已经发挥了作用。