티스토리 뷰

1. 개요
로컬 환경은 Spring Framework와 Tomcat 서버를 기반으로 개발되어 있었으며, 파일 업로드 기능은 MultipartFile을 활용하여 구현되어 있었다.
프로젝트의 서버 환경의 경우 WAS(Web Application Server)를 Tomcat이 아닌 Resin을 사용하는 것을 뒤늦게 확인하였고
이 과정에서 파일 업로드 기능에 문제가 발생하였다.

2. 문제 상황
Resin 서버로 이관 후, 클라이언트에서 전송한 파일이 서버에서 MultipartFile 객체로 정상적으로 매핑되지 않거나,
transferTo() 호출 시 내부적으로 발생하는 권한/호환성 오류로 인해 업로드가 실패하였다.
대표적인 예외 메시지는 다음과 같았다.

java.lang.NullPointerException : null
at cohttp://m.caucho.server.http.MultipartRequest$PartImpl.write(AbstractCauchoRequest.java:xxxx)
at org.springframework.web.multipart.support.StandardMultipartHttpServletRequest$StandardMultipartFile.transferTo(StandardMultipartHttpServletRequest.java:xxx)



3. 원인 분석

Resin 서버가 multipart 처리 과정에서 자체적으로 파일을 기록하려 할 때 문제가 발생.

이는 Resin 내부의 가상 파일 시스템(VFS) 처리 방식과 Spring의 Multipart 처리 방식이 충돌한 것으로 보여짐.


* Resin 의 버전별로 MultipartFile.transferTo() 호환여부

    Resin 4.0.65 및 이전 버전: 호환되지 않음

    Resin 4.0.66 이후 버전: 호환

4. 해결 방안
transferTo() 대신 FileOutputStream을 사용하여 업로드된 파일의 바이트를 직접 저장하는 방식으로 변경함으로써 문제를 해결

5. 적용 코드
기존 소스코드

@PostMapping("/upload")
public String handleFileUpload(@RequestParam("file") MultipartFile file) {
    if (file.isEmpty()) {
        return "업로드할 파일을 선택해주세요.";
    }

    try {
        // 저장할 경로 설정
        String uploadDir = "/data/uploads/";
        String filePath = uploadDir + file.getOriginalFilename();

        // 디렉토리 없을 경우 생성
        File dir = new File(uploadDir);
        if (!dir.exists()) dir.mkdirs();

//MultipartFile의 transferTo 사용
       file.transferTo(filePath);

        return "업로드 성공: " + file.getOriginalFilename();
    } catch (IOException e) {
        e.printStackTrace();
        return "업로드 실패: " + e.getMessage();
    }
}



해결 소스코드

@PostMapping("/upload")
public String handleFileUpload(@RequestParam("file") MultipartFile file) {
    if (file.isEmpty()) {
        return "업로드할 파일을 선택해주세요.";
    }

    try {
        // 저장할 경로 설정
        String uploadDir = "/data/uploads/";
        String filePath = uploadDir + file.getOriginalFilename();

        // 디렉토리 없을 경우 생성
        File dir = new File(uploadDir);
        if (!dir.exists()) dir.mkdirs();

        // FileOutputStream을 통한 수동 저장
        try (FileOutputStream fos = new FileOutputStream(filePath)) {
            fos.write(file.getBytes());
        }

        return "업로드 성공: " + file.getOriginalFilename();
    } catch (IOException e) {
        e.printStackTrace();
        return "업로드 실패: " + e.getMessage();
    }
}
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/04   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30
글 보관함