18

Ho problemi con l'acquisizione e la gestione delle risorse comuni di fileupload FileUploadBase.SizeLimitExceededException o spring MaxUploadSizeExceededException durante il caricamento di file di grandi dimensioni.Utilizzo di Spring 3 @ExceptionHandler con commons FileUpload e SizeLimitExceededException/MaxUploadSizeExceededException

Da ciò che posso dire, queste eccezioni vengono generate durante l'associazione dei dati, prima che il controller venga effettivamente raggiunto, risultando quindi in una chiamata 500 e senza il metodo del gestore di eccezioni. Qualcuno l'ha mai visto prima e qual è il modo migliore per gestire correttamente queste eccezioni?

risposta

7

grazie a thetoolman per questa semplice soluzione. L'ho esteso un po '. Volevo lasciare intatta la gestione dei file e trasportare l'eccezione al 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); 
    } 
} 

e nel controllore

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

config molla rimane la stessa. Sarebbe davvero bello avere l'eccezione trasportata al validatore, ma non ho ancora capito come farlo.

+0

Ricorda che impostando 'fileItems = Collections.EMPTY_LIST;', tutti i parametri di richiesta vengono scartati. In altre parole, 'request.getParameterMap()' sarà '{}'. –

+2

Il commento di @Markus è particolarmente importante da tenere presente se uno dei parametri di richiesta è un token csrf. L'impostazione 'fileItems = Collections.EMPTY_LIST;' scarta il token CSRF, facendo in modo che il filtro CSRF consideri questa richiesta non valida. –

1

Questo sembra essere un problema abbastanza comune. Ho avuto problemi simili e domande simili sono state poste, vedi ad esempio this question. Devo ancora vedere una bella soluzione al problema. È possibile utilizzare un filtro servlet vanilla per gestire queste eccezioni, ma ciò duplicherà la gestione degli errori poiché si dispone già di un ExceptionHandler.

+0

Sì, la domanda che hai collegato è stata una delle tante che ho trovato nella mia ricerca in cui viene posta la domanda, ma non è stata trovata alcuna soluzione pulita. Speravo ci fosse un modo più bello, ma sono d'accordo che un filtro o anche un wrapper per il resolver potrebbe essere l'unico modo. – Luke

4

So che questo è vecchio, ma stavo cercando una soluzione a questo pure e non riuscivo a trovare nulla. Stiamo fornendo servizi RESTful usando Spring e stiamo facendo il caricamento dei file e non eravamo sicuri su come gestirlo. Sono venuto con la seguente e speriamo che sia utile a qualcuno:

Tutte le nostre eccezioni vengono gestite con annotazioni, quindi abbiamo set-up il nostro resolver gestore degli errori come questo:

@Configuration 
public class MyConfig{ 

    @Bean 
    public AnnotationMethodHandlerExceptionResolver exceptionResolver(){ 

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

Poi un comune classe che può gestire l'eccezione

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

Poi abbiamo sottoclasse The Commons resolver multipart e implementare l'interfaccia 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); 

    } 
} 
Problemi correlati