JAVA框架——SpringMVC总结(二)拦截器与过滤器的区别,静态资源的访问问题,请求重定向和转发,异常处理以及拦截器,拦截器与过滤器的区别

一、访问静态资源问题

1、*.do

在没有特殊要求的情况下,SpringMVC 的中央调度器 DispatcherServlet 的
常使用后辍匹配方式,如写为*.do 或者 *.action, *.mvc 等。

2、 /

可以写为/,因为 DispatcherServlet 会将向静态资源的获取请求,例如.css、.js、.jpg、.png等资源的获取请求,当作是一个普通的 Controller 请求。中央调度器会调用处理器映射器为其查找相应的处理器。当然也是找不到的,所以在这种情况下,所有的静态资源获取请求也均会报 404 错误。

tomcat本身能处理静态资源的访问, 像html, 图片, js文件都是静态资源

tomcat的web.xml文件有一个servlet 名称是 default , 在服务器启动时创建的。

 <servlet>
        <servlet-name>default</servlet-name>
        <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
        <init-param>
            <param-name>debug</param-name>
            <param-value>0</param-value>
        </init-param>
        <init-param>
            <param-name>listings</param-name>
            <param-value>false</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>

	  <servlet-mapping>
        <servlet-name>default</servlet-name>
        <url-pattern>/</url-pattern>  表示静态资源和未映射的请求都这个default处理
    </servlet-mapping>

default这个servlet作用:
1.处理静态资源
2.处理未映射到其它servlet的请求。

所以我们在webxml文件中配置url-pattern的值为“/”会拦截所有的静态资源。包括jsp,html,js等但是我们的动态资源就是控制器类是可以访问的

<servlet>
    <servlet-name>springmvc</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <!--自定义springmvc读取的配置文件的位置-->
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <!--指定自定义文件的位置-->
        <param-value>classpath:springmvc.xml</param-value>
    </init-param>
    <!--在tomcat启动就会创建Servlet对象-->
    <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>springmvc</servlet-name>
    <!--
        使用框架的时候,url-pattern可以使用两种值
            1.使用扩展名方式,语法: *.xxxx,xxxx是自定义的扩展名,常用方式 *.do  | *.action  | *.mvc等
            2.使用斜杠"/"
            当项目中使用了 / 他会替代tomcat中的default
    -->
    <url-pattern>/</url-pattern>
</servlet-mapping>

3、方式一:使用<mvc:default-servlet-handler/>

因为我们在web.xml中设置了"/"。所以我们静态图片,资源都是无法访问的。
所以我们在application.xml中去设置该注解

  • 声明 了 <mvc:default-servlet-handler /> 后 , springmvc 框 架 会 在 容 器 中 创 建
    DefaultServletHttpRequestHandler 处理器对象。

  • 它会像一个检查员,对进入 DispatcherServlet的 URL 进行筛查,如果发现是静态资源的请求,就将该请求转由 Web 应用服务器默认的Servlet 处理。

  • 一般的服务器都有默认的 Servlet。在 Tomcat 中,有一个专门用于处理静态资源访问的 Servlet 名叫 DefaultServlet。其<servlet-name/>为 default。可以处理各种静态资源访问请求。该 Servlet 注册在 Tomcat 服务器的 web.xml 中。在 Tomcat 安装目录/conf/web.xml。

处理方式:只需要在 springmvc.xml 中添加<mvc:default-servlet-handler/>标签即可
<mvc:default-servlet-handler/>表示使用 DefaultServletHttpRequestHandler 处理器对象。
而该处理器调用了 Tomcat 的 DefaultServlet 来处理静态资源的访问请求。

4、方式二:使用<mvc:resources/>

在 Spring3.0 版本后,Spring 定义了专门用于处理静态资源访问请求的处理器
ResourceHttpRequestHandler。并且添加了<mvc:resources/>标签,专门用于解决静态资源无法访问问题。需要在 springmvc 配置文件中添加如下形式的配置:

 <mvc:resources mapping="/images/" location="/images/**"/>
  • location 表示静态资源所在目录。当然,目录不要使用/WEB-INF/及其子目录。

  • mapping 表 示 对 该 资 源 的 请 求 ( 以 /images/ 开 始 的 请 求 , 如 /image/beauty.jpg ,/images/car.png 等)。注意,后面是两个星号**。

常见开发中,会进行如下配置:

 <mvc:resources mapping="/static/" location="/static/**"/>

5. 方式三:声明注解驱动

