我们使用Spring Boot上传功能的时候,会遇到文件大小超出限制的问题。Tomcat默认的大小是1M。因此,我们首先应该修改这个限制。我们在配置文件application.properties或application.yml上修改上传文件大小限制即可。下面是application.properties的语法:
- spring.servlet.multipart.max-file-size=5MB
- spring.servlet.multipart.max-request-size=10MB
application.yml放在spring 大节下面:
- servlet:
- multipart:
- max-file-size: 5MB
- max-request-size: 10MB
第一个是文件大小限制,第二个是总响应大小限制。
但我们设置后,如果有大于5M的文件上传,还是会抛出异常,且这个异常,在Controller层是catch不到的,因为如果文件超限,在进controller之前,异常已经被抛出了。如何解决这个问题呢?
方式一:
增加异常捕获类
- @RestControllerAdvice
- public class MyExceptionHandler {
- /* spring默认上传大小1MB 超出大小捕获异常MaxUploadSizeExceededException */
- @ExceptionHandler(MaxUploadSizeExceededException.class)
- public Map handleMaxUploadSizeExceededException(MaxUploadSizeExceededException e) {
- return Map.of("code", 500, "msg", "文件大小超出5MB限制, 请压缩或降低文件质量! ");
- }
- }
或者
- @RestControllerAdvice
- public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {
- private static final Logger logger =
- LoggerFactory.getLogger(GlobalExceptionHandler.class);
-
- /**
- * 处理上传异常
- * @param t
- * @return
- */
- @ExceptionHandler(MultipartException.class)
- public ResponseEntity<Result> handleAll(Throwable t) throws Exception {
- // TODO do Throwable t
- logger.error("=>"+t.getMessage());
- HttpHeaders headers = new HttpHeaders();
- headers.set("Content-Type","application/json;charset=UTF-8");
- return new ResponseEntity<>(new Result(-1,"上传文件异常!",null),headers, HttpStatus.OK);
- }
此处注意使用
- @RestControllerAdvice
而不能
- @ControllerAdvice(
- annotations = {RestController.class}
- )
方式二:
文件大小的校验是在controller之前的,可以通过继承CommonsMultipartResolver类,覆盖parseRequest方法,捕获异常后自己处理
在使用Spring Security时,CommonsMultipartResolver不会作为“multipartResolver”bean添加,而是作为“filterMultipartResolver”:
- @Bean(name="filterMultipartResolver")
- CommonsMultipartResolver filterMultipartResolver() {
- CommonsMultipartResolver filterMultipartResolver = new CommonsMultipartResolver();
- filterMultipartResolver.setMaxUploadSize(MAXSIZE);
- return filterMultipartResolver;
- }
如果我设置filterMultipartResolver.setResolveLazily(true);没什么区别.
如果我用自己的子类化CommonsMultipartResolver,并用捕获MaxUploadSizeExceededException并返回一个空的MultipartParsingResult的东西来覆盖parseRequest()方法,我会得到一个“403 Forbidden”错误:
- public class ExtendedCommonsMultipartResolver extends CommonsMultipartResolver {
- protected MultipartParsingResult parseRequest(HttpServletRequest request) throws MultipartException {
- String encoding = determineEncoding(request);
- try {
- return super.parseRequest(request);
- } catch (MaxUploadSizeExceededException e) {
- return parseFileItems(Collections.<FileItem> emptyList(), encoding);
- }
- }
- }
最后,实现某种本地或全局的ExceptionHandler没有任何意义,因为它永远不会被调用.
尝试使用@ControllerAdvice创建一个单独的类,这将处理来自所有控制器的异常。
- @ControllerAdvice
- public class ExceptionControllerAdvice {
-
- @ExceptionHandler(MaxUploadSizeExceededException.class)
- public String handleException(MaxUploadSizeExceededException e, RedirectAttributes redirectAttributes) {
- redirectAttributes.addFlashAttribute("uploadErrorMessage", e.getCause().getMessage());
- return "redirect:/page";
- }
- }
因此,如果我们在@ControllerAdvice类中定义的方法上我们@ExceptionHandler注解,它将被应用到所有控制器。