이미지 저장 방식
- 이미지 자체를 DB에 저장하는 방식
-> DB 병목등의 문제
- 경로 저장 방식
-> 다른 저장소에 따로 저장 하고, 해당 주소를 DB에 저장하는 방식
2번 방식을 사용해서 이미지 저장을 구현하기로 결정
Photo 클래스
@Entity
@Getter
@Table(name = "photo")
public class Photo {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "photo_id", nullable = false)
private Long photoId;
@ManyToOne
@JoinColumn(name = "user_id", nullable = false)
private User user;
@Column(name = "file_path", nullable = false)
private String filePath;
@Column(name = "upload_time", nullable = false)
private LocalDateTime uploadTime;
@Column(name = "latitude", nullable = false)
private double latitude;
@Column(name = "longitude", nullable = false)
private double longitude;
@Column(name = "status", nullable = false)
private String status;
@Builder
public Photo(Long photoId, User user, String filePath, LocalDateTime uploadTime, double latitude, double longitude, String status) {
this.photoId = photoId;
this.user = user;
this.filePath = filePath;
this.uploadTime = uploadTime;
this.latitude = latitude;
this.longitude = longitude;
this.status = status;
}
public Photo() {
}
PhotoController 클래스
@PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public ResponseEntity<String> uploadPhoto(@RequestPart("file") MultipartFile file, @ModelAttribute PhotoRequest request) {
try {
UUID id = UUID.fromString(request.getId());
Double latitude = Double.valueOf(request.getLatitude());
Double longitude = Double.valueOf(request.getLongitude());
Long userId = userService.findUserIdById(id);
PhotoDTO photoDTO = photoService.storePhoto(file, userId, latitude, longitude);
return ResponseEntity.ok("File uploaded successfully: " + photoDTO.getFilePath());
} catch (Exception e) {
return ResponseEntity.badRequest().body("Failed to upload file: " + e.getMessage());
}
}
프론트에서 Request Body로 전달해야 할 내용
- file (이미지 파일)
- id (사용자 id)
- latitude (사진찍은 위치의 위도)
- longitude (사진찍은 위치의 경도)
...
더 추가될 가능성 있음!
Swagger에서는 사용 불가. Postman으로 실행해봐야 함
gcloud vision api 사용
설정 & 사용법
- glcoud CLI 설치
gcloud init
- gcloud 명령어 환경변수에 넣기
- 결제 활성화
- 자바 코드 실행
텍스트 추출 결과Text: 닌텐도 40만원 →30만원
텍스트 추출 결과Text: 인기반찬 BEST10 1000 삼계탕 오늘의행사 진미채 10,000원 ->5,000원 1- 234567 8. 9 10 11 12 13 14 15 A 16 17 18 19 20 21 22 23 24 25 26 27 28 29
생각보다 성능이 너무 좋아서, 필요 없는 문자들까지 인식되어버리는 문제가 발생했다.
굳이 텍스트 추출을 해야하나?
이미지 자체를 AI에 넘기면 될 것 같은데
Vertex AI를 사용해보자.
AI로 할인 정보 판단 (쓸데없는 텍스트가 존재할 수 있으므로)
일단은 패스
구현 됐다고 생각하자.
위도: 37.5844, 경도: 127.0587
근처 10KM 내에 존재하는 모든 할인 정보를 JSON 형식으로 응답한다.
@PostMapping
public ResponseEntity<String> uploadPhoto(@RequestPart("file") MultipartFile file, @RequestBody PhotoRequest request) {
try {
UUID id = UUID.fromString(request.getId());
Double latitude = Double.valueOf(request.getLatitude());
Double longitude = Double.valueOf(request.getLongitude());
Long userId = userService.findUserIdById(id);
PhotoDTO photoDTO = photoService.storePhoto(file, userId, latitude, longitude);
return ResponseEntity.ok("File uploaded successfully: " + photoDTO.getFilePath());
} catch (Exception e) {
return ResponseEntity.badRequest().body("Failed to upload file: " + e.getMessage());
}
}
위의 uploadPhoto
메소드를 실행했더니 다음과 같은 오류가 발생했다.
Resolved [org.springframework.web.HttpMediaTypeNotSupportedException:
Content-Type 'multipart/form-data;boundary=--------------------------440780948424522369548408;
charset=UTF-8' is not supported]
위의 오류에 대해서 구글링을 해봤는데, StackOverflow에서 다음과 같은 문구를 발견했다.
In case of MultipartFile you can't use JSON data so you can't use @RequestBody
First Try (실패)
file을 PhotoRequest의 새로운 필드로 넣으면 되지 않을까?
➜@RequestBody
는 데이터를 JSON 형태로 전달받는다.
단순히 내부에 MultipartFile 형태의 필드를 추가했다고해서 해당 값을@RequestBody
로 바인딩 할 수는 없다.
Second Try (성공)
@RequestBody
를@ModelAttribute
로 변경
➜ @ModelAttribute는 multipart/form-data를 포함하여 모든 폼 데이터를 객체에 바인딩할 수 있는 메커니즘을 제공한다.