오늘부터 만들기 시작했는데,
아직 API 작성과 ERD 작성을 하고 있다.
설계하는 부분이 가장 어려운 것 같다..
API 설계
표로 해 보려다가 GitBook 이라는걸 찾아서써보고 있다.
아직 기능 파악중!
ERD 설계
이런식으로 하는게 맞겠지?!
관심상품 API 구현
관심상품 조회 API
Scheduler 구현
매일 가격 갱신 요청 들어왔다고 가즈엉
@EnableScheduling 설정
@Slf4j(topic = "Scheduler") : 로그 찍기 위함이다.
@RequiredArgsConstructor : 주입
주입 하는 이유 :
재 검색 해야 하므로
검색해야할 product 목록
product repository 필요
cron : 특정 시간 마다 특정 작업 수행하는 scheduler 역할
// 초, 분, 시, 일, 월, 주 순서
회원가입 기능 구현
UserDetailsImpl : security 할 때 사용
인증, 인가 필터 만듬(Security 패키지 안)
토큰 사용..
헤더에 담을 수 있다.
클라이언트쪽으로 Jwt 보내줄 수 있게 된다.
unsuccessfulAuthentication 이쪽에서 status 코드 말고 추가적인 정보 보내줘도 좋다.
Config
설정 하는곳
jwt.io 에서 jwt 토큰 확인
회원별 상품 API
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id", nullable = false)
private User user;
상품 페이징 및 정렬
노션 페이지 확인..
전체 페이지 수 나타내는 법 : totalElement / size 결과를 소수점 올림
ex) 1/10 = 0.1 = 1페이지
11/10 = 1.1 = 2페이지
쿼리메서드 : 함수 이름 자체가 쿼리인것
admin 시점에서 가져왔던것 지움
-> 따로 api 만들면 또 만들어줘야되니까 비효율적이라서
-> 하나로 합쳤다.
Page는 변환이 가능하다
productList 안에 여러개의 Page들이 들어있는데 그걸 .map 메서드를 통해 변환해서 반환한다.
public Page<ProductResponseDto> getProducts(User user, int page, int size, String sortBy, boolean isAsc) {
Sort.Direction direction = isAsc ? Sort.Direction.ASC : Sort.Direction.DESC;
Sort sort = Sort.by(direction, sortBy);
Pageable pageable = PageRequest.of(page, size, sort);
UserRoleEnum userRoleEnum = user.getRole();
Page<Product> productList;
if(userRoleEnum == UserRoleEnum.USER){
productList = productRepository.findAllByUser(user, pageable);
} else{
productList = productRepository.findAll(pageable);
}
return productList.map(ProductResponseDto::new);
}
정리 :
정렬
페이징 처리하기 위한 pagealbe 객체
유저의 권한 확인
일반이면 findByAllUser 쿼리메서드
어드민이면 findAll
반환은 페이지타입
TestDataRunner 라는 테스트러너를 만들어서 테스트.(이후 주석처리 해야함)
상품 폴더 설계
페이징말고 폴더로 해달라는 요구사항
폴더를 추가할땐 여러가지 한번에 추가
관심상품에 폴더 설정
폴더 별 조회
폴더 : 회원은 N : 1 관계
folder의 정보를 가져올 때 항상 회원의 정보를 가져올 필요는 없기 때문에 FetchType은 LAZY
폴더 : 상품 = 1 : N
결과적으로 상품 : 폴더 = N : M 다대다 관계
이렇게 풀어서 만듬.
@Table(name = "product_folder") // 외래키의 주인
폴더 생성 및 조회 구현
@RequiredArgsConstructor <- 이거 Lombok때문에 쓰는건가? 검색 ㄱ
List<Folder> existFolderList = folderRepository.findAllByUserAndNameIn(user,folderNames); // 전체를 찾을건데 User기준으로 찾고, 폴더테이블의 이름도 찾을것. In은 여러개라는 조건을 위해 써야함
// select * from folder where user_id = ? and name in (?, ?, ?)
를 이번 강의해서 했다..
관심 상품에 폴더 추가
API : 폴더 전체 조회 / 폴더 추가
폴더 전체 조회 : 회원이 등록한 모든 폴더를 조회 하는 기능
= 회원의 정보를 받아와야 함
= JwtAuthorizationFilter를 구현해서 회원의 정보를 UserDetails에 담고
= 그 UserDetails는 Authentication이라는 인증객체 Principal 부분에 저장이 됨.
public void addFolder(Long productId, Long folderId, User user) {
Product product = productRepository.findById(productId).orElseThrow(
() -> new NullPointerException("해당 상품이 존재하지 않습니다.")
);
Folder folder = folderRepository.findById(folderId).orElseThrow(
() -> new NullPointerException("해당 폴더가 존재하지 않습니다.")
);
}
폴더 별 관심 상품 조회
public Page<ProductResponseDto> getProductsInFolder(Long folderId, int page, int size, String sortBy, boolean isAsc, User user) {
// 페이징 처리
Sort.Direction direction = isAsc ? Sort.Direction.ASC : Sort.Direction.DESC;
Sort sort = Sort.by(direction, sortBy);
Pageable pageable = PageRequest.of(page, size, sort);
// 해당 폴더에 등록되어 있는 상품 가져오기
// 현재 양방향으로 조회중
// folder_id에 번호를 주면 product_id도 같이 있으니까(어떤 특정한 폴더에 있는 product_id를 기준으로 product list(여러개)를 가져올 수 있다)
// QueryMethod는 ResponseDto를 반환하지 못한다. -> product로 반환
Page<Product> productList = productRepository.findAllByUserAndProductFolderList_FolderId(user, folderId, pageable);
// 변환
Page<ProductResponseDto> responseDtoList = productList.map(ProductResponseDto::new);
return responseDtoList;
}
findAllByUserAndProductFolderList_FolderId
아래와 위는 같은 뜻!
select
p.id, p.title as product_title, pf.product_id as product_id, pf.folder_id as folder_id
from
product p left join product_folder pf
on p.id = pf.product_id
where p.user_id = 1
and
pf.folder_id = 3;
order by p.id desc
limit 0, 10;
// limit 시작위치, 제한갯수