[Spring] 파일 업로드시 dto도 같이 받고 싶으면 어떻게 할까? / 부제 : @PutMapping에 파일 업로드 해도 되나?
면적면적 개발 도중...궁금한게 생겼다.
이건 북적북적의 책 정보 수정 화면인데, 커버이미지를 수정할 수도 있다.
이런저런 예제를 찾아보다 알게된 사실은
1. 파일업로드시엔 @RequestPart로 한다.
2. 이건 form-data니까 dto를 보낼때도 기존의 @RequestBody가 아니라 @RequestPart를 붙여야한다.
뭐 그래...post 때는 커버이미지가 필수일테니 이럼 되겠거니 하겠는데...
난 지금 수정을 하려는 것이다. 그니까 기존 이미지가 수정될수도 있고 안될 수도 있는데
VIVA 때도 프로필 수정이 이런 로직이었던 것 같아서 코드를 찾아봤다.
// Router
router.post("/", upload.single('profile_img'), (req, res) => {
try {
res.send({ //파일 정보 넘김
message: "upload success",
status: 'success',
data: {
file: req.file
}
});
} catch (err) { //무언가 문제가 생김
res.send({
message: "ERROR",
status: 'fail'
})
}
});
// Update userInfo
//localhost:3001/api/user/profile/samdol
router.put('/:stu_id', function (req, res, next) {
const id = req.params.stu_id;
let body = req.body;
models.student.update({
stu_nick: body.stu_nick,
stu_grade: body.stu_grade,
stu_photo: body.stu_photo
}, {
where: { stu_id: id }
})
.then(num => {
if (num == 1) {
res.send({
message: "UserInfo was updated successfully.",
status: 'success'
});
} else {
res.send({
message: "Data was not found or req.body is empty!",
status: 'fail'
});
}
})
.catch(err => {
res.send({
message: "Error updating UserInfo",
status: 'fail'
});
console.log(err);
});
});
그랬다...당시 아무것도 모르던 나는 이미지 업로드와 프로필 수정을 따로 했었다.
그렇게 혼란속 구글링을 이어나가다가...@RequestPart의 required를 false로 할 수 있다는 것을 알아냈다.
그럼 뭐 null인 경우를 핸들링해주면 이미지를 수정하지 않아도 될 것 같은데 갑자기 이런 생각이 든 것이다.
사진 업로드는 엄밀히 따지면 POST인데 PUT에 해도 되는건가..? 근데 POST와 PUT의 차이점이 정확히 뭐지?
막연히 POST는 추가, PUT은 수정이라고 써오긴 했지만 갑자기 그 둘의 차이가 이거말고 뭔데?라고 생각하니 말이 안나왔다.
그래서 난 파일 업로드에 PutMapping을 쓸 수 있단 걸까?
쓸 수 있을 것 같기도 하고...그래서 일단 하나하나 해보기로 했다.
@PutMapping(value = "/info/{bookId}")
public void bookshelfInfo(@AuthenticationPrincipal User user,
@PathVariable Long bookId,
@RequestPart(required = false) MultipartFile thumbnail,
@Valid @RequestPart BookshelfInfoUpdateReqDto bookshelfInfoUpdateReqDto) {
log.info("[Request] Update book info " + bookId);
log.info("file name = "+thumbnail.getOriginalFilename());
log.info("dto info = "+bookshelfInfoUpdateReqDto.getTitle());
}
대충 이렇게 짜고
날렸는데
오류가 떴다!
이런저런 삽질을 해본 뒤 고쳤다.
여기 dto를 넘기는 부분을 application/json으로 바꾸고
된다!
용량이 맞는 사진이 삼돌이 사진밖에 없어서 어쩌다보니 이걸로 테스트했다. 견상권 침해로 고소당해도 할 말은 없는..
근데 이걸 뺴니까 nullPointerException이 발생한다. required=false를 했는데 왜지?
@PutMapping(value = "/info/{bookId}")
public void bookshelfInfo(@AuthenticationPrincipal User user,
@PathVariable Long bookId,
@RequestPart(required = false) MultipartFile thumbnail,
@Valid @RequestPart BookshelfInfoUpdateReqDto bookshelfInfoUpdateReqDto) {
log.info("[Request] Update book info " + bookId);
if(thumbnail!=null)
log.info("file name = "+thumbnail.getOriginalFilename());
log.info("dto info = "+bookshelfInfoUpdateReqDto.getTitle());
}
아주 기초적인 실수였다.
어쨌든 결론은 PutMapping이어도 required=false 해놓고 넘기면 괜찮다는 것이다.
다만 지금은 아주 기초적인 것만 한거라 s3 버킷에 업로드 해보면서 문제가 생기진 않는지 봐야겠다.