diff --git a/emopic/src/main/java/mmm/emopic/app/domain/category/repository/CategoryRepositoryImpl.java b/emopic/src/main/java/mmm/emopic/app/domain/category/repository/CategoryRepositoryImpl.java index 3b6bef0..325193f 100644 --- a/emopic/src/main/java/mmm/emopic/app/domain/category/repository/CategoryRepositoryImpl.java +++ b/emopic/src/main/java/mmm/emopic/app/domain/category/repository/CategoryRepositoryImpl.java @@ -1,6 +1,7 @@ package mmm.emopic.app.domain.category.repository; import com.querydsl.core.Tuple; +import com.querydsl.core.types.dsl.BooleanExpression; import com.querydsl.jpa.impl.JPAQueryFactory; import lombok.RequiredArgsConstructor; import mmm.emopic.app.domain.category.repository.CategoryRepositoryCustom; @@ -8,6 +9,7 @@ import java.util.List; +import static mmm.emopic.app.domain.category.QCategory.category; import static mmm.emopic.app.domain.category.QPhotoCategory.photoCategory; @Repository @@ -18,13 +20,24 @@ public class CategoryRepositoryImpl implements CategoryRepositoryCustom { @Override public List getMostCategory(Long size) { + Long defaultId = queryFactory.select(category.id).from(category) + .where(eqDefault()) + .fetchFirst(); + + List queryResults = queryFactory .select(photoCategory.category.id, photoCategory.category.id.count()) .from(photoCategory) .groupBy(photoCategory.category.id) + .having(photoCategory.category.id.ne(defaultId)) .orderBy(photoCategory.category.id.count().desc()) .limit(size) .fetch(); return queryResults; } + + private BooleanExpression eqDefault(){ + return category.name.eq("default"); + } + } diff --git a/emopic/src/main/java/mmm/emopic/app/domain/location/LocationController.java b/emopic/src/main/java/mmm/emopic/app/domain/location/LocationController.java index e3f2b6c..55ff246 100644 --- a/emopic/src/main/java/mmm/emopic/app/domain/location/LocationController.java +++ b/emopic/src/main/java/mmm/emopic/app/domain/location/LocationController.java @@ -72,5 +72,12 @@ public ResponseEntity getPhotoByCity(){ List response = locationService.getPhotoByCity(); return ResponseEntity.ok(new BaseResponse( HttpStatus.OK.value(), "지역별 대표 사진 조회 완료", response)); } - + @GetMapping("/locations/city/photos") + @Operation(summary = "지역의 전체 사진 조회", responses = { + @ApiResponse(responseCode = "200", description = "지역의 전체 사진 조회 완료", content = @Content(schema = @Schema(implementation = PageResponse.class))) + }) + public ResponseEntity getAllPhotoOfCity(@Param("city") String city, @PageableDefault(page = 0, size = 20, sort="snapped_at",direction = Sort.Direction.DESC) Pageable pageable){ + PageResponse response = locationService.getAllPhotosByCity(city,pageable); + return ResponseEntity.ok(new BaseResponse( HttpStatus.OK.value(), String.format("%s의 전체 사진 조회 완료",city), response)); + } } diff --git a/emopic/src/main/java/mmm/emopic/app/domain/location/LocationService.java b/emopic/src/main/java/mmm/emopic/app/domain/location/LocationService.java index c3d345f..5996993 100644 --- a/emopic/src/main/java/mmm/emopic/app/domain/location/LocationService.java +++ b/emopic/src/main/java/mmm/emopic/app/domain/location/LocationService.java @@ -1,18 +1,33 @@ package mmm.emopic.app.domain.location; import lombok.RequiredArgsConstructor; +import mmm.emopic.app.domain.category.Category; +import mmm.emopic.app.domain.category.PhotoCategory; +import mmm.emopic.app.domain.category.repository.CategoryRepository; +import mmm.emopic.app.domain.category.repository.PhotoCategoryRepository; +import mmm.emopic.app.domain.emotion.Emotion; +import mmm.emopic.app.domain.emotion.PhotoEmotion; +import mmm.emopic.app.domain.emotion.repository.EmotionRepository; +import mmm.emopic.app.domain.emotion.repository.PhotoEmotionRepository; import mmm.emopic.app.domain.location.dto.response.CityResponse; import mmm.emopic.app.domain.location.dto.response.LocationPhotoResponse; import mmm.emopic.app.domain.location.dto.response.LocationPointResponse; import mmm.emopic.app.domain.location.dto.response.LocationRecentResponse; import mmm.emopic.app.domain.photo.Photo; import mmm.emopic.app.domain.photo.dto.response.KakaoCoord2regionResponse; +import mmm.emopic.app.domain.photo.dto.response.PageResponse; +import mmm.emopic.app.domain.photo.dto.response.PhotosInformationResponse; import mmm.emopic.app.domain.photo.repository.PhotoRepositoryCustom; import mmm.emopic.app.domain.photo.support.KakaoMapAPI; +import mmm.emopic.exception.ResourceNotFoundException; import org.locationtech.jts.geom.Point; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageImpl; +import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; @@ -20,7 +35,10 @@ @RequiredArgsConstructor @Transactional(readOnly = true) public class LocationService { - + private final CategoryRepository categoryRepository; + private final EmotionRepository emotionRepository; + private final PhotoEmotionRepository photoEmotionRepository; + private final PhotoCategoryRepository photoCategoryRepository; private final PhotoRepositoryCustom photoRepositoryCustom; private final KakaoMapAPI kakaoMapAPI; @@ -50,4 +68,27 @@ public List getPhotoByCity() { List result = photoRepositoryCustom.findPhotosGroupByCity(); return result.stream().map(photo -> new CityResponse(photo)).collect(Collectors.toList()); } + + public PageResponse getAllPhotosByCity(String city, Pageable pageable) { + + Page result = photoRepositoryCustom.findAllPhotosByCity(city,pageable); + List photosInformationResponseList = new ArrayList<>(); + for(Photo photo: result) { + List photoCategoryList = photoCategoryRepository.findByPhotoId(photo.getId()); + List categories = new ArrayList<>(); + for (PhotoCategory photoCategory : photoCategoryList) { + Long cid = photoCategory.getCategory().getId(); + categories.add(categoryRepository.findById(cid).orElseThrow(() -> new ResourceNotFoundException("category", cid))); + } + List photoEmotionList = photoEmotionRepository.findByPhotoId(photo.getId()); + List emotions = new ArrayList<>(); + for (PhotoEmotion photoEmotion : photoEmotionList) { + Long eid = photoEmotion.getEmotion().getId(); + emotions.add(emotionRepository.findById(eid).orElseThrow(() -> new ResourceNotFoundException("emotion", eid))); + } + photosInformationResponseList.add(new PhotosInformationResponse(photo,categories,emotions)); + } + return new PageResponse(new PageImpl<>(photosInformationResponseList,result.getPageable(),result.getTotalElements())); + + } } diff --git a/emopic/src/main/java/mmm/emopic/app/domain/photo/Photo.java b/emopic/src/main/java/mmm/emopic/app/domain/photo/Photo.java index 41f1cd0..2f8d871 100644 --- a/emopic/src/main/java/mmm/emopic/app/domain/photo/Photo.java +++ b/emopic/src/main/java/mmm/emopic/app/domain/photo/Photo.java @@ -62,8 +62,8 @@ public Photo(Long id, String name, LocalDateTime snapped_at, String caption, Boo this.location = location; } - public void createSnappedAt(Date date){ - this.snapped_at = LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault()); + public void createSnappedAt(LocalDateTime date){ + this.snapped_at = date; } public void createLocation(Location location){ diff --git a/emopic/src/main/java/mmm/emopic/app/domain/photo/PhotoService.java b/emopic/src/main/java/mmm/emopic/app/domain/photo/PhotoService.java index f169caf..723179d 100644 --- a/emopic/src/main/java/mmm/emopic/app/domain/photo/PhotoService.java +++ b/emopic/src/main/java/mmm/emopic/app/domain/photo/PhotoService.java @@ -106,40 +106,41 @@ public PhotoUploadResponse createPhoto(PhotoUploadRequest photoUploadRequest) { boolean exists_gps_info = false; Location location = null; + Optional point = null; - - // 저장하기 - Photo savedPhoto = photoRepository.save(photo); - + KakaoCoord2regionResponse info = null; if(metadata.isPresent()){ - Optional point = metadataExtractor.getLocationPoint(metadata.get()); + point = metadataExtractor.getLocationPoint(metadata.get()); if(point.isPresent()){ // GPS 정보 있으면 추출 Optional LocationInfo = kakaoMapAPI.getLocationInfo(point.get().getX(),point.get().getY()); if(LocationInfo.isPresent()){ - KakaoCoord2regionResponse info = LocationInfo.orElseThrow(() -> new RuntimeException("Kakao Map api 사용 도중 에러가 발생했습니다")); + info = LocationInfo.orElseThrow(() -> new RuntimeException("Kakao Map api 사용 도중 에러가 발생했습니다")); exists_gps_info = true; - location = Location.builder() - .full_address(info.getAddress_name()) - .address_1depth(info.getRegion_1depth_name()) - .address_2depth(info.getRegion_2depth_name()) - .address_3depth(info.getRegion_3depth_name()) - .address_4depth(info.getRegion_4depth_name()) - .latitude(point.get().getX()) - .longitude(point.get().getY()) - .photoId(savedPhoto.getId()) - .build(); } } - Optional snappedDate = metadataExtractor.getSnappedDate(metadata.get()); + Optional snappedDate = metadataExtractor.getSnappedDate(metadata.get()); if(snappedDate.isPresent()){ // 날짜 정보가 있으면 추출 photo.createSnappedAt(snappedDate.get()); } else{ - photo.createSnappedAt(new Date()); + photo.createSnappedAt(LocalDateTime.now()); } } + // 저장하기 + Photo savedPhoto = photoRepository.save(photo); + if(exists_gps_info){//위치 정보가 있으면 저장 + location = Location.builder() + .full_address(info.getAddress_name()) + .address_1depth(info.getRegion_1depth_name()) + .address_2depth(info.getRegion_2depth_name()) + .address_3depth(info.getRegion_3depth_name()) + .address_4depth(info.getRegion_4depth_name()) + .latitude(point.get().getX()) + .longitude(point.get().getY()) + .photoId(savedPhoto.getId()) + .build(); Location saved = locationRepository.save(location); photo.createLocation(saved); } @@ -164,11 +165,7 @@ public void requestCategories(Photo photo){ CategoryInferenceResponse categoryInferenceResponse = photoInferenceWithAI.getClassificationsByPhoto(photo.getSignedUrl()).orElseThrow(() -> new RuntimeException("classification 과정에서 오류 발생")); - List requiredTranslateResult = categoryInferenceResponse.getCategories(); - List result = new ArrayList<>(); - for(String translateText :requiredTranslateResult){ - result.add(translators.papagoTranslate(translateText)); - } + List result = categoryInferenceResponse.getCategories(); for(String categoryName : result){ Category category = categoryRepository.findByName(categoryName).orElseGet(() -> createCategory(categoryName)); PhotoCategory photoCategory = PhotoCategory.builder().photo(photo).category(category).build(); diff --git a/emopic/src/main/java/mmm/emopic/app/domain/photo/dto/response/PhotoInformationResponse.java b/emopic/src/main/java/mmm/emopic/app/domain/photo/dto/response/PhotoInformationResponse.java index c9aab6d..762c633 100644 --- a/emopic/src/main/java/mmm/emopic/app/domain/photo/dto/response/PhotoInformationResponse.java +++ b/emopic/src/main/java/mmm/emopic/app/domain/photo/dto/response/PhotoInformationResponse.java @@ -1,5 +1,6 @@ package mmm.emopic.app.domain.photo.dto.response; +import lombok.Builder; import lombok.Getter; import mmm.emopic.app.domain.category.Category; import mmm.emopic.app.domain.category.PhotoCategory; @@ -24,6 +25,8 @@ public class PhotoInformationResponse { private String signedUrl; + private String caption; + private String uploadDateTime; private Long diaryId; @@ -40,6 +43,7 @@ public PhotoInformationResponse(Photo photo, Diary diary, List categor this.photoId = photo.getId(); this.signedUrl = photo.getSignedUrl(); this.diaryId = diary.getId(); + this.caption = photo.getCaption(); Optional optionDiaryContent = Optional.ofNullable(diary.getContent()); if(optionDiaryContent.isPresent()){ this.diaryContent = diary.getContent(); diff --git a/emopic/src/main/java/mmm/emopic/app/domain/photo/dto/response/PhotosInformationResponse.java b/emopic/src/main/java/mmm/emopic/app/domain/photo/dto/response/PhotosInformationResponse.java index 46ed4c8..1aaf895 100644 --- a/emopic/src/main/java/mmm/emopic/app/domain/photo/dto/response/PhotosInformationResponse.java +++ b/emopic/src/main/java/mmm/emopic/app/domain/photo/dto/response/PhotosInformationResponse.java @@ -1,5 +1,6 @@ package mmm.emopic.app.domain.photo.dto.response; +import lombok.Getter; import mmm.emopic.app.domain.category.Category; import mmm.emopic.app.domain.diary.Diary; import mmm.emopic.app.domain.emotion.Emotion; @@ -13,6 +14,7 @@ import java.util.Optional; import java.util.stream.Collectors; +@Getter public class PhotosInformationResponse { private Long photoId; diff --git a/emopic/src/main/java/mmm/emopic/app/domain/photo/repository/PhotoRepositoryCustom.java b/emopic/src/main/java/mmm/emopic/app/domain/photo/repository/PhotoRepositoryCustom.java index 934c64f..85f1618 100644 --- a/emopic/src/main/java/mmm/emopic/app/domain/photo/repository/PhotoRepositoryCustom.java +++ b/emopic/src/main/java/mmm/emopic/app/domain/photo/repository/PhotoRepositoryCustom.java @@ -20,4 +20,6 @@ public interface PhotoRepositoryCustom { Optional findRecentPhoto(); List findPhotosGroupByCity(); + + Page findAllPhotosByCity(String city, Pageable pageable); } diff --git a/emopic/src/main/java/mmm/emopic/app/domain/photo/repository/PhotoRepositoryCustomImpl.java b/emopic/src/main/java/mmm/emopic/app/domain/photo/repository/PhotoRepositoryCustomImpl.java index 77d348b..85d7284 100644 --- a/emopic/src/main/java/mmm/emopic/app/domain/photo/repository/PhotoRepositoryCustomImpl.java +++ b/emopic/src/main/java/mmm/emopic/app/domain/photo/repository/PhotoRepositoryCustomImpl.java @@ -140,6 +140,28 @@ public List findPhotosGroupByCity() { return result; } + @Override + public Page findAllPhotosByCity(String city, Pageable pageable) { + + List queryResults = queryFactory + .selectFrom(photo) + .where( + eqLocationCity(city) + ) + .orderBy(makeOrder(pageable.getSort())) + .offset(pageable.getOffset()) + .limit(pageable.getPageSize()) + .fetch(); + JPQLQuery count = queryFactory + .select(photo) + .from(photo) + .where( + eqLocationCity(city) + ); + + return PageableExecutionUtils.getPage(queryResults,pageable,() -> count.fetchCount()); + } + private OrderSpecifier[] makeOrder(Sort sort) { List orders = new ArrayList<>(); @@ -178,5 +200,4 @@ private OrderSpecifier[] makeAscOrder(String properties){ private Sort makeSort(String properties, Sort.Direction direction){ return Sort.by(direction,properties); } - } diff --git a/emopic/src/main/java/mmm/emopic/app/domain/photo/support/MetadataExtractor.java b/emopic/src/main/java/mmm/emopic/app/domain/photo/support/MetadataExtractor.java index 312bc80..63a8ef2 100644 --- a/emopic/src/main/java/mmm/emopic/app/domain/photo/support/MetadataExtractor.java +++ b/emopic/src/main/java/mmm/emopic/app/domain/photo/support/MetadataExtractor.java @@ -14,23 +14,28 @@ import org.springframework.web.multipart.MultipartFile; import java.io.IOException; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; import java.util.Date; import java.util.Optional; +import java.util.TimeZone; @Configuration public class MetadataExtractor { - public Optional getSnappedDate(Metadata metadata){ + public Optional getSnappedDate(Metadata metadata){ if(metadata.containsDirectoryOfType(ExifIFD0Directory.class)){ ExifIFD0Directory exif = metadata.getFirstDirectoryOfType(ExifIFD0Directory.class); if(exif.containsTag(306)){ - return Optional.of(exif.getDate(306)); + LocalDateTime date = LocalDateTime.parse(exif.getString(306), DateTimeFormatter.ofPattern("yyyy:MM:dd HH:mm:ss")); + return Optional.of(date); } } if(metadata.containsDirectoryOfType(ExifSubIFDDirectory.class)) { ExifSubIFDDirectory subExif = metadata.getFirstDirectoryOfType(ExifSubIFDDirectory.class); if(subExif.containsTag(306)){ - return Optional.of(subExif.getDate(306)); + LocalDateTime date = LocalDateTime.parse(subExif.getString(306), DateTimeFormatter.ofPattern("yyyy:MM:dd HH:mm:ss")); + return Optional.of(date); } } return Optional.empty();