Filter:简单来说就是设立在客户端和服务器之间的一个拦截关卡,当发现客户端请求的资源或者服务器响应给客户端的资源不规范(比如:敏感字符等)就会拦截该资源
还有一个作用就是:可以在拦截关卡这里存放一些权限控制在里面

注意1:这个实现的Filter是 javax.servlet包下的Filter
注意2:只要Filter的拦截路径是/* 那么客户端访问的路径资源或者服务器响应的资源 都是会先被拦截下来的,然后放不放行看代码

代码演示:
eg:当我们没有Filter拦截的时候我们开启服务器访问hello.jsp资源结果如下:(正常访问该资源)

eg:当我们开启Filter拦截不放行的时候我们开启服务器访问hello.jsp资源结果如下:(假设我们不放行 那么相当于客户端访问hello.jsp的请求就被我们拦截下来了而且我们不放行 那么也就是说获取不到资源了)
注意:不放行直接不用写代码即可 放行需要调用放行方法

开启服务器客户端访问hello.jsp资源:
会发现拿不到资源数据了,因为客户端的请求被拦截下来了

eg:当我们开启Filter拦截 放行的时候(也就是说拦截到了客户端的请求但是我们放行了)客户端能获取到相应的路径下资源:

开启服务器客户端访问hello.jsp资源:



用代码演示上图的执行流程:
hello.jsp:


访问hello.jsp的结果:如果输出 1 2 3 说明方形访问完资源后会回到Filter中执行放行后的代码逻辑



Filter的优先级:


代码演示过滤器链(看是否按着上面的第一步.第二步.....代码执行的):
FilterDemo (Filter1):

FilterDemo2 (Fiter2):

hello.jsp:
开启服务器访问hello.jsp看执行结果说明验证上图成功:


我们已经写过登录的界面:LoginServlet
- package com.itheima.web;
- import com.itheima.pojo.User;
- import com.itheima.service.UserService;
- import javax.servlet.ServletException;
- import javax.servlet.annotation.WebServlet;
- import javax.servlet.http.*;
- import java.io.IOException;
-
- @WebServlet("/loginServlet")
- public class LoginServlet extends HttpServlet {
- @Override
- protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
- // 1、接收客户端用户名和密码
- String username =request.getParameter("username");
- String password =request.getParameter("password");
-
- // 获取复选框数据
- String remember =request.getParameter("remember");
-
- // 2、调用service层进行查询
- UserService userService =new UserService();
- User user =userService.login(username,password);
-
- // 3、判断查询是否有结果
- if (user != null){
- // 判断user不为null说明登录成功了
-
- // 判断用户是否勾选了记住我 remember
- // 这里用:"1".equals(remember) 而不用remember.equals("1")
- // 是为了防止空指针异常 因为remember有可能用户没勾选 为null 然后比较的话会空指针
- if ("1".equals(remember)){
- // 勾选了,发送Cookie
-
- // 1 创建Cookie对象
- Cookie c_username =new Cookie("username",username);
- Cookie c_password =new Cookie("password",password);
- // 设置Cookie数据在客户端存活的时间
- c_username.setMaxAge(60*60*24*60);
- c_password.setMaxAge(60*60*24*60);
- // 2 发送Cookie
- response.addCookie(c_username);
- response.addCookie(c_password);
-
- }
-
- // 2. 把user查询出来的数据先封装到Session域当中 (数据保存在了服务器之间共享)
- HttpSession httpSession =request.getSession();
- // 存储到Session域中
- httpSession.setAttribute("user",user);
-
- // 1.登录成功 (要求:动态重定向到MVC三层架构讲的商品增删改查操作:SelectAllServlet资源下查询所有)
- String path =request.getContextPath();
- response.sendRedirect(path+"/selectAllServlet");
-
- } else {
- // 登录失败
- // 储存错误提示信息到request域当中 转发给login.jsp
- request.setAttribute("login_msg","用户名或密码错误");
- // 跳转到登录的login.jsp页面
- request.getRequestDispatcher("/login.jsp").forward(request,response);
- }
-
- }
- @Override
- protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
- this.doGet(request, response);
- }
- }
-
从代码中可以看出我们在判断user不为null的时候说明用户输入的账户和密码是正确的,登录成功的,那么此时我们又把用户输入的信息user储存到了Session域中
因此我们的拦截器只需要拿到Session域中的user数据判断user数据是否为null 、不为null说明用户登录的信息是正确的 那么我们就放行 让用户访问登录后的资源,如果为null 说明用户压根就输入的账户和密码不正确 那么我们就转发到登录的页面 (注意:第一次的时候拦截器里面拿到的user对象肯定为null,因为当客户端访问路径的时候会先进入拦截器路径下,此时的user对象还没有封装到Session域当中 )
拦截器:
客户端访问想要的资源路径的时候 拦截器路径为/* 所以会先进入拦截器中 因此这就说明了上面的红字问题
- package com.itheima.web.filter;
- import javax.servlet.*;
- import javax.servlet.annotation.*;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpSession;
- import java.io.IOException;
-
- /**
- * 登陆验证的过滤器
- */
-
- @WebFilter("/*")
- public class LoginFilter implements Filter {
-
- @Override
- public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
-
- // 1.判断Session中是否有user (LoginServlet登录中查询出来存储在Session域中的用户信息)
-
- HttpServletRequest req =(HttpServletRequest) request;
- // 注意:Session中的调用getSession()方法的request是HttpServletRequest包下的request所以需要把
- // Filter包下的request转换成HttpServletRequest包下的request
- HttpSession session =req.getSession();
- Object user =session.getAttribute("user");
-
- // 判断user是否为null
- if (user != null){
- // 不为null,说明用户登录过了
- // 放行
- chain.doFilter(request, response);
- }
- else {
- // 为null,说明用户未登录 (跳转到登录页面)
- request.setAttribute("login_msg","您尚未登陆!");
- request.getRequestDispatcher("/login.jsp").forward(req,response);
- }
- }
-
-
-
-
- public void init(FilterConfig config) throws ServletException {
- }
-
- public void destroy() {
- }
- }
当我们开启服务器客户端访问资源的时候:

