일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 | 31 |
- 백준#BOJ#1939#중량제한
- 백준#BOJ#12865#평범한배낭
- 백준#BOJ#14501#퇴사#브루트포스
- 백준#boj#16932#모양만들기
- 백준#boj#12755
- 백준#BOJ#8012#한동이는영업사원
- 백준#BOJ#2615#오목
- Today
- Total
순간을 성실히, 화려함보단 꾸준함을
인텔리제이 .http 파일로 MultipartFile 전송해보기 본문
안녕하세요!
글또 활동을 마치고 처음 적는 글입니다
오늘은 아무리 구글링해도 알 수 없어서 제가 직접 하나하나 고생하면서 알아낸 Tip(?) 을 ㅋㅋㅋㅋㅋ 적어보려고 합니다.
제목 처럼 인텔리제이에서 .http 파일을 사용하여 http 요청을 보낼 수 있습니다.
IntelliJ의 .http를 사용해 Postman 대체하기 (tistory.com)
유명한 블로그이시자 개발바닥 채널을 운영하고 계시는 향로님의 글인데 이 글을 읽기전에 참고하시면 좋을 것 같습니다.
배경
사이드 프로젝트를 진행 도중에 image 파일을 업로드하는 API 를 테스트 해야됐습니다.
postman 을 사용하여 테스트 했을땐 문제없이 원하는 바로 동작을 했습니다.
그 다음 .http 파일을 생성하여 인텔리제이에서 동일하게 해당 API 를 테스트 하려고 했지만,,,,,file 은 어떻게 요청을 보내야지???? 라는 의문점과 같이 열심히 구글링을 했지만 정확히 어떤식으로 정의해야 할지 모르겠더라고요...
과정
1. postman 으로 요청 정상 확인
@Slf4j
@RestController
@RequiredArgsConstructor
@RequestMapping("/api/user")
public class UserController {
private final UserService userService;
...
/**
* 유저 프로필 사진 업로드(U002)
*/
@PostMapping("/profile/image")
public CommonResponseEntity<UserProfileImageResponseDTO> uploadProfileImage(
@Authentication LoginSession session,
@ModelAttribute @Valid UserProfileImageRequestDTO imageDTO){
return CommonResponseEntity.toResponseEntity(
ResponseType.U002,userService.saveProfileImage(session,imageDTO),1);
}
}
유저의 프로필 사진을 업로드 하는 API 가 존재합니다.
(LoginSession 은 무시해주세요!!!)
@Setter
@Getter
@NoArgsConstructor
public class UserProfileImageRequestDTO {
@ValidFile(message = "EXU005")
private MultipartFile file;
public UserProfileImageRequestDTO(MultipartFile file) {
this.file = file;
}
}
request dto 는 MultipartFile 객체 하나만 받고 있습니다.
※@ModelAttribute
@ModelAttribute 의 동작 방식을 재대로 이해하지 못하는 분들이 꽤 계시는데 @NoArgsConstructor 어노테이션을 사용한다면 반드시 @Getter 와 @Setter 가 필수적입니다.
HandlerMethodArgumentResolver 를 implements 하는 ModelAttributeProcessor 는 기본생성자를 통해 객체를 생성하고 setter 를 이용하여 데이터를 바인딩 해주기 때문입니다.
그럼 무조건 위와 같은 방식으로만 동작하는건가요?!!!
절대!! 아닙니다.
@NoArgsConstructor 가 아닌 @AllArgsConstructor 를 사용한다면 @Setter는 강제되지 않습니다.
더 많은 정보를 얻고 싶으신 분들은 [Spring] @ModelAttribute 처리 흐름 (tistory.com) 해당 블로그를 참고해주세요!
해당 프로젝트를 실행시키고 postman 으로 한번 요청을 보내봅시다 !
위와 같이 요청을 보낸 후 controller 에서 breaking point 를 걸어서 확인해보면
정상적으로 잘 요청이 온 걸 확인할 수 있습니다
2. .http 파일을 사용해보기
이제 문제의 .http 파일을 이용하여 MultipartFile 을 요청보내보도록 해봅시다.
Exploring the HTTP request syntax | IntelliJ IDEA Documentation (jetbrains.com)
jetbrain 공식홈페이지에 나와있는 공식문서를 참고하였습니다.
To send a file as part of the multipart/form-data message, include the filename parameter in the Content-Disposition header.
파일을 포함한 multipart/form-data 를 요청할때는 Content-Disposition header 에 filename 파라미터를 정의하라고 하네요!
그리고 각 파라미터는 boundary 로 구분이 되어져야 합니다!
(주의할 점은 마지막 boundary 는 끝에 -- 문자를 추가해주어서 끝이라는걸 알려주어야 합니다)
이렇게 정의하고 요청을 보내면?
마찬가지로 정상적으로 들어오는걸 확인할 수 있었습니다.
지금은 file 하나만 요청받고 있는데 만약 다른 변수들과 같이 전송할때는 어떻게 해야 될까요????
위에 기술했듯이 boundary 로 구분해 준 후 Content-Disposition header 에 파라미터명을 정의해주면 됩니다.
예시로 하나의 게시글에는 이미지를 포함한 게시글 제목, 게시글 내용 등등 많은 컨텐츠들이 들어갈 수 있겠죠?
위와 같이 정의해주면 됩니다!
3. postman 요청은 되는데 .http 요청은 안돼요!!!!
이번 게시글의 핵심인데요, 사실 저는 공식문서를 참고하지 않고 문제를 해결했었습니다.
postman 으로는 잘 들어가는데 .http 파일에서는 어떻게 정의해서 요청을 보내야 될지 잘 몰랐거든요.....
그래서 제가 선택한 방법은 Content-Type 이 multipart/form-data 일때 http request message 을 확인해보자!!!!였습니다.
바로 Http11InputBuffer 를 사용해서 말이죠.
Http11InputBuffer 가 뭔데요?????
Http11InputBuffer 란?
- tomcat 웹 서버 컨테이너에서 사용되는 클래스로 Http 요청의 본문 데이터를 읽어오는 역할을 수행합니다.
기능
1. 클라이언트로부터 Http request message 를 파싱하여 요청 라인, 헤더 및 본문 데이터로 분리합니다.
2. 요청 본문을 처리합니다. Post , Put 과 같은 요청이 해당되겠네요
3. 클라이언트가 멀티파트 형식으로 파일을 업로드 하면 해당 파일 데이터를 처리하고 저장합니다.
즉, Http11InputBuffer 를 통해서 요청받는 http message 가 어떤형식으로 들어오는지 확인할 수 있다는 걸 뜻합니다.
Http11InputBuffer 라는 존재를 알았으니 이를 활용하여 우리가 직접 http request message 를 확인해봐야겠죠?
loggin level 에서 debug 모드로 설정한다면 console 창에 확인할 수 있습니다.
자, 그러면 요청을 보내볼까요?
console 창에 잘 나오는걸 확인할 수 있었습니다.
그래서 전 인텔리제이 .http 에서 위와 같은 message 를 확인하여 동일하게 적용해주어서 해결할 수 있었습니다.
결과
배울 수 있었던 점이 많았던 귀한 경험이었습니다.
1. @ModelAttribute 동작방식
2. 인텔리제이 .http 를 이용하여 multipart/form-data 를 요청보내는 방법
3. Http11InputBuffer
혹시 다른분들도 저와 비슷한 문제를 마주하셨다면 위 글이 도움이 되셨으면 좋겠네요
감사합니다!
'나의 개발 메모장' 카테고리의 다른 글
동시성 문제에 관하여... (0) | 2023.12.10 |
---|---|
MultipartFile 은 어떻게 validation 체크를 해야할까?(ConstraintValidator.class) (0) | 2023.09.03 |
글또 8기를 마치며 (4) | 2023.07.16 |
wsl+docker 를 사용한 spring boot + Redis 사용하기!! (0) | 2023.06.11 |
Http method 에 따라 동일한 URI 를 다르게 처리하는 방법 (0) | 2023.06.03 |