spring - 异常: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()
}
解决方案
推荐阅读
- java - PayUMoney Android 中的付款时间问题
- html - 动态表格高度超过页面高度
- javascript - 如何将一个模式引用到另一个模式中?
- javascript - 如何在Opera浏览器中打开控制台登录?(javascript问题)
- php - 高山 JS 到 Livewire?
- kotlin - PreferenceActivity 中的 PreferenceDialog - 目标片段必须实现 TargetFragment 接口
- kotlin - Kotlin、RecyclerView、ViewBinding
- graph - “图数据库”或“图算法”和“网络分析”是一回事吗?
- javascript - 为什么我无法在 axios 中读取服务端响应?
- javascript - 如何将数组对象的小写转换为大写