본문 바로가기
Projects/청하-청년을 위한 커뮤니티 서비스

[청하] 6. 게시글 등록 기능 - @ModelAttribute를 이용한 form-data 처리 개선

by Lpromotion 2024. 10. 7.

지난번에는 @RequestPart 를 사용하여 JSON 데이터와 파일 데이터를 분리하여 처리하도록 변경했었다. 이번에는 텍스트 데이터와 파일 데이터를 모두 multipart/form-data로 요청하는 것이 더 편할 것 같다는 Android 팀원의 의견에 따라 수정하기로 했다.

그리고 파일 업로드도 선택적으로 할 수 있도록 파일 처리 로직을 수정하였다.

 

1. 컨트롤러 수정

기존 코드

@RestController
@RequiredArgsConstructor
@RequestMapping("/api/v1/posts")
public class PostController {
    private final PostService postService;

    // 게시글 등록
    @PostMapping("/register")
    public ResponseDto<PostRegisterResponseDto> registerPost(@UserId Long userId,
                                                             @Valid @RequestPart("postRegisterRequest") PostRegisterRequestDto postRegisterRequestDto,
                                                             @RequestPart("imageFiles") List<MultipartFile> imageFiles) {
        Long postId = postService.registerPost(userId, postRegisterRequestDto, imageFiles);
        return ResponseDto.ok(new PostRegisterResponseDto(postId));
    }
}

 

수정 코드

@RestController
@RequiredArgsConstructor
@RequestMapping("/api/v1/posts")
public class PostController {
    private final PostService postService;
    // 게시글 등록
    @PostMapping(value = "/register", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    public ResponseDto<PostRegisterResponseDto> registerPost(@UserId Long userId,
                                                             @Valid @ModelAttribute("postRegisterRequest") PostRegisterRequestDto postRegisterRequestDto,
                                                             @RequestPart(value = "imageFiles", required = false) List<MultipartFile> imageFiles) {
        List<MultipartFile> file = Optional.ofNullable(imageFiles).orElse(Collections.emptyList());
        Long postId = postService.registerPost(userId, postRegisterRequestDto, file);
        return ResponseDto.ok(new PostRegisterResponseDto(postId));
    }
}

 

@PostMapping 어노테이션에 속성 추가

consumes 속성 추가

consumes = MediaType.MULTIPART_FORM_DATA_VALUE 를 지정하여 이 엔드포인트가 multipart/fom-data 형식의 요청만 처리하도록 했다.

클라이언트는 반드시 multipart/foma-data 형식으로만 요청해야하고, 다른 형식의 요청은 “415 Unsupported Media Type” 에러를 반환한다.

 

@ModelAttribute 사용

@Valid @ModelAttribute("postRegisterRequest") PostRegisterRequestDto postRegisterRequestDto

@ModelAttribute 는 multipart/form-data 요청의 필드들을 자동으로 객체의 속성에 바인딩한다. “title” 필드는 PostRegisterRequestDto의 title 속성에 자동으로 매핑된다.

클라이언트에서 form-data 형식으로 모든 데이터를 전송할 수 있고, @RequestPart와 다르게 JSON 파싱 과정이 필요없어서 구현이 좀 더 간단해진다.

 

파일 처리 로직 개선

@RequestPart(value = "imageFiles", required = false) List<MultipartFile> imageFiles

required = false로 변경해 파일 업로드를 선택 사항으로 만들었다.

 

List<MultipartFile> file = Optional.ofNullable(imageFiles).orElse(Collections.emptyList());

파라미터 부분에서 imageFiles는 null 이 되는 경우도 허용하도록 설정했기 때문에, NullPointerException이 발생하지 않아야 한다. 그래서 imageFIles가 null 이면 빈 리스트를 서비스에 넘겨주도록 구현했다.

 


위와 같이 수정하면 텍스트 데이터와 파일 데이터 모두 multipart/form-data 형식으로 요청할 수 있고, 요청된 파일이 없는 경우에는 빈 리스트를 가지고 서비스 로직을 수행할 수 있다.

반응형

댓글