解决动态资源和静态资源冲突的问题,在 springmvc 配置文件加入:

 <!--加入注解驱动-->
    <mvc:annotation-driven/>

二、请求重定向与转发

1.请求转发

处理器方法返回 ModelAndView 时,需在 setViewName()指定的视图前添加 forward:且此时的视图不再与视图解析器一同工作,这样可以在配置了解析器时指定不同位置的视图

视图页面必须写出相对于项目根的路径。forward 操作不需要视图解析器。

处理器方法返回 String,在视图路径前面加入 forward: 视图完整路径

@RequestMapping( value = "/doForward.do" )
    public ModelAndView doForward(){

        ModelAndView modelAndView = new ModelAndView();

        //显示转发,明显的说明 这是一个转发
        //modelAndView.setViewName("forward:/WEB-INF/show.jsp");
        modelAndView.setViewName("forward:/hello.jsp");
        return  modelAndView;
    }

注意此处,我们如果想要脱离视图解析器,可以使用该方法,跳出规则限制。想转发到哪个页面就哪个页面, 也称为显示转发,明显的说明这是一个转发

2.请求重定向

在处理器方法返回的视图字符串的前面添加 redirect:,则可实现重定向跳转。

/*
     * 处理器方法返回ModelAndView,实现转发forword
     * 语法:setViewName("redirect:视图文件完整路径")
     * redirect特点:不和视图解析器一同使用,就当项目中没有视图解析器
     *
     * */
    @RequestMapping( value = "/doRedirect.do" )
    public ModelAndView doRedirect(){

        ModelAndView modelAndView = new ModelAndView();

        modelAndView.setViewName("redirect:/hello.jsp");

        return  modelAndView;
    }

此时我们通过表单请求去重定向页面

<h1>返回ModelAndView实现redirect</h1>
<form action="doRedirect.do" method="post">
    姓名:<input type="text" name="name"><br/>
    年龄:<input type="text" name="age"><br/>
    <input type="submit" value="提交参数">
</form>

此时我们并不能用EL从中获取到数据,而是变成了GET请求方式
在这里插入图片描述 注意

  • 框架对重定向的操作是框架会把Model的简单类型的数据,转为String使用,作为show.jsp的get请求参数使用。目的是在doRedirect.do和show.jsp两次请求之间传递数据
  • 该处不能进行直接访问,因为我们重定向不能访问WEB-INF下面的路径文件

如果我们想要获取该数据,我们可以使用param可以获取到域中的参数

body>
    <h1>WEB-INF/view/show.jsp</h1>
    <h3>myname数据:${param.myname}</h3>
    <h3>myage数据:${param.myage}</h3>
</body>

三、异常处理

  • SpringMVC框架采用的是统一,全局的异常处理。把Controller中的所有异常处理都几种到一个地方。采用aop的思想。把业务逻辑和异常处理代码分开,解耦合。

  • 使用两个注解@ExceptionHandler@ControllerAdvice

1.异常处理步骤:

  • 1.新建maven web项目

  • 2.加入依赖

  • 3.新建一个自定义异常类 MyUserException , 再定义它的子类NameException ,AgeException

  • 4.在controller抛出NameException , AgeException

  • 5.创建一个普通类,作用全局异常处理类

    • 在类的上面加入@ControllerAdvice
    • 在类中定义方法,方法的上面加入@ExceptionHandler
  • 6.创建处理异常的视图页面

  • 7.创建springmvc的配置文件

    • 1)组件扫描器 ,扫描@Controller注解
    • 2)组件扫描器,扫描@ControllerAdvice所在的包名
    • 3)声明注解驱动

2.代码实现

书写一个index页面

<h1>全局异常处理</h1>
<form action="some.do" method="post">
    姓名:<input type="text" name="name"><br/>
    年龄:<input type="text" name="age"><br/>
    <input type="submit" value="提交参数">
</form>

书写三个异常类,用于处理姓名和年龄异常

//用户异常
public class MyUserExpection extends Exception{
    public MyUserExpection() {
        super();
    }

    public MyUserExpection(String message) {
        super(message);
    }
}

//姓名异常
public class NameExpection extends MyUserExpection {
    public NameExpection() {
        super();
    }

    public NameExpection(String message) {
        super(message);
    }
}
//年龄异常
public class AgeExpection extends MyUserExpection {
    public AgeExpection() {
        super();
    }

    public AgeExpection(String message) {
        super(message);
    }
}