因此我们需要修改代码,当客户端访问到是登录(注册)页面的时候,把关于登录(注册)页面中的资源(css、html等)展示给用户并且放行不被拦截:
- package com.itheima.web.filter;
- import javax.servlet.*;
- import javax.servlet.annotation.*;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpSession;
- import java.io.IOException;
-
- /**
- * 登陆验证的过滤器
- */
-
- @WebFilter("/*")
- public class LoginFilter implements Filter {
-
- @Override
- public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
- HttpServletRequest req =(HttpServletRequest) request;
- // 注意:Session中的调用getSession()方法的request是HttpServletRequest包下的request所以需要把
- // Filter包下的request转换成HttpServletRequest包下的request
-
- // !判断访问资源路径是否和登录注册有关
- String[] urls = {"/login.jsp","/register.jsp","/imgs/","/css/","/loginServlet","/registerServlet","/checkCodeServlet"};
- // ! 获取当前访问的资源路径
- String url =req.getRequestURL().toString(); // http://localhost:8089/brand-demo/register.jsp 类型
-
- // ! 判断
- for (String u:urls) { // 遍历urls数组里面地址
- if (url.contains(u)){ // 如果url包含遍历出来的u
-
- // 包含的话 说明用户访问的是登录或者注册相关的资源路径
- // 放行即可
- chain.doFilter(request, response);
- return;
-
- }
- }
- // (5个就依次判断就可以了 判断完发现不包含就继续往下执行代码了)
-
-
- // 1.判断Session中是否有user (LoginServlet登录中查询出来存储在Session域中的用户信息)
-
- HttpSession session =req.getSession();
- Object user =session.getAttribute("user");
-
- // 判断user是否为null
- if (user != null){
- // 不为null,说明用户登录过了
- // 放行
- chain.doFilter(request, response);
- }
- else {
- // 为null,说明用户未登录 (跳转到登录页面)
- request.setAttribute("login_msg","您尚未登陆!");
- request.getRequestDispatcher("/login.jsp").forward(req,response);
- }
- }
-
-
-
-
- public void init(FilterConfig config) throws ServletException {
- }
-
- public void destroy() {
- }
- }
特别注意的小细节:转发、重定向等,只要是跳转新的页面的,URL地址栏就会发现变化,那么拦截器就会当成是一次新的访问请求 然后给拦截下来了 最后决定放不放行
拦截器代码:
- package com.itheima.web.filter;
- import javax.servlet.*;
- import javax.servlet.annotation.*;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpSession;
- import java.io.IOException;
-
- /**
- * 登陆验证的过滤器
- */
-
- @WebFilter("/*")
- public class LoginFilter implements Filter {
-
- @Override
- public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
- HttpServletRequest req =(HttpServletRequest) request;
- // 注意:Session中的调用getSession()方法的request是HttpServletRequest包下的request所以需要把
- // Filter包下的request转换成HttpServletRequest包下的request
-
- // !判断访问资源路径是否和登录注册有关
- String[] urls = {"/login.jsp","/register.jsp","/imgs/","/css/","/loginServlet","/registerServlet","/checkCodeServlet"};
- // ! 获取当前访问的资源路径
- String url =req.getRequestURL().toString(); // http://localhost:8089/brand-demo/register.jsp 类型
-
- // ! 判断
- for (String u:urls) { // 遍历urls数组里面地址
- if (url.contains(u)){ // 如果url包含遍历出来的u
-
- // 包含的话 说明用户访问的是登录或者注册相关的资源路径
- // 放行即可
- chain.doFilter(request, response);
- return; // 结束代码了 下面的代码也不执行了
-
- }
- }
- // (5个就依次判断就可以了 判断完发现不包含就继续往下执行代码了)
-
-
- // 1.判断Session中是否有user (LoginServlet登录中查询出来存储在Session域中的用户信息)
-
- HttpSession session =req.getSession();
- Object user =session.getAttribute("user");
-
- // 判断user是否为null
- if (user != null){
- // 不为null,说明用户登录过了
- // 放行
- chain.doFilter(request, response);
- }
- else {
- // 为null,说明用户未登录 (跳转到登录页面)
- request.setAttribute("login_msg","您尚未登陆!");
- request.getRequestDispatcher("/login.jsp").forward(req,response);
- }
- }
-
-
-
-
- public void init(FilterConfig config) throws ServletException {
- }
-
- public void destroy() {
- }
- }
假设我们开启服务器后访问的是login.jsp路径下的资源:

