Skip to content

Commit

Permalink
feat: 날짜에 해당하는 이미지 목록 조회 구현 (#243)
Browse files Browse the repository at this point in the history
  • Loading branch information
ywonchae1 committed Dec 4, 2024
1 parent 5a891a8 commit 52b0694
Show file tree
Hide file tree
Showing 10 changed files with 256 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package org.ioteatime.meonghanyangserver.common.type;

public enum ImageSuccessType implements SuccessTypeCode {
GET_LIST_OF_DATE(200, "OK", "날짜에 해당하는 이미지 목록 조회에 성공하였습니다.");

private final Integer code;
private final String message;
private final String description;

ImageSuccessType(Integer code, String message, String description) {
this.code = code;
this.message = message;
this.description = description;
}

@Override
public Integer getCode() {
return this.code;
}

@Override
public String getMessage() {
return this.message;
}

@Override
public String getDescription() {
return this.description;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package org.ioteatime.meonghanyangserver.image.controller;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.ioteatime.meonghanyangserver.common.api.Api;
import org.ioteatime.meonghanyangserver.common.utils.LoginMember;
import org.ioteatime.meonghanyangserver.image.dto.response.GroupDateImageResponse;
import org.springframework.web.bind.annotation.RequestParam;

@Tag(name = "Image Api", description = "Image 관련 API 목록입니다.")
public interface ImageApi {
@Operation(
summary = "회원이 속한 그룹의 날짜별 객체 탐지 이미지 목록을 시간 순서대로 조회합니다.",
description =
"담당자: 양원채\n\n달력의 날짜를 클릭했을 때 해당 날짜의 이미지 목록을 조회할 떄 사용합니다.\n\nURL QueryParameter로 날짜를 담아 요청 주시면 됩니다.")
Api<GroupDateImageResponse> groupDateImageList(
@LoginMember Long memberId,
@RequestParam("year") Short year,
@RequestParam("month") Byte month,
@RequestParam("day") Byte day);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package org.ioteatime.meonghanyangserver.image.controller;

import lombok.RequiredArgsConstructor;
import org.ioteatime.meonghanyangserver.common.api.Api;
import org.ioteatime.meonghanyangserver.common.type.ImageSuccessType;
import org.ioteatime.meonghanyangserver.common.utils.LoginMember;
import org.ioteatime.meonghanyangserver.image.dto.response.GroupDateImageResponse;
import org.ioteatime.meonghanyangserver.image.service.ImageService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequiredArgsConstructor
@RequestMapping("/api/image")
public class ImageController implements ImageApi {
private final ImageService imageService;

@GetMapping
public Api<GroupDateImageResponse> groupDateImageList(
@LoginMember Long memberId,
@RequestParam("year") Short year,
@RequestParam("month") Byte month,
@RequestParam("day") Byte day) {
GroupDateImageResponse response =
imageService.findAllByMemberIdAndDate(memberId, year, month, day);
return Api.success(ImageSuccessType.GET_LIST_OF_DATE, response);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package org.ioteatime.meonghanyangserver.image.dto.response;

import io.swagger.v3.oas.annotations.media.Schema;
import java.util.List;

@Schema(description = "날짜에 해당하는 그룹의 이미지 목록 응답")
public record GroupDateImageResponse(
@Schema(description = "날짜에 해당하는 그룹의 이미지 목록") List<ImageResponse> images) {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package org.ioteatime.meonghanyangserver.image.dto.response;

import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
import lombok.Builder;
import lombok.Getter;

@Getter
@Schema(description = "이미지 단일 응답")
public class ImageResponse {
@NotNull
@Schema(description = "이미지 ID", example = "1")
private final Long imageId;

@NotNull
@Schema(description = "이미지 원본 이름", example = "test-image.jpg")
private final String imageName;

@NotNull
@Schema(
description = "이미지 URL",
example = "https://bucket.s3.ap-northeast-2.amazonaws.com/path/to/test-image.jpg")
private String imagePath;

@NotNull
@Schema(description = "형식이 있는 이미지 생성 시각", example = "2024.10.22.13:00")
private final String formattedCreatedAt;

@Builder
public ImageResponse(
Long imageId, String imageName, String imagePath, String formattedCreatedAt) {
this.imageId = imageId;
this.imageName = imageName;
this.imagePath = imagePath;
this.formattedCreatedAt = formattedCreatedAt;
}

public ImageResponse updateToPresignedUrl(String imagePresignedPath) {
this.imagePath = imagePresignedPath;
return this;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package org.ioteatime.meonghanyangserver.image.mapper;

import java.util.List;
import org.ioteatime.meonghanyangserver.image.dto.response.GroupDateImageResponse;
import org.ioteatime.meonghanyangserver.image.dto.response.ImageResponse;

public class ImageResponseMapper {
public static GroupDateImageResponse from(List<ImageResponse> images) {
return new GroupDateImageResponse(images);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package org.ioteatime.meonghanyangserver.image.repository;

import org.ioteatime.meonghanyangserver.image.domain.ImageEntity;
import org.springframework.data.jpa.repository.JpaRepository;

public interface ImageJpaRepository extends JpaRepository<ImageEntity, Long> {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package org.ioteatime.meonghanyangserver.image.repository;

import java.time.LocalDateTime;
import java.util.List;
import org.ioteatime.meonghanyangserver.image.dto.response.ImageResponse;

public interface ImageRepository {
List<ImageResponse> findAllByGroupIdAndDate(Long groupId, LocalDateTime searchDate);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package org.ioteatime.meonghanyangserver.image.repository;

import static org.ioteatime.meonghanyangserver.group.domain.QGroupEntity.groupEntity;
import static org.ioteatime.meonghanyangserver.image.domain.QImageEntity.imageEntity;

import com.querydsl.core.types.Projections;
import com.querydsl.core.types.dsl.Expressions;
import com.querydsl.jpa.impl.JPAQueryFactory;
import java.time.LocalDateTime;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.ioteatime.meonghanyangserver.image.dto.response.ImageResponse;
import org.springframework.stereotype.Repository;

@Repository
@RequiredArgsConstructor
public class ImageRepositoryImpl implements ImageRepository {
private final JPAQueryFactory queryFactory;
private final ImageJpaRepository imageJpaRepository;

@Override
public List<ImageResponse> findAllByGroupIdAndDate(Long groupId, LocalDateTime searchDate) {
String dateFormat = "DATE_FORMAT({0}, '%Y.%m.%d.%H:%i')";
return queryFactory
.select(
Projections.constructor(
ImageResponse.class,
imageEntity.id.as("imageId"),
imageEntity.imageName.as("imageName"),
imageEntity.imagePath.as("imagePath"),
Expressions.stringTemplate(dateFormat, imageEntity.createdAt)
.as("formattedCreatedAt")))
.from(imageEntity)
.join(imageEntity.group, groupEntity)
.where(
imageEntity
.group
.id
.eq(groupId)
.and(imageEntity.createdAt.year().eq(searchDate.getYear()))
.and(imageEntity.createdAt.month().eq(searchDate.getMonthValue()))
.and(
imageEntity
.createdAt
.dayOfMonth()
.eq(searchDate.getDayOfMonth())))
.fetch();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package org.ioteatime.meonghanyangserver.image.service;

import com.amazonaws.HttpMethod;
import java.time.LocalDateTime;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.ioteatime.meonghanyangserver.clients.s3.S3Client;
import org.ioteatime.meonghanyangserver.common.exception.NotFoundException;
import org.ioteatime.meonghanyangserver.common.type.GroupErrorType;
import org.ioteatime.meonghanyangserver.group.domain.GroupEntity;
import org.ioteatime.meonghanyangserver.groupmember.repository.GroupMemberRepository;
import org.ioteatime.meonghanyangserver.image.dto.response.GroupDateImageResponse;
import org.ioteatime.meonghanyangserver.image.dto.response.ImageResponse;
import org.ioteatime.meonghanyangserver.image.mapper.ImageResponseMapper;
import org.ioteatime.meonghanyangserver.image.repository.ImageRepository;
import org.springframework.stereotype.Service;

@Service
@RequiredArgsConstructor
public class ImageService {
private final S3Client s3Client;
private final ImageRepository imageRepository;
private final GroupMemberRepository groupMemberRepository;

public GroupDateImageResponse findAllByMemberIdAndDate(
Long memberId, Short year, Byte month, Byte day) {
// 그룹멤버를 찾아 그룹 id 확인
// 없으면 에러, 이미지를 조회할 수 없음
// 그룹 id와 날짜를 기준으로 이미지 리스트 조회
GroupEntity groupEntity =
groupMemberRepository
.findGroupFromGroupMember(memberId)
.orElseThrow(
() -> new NotFoundException(GroupErrorType.GROUP_MEMBER_NOT_FOUND));
LocalDateTime searchDate =
LocalDateTime.of(year.intValue(), month.intValue(), day.intValue(), 0, 0);
List<ImageResponse> imageResponses =
imageRepository.findAllByGroupIdAndDate(groupEntity.getId(), searchDate).stream()
.map(
image -> {
// 경로를 PresignedUrl로 변경
String preSignedUrl =
s3Client.generatePreSignUrl(
image.getImagePath(), HttpMethod.GET);
return image.updateToPresignedUrl(preSignedUrl);
})
.toList();
return ImageResponseMapper.from(imageResponses);
}
}

0 comments on commit 52b0694

Please sign in to comment.