首页 > 解决方案 > 异常:Spring Boot 中的 multipart/form-data 请求失败

问题描述

技术栈:Java 14、Spring Boot 2.5.3、MySQL 8.0.26、JPA

我有一个 Spring Boot 上传 Excel Web 应用程序。14KB 大小的 Excel 文件上传成功。但是,如果您尝试上传 15MB 和 50MB 容量的 Excel 文件,则会出现以下异常。

我猜上传时服务器连接超时。由于服务器连接时间短,我想在上传文件之前关闭服务器。为了解决这个问题,我尝试在application.properties. 我找到了一些财产。但这不合适。IDE 下划线是这样的。我还访问了Spring Common Application Properties Page以找到相应的属性,但我找不到它。

我想知道是什么导致了异常。我想知道这是否是解决问题的正确方法。

先感谢您。如果您回复,我会尽快回复。

异常控制台

Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.web.multipart.MultipartException: Failed to parse multipart servlet request; nested exception is java.io.IOException: org.apache.tomcat.util.http.fileupload.impl.IOFileUploadException: Processing of multipart/form-data request failed. java.io.EOFException] with root cause

java.io.EOFException: null
    at org.apache.tomcat.util.net.NioEndpoint$NioSocketWrapper.fillReadBuffer(NioEndpoint.java:1294) ~[tomcat-embed-core-9.0.52.jar:9.0.52]
    at org.apache.tomcat.util.net.NioEndpoint$NioSocketWrapper.read(NioEndpoint.java:1206) ~[tomcat-embed-core-9.0.52.jar:9.0.52]
    at org.apache.coyote.http11.Http11InputBuffer.fill(Http11InputBuffer.java:805) ~[tomcat-embed-core-9.0.52.jar:9.0.52]
    at org.apache.coyote.http11.Http11InputBuffer.access$300(Http11InputBuffer.java:42) ~[tomcat-embed-core-9.0.52.jar:9.0.52]
    at org.apache.coyote.http11.Http11InputBuffer$SocketInputBuffer.doRead(Http11InputBuffer.java:1172) ~[tomcat-embed-core-9.0.52.jar:9.0.52]
    at org.apache.coyote.http11.filters.IdentityInputFilter.doRead(IdentityInputFilter.java:101) ~[tomcat-embed-core-9.0.52.jar:9.0.52]
    at org.apache.coyote.http11.Http11InputBuffer.doRead(Http11InputBuffer.java:249) ~[tomcat-embed-core-9.0.52.jar:9.0.52]
    at org.apache.coyote.Request.doRead(Request.java:640) ~[tomcat-embed-core-9.0.52.jar:9.0.52]
    at org.apache.catalina.connector.InputBuffer.realReadBytes(InputBuffer.java:317) ~[tomcat-embed-core-9.0.52.jar:9.0.52]
    at org.apache.catalina.connector.InputBuffer.checkByteBufferEof(InputBuffer.java:600) ~[tomcat-embed-core-9.0.52.jar:9.0.52]
    at org.apache.catalina.connector.InputBuffer.read(InputBuffer.java:340) ~[tomcat-embed-core-9.0.52.jar:9.0.52]
    at org.apache.catalina.connector.CoyoteInputStream.read(CoyoteInputStream.java:132) ~[tomcat-embed-core-9.0.52.jar:9.0.52]
    at java.base/java.io.FilterInputStream.read(FilterInputStream.java:132) ~[na:na]
    at org.apache.tomcat.util.http.fileupload.util.LimitedInputStream.read(LimitedInputStream.java:132) ~[tomcat-embed-core-9.0.52.jar:9.0.52]
    at org.apache.tomcat.util.http.fileupload.MultipartStream$ItemInputStream.makeAvailable(MultipartStream.java:975) ~[tomcat-embed-core-9.0.52.jar:9.0.52]
    at org.apache.tomcat.util.http.fileupload.MultipartStream$ItemInputStream.read(MultipartStream.java:879) ~[tomcat-embed-core-9.0.52.jar:9.0.52]
    at java.base/java.io.FilterInputStream.read(FilterInputStream.java:132) ~[na:na]
    at org.apache.tomcat.util.http.fileupload.util.LimitedInputStream.read(LimitedInputStream.java:132) ~[tomcat-embed-core-9.0.52.jar:9.0.52]
    at java.base/java.io.FilterInputStream.read(FilterInputStream.java:106) ~[na:na]
    at org.apache.tomcat.util.http.fileupload.util.Streams.copy(Streams.java:98) ~[tomcat-embed-core-9.0.52.jar:9.0.52]
    at org.apache.tomcat.util.http.fileupload.FileUploadBase.parseRequest(FileUploadBase.java:291) ~[tomcat-embed-core-9.0.52.jar:9.0.52]
    at org.apache.catalina.connector.Request.parseParts(Request.java:2922) ~[tomcat-embed-core-9.0.52.jar:9.0.52]
    at org.apache.catalina.connector.Request.getParts(Request.java:2824) ~[tomcat-embed-core-9.0.52.jar:9.0.52]
    at org.apache.catalina.connector.RequestFacade.getParts(RequestFacade.java:1098) ~[tomcat-embed-core-9.0.52.jar:9.0.52]
    at org.springframework.web.multipart.support.StandardMultipartHttpServletRequest.parseRequest(StandardMultipartHttpServletRequest.java:95) ~[spring-web-5.3.9.jar:5.3.9]
    at org.springframework.web.multipart.support.StandardMultipartHttpServletRequest.<init>(StandardMultipartHttpServletRequest.java:88) ~[spring-web-5.3.9.jar:5.3.9]
    at org.springframework.web.multipart.support.StandardServletMultipartResolver.resolveMultipart(StandardServletMultipartResolver.java:122) ~[spring-web-5.3.9.jar:5.3.9]
    at ...

