[Web 게시판] MultipartFile로 게시판 첨부파일 업로드 | MultipartFile

2025. 2. 12. 13:42·Spring/웹 게시판

🔍 1. Multipart란?

  • Multipart는 웹 요청에서 여러 부분(part)을 포함하는 데이터 형식으로 하나의 요청에 여러 개의 데이터를 포함시킬 수 있는 방식입니다. (텍스트 데이터 (text/plain, application/json) + 파일 데이터 (image/png, application/pdf 등)
  • 보통 파일 업로드와 같이 여러 가지 정보를 함께 전송할 때 사용됩니다.
  • HTTP에서 multipart/form-data는 파일 업로드를 지원하는 특수한 content-type입니다.
    이 방식은 폼데이터와 파일을 한 번에 서버로 보내는 데 사용됩니다.

이 방식으로 텍스트 데이터(json)와 파일 데이터를 각각 분리해서 처리할 수 있도록 해주는 것입니다!

 

🔍 2. MultipartFile은?

  • MultipartFile은 Spring에서 제공하는 인터페이스로, 클라이언트로부터 전송된 파일을 다루기 위해 사용됩니다.
  • MultipartFile 객체는 파일의 내용, 이름, 크기, MIME 타입 등을 다룰 수 있는 메서드를 제공해줍니다.
  • Spring MVC에서 @RequestParam 또는 @RequestPart와 함께 사용되어 클라이언트에서 업로드한 파일을 서버에서 받을 수 있게 됩니다.
getName(): 업로드된 파일의 이름을 반환
getOriginalFilename(): 원본 파일명을 반환
getSize(): 파일의 크기를 반환 (byte 단위)
getContentType(): 파일의 MIME 타입(예: image/png)을 반환
getBytes(): 파일 내용을 바이트 배열로 반환
getInputStream(): 파일을 읽을 수 있는 InputStream을 반환

 

🎯 3. MultipartFile로 게시판에 첨부파일 업로드 해보기

  • File 엔티티- 첨부파일 관리를 위한 엔티티와 DTO 설계(추후에 다중 첨부 파일 관리를 편하게 하려고)
  • Post service 수정 - 작성 시 첨부파일 첨부 기능 추가
  • Post 작성 controller 수정

(1) PostFile Entity

PostFile 엔티티는 파일의 메타데이터를 저장합니다.

데이터베이스에서 파일 정보를 저장하는 엔티티로, 파일의 이름, 경로를 저장하도록 합니다.

(게시글의 Id는 다중 파일 첨부를 위해 외래키로 가져오도록 한 것입니다!!)

@Entity(name = "filepost")
@Getter @Setter
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class PostFile {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name="post_id")
    private Post post;

    private String filename;

    private String filepath;
}

 

(2) Post 작성 서비스 수정

  • 파일 업로드 처리: 파일을 업로드한 후, PostFile 엔티티로 저장하는 과정
  • 파일 삭제 처리: 파일이 삭제될 때, 관련된 데이터베이스의 파일 정보를 삭제하고, 서버에서 실제 파일도 제거하는 로직
    (파일 삭제는 추후 구현)
@Transactional
    public Long write(String nickname, PostDto.Request postDto, MultipartFile file) {

        User user = userRepository.findByNickname(nickname);
        postDto.setUser(user);
        log.info("write post 실행");
        Post post = postDto.toEntity();
        postRepository.save(post);


        if(file!=null && !file.isEmpty()) {
            try {
                //파일 저장 경로
                String uploadDir = System.getProperty("user.dir") + "/src/main/resources/static/files/";
                String filePath = uploadDir + file.getOriginalFilename();

                File dest = new File(filePath);
                file.transferTo(dest);

                PostFile postFile = PostFile.builder()
                        .post(post)
                        .filename(file.getOriginalFilename())
                        .filepath(filePath)
                        .build();

                postFileRepository.save(postFile);
            }catch (IOException e) {
                log.error("파일 저장 오류 발생", e);
                throw new RuntimeException("파일 저장 실패");

            }
        }

        return post.getId();
    }

 

사실 파일 저장 경로를 저렇게 하드코딩하지 않는 것이 좋겠지만, 흐름을 파악하기 위해 따로 남겨두었습니다.

 

if문부터 참고하면, Post 작성 시 첨부파일이 첨부되지 않아도 Post 저장은 되어야 하므로 

실제 파일이 업로드된 경우에만 파일 저장을 진행하도록 합니다.

File dest = new File(filePath);
file.transferTo(dest);

 

위 코드는 파일을 저장할 경로와 파일명을 지정한 File 객체를 생성하고 업로드된 파일을 지정한 경로로 저장하는 부분입니다.

