2023 / 09 / 16 해커톤을 진행하면서 이미지를 저장할 일이 있어서 이미지를 저장하는 방법을 알아보고 개발했습니다.
어플리케이션 구조는 React - Spring Boot 였고 이번 포스트에서는 Http로 부터 이미지를 받아오는 방법, Spring jpa에 이미지를 저장하는 방법, 이미지와 Json 데이터를 같이 받아오는 방법을 알아보겠습니다.
주관적인 방식이 들어간 점 양해바랍니다.
프로젝트에서 Review에 대한 정보와 함께 이미지를 받아와야하는 상황이 발생했다.
자바에서 이미지는 MultipartFile 이라는 인터페이스로 받아올 수 있다.
@PostMapping()
public ResponseEntity<JSONObject> createReview(
@RequestPart("body") ReviewDTO reviewDTO,
@RequestPart("images")List<MultipartFile> images
) throws IOException {
logger.info("[ReviewController] create review : {}", reviewDTO.toString() );
JSONObject jsonObject = this.reviewService.createReview(reviewDTO, images);
if(!jsonObject.containsValue("success")){
return ResponseEntity.status(400).body(jsonObject);
}
return ResponseEntity.status(201).body(jsonObject);
}
해당 엔드포인트를 정의한 코드이다.
이미지는 Content-type : multipart/form-data로 받아야 하고 form-data는 key - value와 비슷하다고 생각하면 편하다.
images를 리스트로 받은 이유는 form-data에 같은 키로 이미지를 받는다면 List형태로 압축되서 받을 수 있다.
또한 팁을 주자면 ReviewDTO 처럼 Json 형태의 타입도 받을 수 있다..
이걸 몰라서 처음에는 DTO 요소 하나하나를 form-data key-value로 받았다.
Post Man으로 테스트를 할 때는 body에 form-data를 선택하면되고 json을 보낼 때는 String으로 선택하고 value에 json 형태로 값을 넣으면 된다.
하지만 이렇게 하면 오류가 날것이다.
우측 점세개를 클릭하고 Content Type을 열어서 application/json을 입력해줘야 오류없이 값이 매핑된다..
이걸 몰라서 많이 헤맸다.
여러분들은 헤매지 마시길 바란다.
여기까지 하면 body라는 Key를 가진 값은 DTO로 매핑되고 images라는 Key를 가진 값은 List<MultipartFile>로 매핑된다.
다음은 이미지를 jpa를 이용하여 database에 넣는 방법이다.
@Entity
@Getter
@Setter
@ToString
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class ImageEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false)
@Lob
private byte[] image;
}
여기서는 MultipartFile이 아닌 byte[]로 저장하고 @Lob을 통해 database의 자료형을 정의하여 저장한다.
MultipartFile은 Byte[]로 변환하는 것이 인터페이스 메소드에 정의되어 있기 때문에 그대로 변환하면 된다.
for(MultipartFile multipartFile : multipartFiles){
images.add(this.imageService.upload(multipartFile.getBytes()));
}
이렇게 받은 바이트 배열을 DAO에서 저장하면 된다!
@Override
public ImageEntity upload(ImageEntity imageEntity) {
return this.imageRepository.save(imageEntity);
}
그럼 다시 이미지를 다운로드 하는 방법은 뭘까?
byte[]을 반환하면 된다.
// DB에 저장된 사진을 가져온다.
@GetMapping(value = "/{id}", produces = {MediaType.IMAGE_JPEG_VALUE, MediaType.IMAGE_PNG_VALUE})
public ResponseEntity<?> download(@PathVariable("id") Long id){
try{
byte[] image = this.imageService.download(id);
if(image != null){
logger.info("asd"+image.toString());
return ResponseEntity.status(200).body(image);
}
return ResponseEntity.status(404).body("not found");
}catch (NullPointerException e){
return ResponseEntity.status(404).body("not found");
}
}
여기서 유의할 점은 GetMapping 어노테이션의 produces속성으로 반환값의 타입을 작성해주어야 한다.
Spring Boot에서는 IMAGE_JPEG, IMAGE_PNG, IMAGE_GIF 이렇게 3가지 타입이 있는 것 같다.
Spring jpa로 쉽게 이미지를 저장하고 불러오고 multipart/form-data와 application/json을 함께 받아오는 방법을 알아보았다.
틀린점이나 안되는 것 또는 다른 방법이 있다면 댓글로 알려주면 감사합니다!
'웹' 카테고리의 다른 글
Image 데이터를 RestTemplate로 통신하면서 발생한 에러 (0) | 2023.11.13 |
---|---|
Spring Cloud Eureka란? (0) | 2023.10.30 |
Spring Boot에서 보안을 위한 JWT를 발급하는 방법 (0) | 2023.10.27 |
JWT란? (0) | 2023.10.26 |
Spring Boot를 이용하여 MSA 구조 구현의 어려웠던 점 (0) | 2023.09.05 |