控制器类

 @RequestMapping( value = "/some.do" )
    public ModelAndView doSome(String name,Integer age) throws MyUserExpection {
        ModelAndView modelAndView = new ModelAndView();
        if (!"zs".equals(name)) {
            throw  new NameExpection("姓名不正确");
        }
        if (age == null || age >80) {
            throw  new AgeExpection("年龄较大");
        }
        modelAndView.addObject("myname",name);
        modelAndView.addObject("myage",age);
        modelAndView.setViewName("show");
        return  modelAndView;
    }

xml中配置注解扫描器

<!--处理异常-->
<context:component-scan base-package="com.aiit.hander"/>
<mvc:annotation-driven/>

总异常处理类

 异常发生处理逻辑
  1.需要把异常记录下来,记录到数据库,日志文件
      记录日志发生的时间,哪个方法发生的,异常错误内容
   2.发送通知,把异常的信息通过邮箱,短信,微信发送给相关人员
   3.给用户有友好的提示

注意使用两个注解即可@ControllerAdvice@ExceptionHandler

/*
* @ControllerAdvice 控制器增强(给控制器去增加功能——异常处理功能)
*       位置:在类的上面
*   特点:必须让框架知道这个注解所在的包名,需要在springmvc配置文件声明组件扫描器
*   指定@ControllerAdvice所在的包名
* */
@ControllerAdvice
public class GlobalExceptionHandler {
    //定义方法,处理发生的异常
    /*
    *  处理异常的方法和控制器方法的定义一样,可以有多个参数,可以有ModelAndView,
    *   String ,void ,对象类型的返回值
    * 
    *   形参:Expection。表示Controller中抛出的异常对象
    *   通过形参可以获取发生的异常信息
    *
    *   @ExceptionHandler(异常Class):表示异常的类型,当发生此类型异常时,
    *   由当前方法处理
    * */
    @ExceptionHandler( value = NameExpection.class)
    public ModelAndView doNameException(Exception exe){
        //处理NameException的异常
        /*
        * 异常发生处理逻辑
        *   1.需要把异常记录下来,记录到数据库,日志文件
        *       记录日志发生的时间,哪个方法发生的,异常错误内容
        *   2.发送通知,把异常的信息通过邮箱,短信,微信发送给相关人员
        *   3.给用户有友好的提示
        * */
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.addObject("msg","姓名必须是zs,其他用户不能访问");
        modelAndView.addObject("exe",exe);
        modelAndView.setViewName("nameError");
        return modelAndView;
    }

    @ExceptionHandler( value = AgeExpection.class)
    public ModelAndView doAgeException(Exception exe){
       
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.addObject("msg","年龄不能过大");
        modelAndView.addObject("exe",exe);
        modelAndView.setViewName("ageError");
        return modelAndView;
    }

    //处理其他异常,NameException,AgeException以外,不知的类型异常
    @ExceptionHandler
    public ModelAndView doOtherException(Exception exe){
        //处理其他异常
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.addObject("msg","年龄不能过大");
        modelAndView.addObject("exe",exe);
        modelAndView.setViewName("defaultError");
        return modelAndView;
    }
}

四、拦截器

1.拦截器概述

  • 它的主要作用是拦截指定的用户请求,并进行相应的预处理与后处理。

  • 拦截器是springmvc中的一种,需要实现HandlerInterceptor接口。

  • 过滤器是用来过滤器请求参数,设置编码字符集等工作

  • 拦截器是拦截用户的请求,做请求做判断处理的。

  • 拦截器是全局的,可以对多个Controller做拦截。
    一个项目中可以有0个或多个拦截器, 他们在一起拦截用户的请求。
    拦截器常用在:用户登录处理,权限检查, 记录日志。

2.拦截器使用步骤

  • 定义类实现HandlerInterceptor接口

  • 在springmvc配置文件中,声明拦截器, 让框架知道拦截器的存在

3.创建一个拦截器

//拦截器类:拦截用户的请求。
public class MyInterceptor implements HandlerInterceptor {


    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("拦截器的MyInterceptor的preHandle()");
        //计算的业务逻辑,根据计算结果,返回true或者false
        //给浏览器一个返回结果
        return true;
    }

  
    @Override
    public void postHandle(HttpServletRequest request,
                           HttpServletResponse response,
                           Object handler, ModelAndView mv) throws Exception {
        System.out.println("拦截器的MyInterceptor的postHandle()");


    }

    
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
                                Object handler, Exception ex) throws Exception {
        System.out.println("拦截器的MyInterceptor的afterCompletion()");

    }
}

方法简介

