SpringMVC文件上传、拦截器与异常处理

文件上传

Spring MVC 为文件上传提供了直接的支持,这种支持是通过即插即用的 MultipartResolver 实现的。Spring 用Jakarta Commons FileUpload 技术实现了一个MultipartResolver 实现类:CommonsMultipartResovler,因此需要依赖commons-fileupload.jar。

Spring MVC 上下文中默认没有装配 MultipartResovler,因此默认情况下不能处理文件的上传工作,如果想使用 Spring的文件上传功能,需要在上下文中配置 MultipartResolver:

 <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
     
     <property name="defaultEncoding" value="UTF-8"/>
     
     <property name="maxUploadSize" value="1024000"/>
 bean>

文件上传示例:

@Controller
public class FileUploadController {
    /**
     * 文件上传(支持多个文件),单个文件时也可以使用MultipartFile作为方法参数
     * @param request
     * @return
     * @throws IOException
     */
    @RequestMapping(value = {"/multiFileUpload"})
    public  String multiFileUpload(MultipartHttpServletRequest request) throws IOException {
        //获取所有的文件上传表单内容
        Map filesMap = request.getFileMap();
        Set> entries = filesMap.entrySet();

        //获取项目真实路径
        String realPath = request.getSession().getServletContext().getRealPath("");
        System.out.println(realPath);

        //获取缓冲区
        ByteBuffer byteBuffer = ByteBuffer.allocate(1024);

        for (Map.Entry entry : entries) {

            String key = entry.getKey();
            MultipartFile file = entry.getValue();
            //获取原始文件名
            String filename = file.getOriginalFilename();
            //创建输入/输出通道
            FileInputStream fileInputStream = null;
            FileChannel inChannel = null;
            FileOutputStream fileOutputStream = null;
            FileChannel outChannel = null;
            try {
                fileInputStream = (FileInputStream)file.getInputStream();
                inChannel = fileInputStream.getChannel();
                fileOutputStream = new FileOutputStream(new File(realPath+"\\WEB-INF\\classes\\"+filename));
                outChannel = fileOutputStream.getChannel();
                //上传文件
                while (inChannel.read(byteBuffer) != -1) {
                    byteBuffer.flip();
                    outChannel.write(byteBuffer);
                    byteBuffer.clear();
                }
                System.out.println("上传文件的name属性" + key + "原始文件名:" + filename);
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if (fileInputStream != null) {
                    fileInputStream.close();
                }
                if (fileOutputStream != null) {
                    fileOutputStream.close();
                }
                if (inChannel != null) {
                    inChannel.close();
                }
                if (outChannel != null) {
                    outChannel.close();
                }
            }

        }
        return "success";
    }
}

拦截器

在SpringMVC源码分析之数据绑定与国际化中我们提到了LocaleChangeInterceptor拦截器用于拦截locale参数实现国际化切换。SpringMVC提供了HandlerInterceptor接口可用于自定义拦截器。

自定义拦截器示例:

