본문 바로가기
Frameworks/SPRING

JAVA SPRING 파일 업로드 기능 구현하기

by 달팽이 "@... 2022. 2. 18.

많은 레퍼런스들을 참고하여 고민하며 구현한 코드지만 저 스스로도 취업준비생인 초보 개발자이기 때문에 코드 상의 문제 혹은 더 바람직한 우수사례들이 있을 수 있습니다.  코드 작성 시 참고 정도로 활용해주시고 문제나 개선 가능한 부분 발견 시 공유해주신다면 감사하겠습니다.

 

CONTROLLER


    @PostMapping("create")
    public String createPost(MultipartHttpServletRequest mtfRequest, BoardVO boardVO) {

        // 게시글 저장
        boardService.create(boardVO);

        // 업로드 파일이 존재할 때
        if (mtfRequest != null) {

            // 파일(들)을 지정된 경로에 저장하고 데이터베이스에 기록될 경로(들)을 ArrayList로 반환
            List<String> fileDirs = UploadFileUtils.fileUpload(mtfRequest);

            // file 데이터를 담을 VO 생성
            FileVO fileVO = new FileVO();

            // fileDirs 리스트를 순회하며 vo에 데이터를 담기
            for (String fileDir : fileDirs) {

                // board의 insert 수행 후 자동생성된 bno가 담긴 boardVO의 멤버변수 bno 가져오기
                int bno = boardVO.getBno();

                // fileVO 객체에 데이터 채우기
                fileVO.setBno(bno);
                fileVO.setFile(fileDir);

                // 데이터베이스에 저장
                fileService.save(fileVO);
            }

        } else {
            System.out.println("첨부 파일이 없습니다.");
        }

        return "redirect:/board";
    }

 

 

UploadFileUtils


public class UploadFileUtils {

    public static List<String> fileUpload(MultipartHttpServletRequest mtfRequest) {

        // multipartFile 리스트
        List<MultipartFile> mtfs = mtfRequest.getFiles("image");

        // 데이터베이스에 기록되는 경로를 담을 리스트
        List<String> fileList = new ArrayList<>();

        for (MultipartFile mtf : mtfs) {

            // 파일 이름
            String originalFileName = mtf.getOriginalFilename();

            // 업로드 경로
            String uploadPath = mtfRequest.getSession().getServletContext().getRealPath(File.separator + "uploadedImages" + File.separator);

            // 조회시 과부하를 막기 위한 경로 구분용 현재 날짜를 yyyyMMdd 형태로 반환받기
            String date = getTodayDate();

            // 파일 이름 중복문제를 해결하기 위한 UUID
            String uuid = UUID.randomUUID().toString();

            // 데이터베이스에 기록될 경로 형태
            // 현재날짜 + UUID + "_" + 파일
            String dbFile = date + uuid + "_" + originalFileName;

            // 파일 저장 경로
            String saveFile = uploadPath + dbFile;

            // 위에서 생성했던 리스트에 파일 이름 담기
            fileList.add(dbFile);

            try {
                // 파일 경로에 저장하기
                mtf.transferTo(new File(saveFile));

            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        return fileList;  // 파일 리스트 반환

    }

    private static String getTodayDate() {

        // Calendar 객체 생성
        Calendar cal = Calendar.getInstance();

        // 날짜 담을 변수
        String datePath;

        // 날짜 + 세퍼레이터 스트링
        datePath = String.format("%04d%02d%02d%s", cal.get(Calendar.YEAR), cal.get(Calendar.MONTH) + 1, cal.get(Calendar.DAY_OF_MONTH), File.separator);

        return datePath;
    }
}

 

 

BoardMapper.xml (Insert 부분)

    <insert id="insert" parameterType="BoardVO">

        -- file 테이블의 외래키로 사용될 bno를 반환받아 BoardVO에 담김
        <selectKey keyProperty="bno" resultType="int" order="BEFORE">
            select QUE_SEQUENCE.NEXTVAL from dual
        </selectKey>

        INSERT INTO BOARD (bno, title, content, writer)
        VALUES (#{bno}, #{title}, #{content}, #{writer})
    </insert>

ORACLE을 사용중이기 때문에 별도의 SEQUENCE를 생성했으므로 selectKey 태그를 사용했습니다.

MySQL이나 MS_SQL을 사용할 경우 링크(https://roqkffhwk.tistory.com/180) 참고하셔서 작성하시길 바랍니다.