1

tech stack: Java 14, Spring Boot 2.5.3, MySQL 8.0.26, JPA

I'v got a spring boot uploading Excel web application. Excel file with 14KB capacity was uploaded successfully. However, if you try to upload an Excel file with 15MB and 50MB capacity, the following exception occurs.

I guess that server connection timed out when uploading. I guess the server to be closed before file is uploaded due to the short server connection time. To solve this problem, I tried to change the server settings in application.properties. I found some property. But it was not proper. The IDE underlines like this. I also visited Spring Common Application Properties Page to find the appropriate property, but I couldn't find it.

I would like to know what causes the exception. And I wonder if this is the right way to solve the problem.

Thank you in advance. If you reply, I will reply as soon as possible.

exception console

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 ...

application.properties

server.tomcat.connection-timeout is right. But server.tomcat.disable-upload-timeout and server.connectionUploadTimeout are not proper.

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

controller

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

service

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

build.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()
}


1 Answer 1

2

I had similar error and updated the following configuration parameters in the application.properties file like so:

spring.servlet.multipart.max-file-size=XX MB
spring.servlet.multipart.max-request-size=XX MB
server.tomcat.connectionUploadTimeout=XXX (in miliseconds)
server.tomcat.connectionTimeout=XXX (in miliseconds)
server.tomcat.connection-timeout=XXX (in miliseconds)
server.tomcat.max-swallow-size=XX MB
server.tomcat.max-http-form-post-size=XX MB

server.tomcat.background-processor-delay=XXX (in miliseconds)
server.tomcat.keep-alive-timeout=XXX (in miliseconds)

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

Setting these parameters like shown should solve the problem.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.