Skip to content

Commit

Permalink
#49 찜꽁리스트 테이블 설계 변경에 따른 기능 재개발
Browse files Browse the repository at this point in the history
- 기존) 비식별관계 테이블 설계
- 현재) 식별관계 테이블 설계
  • Loading branch information
dldmsql committed Oct 29, 2023
1 parent 778b8b7 commit 828a129
Show file tree
Hide file tree
Showing 12 changed files with 461 additions and 0 deletions.
19 changes: 19 additions & 0 deletions src/main/java/com/example/myongsick/domain/mark/MarkRequest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.example.myongsick.domain.mark;

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import lombok.Getter;

@Getter
@ApiModel(description = "찜꽁 리스트에 가게 등록")
public class MarkRequest {
@NotNull
@NotBlank
@ApiModelProperty(required = true, dataType = "String")
private String phoneId;
@NotNull @NotBlank
@ApiModelProperty(required = true, dataType = "String")
private String code;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
package com.example.myongsick.domain.mark;

import com.example.myongsick.domain.mark.service.StoreMarkService;
import com.example.myongsick.domain.scrap.dto.ScrapCountResponse;
import com.example.myongsick.domain.scrap.dto.ScrapResponse;
import com.example.myongsick.global.object.ApplicationResponse;
import io.swagger.annotations.ApiOperation;
import io.swagger.v3.oas.annotations.media.Schema;
import javax.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.repository.query.Param;
import org.springframework.data.web.PageableDefault;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
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/v3/marks")
public class StoreMarkController {

private final StoreMarkService storeMarkService;

@GetMapping
@ApiOperation(value = "가게별 담은 유저 수 조회 \n"
+ "")
public ApplicationResponse<Page<ScrapCountResponse>> getStoreMarkCntList(
@Param("campus") String campus,
@RequestParam(value = "offset", defaultValue = "0")
@Schema(title = "페이지 번호", example = "0", description = "0부터 시작합니다")
Integer offset,
@RequestParam(value = "limit", defaultValue = "10")
@Schema(
title = "Data 갯수",
example = "10",
description = "한 페이지에 보여지는 데이터 수 입니다.")
Integer limit,
@RequestParam(value = "orderBy")
@Schema(
title = "정렬 기준",
description = "정렬 기준은 distance (거리) | scrapCount (찜꽁수)가 있습니다..",
allowableValues = {
"distance",
"scrapCount",
})
String orderBy
) {
return ApplicationResponse.ok(storeMarkService.getMarkCount(campus, PageRequest.of(offset, limit), orderBy));
}

@PostMapping
@ApiOperation(value = "찜꽁 리스트 추가")
public ApplicationResponse<Void> createMark(
@RequestBody @Valid MarkRequest request
) {
storeMarkService.createMark(request.getPhoneId(), request.getCode());
return ApplicationResponse.ok();
}

@DeleteMapping
@ApiOperation(value = "찜꽁 리스트 삭제")
public ApplicationResponse<Void> deleteMark(
@RequestBody @Valid MarkRequest request
) {
storeMarkService.deleteMark(request.getPhoneId(), request.getCode());
return ApplicationResponse.ok();
}

@GetMapping("/my")
@ApiOperation(value = "유저 찜꽁 리스트 조회")
public ApplicationResponse<Page<ScrapResponse>> getMyMarkList(
@RequestParam String phoneId,
@RequestParam(value = "offset", defaultValue = "0")
@Schema(title = "페이지 번호", example = "0", description = "0부터 시작합니다")
Integer offset,
@RequestParam(value = "limit", defaultValue = "10")
@Schema(
title = "Data 갯수",
example = "10",
description = "한 페이지에 보여지는 데이터 수 입니다.")
Integer limit
) {
return ApplicationResponse.ok(storeMarkService.getMarkList(phoneId, PageRequest.of(offset, limit)));
}
}
16 changes: 16 additions & 0 deletions src/main/java/com/example/myongsick/domain/mark/entity/MarkId.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.example.myongsick.domain.mark.entity;

import java.io.Serializable;

public class MarkId implements Serializable {

private Long user;
private Long store;

public MarkId(){}
public MarkId(Long user, Long store) {
super();
this.user = user;
this.store = store;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package com.example.myongsick.domain.mark.entity;

import com.example.myongsick.domain.scrap.entity.Store;
import com.example.myongsick.domain.user.entity.User;
import com.fasterxml.jackson.annotation.JsonBackReference;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.IdClass;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Entity
@Table(name = "mark")
@Getter
@NoArgsConstructor
@AllArgsConstructor
@Builder
@IdClass(MarkId.class)
public class StoreMark implements Serializable {

@Id
@ManyToOne
@JoinColumn(name = "user_id")
private User user;

@Id
@ManyToOne
@JoinColumn(name = "store_id")
private Store store;

public StoreMark StoreMark(
User user,
Store store
) {
this.user = user;
this.store = store;
return this;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.example.myongsick.domain.mark.repository;

import com.example.myongsick.domain.mark.entity.MarkId;
import com.example.myongsick.domain.mark.entity.StoreMark;
import com.example.myongsick.domain.scrap.entity.Scrap;
import java.util.List;
import java.util.Optional;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;

public interface StoreMarkRepository extends JpaRepository<StoreMark, MarkId> {
Page<StoreMark> findAllByUserId(Long userId, Pageable pageable);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.example.myongsick.domain.mark.repository;

import com.example.myongsick.domain.mark.entity.StoreMark;
import com.example.myongsick.domain.scrap.dto.ScrapCountResponse;
import com.example.myongsick.domain.scrap.dto.ScrapResponse;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;

public interface StoreMarkRepositoryCustom {

StoreMark findByUserIdAndStoreId(Long userId, Long storeId);

Page<ScrapCountResponse> findByCampus(String campus, Pageable pageable, String orderBy);

Page<ScrapResponse> findByUserId(Long userId, Pageable pageable);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
package com.example.myongsick.domain.mark.repository;

import static com.example.myongsick.domain.mark.entity.QStoreMark.storeMark;
import static com.example.myongsick.domain.scrap.entity.QStore.store;
import static com.example.myongsick.domain.user.entity.QUser.user;

import com.example.myongsick.domain.mark.entity.StoreMark;
import com.example.myongsick.domain.scrap.dto.QScrapCountResponse;
import com.example.myongsick.domain.scrap.dto.QScrapResponse;
import com.example.myongsick.domain.scrap.dto.ScrapCountResponse;
import com.example.myongsick.domain.scrap.dto.ScrapResponse;
import com.example.myongsick.domain.scrap.entity.CampusType;
import com.querydsl.core.types.Order;
import com.querydsl.core.types.OrderSpecifier;
import com.querydsl.jpa.impl.JPAQueryFactory;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Repository;

@Repository
@RequiredArgsConstructor
public class StoreMarkRepositoryImpl implements StoreMarkRepositoryCustom {

private final JPAQueryFactory jpaQueryFactory;
/**
* =============================================================================================
* 유저가 가게를 찜꽁했는지 조회 -- 1건 조회
* =============================================================================================
* */
@Override
public StoreMark findByUserIdAndStoreId(Long userId, Long storeId) {
return jpaQueryFactory
.select(storeMark)
.from(storeMark)
.where(
storeMark.user.id.eq(userId),
storeMark.store.id.eq(storeId))
.fetchOne();
}
/**
* =============================================================================================
* 캠퍼스별 가게 목록 조회 -- 스크랩 수 포함
* =============================================================================================
* */
@Override
public Page<ScrapCountResponse> findByCampus(String campus, Pageable pageable, String orderBy) {
var result = jpaQueryFactory
.select(new QScrapCountResponse(
store.id.as("storeId"),
store.code,
store.name,
store.category,
store.address,
store.contact,
store.urlAddress,
store.distance,
store.latitude,
store.longitude,
store.storeMarkList.size().intValue().as("scrapCount")
))
.from(store)
.where(store.campus.eq(CampusType.valueOf(campus)))
.orderBy(getOrderSpecifier(orderBy))
.fetch();
var countQuery = jpaQueryFactory
.select(store.storeMarkList.size())
.from(store)
.where(store.campus.eq(CampusType.valueOf(campus)))
.fetch().size();
return new PageImpl<>(result, pageable, countQuery);
}
/**
* =============================================================================================
* 유저의 찜꽁리스트 조회
* =============================================================================================
* */
@Override
public Page<ScrapResponse> findByUserId(Long userId, Pageable pageable) {
var result = jpaQueryFactory
.select(new QScrapResponse(
store.id,
store.code,
store.name,
store.category,
store.address,
store.urlAddress,
store.distance,
store.latitude,
store.longitude
))
.from(storeMark)
.leftJoin(storeMark.store, store)
.leftJoin(storeMark.user, user)
.where(user.id.eq(userId))
.groupBy(storeMark.store, storeMark.user)
.fetch();
var countQuery = jpaQueryFactory
.select(storeMark.count())
.from(storeMark)
.leftJoin(storeMark.store, store)
.leftJoin(storeMark.user, user)
.where(user.id.eq(userId))
.groupBy(storeMark.store, storeMark.user)
.fetch().size();
System.out.println(countQuery);
return new PageImpl<>(result, pageable, countQuery);
}
/**
* =============================================================================================
* PRIVATE FUNCTION
* =============================================================================================
* */
private OrderSpecifier getOrderSpecifier(String orderBy) {
if (orderBy.equals("distance")) {
return new OrderSpecifier(Order.DESC, store.distance.castToNum(Long.class));
} else {
return new OrderSpecifier(Order.DESC, store.storeMarkList.size());
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.example.myongsick.domain.mark.service;

import com.example.myongsick.domain.scrap.dto.ScrapCountResponse;
import com.example.myongsick.domain.scrap.dto.ScrapResponse;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;

public interface StoreMarkService {
Page<ScrapResponse> getMarkList(String phoneId, Pageable pageable);
void createMark(String phoneId, String storeCode);
void deleteMark(String phoneId, String storeCode);
Page<ScrapCountResponse> getMarkCount(String campus, Pageable pageable, String orderBy);
}
Loading

0 comments on commit 828a129

Please sign in to comment.