programing

스프링 - 로컬 파일 시스템에 저장하지 않고 대용량 멀티파트 파일 업로드를 데이터베이스로 스트리밍하는 방법

subpage 2023. 3. 15. 19:36
반응형

스프링 - 로컬 파일 시스템에 저장하지 않고 대용량 멀티파트 파일 업로드를 데이터베이스로 스트리밍하는 방법

스프링 부트의 기본 MultiPart Resolver 인터페이스는 로컬 파일 시스템에 저장하여 멀티파트 파일 업로드를 처리합니다.컨트롤러 방식을 입력하기 전에 멀티파트 파일 전체가 서버로의 업로드를 완료해야 합니다.

업로드된 모든 파일을 데이터베이스에 직접 저장하고 서버의 디스크 할당량은 매우 작기 때문에 대용량 파일이 업로드되면IOExeption - Disk quota exceeded.

Spring의 MultiPartResolver가 파일을 로컬 파일 시스템에 저장하기 전에 클라이언트의 수신 요청에서 직접 스트림을 가져와 직접 db로 스트리밍할 수 있는 방법이 있습니까?

https://commons.apache.org/proper/commons-fileupload/streaming.html에서 설명한 바와 같이 Apache를 직접 사용할 수 있습니다.

@Controller
public class UploadController {

    @RequestMapping("/upload")
    public String upload(HttpServletRequest request) throws IOException, FileUploadException {

        ServletFileUpload upload = new ServletFileUpload();

        FileItemIterator iterator = upload.getItemIterator(request);
        while (iterator.hasNext()) {
            FileItemStream item = iterator.next();

            if (!item.isFormField()) {
                InputStream inputStream = item.openStream();
                //...
            }
        }
    }
}

스프링 멀티파트 해결 메커니즘을 비활성화해야 합니다.

application.yml:

spring:
   http:
      multipart:
         enabled: false

사실 그것은 사소한 일이 아니다.클라이언트에서 데이터베이스로 스트림을 직접 쓰려면 요청을 수동으로 처리해야 합니다.이 작업을 단순화할 수 있는 라이브러리가 몇 개 있습니다.그 중 하나가 "Apache Commons FileUpload"입니다.다음의 매우 간단한 예에서는, 착신을 처리하는 방법을 설명합니다.multipart/form-data이 라이브러리의 요청입니다.

@Controller
public class Controller{

    @RequestMapping("/upload")
    public String upload(HttpServletRequest request){
        
        String boundary = extractBoundary(request);

        try {
            MultipartStream multipartStream = new MultipartStream(request.getInputStream(), 
                boundary.getBytes(), 1024, null);
            boolean nextPart = multipartStream.skipPreamble();
            while(nextPart) {
                String header = multipartStream.readHeaders();

                if(header.contains("filename")){
                    //if input is file
                    OutputStream output = createDbOutputStream();
                    multipartStream.readBodyData(output);
                    output.flush();
                    output.close();
                } else {
                    //if input is not file (text, checkbox etc)
                    ByteArrayOutputStream output = new ByteArrayOutputStream();
                    multipartStream.readBodyData(output);
                    String value = output.toString("utf-8");
                    //... do something with extracted value
                }
                nextPart = multipartStream.readBoundary();
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }    
    }

    private String extractBoundary(HttpServletRequest request) {
        String boundaryHeader = "boundary=";
        int i = request.getContentType().indexOf(boundaryHeader)+
            boundaryHeader.length();
        return request.getContentType().substring(i);
    }    
}

파일 필드의 헤더는 다음과 같습니다.

Content-Disposition: form-data; name="fieldName"; filename="fileName.jpg"
Content-Type: image/jpeg

단순 필드의 헤더는 다음과 같습니다.

Content-Disposition: form-data; name="fieldName";

참고로 이 스니펫은 방향을 나타내는 단순한 예에 불과합니다.헤더에서 필드 이름을 추출하거나 데이터베이스 출력 스트림을 작성하는 등의 세부 사항은 없습니다.이 모든 것을 직접 구현할 수 있습니다.RFC 1867에서 볼 수 있는 멀티파트 요청 필드 헤더의 예.에 대해서multipart/form-data RFC2388.

언급URL : https://stackoverflow.com/questions/37870989/spring-how-to-stream-large-multipart-file-uploads-to-database-without-storing

반응형