
StoreMenuEntity를 만들어보자@Getter
@EqualsAndHashCode(callSuper = true)
@NoArgsConstructor
@AllArgsConstructor
@SuperBuilder
@Entity
@Table(name = "store_menu")
public class StoreMenuEntity extends BaseEntity {
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "store_id")
StoreEntity storeEntity;
@Column(length = 100, nullable = false)
private String name;
@Column(precision = 11,scale = 4, nullable = false)
private BigDecimal amount;
@Column(length = 50, nullable = false)
@Enumerated(EnumType.STRING)
private StoreMenuStatus status;
@Column(length = 200, nullable = false)
private String thumbnailUrl;
private int likeCount;
private int sequence;
Lazy로 지연로딩을 해주었고, @JoinColumn에 pk키인 store_id를 넣어주었다public interface StoreMenuRepository extends JpaRepository<StoreMenuEntity,Long> {
// 유효한 매뉴 체크
// select * from store_menu where id =? and status =? order by id desc limit 1;
Optional<StoreMenuEntity> findFirstByIdAndStatusOrderByIdDesc(Long id, StoreMenuStatus status);
// 특정 가게의 매뉴 가져오기
// select * from store_menu where store_id =? and status =? order by sequence desc;
List<StoreMenuEntity> findAllByIdAndStatusOrderBySequenceDesc(Long id, StoreMenuStatus status);
}
findFirstByIdAndStatusOrderByIdDesc와findAllByIdAndStatusOrderBySequenceDesc가 있다@Service
@RequiredArgsConstructor
public class StoreMenuService {
private final StoreMenuRepository storeMenuRepository;
public StoreMenuEntity getStoreMenuWithThrow(Long id){
Optional<StoreMenuEntity> entity = storeMenuRepository.findFirstByIdAndStatusOrderByIdDesc(id, StoreMenuStatus.REGISTERED);
return entity.orElseThrow(()-> new ApiException(ErrorCode.NULL_POINT));
}
public List<StoreMenuEntity> getStoreMenuStoreId(Long storeId){
return storeMenuRepository.findAllByIdAndStatusOrderBySequenceDesc(storeId,StoreMenuStatus.REGISTERED);
}
public StoreMenuEntity register(StoreMenuEntity storeMenuEntity){
return Optional.ofNullable(storeMenuEntity)
.map((it)->{
it.changeStatus(StoreMenuStatus.REGISTERED);
return storeMenuRepository.save(it);
}).orElseThrow(()-> new ApiException(ErrorCode.NULL_POINT));
}
}
getStoreMenuWithThrow와getStoreMenuStoreIdregister 메서드가 있다public void changeStatus(StoreMenuStatus status){
this.status = status;
}
@Data
@NoArgsConstructor
@AllArgsConstructor
public class StoreMenuRegisterRequest {
@NotNull
private Long storeId;
@NotBlank
private String name;
@NotNull
private BigDecimal amount;
@NotBlank
private String thumbnailUrl;
}
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class StoreMenuResponse {
private Long id;
private Long storeId;
private String name;
private BigDecimal amount;
private StoreMenuStatus status;
private String thumbnailUrl;
private int likeCount;
private int sequence;
}
@Converter
public class StoreMenuConverter {
public StoreMenuEntity toEntity(StoreMenuRegisterRequest request, StoreEntity storeEntity){
return Optional.ofNullable(request)
.map(it->{
return StoreMenuEntity.builder()
.storeEntity(storeEntity)
.name(request.getName())
.amount(request.getAmount())
.thumbnailUrl(request.getThumbnailUrl())
.build();
})
.orElseThrow(()-> new ApiException(ErrorCode.NULL_POINT));
}
public StoreMenuResponse toResponse(StoreMenuEntity storeMenuEntity){
return Optional.ofNullable(storeMenuEntity)
.map(it->{
return StoreMenuResponse.builder()
.id(storeMenuEntity.getId())
.name(storeMenuEntity.getName())
.storeId(storeMenuEntity.getStoreEntity().getId())
.status(storeMenuEntity.getStatus())
.amount(storeMenuEntity.getAmount())
.thumbnailUrl(storeMenuEntity.getThumbnailUrl())
.likeCount(storeMenuEntity.getLikeCount())
.sequence(storeMenuEntity.getSequence())
.build();
})
.orElseThrow(()-> new ApiException(ErrorCode.NULL_POINT));
}
}

business, converter, service 3계층으로 나눠서 고민해야할게 생겼던거 같다 ✅고민 해결 방법!!!
- request에는 StoreMenuEntity의 정보가 없다. 오직 store의 id만 있다
- 결국 business 영역에서 converter을 사용한다
- business영역에서 storeService를 의존관계 주입을 받아, request의 id를 이용해
- entity를 넣어서 builder로 생성하자!!
- 그렇기 위해서는 파라미터로 storeEntity를 받게 코딩을 하였다
@Business
@RequiredArgsConstructor
public class StoreMenuBusiness {
public final StoreService storeService;
private final StoreMenuService storeMenuService;
private final StoreMenuConverter storeMenuConverter;
// register
@Transactional
public StoreMenuResponse register(StoreMenuRegisterRequest request){
StoreEntity store = storeService.findById(request.getStoreId())
.orElseThrow(()-> new ApiException(ErrorCode.NULL_POINT));
// req -> entity ->save -> response
StoreMenuEntity entity = storeMenuConverter.toEntity(request,store);
StoreMenuEntity newEntity = storeMenuService.register(entity);
StoreMenuResponse response = storeMenuConverter.toResponse(newEntity);
return response;
}
// 특정 가게 검색
public List<StoreMenuResponse> search(Long storeId){
List<StoreMenuEntity> list = storeMenuService.getStoreMenuStoreId(storeId);
return list.stream()
.map(storeMenuEntity -> {
return storeMenuConverter.toResponse(storeMenuEntity);
})
.collect(Collectors.toList());
}
}
Business계층을 만들었고register을 보면, findById를 통해 StoreEntity를 찾고builder 패턴을 이용해, StoreMenuRegisterRequest -> StoreMenuEntity로 잘 변환한 것을 알 수 있다List<StoreMenuResponse>로 잘 반환해서, 반환하였다@RestController
@RequiredArgsConstructor
@RequestMapping("/open-api/store-menu")
public class StoreMenuOpenApiController {
private final StoreMenuBusiness storeMenuBusiness;
@PostMapping("/register")
public Api<StoreMenuResponse> register(@Valid @RequestBody Api<StoreMenuRegisterRequest> request){
StoreMenuRegisterRequest req = request.getBody();
StoreMenuResponse response = storeMenuBusiness.register(req);
return Api.OK(response);
}
}
@RestController
@RequestMapping("/api/store-menu")
@RequiredArgsConstructor
public class StoreMenuApiController {
private final StoreMenuBusiness storeMenuBusiness;
@GetMapping("/search")
public Api<List<StoreMenuResponse>> search(@RequestParam("storeId") Long storeId){
List<StoreMenuResponse> response = storeMenuBusiness.search(storeId);
return Api.OK(response);
}
}




어라??? 계속 자몽애이드만 나왔다
@Query("SELECT sm FROM StoreMenuEntity sm " +
"WHERE sm.storeEntity.id = :storeId " +
"AND sm.status = :status " +
"ORDER BY sm.sequence DESC")
List<StoreMenuEntity> findAllByStoreIdAndStatusOrderBySequenceDesc(@Param("storeId") Long storeId, @Param("status") StoreMenuStatus status);
