SpringMVC拦截器 和servlet过滤器 的使用

servlet过滤器

1.什么是过滤器

过滤器实际上就是对web资源进⾏拦截,做⼀些处理后再交给下⼀个过滤器或servlet处理,通常都 是⽤来拦截request进⾏处理的,也可以对返回的response进⾏拦截处理,可以同时设置多个过滤器。过滤器依赖于servlet,一个过滤器可以加在多个servlet上,(多个过滤器也可以加在一个servlet上)

2.过滤器的语法格式

实现Javax.serlvet.Filter接口,重写里面的方法(对应servlet-api.jar)

package util;


import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class FirstFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("初始化filter");//当服务器启动时执行init
    }

    @Override   //请求和响应时都会执行这个方法
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("过滤器开始");

        //调取下一个过滤器,或者调取servlet
        filterChain.doFilter(servletRequest, servletResponse);
        System.out.println("过滤器结束");

    }

    @Override
    public void destroy() {
        System.out.println("销毁filter");
    }
}

3.在web.xml⽂件中配置

<filter>
 <filter-name>过滤器名称</filter-name>
 <filter-class>过滤器所在的路径</filter-class>
 </filter>
 <filter-mapping>
 <filter-name>过滤器名称</filter-name>
 <url-pattern>需要过滤的资源</url-pattern>
 </filter-mapping>

示例:

  <filter>
        <filter-name>f1</filter-name>
        <filter-class>
            util.FirstFilter
        </filter-class>
    </filter>
    <filter-mapping>
        <filter-name>f1</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

4.使⽤场景

1.如何防⽌⽤户未登录就执⾏后续操作

String name=(String)session.getAttribute("key");