1、preHandle:预处理方法

  • 是整个项目的入口,门户。 当preHandle返回true 请求可以被处理。

  • 参数

    • Object handler : 被拦截的控制器对象
    • 返回值boolean
    1.  true:请求是通过了拦截器的验证,可以执行处理器方法。
          拦截器的MyInterceptor的preHandle()
           =====执行MyController中的doSome方法=====
           拦截器的MyInterceptor的postHandle()
           拦截器的MyInterceptor的afterCompletion()
    
      
      2. false:请求没有通过拦截器的验证,请求到达拦截器就截止了。 请求没有被处理
         拦截器的MyInterceptor的preHandle()
    
  • 特点

     1.方法在控制器方法(MyController的doSome)之前先执行的。
       用户的请求首先到达此方法
    
     2.在这个 方法中可以获取请求的信息, 验证请求是否符合要求。
       可以验证用户是否登录, 验证用户是否有权限访问某个连接地址(url)。
        如果验证失败,可以截断请求,请求不能被处理。
        如果验证成功,可以放行请求,此时控制器方法才能执行。
    

2、postHandle:后处理方法。

  • 参数
    Object handler:被拦截的处理器对象MyController
    ModelAndView mv:处理器方法的返回值

  • 特点

      1.在处理器方法之后执行的(MyController.doSome())
      
      2.能够获取到处理器方法的返回值ModelAndView,可以修改ModelAndView中的
      数据和视图,可以影响到最后的执行结果。
      
      3.主要是对原来的执行结果做二次修正,
    
      ModelAndView mv = MyController.doSome();
      postHandle(request,response,handler,mv);
    

3、afterCompletion:最后执行的方法

  • 参数
    Object handler:被拦截器的处理器对象
    Exception ex:程序中发生的异常

  • 特点:

     1.在请求处理完成后执行的。框架中规定是当你的视图处理完成后,对视图执行了forward。就认为请求处理完成。
     
     2.一般做资源回收工作的, 程序请求过程中创建了一些对象,在这里可以删除,把占用的内存回收。
    

4.拦截器执行顺序

在这里插入图片描述

5.执行多个拦截器

我们只需要多写一个拦截器类即可。并且在Spring.xml中声明多个拦截器即可

 <mvc:interceptors>
        <!--声明第一个拦截器-->
        <mvc:interceptor>
            <!--用来指定拦截的请求uri地址
                path:就是uri地址,可以使用通配符
                **表示任意字符,文件或者多级目录和目录中的文件
                如/user/**
                /**表示拦截所有
            -->
            <mvc:mapping path="/**"/>
            <!--声明拦截器对象-->
            <bean class="com.aiit.handler.MyInterceptor"/>
        </mvc:interceptor>
        <!--声明第二个拦截器-->
        <mvc:interceptor>
            <mvc:mapping path="/**"/>
            <bean class="com.aiit.handler.MyInterceptor2"/>
        </mvc:interceptor>
    </mvc:interceptors>

注意:

  • 声明拦截器,拦截器可以有0或多个
  • 在框架中保存多个拦截器是ArrayList。
  • 按照声明的先后顺序放入到ArrayList中

输出结果:
在这里插入图片描述
类似于栈的执行顺序,先进后出的概念

6.拦截器的执行链

两个拦截器中

第一个preHandle返回值为true,第二个preHandle返回值为false
在这里插入图片描述第一个preHandle返回值为false,第二个preHandle返回值为true
在这里插入图片描述

结论:不论是哪个拦截器,只要有一个拦截器的preHandle的一个返回值为false那么均不会执行控制器中的方法,我们只要在不同的拦截器中进行不同的功能即可,均正确才能返回我们的控制器类

五、过滤器和拦截器的区别

  • 过滤器是servlet中的对象, 拦截器是框架中的对象

  • 过滤器实现Filter接口的对象, 拦截器是实现HandlerInterceptor

  • 过滤器是用来设置request,response的参数,属性的,侧重对数据过滤的。

  • 拦截器是用来验证请求的,能截断请求。

  • 过滤器是在拦截器之前先执行的

  • 过滤器是tomcat服务器创建的对象

  • 拦截器是springmvc容器中创建的对象

  • 过滤器是一个执行时间点

  • 拦截器有三个执行时间点

  • 过滤器可以处理jsp,js,html等等

  • 拦截器是侧重拦截对Controller的对象。 如果你的请求不能被DispatcherServlet接收, 这个请求不会执行拦截器内容

  • 拦截器拦截普通类方法执行,过滤器过滤servlet请求响应

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值