如何处理 MaxUploadSizeExceededException

Posted

技术标签:

【中文标题】如何处理 MaxUploadSizeExceededException【英文标题】:How to handle MaxUploadSizeExceededException 【发布时间】:2011-02-11 00:15:52 【问题描述】:

MaxUploadSizeExceededException 当我上传的文件大小超过允许的最大值时出现异常。我想在出现此异常时显示错误消息(如验证错误消息)。在 Spring 3 中如何处理此异常以执行此类操作?

谢谢。

【问题讨论】:

通过在 Java 中捕获异常并显示错误页面? @skaffman 我更愿意返回表单页面并在那里显示错误,但是在它到达填充模型属性的控制器之前抛出异常 看看 HandlerExceptionResolver:static.springsource.org/spring/docs/3.0.x/… 【参考方案1】:

这是一个老问题,所以我将其添加给正在努力使用 Spring Boot 2 进行此工作的未来人(包括未来的我)。

首先你需要配置spring应用(在属性文件中):

spring.servlet.multipart.max-file-size=10MB
spring.servlet.multipart.max-request-size=10MB

如果您使用的是嵌入式 Tomcat(很可能是,因为它是标准配置),配置 Tomcat 以不取消大主体的请求也很重要

server.tomcat.max-swallow-size=-1

或至少将其设置为相对较大的尺寸

server.tomcat.max-swallow-size=100MB

如果您不为 Tomcat 设置 maxSwallowSize,您可能会浪费大量时间来调试为什么会处理错误但浏览器没有响应 - 这是因为如果没有此配置,Tomcat 将取消请求,即使您会在记录该应用程序正在处理错误,浏览器已经收到来自 Tomcat 的取消请求并且不再监听响应。

要处理 MaxUploadSizeExceededException,您可以添加 ControllerAdviceExceptionHandler

这是 Kotlin 中的一个简单示例,它简单地设置一个带有错误的 flash 属性并重定向到某个页面:

@ControllerAdvice
class FileSizeExceptionAdvice 
    @ExceptionHandler(MaxUploadSizeExceededException::class)
    fun handleFileSizeException(
        e: MaxUploadSizeExceededException, 
        redirectAttributes: RedirectAttributes
    ): String 
        redirectAttributes.addFlashAttribute("error", "File is too big")
        return "redirect:/"
    

注意:如果您想直接在控制器类中使用 ExceptionHandler 处理 MaxUploadSizeExceededException,您应该配置以下属性:

spring.servlet.multipart.resolve-lazily=true

否则会在请求映射到控制器之前触发异常。

【讨论】:

非常感谢。这正是我浪费我的早晨!直奔主题。 属性 spring.servlet.multipart.resolve-lazily 真的很有帮助。谢谢! 你应该获得金牌并将其标记为正确答案。 @AbstractVoid 我尝试了你的方法并使用 resolve-lazily...,但它仍然不起作用。您能否更具体地说明如何处理控制器类中的异常? 谢谢你,我喜欢 Kotlin,你的解决方案非常聪明,非常感谢【参考方案2】:

我终于找到了一个可以使用 HandlerExceptionResolver 的解决方案。

将多部分解析器添加到您的 Spring 配置中

<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">    
   <!--  the maximum size of an uploaded file in bytes -->
   <!-- <property name="maxUploadSize" value="10000000"/> -->
   <property name="maxUploadSize" value="1000"/>
</bean>   

模型 - UploadedFile.java

package com.mypkg.models;

import org.springframework.web.multipart.commons.CommonsMultipartFile;

public class UploadedFile

    private String title;

    private CommonsMultipartFile fileData;

    public String getTitle()
    
        return title;
    

    public void setTitle(String title)
    
        this.title = title;
    

    public CommonsMultipartFile getFileData()
    
        return fileData;
    

    public void setFileData(CommonsMultipartFile fileData)
    
        this.fileData = fileData;
    


查看 - /upload.jsp

<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
    <head>
        <title>Test File Upload</title>
    </head>
    <body>
        <h1>Select a file to upload</h1>
        <c:if test="$not empty errors">
            <h2 style="color:red;">$errors.</h2>
        </c:if>
        <form:form modelAttribute="uploadedFile" method="post" enctype="multipart/form-data" name="uploadedFileform" id="uploadedFileform">
            <table  border="0" align="left" cellpadding="0" cellspacing="0" id="pdf_upload_form">
                <tr>
                    <td ><label class="title">Title:</label></td>
                    <td ><form:input id="title" path="title" cssClass="areaInput" size="30" maxlength="128"/></td>
                </tr>
                <tr>
                    <td ><label class="title">File:</label></td>
                    <td ><form:input id="fileData" path="fileData" type="file" /></td>
                 </tr>
                 <tr>
                    <td ></td>
                    <td ><input type="submit" value="Upload File" /></td>
                 </tr>
            </table>
        </form:form>
    </body>
