18

Ich habe Probleme mit dem Erfassen und ordentlichen Umgang mit Commons Fileupload FileUploadBase.SizeLimitExceededException oder Frühling MaxUploadSizeExceededException beim Hochladen von großen Dateien.Verwenden von Spring 3 @ExceptionHandler mit Commons FileUpload und SizeLimitExceededException/MaxUploadSizeExceededException

Von dem, was ich sagen kann, werden diese Ausnahmen während der Datenbindung geworfen, bevor der Controller tatsächlich erreicht wird, was zu einem 500 und keinem Aufruf der Exception-Handler-Methode führt. Ist jemand schon einmal darauf gestoßen und was ist der beste Weg, um diese Ausnahmen richtig zu behandeln?

Antwort

7

Dank thetoolman für diese einfache Lösung. Ich habe es ein wenig erweitert. Ich wollte die Handhabung der Datei unberührt lassen und die Exception zum Controller transportieren.

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

und in der Steuerung

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

die Feder Config bleibt gleich. Es wäre wirklich schön, die Ausnahme zum Validator transportieren zu lassen, aber ich habe noch nicht herausgefunden, wie das geht.

+0

Beachten Sie, dass durch Festlegen von 'fileItems = Collections.EMPTY_LIST;' alle Anforderungsparameter verworfen werden. Mit anderen Worten, 'request.getParameterMap()' ist '{}'. –

+2

Der Kommentar von @Markus ist besonders wichtig, wenn einer der Anforderungsparameter ein csrf-Token ist. Das Setzen von 'fileItems = Collections.EMPTY_LIST;' verwirft das CSRF-Token, wodurch der CSRF-Filter diese Anfrage als ungültig behandelt. –

1

Dies scheint ein recht häufiges Problem zu sein. Ich hatte ähnliche Probleme und ähnliche Fragen wurden gestellt, siehe zum Beispiel this question. Ich habe noch keine gute Lösung für das Problem gefunden. Sie könnten einen Vanilla-Servlet-Filter verwenden, um diese Ausnahmen zu behandeln, aber das wird Ihre Fehlerbehandlung duplizieren, da Sie bereits einen ExceptionHandler haben.

+0

Ja, die Frage, die Sie gestellt haben, war eine der vielen, die ich in meinen Recherchen gefunden habe, wo die Frage gestellt wurde, aber keine saubere Lösung gefunden wurde. Ich hatte gehofft, dass es einen schöneren Weg gab, aber ich stimme zu, dass ein Filter oder sogar ein Wrapper für den Resolver der einzige Weg sein könnte. – Luke

4

Ich weiß, das ist alt, aber ich suchte auch nach einer Lösung und konnte nichts finden. Wir bieten REST-konforme Dienste mit Spring an und führen Dateiuploads durch und waren nicht sicher, wie wir damit umgehen sollten. Ich kam mit der folgenden, und hoffentlich wird es nützlich sein, jemand:

Alle Ausnahmen werden mit Anmerkungen behandelt, so haben wir unsere Fehlerbehandlungs Resolver wie diese Set-up:

@Configuration 
public class MyConfig{ 

    @Bean 
    public AnnotationMethodHandlerExceptionResolver exceptionResolver(){ 

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

Dann wird eine gemeinsame Klasse, die die Ausnahme behandeln kann

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

Dann Unterklasse wir die commons mehrt Resolver und implementieren die HandlerExceptionResolver Schnittstelle

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

    } 
} 
Verwandte Themen