Spring MVC (二)

1. 文件上传

  • Spring MVC为文件上传提供了直接的支持,这种支持是通过MultipartResovler实现的。Spring用Jakarta Commons Fileupload技术实现一个MultipartResovler实现类:CommonsMultipartResolver

  • Spring MVC上下文中默认没有装配MultipartResovler,因此默认情况下不能处理文件上传功能。

  • XML配置:
    <!--配置MultipartResolver-->
    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <property name="defaultEncoding" value="UTF-8"/>
        <property name="maxUploadSize" value="1024"/>
    </bean>
  • 控制器代码
    @RequestMapping("/testFileUpload")
    public String testFileUpload(@RequestParam("desc")String desc,
                                 @RequestParam("file")MultipartFile file) throws IOException {
        System.out.println("Desc: "+desc);
        System.out.println("OriginalFilename: "+file.getOriginalFilename());
        System.out.println("InputStream: "+file.getInputStream());
        return "success";
    }
  • Jsp代码
<form action="${pageContext.request.contextPath}/testFileUpload" method="post" enctype="multipart/form-data">
    File:<input type="file" name="file"/>
    Desc:<input type="text" name="desc"/><br/>
    <input type="submit" value="testFileUpload"/>
</form>
  • 控制台打印

    Desc: ABCDFile
    OriginalFilename: abcd.txt
    InputStream: java.io.ByteArrayInputStream@5b700e7c
    

2. 拦截器

2.1. 第一个Interceptor例子

  • 实现HandlerInterceptor接口
public class FirstInterceptor implements HandlerInterceptor{
    @Override
    public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
        System.out.println("[FirstInterceptor] preHandle");
        return false;

    }

    @Override
    public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
        System.out.println("[FirstInterceptor] postHandle");
    }

    @Override
    public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
        System.out.println("[FirstInterceptor] afterCompletion");
    }
}
  • XML配置
    <mvc:interceptors>
        <!--配置自定义拦截器-->
        <bean class="interceptors.FirstInterceptor"/>
    </mvc:interceptors>

2.2. 拦截器方法调用顺序

方法 调用时间 用途
preHandle() 在目标方法之前被调用;若返回true,则继续调用后续拦截器和目标方法,而返回false,将不会调用后续拦截器和目标方法。 权限、日志、事务等
postHandle() 在调用目标方法之后,但渲染视图之前被调用。 可以对请求域中属性或视图进行修改
afterCompletion() 渲染视图之后被调用 释放资源

2.3. 拦截器配置

  • XML配置
    <mvc:interceptors>
        <!--配置自定义拦截器-->
        <bean class="interceptors.FirstInterceptor"/>

        <!--配置拦截器(不)作用的路径-->
        <mvc:interceptor>
            <mvc:mapping path="/emps"/>
            <!--exclude-mapping不能作为开头-->
            <mvc:exclude-mapping path="/emps"/>
            <bean class="interceptors.SecondInterceptor"></bean>
        </mvc:interceptor>
    </mvc:interceptors>

2.4. 多个拦截器的顺序

1.当FirstInterceptor的preHandle()方法返回true,而SecondInterceptor的preHandle()方法返回true时,控制台打印顺序:

[FirstInterceptor] preHandle
[SecondInterceptor] preHandle
[SecondInterceptor] postHandle
[FirstInterceptor] postHandle
[SecondInterceptor] afterCompletion
[FirstInterceptor] afterCompletion

2.当FirstInterceptor的preHandle()方法返回false,则不继续执行后续方法
3.当FirstInterceptor的preHandle()方法返回true,而SecondInterceptor的preHandle()方法返回false时,控制台打印顺序:

[FirstInterceptor] preHandle
[SecondInterceptor] preHandle
[FirstInterceptor] afterCompletion

3. 异常处理

3.1. HandlerExceptionResolver概述

1.Spring MVC通过 HandlerExceptionResolver 处理程序发生的异常,包括Handler映射、数据绑定以及目标方法执行时异常。
2.Spring MVC提供的HandlerExceptionResolver的实现类,如下:

  • AbstractHandlerExceptionResolver
    • SimpleMappingExceptionResolver
    • DefaultHandlerExceptionResolver
    • AnnotationMethodHandlerExceptionResolver(@deprecated)
    • ResponseStatusExceptionResolver
    • AbstractHandlerMethodExceptionResolver
      • ExceptionHandlerExceptionResolver
  • HandlerExceptionResolverComposite

3.DispatcherServlet默认装配的HandlerExceptionResolver

  • 没有使用<mvc:annotation-driven/>配置:

    AnnotationMethodHandlerExceptionResolver
    ResponseStatusExceptionResolver
    DefaultHandlerExceptionResolver
    
  • 使用<mvc:annotation-driven/>配置

    ExceptionHandlerExceptionResolver
    ResponseStatusExceptionResolver
    DefaultHandlerExceptionResolver
    

3.2. 处理当前controller异常

  • Java代码
    @RequestMapping("testExceptionHandlerExceptionResolver")
    public String testExceptionHandlerExceptionResolver(@RequestParam("i") int i){
        System.out.println("result : "+10/i);
        return "success";
    }

    @ExceptionHandler({ArithmeticException.class})
    public String handleArithmeticException(Exception ex){
        System.out.println("异常:"+ex);
        return "error";
    }
  • Jsp代码:
