使用Spring 3 @ExceptionHandler和commons FileUpload和SizeLimitExceededException / MaxUploadSizeExceededException

时间:2010-10-27 02:32:26

标签: spring-mvc file-upload exception-handling apache-commons-fileupload

在上传大文件时,我无法捕捉并优雅地处理commons fileupload FileUploadBase.SizeLimitExceededException或spring MaxUploadSizeExceededException

据我所知,这些异常在数据绑定期间抛出,在实际到达控制器之前,因此导致500并且不调用异常处理程序方法。有没有人遇到过这个问题,正确处理这些例外的最佳方式是什么?

3 个答案:

答案 0 :(得分:7)

感谢thetoman这个简单的解决方案。我扩展了一下。我想保持文件处理不变,并将Exception传输到Controller。

package myCompany; 

public class DropOversizeFilesMultipartResolver extends CommonsMultipartResolver {

    /**
     * Parse the given servlet request, resolving its multipart elements.
     * 
     * Thanks Alexander Semenov @ http://forum.springsource.org/showthread.php?62586
     * 
     * @param request
     *            the request to parse
     * @return the parsing result
     */
    @Override
    protected MultipartParsingResult parseRequest(final HttpServletRequest request) {

        String encoding = determineEncoding(request);
        FileUpload fileUpload = prepareFileUpload(encoding);

        List fileItems;

        try {
            fileItems = ((ServletFileUpload) fileUpload).parseRequest(request);
        } catch (FileUploadBase.SizeLimitExceededException ex) {
            request.setAttribute(EXCEPTION_KEY, ex);
            fileItems = Collections.EMPTY_LIST;
        } catch (FileUploadException ex) {
            throw new MultipartException("Could not parse multipart servlet request", ex);
        }

        return parseFileItems(fileItems, encoding);
    }
}

并在控制器中

  @InitBinder("fileForm")
  protected void initBinderDesignForm(WebDataBinder binder) {
    binder.setValidator(new FileFormValidator());
  }

    @RequestMapping(value = "/my/mapping", method = RequestMethod.POST)
  public ModelAndView acceptFile(HttpServletRequest request, Model model, FormData formData,
      BindingResult result) {

    Object exception = request.getAttribute(DropOversizeFilesMultipartResolver.EXCEPTION_KEY);
    if (exception != null && FileUploadBase.SizeLimitExceededException.class.equals(exception.getClass())) {
      result.rejectValue("file", "<your.message.key>");
      LOGGER.error(exception);
    }

弹簧配置保持不变。把异常传递给验证器真的很好,但我还没弄明白怎么做。

答案 1 :(得分:4)

我知道这是旧的,但我也在寻找解决方案,但找不到任何东西。我们使用Spring提供RESTful服务,我们正在进行文件上传,并且不确定如何处理这个问题。我想出了以下内容,希望对某人有用:

我们所有的异常都是用注释处理的,所以我们有这样的错误处理程序解析器设置:

@Configuration
public class MyConfig{

    @Bean
    public AnnotationMethodHandlerExceptionResolver exceptionResolver(){

        final AnnotationMethodHandlerExceptionResolver resolver = new AnnotationMethodHandlerExceptionResolver();
        resolver.setMessageConverters(messageConverters());
        resolver;
    }
}

然后是一个可以处理异常的公共类

public class MultipartExceptionHandler
{

    @ExceptionHandler(MaxUploadSizeExceededException.class)
    @ResponseStatus(value = HttpStatus.PRECONDITION_FAILED)
    @ResponseBody
    protected CustomError handleMaxUploadSizeExceededException(final HttpServletRequest request,
            final HttpServletResponse response, final Throwable e)
            throws IOException
    {
        logger.error(e);
        CustomError c = new CustomErrorMaxFileSize("Max file size exceeded", MAX_FILE_SIZE);
        return c;
    }

    @ExceptionHandler(MultipartException.class)
    @ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
    @ResponseBody
    protected CustomError handleGenericMultipartException(final HttpServletRequest request,
            final HttpServletResponse response, final Throwable e)
            throws IOException
    {
        logger.error(e);
        CustomError c = new CustomErrorGeneric("There was a problem with the upload");
        return c;
    }
}

然后我们将commons多部分解析器子类化并实现HandlerExceptionResolver接口

@Component(value="multipartResolver") // Spring expects this name
public class MyMultipartResolver extends CommonsMultipartResolver implements HandlerExceptionResolver
{

    // This is the Spring bean that handles exceptions
    // We defined this in the Java configuration file
    @Resource(name = "exceptionResolver")
    private AnnotationMethodHandlerExceptionResolver exceptionResolver;

    // The multipart exception handler with the @ExceptionHandler annotation
    private final MultipartExceptionHandler multipartExceptionHandler = new MultipartExceptionHandler();

    // Spring will call this when there is an exception thrown from this
    // multipart resolver
    @Override
    public ModelAndView resolveException(
            final HttpServletRequest request,
            final HttpServletResponse response,
            final Object handlerParam,
            final Exception ex)
    {

        // Notice that we pass this.multipartExceptionHandler 
        // and not the method parameter 'handlerParam' into the 
        // exceptionResolver. We do this because the DispatcherServlet 
        // doDispatch() method calls checkMultipart() before determining
        // the handler for the request. If doing the multipart check fails 
        // with a MultipartException, Spring will never have a reference  
        // to the handler and so 'handlerParam' will be null at this point. 
        return exceptionResolver.resolveException(request, response, this.multipartExceptionHandler, ex);

    }
}

答案 2 :(得分:1)

这似乎是一个非常普遍的问题。我遇到了类似的问题,并提出了类似的问题,例如this question。我还没有看到解决问题的好方法。您可以使用vanilla servlet过滤器来处理这些异常,但由于您已经拥有ExceptionHandler,因此会重复您的错误处理。