我们从拦截器的urls数组里面可以看到,我们放行了login.jsp 并且点击登录后进入的是loginServlet路径下的资源 我们也放行了,
这里有一个细节:就是我们放行进入loginServlet路径资源下后看代码:
(我们把用户登录的信息封装成user对象封装到了Session域当中了,此时登录成功的话我们是重定向到selectAllServlet路径下的,注意:重定向的时候我们的URL地址栏就会发现变化,相当于重新访问了,那么就再次会被拦截器当成新的客户端请求拦截请求数据,然后决定放不放行,我们通过循环判断发现selectAllServlet不是我们所包含的对象,那么就会循环完后进入下面的代码判断user是否为null,注意:就是因为我们刚才登录的时候在loginServlet路径下已经把user对象封装在Session域当中了 所以这时候user不为null了 ,我们的代码是放行的, 因此我们就能查看到所有商品的数据了,再在selectAllServlet路径资源下再转发、重定向等新的URL地址时也会放行了,因为user已经有数据了)
- package com.itheima.web;
- import com.itheima.pojo.User;
- import com.itheima.service.UserService;
- import javax.servlet.ServletException;
- import javax.servlet.annotation.WebServlet;
- import javax.servlet.http.*;
- import java.io.IOException;
-
- @WebServlet("/loginServlet")
- public class LoginServlet extends HttpServlet {
- @Override
- protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
- // 1、接收客户端用户名和密码
- String username =request.getParameter("username");
- String password =request.getParameter("password");
-
- // 获取复选框数据
- String remember =request.getParameter("remember");
-
- // 2、调用service层进行查询
- UserService userService =new UserService();
- User user =userService.login(username,password);
-
- // 3、判断查询是否有结果
- if (user != null){
- // 判断user不为null说明登录成功了
-
- // 判断用户是否勾选了记住我 remember
- // 这里用:"1".equals(remember) 而不用remember.equals("1")
- // 是为了防止空指针异常 因为remember有可能用户没勾选 为null 然后比较的话会空指针
- if ("1".equals(remember)){
- // 勾选了,发送Cookie
-
- // 1 创建Cookie对象
- Cookie c_username =new Cookie("username",username);
- Cookie c_password =new Cookie("password",password);
- // 设置Cookie数据在客户端存活的时间
- c_username.setMaxAge(60*60*24*60);
- c_password.setMaxAge(60*60*24*60);
- // 2 发送Cookie
- response.addCookie(c_username);
- response.addCookie(c_password);
-
- }
-
- // 2. 把user查询出来的数据先封装到Session域当中 (数据保存在了服务器之间共享)
- HttpSession httpSession =request.getSession();
- // 存储到Session域中
- httpSession.setAttribute("user",user);
-
- // 1.登录成功 (要求:动态重定向到MVC三层架构讲的商品增删改查操作:SelectAllServlet资源下查询所有)
- String path =request.getContextPath();
- response.sendRedirect(path+"/selectAllServlet");
-
- } else {
- // 登录失败
- // 储存错误提示信息到request域当中 转发给login.jsp
- request.setAttribute("login_msg","用户名或密码错误");
- // 跳转到登录的login.jsp页面
- request.getRequestDispatcher("/login.jsp").forward(request,response);
- }
-
- }
- @Override
- protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
- this.doGet(request, response);
- }
- }
-
login.jsp:
- <%@ page contentType="text/html;charset=UTF-8" isELIgnored="false" language="java" %>
- <!DOCTYPE html>
- <html lang="en">
-
- <head>
- <meta charset="UTF-8">
- <title>login</title>
- <link href="css/login.css" rel="stylesheet">
- </head>
- <body>
- <div id="loginDiv" style="height: 350px">
- <form action="/brand-demo/loginServlet" id="form">
- <h1 id="loginMsg">LOGIN IN</h1>
- <div id="errorMsg">${login_msg} ${register_msg}</div>
- <%--
- ${login_msg} 就是我们在LoginServlet资源下登录失败后转发到login页面把
- 登录页面展示给用户,并且把转发时储存到request域当中的数据(用户名或密码错误)拿
- 到展示在登录页面上 ${login_msg}:EL表达式 拿储存在域中数据的
-
- ${register_msg} 拿到的是RegisterServlet资源下封装到request域当中的数据通过转发过来
- (注册成功,请登录)展示在登录的页面上
- --%>
-
-
- <p>Username:<input id="username" name="username" value="${cookie.username.value}" type="text"></p>
-
- <p>Password:<input id="password" name="password" value="${cookie.password.value}" type="password"></p>
-
-
- <%-- value 的作用就是在复选框中,假设选中了该复选框那么该复选框的值也就是该value的值
- 这里remember是复选框 当我们勾选后 该默认值为“1”
- --%>
- <p>Remember:<input id="remember" name="remember" value="1" type="checkbox"></p>
- <div id="subDiv">
- <input type="submit" class="button" value="login up">
- <input type="reset" class="button" value="reset">
- <a href="register.jsp">没有账号?</a>
- </div>
- </form>
- </div>
-
-
- </body>
-
- </html>

