Подтвердить что ты не робот

Использование Spring 3 @ExceptionHandler с общедоступными файлами FileUpload и SizeLimitExceededException/MaxUploadSizeExceededException

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

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

4b9b3361

Ответ 1

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

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

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

Ответ 2

Я знаю, что это старо, но я искал для этого решения и ничего не мог найти. Мы предоставляем услуги 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;
    }
}

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

    }
}

Ответ 3

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