❗그러나, file.getOriginalFilename()을 그대로 사용하면 같은 이름의 파일이 업로드될 경우 덮어쓰기 문제가 발생할 수 있습니다. -> UUID를 추가하여 파일명을 변경하는 것이 더 안전합니다.

 

PostFile postFile = PostFile.builder()
        .post(post)
        .filename(file.getOriginalFilename())
        .filepath(filePath)
        .build();

postFileRepository.save(postFile);

 

파일 정보를 저장할 PostFile 엔티티를 생성하여 파일 정보를 DB에 저장합니다.

 

(4) Post 작성 Controller 수정

 

> 이전 RestController

@PostMapping("/api/post/writePro")
public ResponseEntity<Long> write(
        @RequestBody @Valid PostDto.Request postDto, 
        @LoginUser UserDto.Response userDto) {

    Long postId = postService.write(userDto.getNickname(), postDto);
    return ResponseEntity.ok(postId);
}

 

이전에는 Post 작성 폼에서 받은 입력 데이터를 json으로 변환하기 위해 @RequestBody로 PostDto.Request를 받도록 설계했지만,

MultipartFile 데이터를 받기 위해서는 @RequestBody가 아닌 multipart/form-data로 받아야 합니다.

 

> MultipartFile을 받도록 수정한 RestController

@PostMapping(value = "/api/post/writePro", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public ResponseEntity<Long> write(
        @RequestPart("post") @Valid PostDto.Request postDto, 
        @RequestPart(value = "file", required = false) MultipartFile file,
        @LoginUser UserDto.Response userDto) {

    Long postId = postService.write(userDto.getNickname(), postDto, file);
    return ResponseEntity.ok(postId);
}

 

@RequestPart : multipart/form-data 요청에서 JSON 데이터(post 필드)와 파일(file 필드)을 함께 받을 수 있습니다.

(파일이 없을 수도 있으므로 required = false 설정하여 파일 첨부 없이도 글 작성 가능하게 만듦)

https://gaeran.tistory.com/59

 

@RequestPart 알아보기

📌1.  @RequestPart란?@RequestPart는 멀티파트 요청 (multipart request) 에서 특정 파일이나 JSON 데이터를 개별적으로 매핑할 때 사용되는 Spring MVC의 어노테이션입니다.2. @RequestParam vs @RequestBody vs @RequestPart

gaeran.tistory.com

 

 

📝 프론트엔드 요청 예시

POST /api/post/writePro
Content-Type: multipart/form-data

------WebKitFormBoundary
Content-Disposition: form-data; name="post"
Content-Type: application/json

{
  "title": "게시글 제목",
  "content": "게시글 내용",
  "category": "공지",
  "writer": "사용자1"
}

------WebKitFormBoundary
Content-Disposition: form-data; name="file"; filename="example.jpg"
Content-Type: image/jpeg

(바이너리 파일 데이터)
------WebKitFormBoundary--

 

'Spring > 웹 게시판' 카테고리의 다른 글

[Web 게시판] 게시글 관리 설계 | 게시글 조회수 카운팅  (0) 2025.01.30
[Web 게시판] 회원 관리 설계 | User 엔티티 설계와 비즈니스 로직  (0) 2025.01.18
[Web 게시판] DB 설계 및 Entity 구성  (2) 2025.01.02
'Spring/웹 게시판' 카테고리의 다른 글
  • [Web 게시판] 게시글 관리 설계 | 게시글 조회수 카운팅
  • [Web 게시판] 회원 관리 설계 | User 엔티티 설계와 비즈니스 로직
  • [Web 게시판] DB 설계 및 Entity 구성
힐안
힐안
나 지금 학비 내면서 개발 독학하잖아.
  • 힐안
    후라이
    힐안
  • 전체
    오늘
    어제
    • 분류 전체보기 (59)
      • HTTP (9)
      • Spring (28)
        • 웹 게시판 (4)
      • Neural Network (1)
        • CNN (1)
        • RNN (0)
      • Deep Learning (6)
      • Audio (3)
      • 알고리즘(JAVA) (2)
      • 백준 (10)
        • Bronze (0)
        • Silver (2)
        • Gold (8)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    스프링부트
    Genrative_model
    JSON
    web
    API
    백준
    MVC
    dcgan
    오블완
    프레임워크
    비지도학습
    웹
    HTTP
    springboot
    플로이드와샬
    MNIST
    다익스트라
    딥러닝
    벨만포드
    티스토리챌린지
    백엔드
    최단경로알고리즘
    GAN
    자바
    Spring
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
힐안
[Web 게시판] MultipartFile로 게시판 첨부파일 업로드 | MultipartFile
상단으로

티스토리툴바