public class MyInterceptor implements HandlerInterceptor {
    /**
     * @desc 在处理器实际执行之前执行
     * 当方法返回 true时,处理器链会继续执行;
     * 若方法返回 false, DispatcherServlet即认为拦截器自身已经完成了
     * 对请求的处理(比如说,已经渲染了一个合适的视图),那么其余的拦
     * 截器以及执行链中的其他处理器就不会再被执行了
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("preHandle");
        return true;
    }
    /**
     * @desc 在处理器实际执行之后执行
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("postHandler");
    }
    /**
     * @desc 出现异常或在整个请求处理完成之后被执行
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("afterCompletion");
    }
}

拦截器注册:

<mvc:interceptors>
    
    <bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor"/>
    
    <mvc:interceptor>
        <mvc:mapping path="/hello"/>
        <bean class="com.intercepor.MyInterceptor"/>
    mvc:interceptor>
mvc:interceptors>

异常处理

Spring MVC 通过 HandlerExceptionResolver 处理程序的异常,包括 Handler 映射、数据绑定以及目标方法执行时发生的异常。HandlerExceptionResolver 接口及实现类如下:
SpringMVC文件上传、拦截器与异常处理_第1张图片

SpringMVC默认装配AnnotationMethodHandlerExceptionResolver、ResponseStatusExceptionResolver和DefaultHandlerExceptionResolver三种HandlerExceptionResolver,当开启时与HandlerMapping相似,AnnotationMethodHandlerExceptionResolver会被ExceptionHandlerExceptionResolver所替代。

ExceptionHandlerExceptionResolver

主要处理 Handler 中用 @ExceptionHandler 注解定义的方法。

  • @ExceptionHandler 注解定义的方法总是以更具体的Exception优先:例如发生的是NullPointerException,但是声明的异常有NullPointerException和RuntimeException ,此时会以NullPointerException优先
  • ExceptionHandlerMethodResolver在处理器中若找不到@ExceptionHandler 注解的方法,会找@ControllerAdvice 中的@ExceptionHandler 注解方法
  @RequestMapping("/testException")
  public String testException(@RequestParam("i") int i) {
      System.out.println(10/i);
      return "success";
  }

  /**
   * 在@ExceptionHandler方法的入参中可以加入Exception类型的参数,该参数即对应发生的异常对象
   * 如果想把异常信息传递给页面,不可以在方法参数中使用Map等参数,可以返回ModelAndView对象
   * @param e
   * @return
   */
  @ExceptionHandler(value = {ArithmeticException.class})
  public ModelAndView handleArithmeticException(Exception e) {
      ModelAndView mv = new ModelAndView("error");
      mv.addObject("exception",e);
      System.out.println("出现异常:"+e);
      return mv;
  }

@ExceptionHandler方法也可以放在标注了@ControllerAdvice的类中作为全局处理。实际项目中,我们可以自定义异常做统一的封装然后通过@ControllerAdvice将异常信息存入ModelAndView中返回给客户端。

ResponseStatusExceptionResolver

在异常及异常父类中找到 @ResponseStatus 注解,然后使用这个注解的属性进行处理。

  • 定义一个 @ResponseStatus 注解修饰的异常类
  • 如果上述异常没有被ExceptionHandlerExceptionResolver解析,则会被ResponseStatusExceptionResolver 解析,根据@ResponseStatus 中注解的信息返回给客户端。
/**
 * 自定义异常类,使用@ResponseStatus定义状态码和message信息
 */
@ResponseStatus(value = HttpStatus.BAD_REQUEST,reason = "用户名与密码不匹配")
public class UserNamePasswordNotMatchException extends Exception {

}

@RequestMapping("/testException")
public String testException(@RequestParam("i") int i) throws UserNamePasswordNotMatchException {
    try {
        System.out.println(10/i);
    } catch (Exception e) {
        throw new UserNamePasswordNotMatchException();
    }
    return "success";
}

DefaultHandlerExceptionResolver

对一些特殊的异常进行处理,比如NoSuchRequestHandlingMethodException、HttpRequestMethodNotSupportedException、HttpMediaTypeNotSupportedException、HttpMediaTypeNotAcceptableException等,具体看DefaultHandlerExceptionResolver的doResolveException方法源码。

SimpleMappingExceptionResolver

如果希望对所有异常进行统一处理,可以使用SimpleMappingExceptionResolver,它将异常类名映射为视图名,即发生异常时使用对应的视图报告异常。

<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
    <property name="exceptionMappings">
        <props>
            
            <prop key="java.lang.ArrayIndexOutOfBoundsException">errorprop>
            <prop key="java.lang.ClassNotFoundException">errorprop>
        props>
    property>
bean>

Exception会被放入ModelAndView中,可以在页面获取异常信息。

你可能感兴趣的:(spring,文件上传,拦截器,异常处理)