</html>

控制器 - FileUploadController.java: 包 com.mypkg.controllers;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.multipart.MaxUploadSizeExceededException;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;

import com.mypkg.models.UploadedFile;

@Controller
public class FileUploadController  implements HandlerExceptionResolver

    @RequestMapping(value = "/upload", method = RequestMethod.GET)
    public String getUploadForm(Model model)
    
        model.addAttribute("uploadedFile", new UploadedFile());
        return "/upload";
    

    @RequestMapping(value = "/upload", method = RequestMethod.POST)
    public String create(UploadedFile uploadedFile, BindingResult result)
    
        // Do something with the file
        System.out.println("#########  File Uploaded with Title: " + uploadedFile.getTitle());
        System.out.println("#########  Creating local file: /var/test-file-upload/" + uploadedFile.getFileData().getOriginalFilename());

        try
        

            InputStream in = uploadedFile.getFileData().getInputStream();
            FileOutputStream f = new FileOutputStream(
                    "/var/test-file-upload/" + uploadedFile.getFileData().getOriginalFilename());
            int ch = 0;
            while ((ch = in.read()) != -1)
            
                f.write(ch);
            
            f.flush();
            f.close();
        
        catch (IOException e)
        
            e.printStackTrace();
        

        return "redirect:/";
    

    /*** Trap Exceptions during the upload and show errors back in view form ***/
    public ModelAndView resolveException(HttpServletRequest request,
            HttpServletResponse response, Object handler, Exception exception)
            
        Map<String, Object> model = new HashMap<String, Object>();
        if (exception instanceof MaxUploadSizeExceededException)
        
            model.put("errors", exception.getMessage());
         else
        
            model.put("errors", "Unexpected error: " + exception.getMessage());
        
        model.put("uploadedFile", new UploadedFile());
        return new ModelAndView("/upload", model);
    



========================================================================

【讨论】:

我也在处理这个问题。但是,我发现请求没有填充任何其他参数,即使它们在我的表单中。 如果所有的controller都实现了这个HandlerExceptionResolver,那么异常发生时都会被调用? 我尝试将相同的方法付诸实践,但没有任何效果。还尝试了与post 中提到的相同的方法。即使发生异常,也不会调用方法resolveException()。我想在同一页面上显示用户友好的错误消息,但我在网页上获得了完整的堆栈跟踪。我错过了 Spring 3.2.0 的某些内容吗? 如何在基于 ajax 的上下文中有效处理 MaxUploadSizeExceededException ?我正在通过 ajax 请求上传文件,所以当文件上传失败时,我想在浏览器中显示 javascript 警报,而不是重定向到某个错误页面。我该怎么做? @faizi 看到我的答案,cmets 中的代码格式太糟糕了,所以我写了一个新答案【参考方案3】:

感谢您解决这个问题。我折腾了好几个小时。

关键是让控制器实现HandlerExceptionResolver并添加resolveException方法。

--鲍勃

【讨论】:

最好的!我正要关闭这个标签,但后来发现了这个!谢谢!【参考方案4】:

使用控制器建议

@ControllerAdvice
public class GlobalExceptionHandler 

    @ExceptionHandler(MaxUploadSizeExceededException.class)
    public ModelAndView handleMaxUploadException(MaxUploadSizeExceededException e, HttpServletRequest request, HttpServletResponse response)
        ModelAndView mav = new ModelAndView();
        boolean isJson = request.getRequestURL().toString().contains(".json");
        if (isJson) 
            mav.setView(new MappingJacksonJsonView());
            mav.addObject("result", "nok");
        
        else mav.setViewName("uploadError");
        return mav;
    

【讨论】:

【参考方案5】:

如果使用ajax,需要响应json,可以在resolveException方法中响应json

@Override
  public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response,
      Object handler, Exception ex) 
    ModelAndView view = new ModelAndView();
    view.setView(new MappingJacksonJsonView());
    APIResponseData apiResponseData = new APIResponseData();

    if (ex instanceof MaxUploadSizeExceededException) 
      apiResponseData.markFail("error message");
      view.addObject(apiResponseData);
      return view;
    
    return null;
  

【讨论】:

以上是关于如何处理 MaxUploadSizeExceededException的主要内容,如果未能解决你的问题,请参考以下文章

如何处理 UsernameNotFoundException 春季安全

如何处理c#中的错误代码

Akka 如何处理消息版本?

开玩笑测试 - 如何处理 JsonWebToken 响应

如何处理 JSON 响应

“不知道如何处理' nvcc 致命错误