应用程序属性

server.tomcat.connection-timeout是正确的。但又server.tomcat.disable-upload-timeout不妥server.connectionUploadTimeout

server.tomcat.connection-timeout=5000
server.tomcat.disable-upload-timeout=false
server.connectionUploadTimeout=5000

# MultiPart
spring.servlet.multipart.max-file-size=50MB
spring.servlet.multipart.max-request-size=50MB

控制器

package com.nc.ojtfirstproject.web;

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;

import com.nc.ojtfirstproject.message.ResponseMessage;
import com.nc.ojtfirstproject.service.StandardProductService;

@Controller
public class StandardProductController {
    
    private final StandardProductService standardProductService;

    public StandardProductController(StandardProductService standardProductService) {
        this.standardProductService = standardProductService;
    }

    @PostMapping("/excel/upload")
    public ResponseEntity<ResponseMessage> uploadFile(@RequestParam("file") MultipartFile file) {

        String TYPE = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
        HttpStatus status = HttpStatus.OK;
        String message = "";
        if (TYPE.equals(file.getContentType())) {
            try {
                standardProductService.save(file);

                status = HttpStatus.OK;
                message = "success: " + file.getOriginalFilename();
            } catch (Exception e) {
                status = HttpStatus.EXPECTATION_FAILED;
                message = "fail: " + file.getOriginalFilename();
            }
        } else {
            status = HttpStatus.BAD_REQUEST;
            message = "Please upload excel file";
        }
        return ResponseEntity.status(status).body(new ResponseMessage(message));
    }
}

服务

package com.nc.ojtfirstproject.service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import com.nc.ojtfirstproject.domain.standardProduct.StandardProduct;
import com.nc.ojtfirstproject.domain.standardProduct.StandardProductRepository;

@Service
public class StandardProductService {

    private final StandardProductRepository standardProductRepository;

    public StandardProductService(StandardProductRepository standardProductRepository) {
        this.standardProductRepository = standardProductRepository;
    }

    @Transactional
    public void save(MultipartFile file) {

        final int TRANSACTION_CHUNK_LIMIT = 10000;
        List<StandardProduct> standardProductList = new ArrayList<StandardProduct>();

        try {
            Workbook workbook = new XSSFWorkbook(file.getInputStream());

            Sheet sheet = workbook.getSheetAt(0);
            
            for (int i = 1; i < sheet.getPhysicalNumberOfRows(); i++) {
                Row row = sheet.getRow(i);
                StandardProduct standardProduct = new StandardProduct();
                
                standardProduct.setCode((int) row.getCell(0).getNumericCellValue());
                standardProduct.setCategoryCode((int) row.getCell(1).getNumericCellValue());
                standardProduct.setName(row.getCell(2).getStringCellValue());
                standardProduct.setLowestPrice((int) row.getCell(3).getNumericCellValue());
                standardProduct.setMobileLowestPrice((int) row.getCell(4).getNumericCellValue());
                standardProduct.setAveragePrice((int) row.getCell(5).getNumericCellValue());
                standardProduct.setCompanies((int) row.getCell(6).getNumericCellValue());
                standardProductList.add(standardProduct);
                
                // TRANSACTION_CHUNK_LIMIT saveAll()
                if (TRANSACTION_CHUNK_LIMIT == standardProductList.size()) {
                    standardProductRepository.saveAll(standardProductList);
                    standardProductList.clear();
                    System.out.println(TRANSACTION_CHUNK_LIMIT + " success");
                }
            }
            
            workbook.close();
            
        } catch (IOException e) {
            throw new RuntimeException("save fail: " + e.getMessage());
        }

        // TRANSACTION_CHUNK_LIMIT saveAll()
        try {
            standardProductRepository.saveAll(standardProductList);
        } catch (Exception e) {
            throw new RuntimeException("save fail: " + e.getMessage());
        }
    }
}

构建.gradle

plugins {
    id 'org.springframework.boot' version '2.5.4'
    id 'io.spring.dependency-management' version '1.0.11.RELEASE'
    id 'java'
}

group = 'com.nc'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '14'

configurations {
    compileOnly {
        extendsFrom annotationProcessor
    }
}

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    implementation 'io.springfox:springfox-boot-starter:3.0.0'
    implementation 'org.apache.poi:poi:4.1.2'
    implementation 'org.apache.poi:poi-ooxml:4.1.2'
    compileOnly 'org.projectlombok:lombok'
    developmentOnly 'org.springframework.boot:spring-boot-devtools'
    runtimeOnly 'mysql:mysql-connector-java'
    annotationProcessor 'org.projectlombok:lombok'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

test {
    useJUnitPlatform()
}


标签: spring

解决方案


推荐阅读