if(name==null){ //跳转到登录⻚⾯ }

.2.设置编码⽅式--统⼀设置编码

3.加密解密(密码的加密和解密)

4.⾮法⽂字筛选

5.下载资源的限制 过滤器的特点:在servlet之前和之后都会被执⾏

5.过滤器中的url-pattern中的 / 和 /*  和/login

 <filter-mapping>
        <filter-name>testFilter1</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

会过滤所有请求,包括对静态资源的访问,都会进入过滤器。

会匹配所有的url:路径型的和后缀型的url(包括/springmvc,.jsp,.js和*.html等)。 这种形式将会覆盖所有其它的servlet。不管你发出了什么样的请求,最终都会在这个servlet中结束。因此,对于servlet来说,这是一个很糟糕的URL模式。通常来讲,你只会想要在一个Filter中使用这种模式。

<filter-mapping>
        <filter-name>testFilter1</filter-name>
        <url-pattern>/</url-pattern>
    </filter-mapping>

会匹配到/springmvc这样的路径型url,不会匹配到模式为*.jsp这样的后缀型url。

这时如果有静态资源的访问,要再处理对静态资源的访问不到的问题。 

<filter-mapping>
        <filter-name>testFilter2</filter-name>
        <url-pattern>/login</url-pattern>
    </filter-mapping>

只会过滤/login访问路径

例子:验证用户登录

过滤器

package util;


import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class FirstFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("初始化filter");//当服务器启动时执行init
    }

    @Override   //请求和响应时都会执行这个方法
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("过滤器开始");
        //处理乱码
        HttpServletRequest request=(HttpServletRequest)servletRequest;
        HttpServletResponse response=(HttpServletResponse)servletResponse;
        request.setCharacterEncoding("utf-8");

        //防止用户在未登录的情况下访问资源
        String requestURI = request.getRequestURI();//获得请求地址
        System.out.println("requestURI="+requestURI);
        Object username = request.getSession().getAttribute("username");

        if(requestURI.endsWith("testsession.jsp")&&username==null){
            response.sendRedirect("index.jsp");
        }

        //调取下一个过滤器,或者调取servlet
        filterChain.doFilter(servletRequest, servletResponse);
        System.out.println("过滤器结束");

    }

    @Override
    public void destroy() {
        System.out.println("销毁filter");
    }
}

后端

package servlet;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;
import java.io.IOException;

@WebServlet(urlPatterns = "/login")
public class LoginServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
       resp.sendRedirect("error.jsp");
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("login-servlet被执行");
        //1.接收参数
        String username = req.getParameter("username");
        String pass = req.getParameter("pass");
        //2.判断正误
        if("admin".equals(username)&&"123456".equals(pass)){
            //登录成功
            //session存值
            HttpSession session = req.getSession();
            session.setAttribute("username",username);
            session.setAttribute("password",pass);
            session.setMaxInactiveInterval(60*30);//单位是秒
            //重定向或者转发时,session数据是不会丢失的,重定向时,request中的数据会丢失
            resp.sendRedirect("success.jsp");
        }else{
            //登录失败
            //1.后台创建cookie
            Cookie cookie = new Cookie("uname",username);
            //2.返回给前端
            resp.addCookie(cookie);
            resp.sendRedirect("index.jsp");
        }
    }
}

前端


<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head>
    <title>$Title$</title>
  </head>
  <body>
<!--需要导入 jstl-jar-->
  <%
    Cookie[] cookies = request.getCookies();
    String value ="";
    if(cookies!=null&&cookies.length>0){
      for (Cookie cookie : cookies) {
        if(cookie.getName().equals("uname")){
          value = cookie.getValue();
          break;
        }
      }
    }
    pageContext.setAttribute("unamecookie",value);

  %>

  <h1>登录</h1>
  <form action="login" method="post">
    用户名:<input type="text" name="username" value="${unamecookie}" ><br>
    密码:<input type="password" name="pass"><br>
    <input type="submit" value="login">

  </form>
  </body>
</html>

SpringMVC 中的 拦截器

1.概念


java中的拦截器是动态拦截action调用的对象。依赖于web框架,在springmvc中依赖于SpringMVC框架,在实现上基于Java的反射机制,属于AOP的一种应用,作用类似于过滤器,但是拦截器只能对Controller请求进行拦截,对其他的直接访问静态资源的请求无法拦截处理。
 

拦截器( Interceptor)是非常重要的,它的主要作用是拦截指定的用户请求,并进行 相应的预处理与后处理。

2.拦截时间

拦截的时间点在“处理器映射器HandlerMapping根据用户提交的请求映射出了所要执行的处理器类,并 且也找到了要执行该处理器类的处理器适配器,在处理器适配器HandlerAdaptor执行处理器之前”。

在处理器映射器映射出所要执行的处理器类时,已经将拦截器与处理器组合为了一个处理器执行链 HandlerExecutionChain,并返回给了前端控制器。

3.实现拦截器

自定义拦截器,需要实现 HandlerInterceptor 接口。而该接口中含有三个方法:

public interface HandlerInterceptor {


default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {

		return true;
	}
default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
			@Nullable ModelAndView modelAndView) throws Exception {
	}
default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
			@Nullable Exception ex) throws Exception {
	}

}

4.拦截器方法说明

preHandle(request,response, Object handler):

该方法在处理器方法执行之前执行。其返回值为boolean,若为true,则紧接着会执行处理器方法,且 会将afterCompletion()方法放入到一个专门的方法栈中等待执行。 postHandle(request,response, Object handler,modelAndView):

该方法在处理器方法执行之后执行。处理器方法若最终未被执行,则该方法不会执行。由于该方法是在处 理器方法执行完后执行,且该方法参数中包含 ModelAndView,所以该方法可以修改处理器方法的处理结果 数据,且可以修改跳转方向。

afterCompletion(request,response, Object handler, Exception ex): 当 preHandle()方法返回true时,会将该方法放到专门的方法栈中,等到对请求进行响应的所工作完 成之后才执行该方法。即该方法是在前端控制器渲染(数据填充)了响应页面之后执行的,此时对 ModelAndView再操作也对响应无济于事。

afterCompletion最后执行的方法,清除资源,例如在Controller方法中加入数据

5.方法使用场景

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class MyInterceptor implements HandlerInterceptor {

    //执行时间: 控制器方法执行之前,在ModelAndView返回之前
    //使用场景: 登录验证
    // 返回值 true : 继续执行控制器方法 表示放行    false: 不会继续执行控制器方法,表示拦截
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("preHandle-------------------");
        return true;
    }

    //执行时间: 控制器方法执行之hou后,在ModelAndView返回之前,有机会修改返回值
    //使用场景: 日记记录,记录登录的ip,时间
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("postHandle-------------------");
    }

    //执行时间: 控制器方法执行之后,在ModelAndView返回之后,没有机会修改返回值
    //使用场景: 全局资源的一些操作
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("afterCompletion-------------------");
    }

6.设置多个拦截器所执行的顺序

(默认对三种方法都实现 )

preHandle1->  preHandle2  ->postHande2  ->perHande2 ->afterCompletion2 ->afterCompletion1

测试

上传的文件是否符合定义的格式,不符合的进行拦截

环境搭建      

1.需要在maven 的pom.xml中引入 的依赖和 插件  

<!--spring-webmvc依赖-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.2.13.RELEASE</version>
        </dependency>
        <!--springmvc底层还是servlet,所以必须添加serlvet依赖-->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>4.0.1</version>
            <scope>provided</scope><!--插件运行的时候没有范围插件启动会失败-->
        </dependency>

<build>
        <plugins>
            <!-- 编码和编译和JDK版本 -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.0</version>
                <configuration>
                    <target>1.8</target>
                    <source>1.8</source>
                </configuration>
            </plugin>
            <!--tomcat插件-->
            <plugin>
                <groupId>org.apache.tomcat.maven</groupId>
                <artifactId>tomcat7-maven-plugin</artifactId>
                <version>2.2</version>
                <configuration>
                    <path>/</path>
                    <port>8080</port>
                </configuration>
            </plugin>
        </plugins>
    </build>

2.springMVC 的xml文件中拦截路径的配置  

拦截关键字路径

当使用/user/xxx拦截时候

这时又多了一个需求就是拦截   /user/manager/xxxx

如何对含有关键字manger路径进行拦截

manger前面如果只有一层路径  使用/*/manger/**    例如  user/manger/xxxx

manger前面含义多层路径  使用    /**/manger/**      此时前面如果没有  路径 由于/**资源通配符的作用,过滤也起作用

  <!--springmvc的配置文件:控制器的bean对象都在这里扫描-->
    <context:component-scan base-package="com.kkb.controller"/>


 <!--配置拦截器-->
    <mvc:interceptors>
        <!--按顺序配置多个拦截器-->
        <mvc:interceptor>
            <mvc:mapping path="/**"/>
            <bean class="com.kkb.interceptor.MyInterceptor" id="myInterceptor"></bean>
        </mvc:interceptor>

        <mvc:interceptor>
            <mvc:mapping path="/**"/>
            <bean class="com.kkb.interceptor.FileInterceptor" id="fileInterceptor"></bean>
        </mvc:interceptor>
    </mvc:interceptors>

如何放行特定的请求路径 

使用<mvc:exclude-mapping path="请求路径"/>

 <mvc:interceptors>
        <!-- 配置登陆拦截器 -->
        <mvc:interceptor>
            <mvc:mapping path="/**"/>
            <!-- 但是排除下面这些,也就是不拦截请求 -->
            <mvc:exclude-mapping path="/login/verify"/>
            <mvc:exclude-mapping path="/register"/>
            <mvc:exclude-mapping path="/index"/>
           <!--admin请求的一级action以login开始的不进行拦截 -->
            <mvc:exclude-mapping path="/amdin/login*"/>
          <!--test请求的一级action不进行拦截 -->
            <mvc:exclude-mapping path="/test/*"/>
            <!-- ajax请求的action不进行拦截 -->
            <mvc:exclude-mapping path="/*.ajax"/>
            <bean class="com.alan.activiti.inteceptor.LoginInteceptor"></bean>
        </mvc:interceptor>
    </mvc:interceptors>

3.实现类

package com.kkb.interceptor;

import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Iterator;
import java.util.Map
public class FileInterceptor implements HandlerInterceptor {
    /**
     * 在文件上传之前判断文件后缀是否合法
     * @param request
     * @param response
     * @param handler
     * @return
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //判断是否是文件上传的请求
        boolean flag=true;
        if(request instanceof MultipartHttpServletRequest){
            //单一上传文件  method="post" enctype="multipart/form-data"
            MultipartHttpServletRequest multipartRequest= (MultipartHttpServletRequest) request;
            Map<String, MultipartFile> fileMap = multipartRequest.getFileMap();
            //遍历文件
               //通过entrySet
//            Set<Map.Entry<String, MultipartFile>> entries = fileMap.entrySet();
//            for (Map.Entry<String, MultipartFile> entry : entries) {
//                System.out.println("key:"+entry.getKey()+" "
//                        +"value:"+entry.getValue());
//            }
            Iterator<String> iterator = fileMap.keySet().iterator();
            while(iterator.hasNext()){
                String key = iterator.next();
                MultipartFile file = multipartRequest.getFile(key);
                String originalFilename = file.getOriginalFilename();
                String hz = originalFilename.substring(originalFilename.lastIndexOf("."));
                //判断后缀是否合法
                if(!hz.toLowerCase().equals(".png") && !hz.toLowerCase().equals(".jpg")){
                    request.getRequestDispatcher("/jsp/fileTypError.jsp").forward(request,response);
                    flag=false;
                }
            }
        }
        return flag;
    }

拦截器实现验证登录

1.aa 

2.bb

过滤器和拦截器的区别:

1 、拦截器是基于java的反射机制的,而过滤器是基于函数回调。

2 、拦截器不依赖与servlet容器,过滤器依赖与servlet容器。

3 、拦截器只能对action请求起作用,而过滤器则可以对几乎所有的请求起作用。

4 、拦截器可以访问action上下文、值栈里的对象,而过滤器不能访问。

5 、在action的生命周期中,拦截器可以多次被调用,而过滤器只能在容器初始化时被调用一次。

参考:java中过滤器和拦截器的区别

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值