Language/Spring Boot || Spring

Spring Boot에서 base64로 이미지 업로드,다운로드 기능 구현하기

Creeper Park 2024. 2. 17. 22:02

Base64 : 이진데이터를 텍스트(ASCII)로 바꾸거나 (인코딩) 반대 과정(디코딩) 을 처리하는 방법 중 하나이다. 이진 데이터는 6비트씩 묶이는 반면에 ASCII 문자는 8비트로 표현되기 때문에 인코딩 과정 후 텍스트 데이터는 원래 데이터보다 크기가 약 33% 증가한다.

 

Board에 byte[] mediaData 엔티티 추가

@Lob
    @Column(name = "mediaData", columnDefinition="LONGBLOB")
    private byte[] mediaData;

    public void setMediaData(MultipartFile file) {
        try {
            this.mediaData = file.getBytes(); // 이미지 파일을 byte 배열로 변환하여 저장
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

MultipartFile 객체에 getBytes()메소드를 호출하면 파일의 바이트를 추출할 수 있다. 

 

BoardService > saveImg 수정

public void saveImg(Board board, MultipartFile file) throws Exception {
        String projectPath = System.getProperty("user.dir") + "/src/main/webapp/files";
        String fileName = UUID.randomUUID() + "_" + file.getOriginalFilename(); // 파일 이름을 랜덤으로 생성
        String filePath = Paths.get(projectPath, fileName).toString(); // 파일 경로 설정

        // 이미지 파일을 디스크에 저장
        Files.copy(file.getInputStream(), Paths.get(projectPath).resolve(fileName), StandardCopyOption.REPLACE_EXISTING);

        // 엔티티에 파일 이름과 경로 설정
        board.setFilename(fileName);
        board.setFilepath("/files/" + fileName);
        boardRepository.save(board);

    }

java.nio.file.Files.copy(Path source, Path target, CopyOption... options) :  파일을 복사하여 /src/main/webapp/files 에 저장한다.

BoardController > boardwritepro 수정

@PostMapping("/board/writepro")
    public String boardWritePro(Board board, Model model, @RequestParam("file") MultipartFile file) {

        try {
            // 이미지 파일을 byte 배열로 변환하여 엔티티에 저장
            board.setMediaData(file);
            boardService.write(board);
            boardService.saveImg(board,file);
            // 게시글과 이미지 정보를 저장
            boardService.write(board);

            model.addAttribute("message", "글 작성이 완료되었습니다.");
            model.addAttribute("searchUrl", "/board/list");
            return "message";
        } catch (Exception e) {
            model.addAttribute("error", "[ERROR] : 글 작성에 실패했습니다. 이미지 파일 형식이 올바르지 않을 수도 있습니다.");
            return "error";
        }
    }

@RequestParam : 클라이언트가 웹 애플리케이션에 HTTP 요청을 보낼 때 URL에 포함된 쿼리 문자열이나 POST 요청의 바디에 포함된 데이터를 가져올 때 쓰인다.

예를 들어, 다음과 같은 URL이 있다고 가정: http://example.com/api/user?id=123&name=John  

이 경우, @RequestParam을 사용하여 id와 name 파라미터 값을 가져올 수 있다.

BoardController > boardview 수정

@GetMapping("/board/view") // localhost:8080/board/view?id=1
    public String boardView(Model model, Integer id){
        Board board = boardService.boardView(id);
        String base64Image = null;
        if (board.getMediaData() != null) {
            base64Image = Base64.getEncoder().encodeToString(board.getMediaData());
        }
        model.addAttribute("board", board);
        model.addAttribute("base64Image", base64Image);
        return "boardview";
    }

Base64.getEncoder()를 사용하여 데이터를 인코딩할 수 있으며, 그 결과로 Base64.Encoder 객체를 얻을 수 있다. 이 객체는 encodeToString(byte[]) 및 encode(byte[])와 같은 메서드를 호출하여 바이트 배열을 Base64 문자열로 인코딩할 수 있다.

 

boardview.html에 img 태그 추가

<img th:unless="${base64Image}==''"
        th:src="'data:image;base64,' + ${base64Image}"
        alt="이미지" />

th:unless는 타임리프의 조건문 문법으로 base64Image가 빈 값이 아니라면 이미지를 화면상에 출력해준다.