<a href="${pageContext.request.contextPath}/testExceptionHandlerExceptionResolver">Test ExceptionHandlerExceptionResolver</a>
  • 控制台打印:

    [FirstInterceptor] preHandle
    异常:java.lang.ArithmeticException: / by zero
    [FirstInterceptor] afterCompletion
    
  • 在@ExceptionHandler方法入参中可以加入Exception类型的参数,该参数即对应发生的异常对象。
  • 在@ExceptionHandler方法入参中不能传入Map,若希望将异常信息传到页面中,需要使用ModelAndView作为返回值。
  • Java代码:
    @ExceptionHandler({ArithmeticException.class})
    public ModelAndView handleArithmeticException(Exception ex) {
        ModelAndView mv = new ModelAndView("error");
        mv.addObject("exception" + ex);
        System.out.println("异常:" + ex);
        return mv;
    }

3.@ExceptionHandler方法标记的异常优先级

    @ExceptionHandler({ArithmeticException.class})
    public ModelAndView handleArithmeticException(Exception ex) {
        ModelAndView mv = new ModelAndView("error");
        mv.addObject("exception" ,ex);
        System.out.println("[ArithmeticException异常]:" + ex);
        return mv;
    }

    @ExceptionHandler({RuntimeException.class})
    public ModelAndView handleArithmeticException2(Exception ex) {
        ModelAndView mv = new ModelAndView("error");
        mv.addObject("exception" ,ex);
        System.out.println("[RuntimeException异常]:" + ex);
        return mv;
    }
  • 控制台打印:

    [FirstInterceptor] preHandle
    [ArithmeticException异常]:java.lang.ArithmeticException: / by zero
    [FirstInterceptor] afterCompletion
    

3.2. 处理全局controller异常

  • 如果在当前controller中找不到@ExceptionHandler方法来处理当前方法出现的异常,则去@ControllerAdvice类标记的@ExceptionHandler来处理异常
@ControllerAdvice
public class ExceptionHandlerDemo {

    @ExceptionHandler({ArithmeticException.class})
    public ModelAndView handleArithmeticException(Exception ex) {
        ModelAndView mv = new ModelAndView("error");
        mv.addObject("exception" ,ex);
        System.out.println("[ArithmeticException异常]:" + ex);
        return mv;
    }
}

3.3. ResponseStatusExceptionResolver

  • ResponseStatusExceptionResolver是HandlerExceptionResolver接口的实现类,使用@ResponseStatus注解将exception映射为HTTP状态码。

  • @ResponseStatus注解在类上

    @ResponseStatus(value = HttpStatus.FORBIDDEN, reason = "用户名和密码不匹配")
    public class NotMatchException extends RuntimeException {

    }
  • @ResponseStatus注解在方法上
    @ResponseStatus(value=HttpStatus.NOT_FOUND, reason = "测试")
    @RequestMapping("/testResponseStatusExceptionResolver")
    public String testResponseStatusExceptionResolver(@RequestParam("i")int i){
        if (i==13){
            throw new NotMatchException();
        }
        System.out.println("testResponseStatusExceptionResolver...");
        return "success";
    }

3.4. DefaultHandlerExceptionResolver

  • DefaultHandlerExceptionResolver是HandlerExceptionResolver接口的实现类,处理标准Spring异常和将异常转换为HTTP的状态码。

  • 处理的Spring异常:

  • NoSuchRequestHandlingMethodException
  • HttpRequestMethodSupportedException
  • HttpMediaTypeNotSupportedException
  • HttpMediaTypeNotAcceptableException等等。

3.5. SimpleMappingExceptionResolver

  • SimpleMappingExceptionResolver,它将异常类名映射为视图名,即发生异常时使用对应的视图报告异常。

  • 配置SimpleMappingExceptionResovler来映射异常:

    <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver" id="exceptionResolver">
        <!--exceptionAttribute默认为exception-->
        <property name="exceptionAttribute" value="ex"/>
        <property name="exceptionMappings">
            <props>
                <prop key="java.lang.ArrayIndexOutOfBoundsException">error</prop>
            </props>
        </property>
    </bean>
  • Java代码:
    @RequestMapping("/testSimpleMappingExceptionResolver")
    public String testSimpleMappingExceptionResolver(@RequestParam("i")int i){
        String[] vals = new String[10];
        System.out.println(vals[i]);

        return "success";
    }

4. Spring 整合 Spring MVC

  • 需要:通常情况下,类似于数据源、事务、整合其他框架都是放在Spring配置文件中(而不是SpringMVC配置文件),实际上放入Spring配置文件对应的 IoC 容器中还有 Service 和 Dao。
  • 不需要:都放在Spring MVC 配置文件中,也可以分为多个 Spring 的配置文件,然后用 import 导入其他的配置文件

4.1. Spring 和 Spring MVC 容器扫描重合

1.使 Spring 的 IoC 容器扫描的包和 SpringMVC 的 IoC 容器扫描的包没有重合的部分。
2.使用 exclude-filter include-filter 子节点来规定只能扫描的注解。

  • spring-config.xml
<context:component-scan base-package="com.chen.demo">
        <context:exclude-filter type="annotation" 
            expression="org.springframework.stereotype.Controller"/>
        <context:exclude-filter type="annotation" 
            expression="org.springframework.web.bind.annotation.ControllerAdvice"/>
    </context:component-scan>
  • springmvc-config.xml
<context:component-scan base-package="com.chen.demo" use-default-filters="false">
        <context:include-filter type="annotation" 
            expression="org.springframework.stereotype.Controller"/>
        <context:include-filter type="annotation" 
            expression="org.springframework.web.bind.annotation.ControllerAdvice"/>
    </context:component-scan>

Spring MVC容器中的bean可以引用Spring容器中的bean,而反过来则不可以。


猜你喜欢

转载自blog.csdn.net/qq_37138933/article/details/79269832