Использование Spring 3 @ExceptionHandler с общими файлами FileUpload и SizeLimitExceededException / MaxUploadSizeExceededException - PullRequest
18 голосов
/ 27 октября 2010

У меня возникли проблемы с перехватом и изящной обработкой общих файловых файлов FileUploadBase.SizeLimitExceededException или пружинных MaxUploadSizeExceededException при загрузке больших файлов.

Из того, что я могу сказать, эти исключения вызываются во время привязки данных, до того, как контроллер действительно будет достигнут, поэтому в результате 500 и не будет вызван метод обработчика исключения. Кто-нибудь сталкивался с этим раньше, и как лучше всего правильно обрабатывать эти исключения?

Ответы [ 3 ]

7 голосов
/ 08 ноября 2011

спасибо thetoolman за это простое решение. Я немного расширил это. Я хотел оставить обработку файла нетронутой и перенести исключение на контроллер.

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);
    }

конфигурация пружины остается прежней. Было бы неплохо перенести исключение в валидатор, но я пока не выяснил, как это сделать.

4 голосов
/ 10 сентября 2012

Я знаю, что это старо, но я тоже искал решение этой проблемы и ничего не смог найти. Мы предоставляем RESTful-сервисы с использованием Spring и загружаем файлы и не знали, как с этим справиться. Я придумал следующее и, надеюсь, кому-то будет полезно:

Все наши исключения обрабатываются с аннотациями, поэтому у нас настроен наш обработчик ошибок:

@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;
    }
}

Затем мы создаем подкласс для многочастного распознавателя и реализуем интерфейс 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);

    }
}
1 голос
/ 27 октября 2010

Это, кажется, довольно распространенная проблема.У меня были похожие проблемы, и мне задавали похожие вопросы, см., Например, этот вопрос .Мне еще предстоит увидеть хорошее решение проблемы.Вы можете использовать ванильный фильтр сервлетов для обработки этих исключений, но это дублирует вашу обработку ошибок, так как у вас уже есть ExceptionHandler.

...