Skip to content

Commit

Permalink
Merge pull request #210 from mju-likelion/feature/lost-item-get-api-#209
Browse files Browse the repository at this point in the history
Feature/#209 분실물 상세 조회 API 개발
  • Loading branch information
Dh3356 authored Oct 2, 2024
2 parents a8877b8 + a0d4ca6 commit 36aa881
Show file tree
Hide file tree
Showing 9 changed files with 151 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ public class ApiPaths {
private static final String LOST_ITEMS = "/lost-items";
public static final String GET_ALL_LOST_ITEMS = LOST_ITEMS;
public static final String SEARCH_LOST_ITEMS = LOST_ITEMS + "/search";
public static final String GET_LOST_ITEM = LOST_ITEMS + "/{id}";
public static final String POST_LOST_ITEM = LOST_ITEMS;
public static final String PATCH_LOST_ITEM = LOST_ITEMS + "/{id}";
public static final String FOUND_LOST_ITEM = LOST_ITEMS + "/{id}/found";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import static org.mju_likelion.festival.common.api.ApiPaths.DELETE_LOST_ITEM;
import static org.mju_likelion.festival.common.api.ApiPaths.FOUND_LOST_ITEM;
import static org.mju_likelion.festival.common.api.ApiPaths.GET_BOOTH_MANAGING_DETAIL;
import static org.mju_likelion.festival.common.api.ApiPaths.GET_LOST_ITEM;
import static org.mju_likelion.festival.common.api.ApiPaths.GET_MY_STAMP;
import static org.mju_likelion.festival.common.api.ApiPaths.ISSUE_BOOTH_QR;
import static org.mju_likelion.festival.common.api.ApiPaths.PATCH_ANNOUNCEMENT;
Expand Down Expand Up @@ -67,9 +68,9 @@ private void addStudentCouncilAuthenticationInterceptor(final InterceptorRegistr
.addPathPatterns(DELETE_LOST_ITEM)
.addPathPatterns(POST_LOST_ITEM)
.addPathPatterns(PATCH_LOST_ITEM)
.addPathPatterns(DELETE_LOST_ITEM)
.addPathPatterns(FOUND_LOST_ITEM)
.excludePathPatterns(SEARCH_LOST_ITEMS);
.excludePathPatterns(SEARCH_LOST_ITEMS)
.excludePathPatterns(GET_LOST_ITEM);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import static org.mju_likelion.festival.common.api.ApiPaths.DELETE_LOST_ITEM;
import static org.mju_likelion.festival.common.api.ApiPaths.FOUND_LOST_ITEM;
import static org.mju_likelion.festival.common.api.ApiPaths.GET_ALL_LOST_ITEMS;
import static org.mju_likelion.festival.common.api.ApiPaths.GET_LOST_ITEM;
import static org.mju_likelion.festival.common.api.ApiPaths.PATCH_LOST_ITEM;
import static org.mju_likelion.festival.common.api.ApiPaths.POST_LOST_ITEM;
import static org.mju_likelion.festival.common.api.ApiPaths.SEARCH_LOST_ITEMS;
Expand All @@ -17,6 +18,7 @@
import org.mju_likelion.festival.lost_item.dto.request.CreateLostItemRequest;
import org.mju_likelion.festival.lost_item.dto.request.LostItemFoundRequest;
import org.mju_likelion.festival.lost_item.dto.request.UpdateLostItemRequest;
import org.mju_likelion.festival.lost_item.dto.response.LostItemDetailResponse;
import org.mju_likelion.festival.lost_item.dto.response.SimpleLostItemsResponse;
import org.mju_likelion.festival.lost_item.service.LostItemQueryService;
import org.mju_likelion.festival.lost_item.service.LostItemService;
Expand Down Expand Up @@ -58,6 +60,13 @@ public ResponseEntity<SimpleLostItemsResponse> getLostItems(
lostItemQueryService.searchLostItems(SortOrder.fromString(sort), keyword, page, size));
}

@GetMapping(GET_LOST_ITEM)
public ResponseEntity<LostItemDetailResponse> getLostItem(
@PathVariable final UUID id) {

return ResponseEntity.ok(lostItemQueryService.getLostItem(id));
}

@PostMapping(POST_LOST_ITEM)
public ResponseEntity<Void> createLostItem(
@RequestBody @Valid final CreateLostItemRequest createLostItemRequest,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package org.mju_likelion.festival.lost_item.domain;

import java.time.LocalDateTime;
import java.util.UUID;
import lombok.AllArgsConstructor;
import lombok.Getter;

@Getter
@AllArgsConstructor
public class LostItemDetail {

private final UUID id;
private final String title;
private final String content;
private final String imageUrl;
private final LocalDateTime createdAt;
private final Boolean isFounded;

@Override
public String toString() {
return "SimpleLostItem{" +
"id=" + id + '\'' +
", title='" + title + '\'' +
", content='" + content + '\'' +
", imageUrl='" + imageUrl + '\'' +
", createdAt=" + createdAt + '\'' +
", isFounded=" + isFounded +
'}';
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@ public class SimpleLostItem {
@Override
public String toString() {
return "SimpleLostItem{" +
"id=" + id +
"id=" + id + '\'' +
", title='" + title + '\'' +
", content='" + content + '\'' +
", imageUrl='" + imageUrl + '\'' +
", createdAt=" + createdAt +
", createdAt=" + createdAt + '\'' +
", isFounded=" + isFounded +
'}';
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package org.mju_likelion.festival.lost_item.domain.repository;

import static org.mju_likelion.festival.common.util.uuid.UUIDUtil.hexToUUID;
import static org.mju_likelion.festival.common.util.uuid.UUIDUtil.uuidToHex;

import java.util.List;
import java.util.UUID;
import lombok.RequiredArgsConstructor;
import org.mju_likelion.festival.common.enums.SortOrder;
import org.mju_likelion.festival.lost_item.domain.LostItemDetail;
import org.mju_likelion.festival.lost_item.domain.SimpleLostItem;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
Expand All @@ -17,6 +19,7 @@
public class LostItemQueryRepository {

private final RowMapper<SimpleLostItem> simpleLostItemRowMapper = simpleLostItemRowMapper();
private final RowMapper<LostItemDetail> lostItemDetailRowMapper = lostItemDetailRowMapper();
private final NamedParameterJdbcTemplate jdbcTemplate;

private RowMapper<SimpleLostItem> simpleLostItemRowMapper() {
Expand All @@ -34,6 +37,21 @@ private RowMapper<SimpleLostItem> simpleLostItemRowMapper() {
};
}

private RowMapper<LostItemDetail> lostItemDetailRowMapper() {
return (rs, rowNum) -> {
String hexId = rs.getString("lostItemId");
UUID uuid = hexToUUID(hexId);
return new LostItemDetail(
uuid,
rs.getString("title"),
rs.getString("content"),
rs.getString("imageUrl"),
rs.getTimestamp("createdAt").toLocalDateTime(),
rs.getBoolean("isFounded")
);
};
}

/**
* 페이지네이션을 적용하여 분실물 간단 정보 List 조회.
*
Expand Down Expand Up @@ -128,4 +146,18 @@ public int findTotalPageByKeyword(final String keyword, final int size) {

return jdbcTemplate.queryForObject(sql, params, Integer.class);
}

public LostItemDetail findLostItemDetailById(final UUID id) {
String sql = "SELECT HEX(li.id) AS lostItemId, li.title AS title, li.content AS content, "
+ "CASE WHEN li.retriever_info IS NULL THEN FALSE ELSE TRUE END AS isFounded, "
+ "i.url AS imageUrl, li.created_at AS createdAt "
+ "FROM lost_item li "
+ "INNER JOIN image i ON li.image_id = i.id "
+ "WHERE li.id = UNHEX(:id)";

MapSqlParameterSource params = new MapSqlParameterSource()
.addValue("id", uuidToHex(id));

return jdbcTemplate.queryForObject(sql, params, lostItemDetailRowMapper);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package org.mju_likelion.festival.lost_item.dto.response;

import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import java.time.LocalDateTime;
import java.util.UUID;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.mju_likelion.festival.lost_item.domain.LostItemDetail;

@Getter
@AllArgsConstructor(access = AccessLevel.PRIVATE)
@NoArgsConstructor
public class LostItemDetailResponse {

private UUID id;
private String title;
private String content;
private String imageUrl;
@JsonSerialize(using = LocalDateTimeSerializer.class)
@JsonDeserialize(using = LocalDateTimeDeserializer.class)
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm")
private LocalDateTime createdAt;
private Boolean isFounded;

public static LostItemDetailResponse from(final LostItemDetail lostItemDetail) {
return new LostItemDetailResponse(
lostItemDetail.getId(),
lostItemDetail.getTitle(),
lostItemDetail.getContent(),
lostItemDetail.getImageUrl(),
lostItemDetail.getCreatedAt(),
lostItemDetail.getIsFounded()
);
}

@Override
public String toString() {
return "SimpleLostItem{" +
"id=" + id + '\'' +
", title='" + title + '\'' +
", content='" + content + '\'' +
", imageUrl='" + imageUrl + '\'' +
", createdAt=" + createdAt + '\'' +
", isFounded=" + isFounded +
'}';
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,13 @@
import org.mju_likelion.festival.common.enums.SortOrder;
import org.mju_likelion.festival.common.exception.NotFoundException;
import org.mju_likelion.festival.lost_item.domain.LostItem;
import org.mju_likelion.festival.lost_item.domain.LostItemDetail;
import org.mju_likelion.festival.lost_item.domain.SimpleLostItem;
import org.mju_likelion.festival.lost_item.domain.repository.LostItemJpaRepository;
import org.mju_likelion.festival.lost_item.domain.repository.LostItemQueryRepository;
import org.mju_likelion.festival.lost_item.dto.response.LostItemDetailResponse;
import org.mju_likelion.festival.lost_item.dto.response.SimpleLostItemsResponse;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

Expand Down Expand Up @@ -55,6 +58,14 @@ public SimpleLostItemsResponse searchLostItems(
return SimpleLostItemsResponse.of(simpleLostItems, totalPage);
}

@Cacheable(value = "lostItem", key = "#lostItemId")
public LostItemDetailResponse getLostItem(final UUID lostItemId) {
validateLostItemExistence(lostItemId);
LostItemDetail lostItemDetail = lostItemQueryRepository.findLostItemDetailById(lostItemId);

return LostItemDetailResponse.from(lostItemDetail);
}

public LostItem getExistLostItem(final UUID lostItemId) {
return lostItemJpaRepository.findById(lostItemId)
.orElseThrow(() -> new NotFoundException(LOST_ITEM_NOT_FOUND_ERROR));
Expand All @@ -65,4 +76,10 @@ public void validatePage(final int page, final int totalPage) {
throw new NotFoundException(PAGE_OUT_OF_BOUND_ERROR);
}
}

public void validateLostItemExistence(final UUID lostItemId) {
if (!lostItemJpaRepository.existsById(lostItemId)) {
throw new NotFoundException(LOST_ITEM_NOT_FOUND_ERROR);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import org.mju_likelion.festival.lost_item.dto.request.CreateLostItemRequest;
import org.mju_likelion.festival.lost_item.dto.request.LostItemFoundRequest;
import org.mju_likelion.festival.lost_item.dto.request.UpdateLostItemRequest;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

Expand Down Expand Up @@ -40,6 +41,7 @@ public void createLostItem(
lostItemJpaRepository.save(lostItem);
}

@CacheEvict(value = "lostItem", key = "#lostItemId")
public void updateLostItem(
final UUID lostItemId,
final UpdateLostItemRequest updateLostItemRequest,
Expand All @@ -53,6 +55,7 @@ public void updateLostItem(
lostItemJpaRepository.save(lostItem);
}

@CacheEvict(value = "lostItem", key = "#lostItemId")
public void foundLostItem(
final UUID lostItemId,
final LostItemFoundRequest lostItemFoundRequest,
Expand All @@ -66,6 +69,7 @@ public void foundLostItem(
lostItemJpaRepository.save(lostItem);
}

@CacheEvict(value = "lostItem", key = "#lostItemId")
public void deleteLostItem(final UUID lostItemId, final UUID studentCouncilId) {
LostItem lostItem = lostItemQueryService.getExistLostItem(lostItemId);
adminQueryService.validateAdminExistence(studentCouncilId);
Expand Down

0 comments on commit 36aa881

Please sign in to comment.