private static final PageRequest page = PageRequest.of(0, 3);
search 하나로 더욱 다양한 기능을 만들 방법을 생각해보았다.
- 페이징을 추가하자
- RequestParam방식으로 페이지를 입력받아 몇 번째 페이지인지를 알려줄 것이다.
- 한 페이지당 기본으로 10개정도의 결과를 가지게 반환시킬 계획이다.
멤버 조회시 아이디, 닉네임, 이메일이 나오므로 총 30줄정도가 나올 것 이므로 10개 정도가 적당하다는 생각이 들었다.
- contains를 동적으로 추가하자
- enum클래스를 만들어 RequestParam으로 검색방식을 정확한 검색인지, 혹은 검색하는 문구가 포함된 값을 구하는지를 정하게 할 것이다.
- 이전에 만들었던 ~~Eq메서드에 enum타입의 값을 받아 만약 Contains를 요청하는 것이라면, contains쿼리문을 실행시킬 계획이다.
이렇게 기능을 추가할 계획이다.
페이징의 경우에는 단순하게 처리가 가능하다.
- 찾으려는 페이지를 입력받는다(페이지의 크기는 위에서 말한대로 10으로 고정할 계획이다)
- 이 페이지와, 10이라는 사이즈를 입력해 PageRequest를 생성해준다.
- 리포지토리 기능을 동작시킬 땐, Pageable 파라미터를 추가해준 뒤, PageRequest를 넣는다.
- 끄읕
그러면 이게 동작하기 위해서 Repository부터 기능을 추가할 계획이다.
@Override
public Page<SearchMemberDto> search(SearchMemberDto searchMemberDto, Pageable pageable) {
if(searchMemberDto.getUsername() == null && searchMemberDto.getNickname() == null && searchMemberDto.getEmail() == null)
throw new NeedToAddSearchConditionException();
QueryResults<SearchMemberDto> result = query
.select(new QSearchMemberDto(member.username, member.nickname, member.email))
.from(member)
.where(usernameEq(searchMemberDto.getUsername()),
nicknameEq(searchMemberDto.getNickname()),
emailEq(searchMemberDto.getEmail()))
.offset(pageable.getOffset())
.limit(pageable.getPageSize())
.fetchResults();
return new PageImpl<SearchMemberDto>(result.getResults(), pageable, result.getTotal());
}
이런식으로 Page타입으로 메서드를 변경해주어야 한다. 이는 MemberCustomRepository도 마찬가지이다.
이후, Query를 바로 반환하는 것이 아닌, QueryResult로 일단 받아둬야 한다.
추가되는 코드로는, offset, limit, fetchResults가 존재한다.
- offset : 시작되는 인덱스를 알려준다.
- limit : 페이지당 크기를 알려준다.
- fetchResults : 말 그대로 결과값을 fetch(잡아온다)
이러한 결과를 PageImpl로 반환해주는데, 이 때 파라미터를 (쿼리의 결과, Pageable, 총 개수)로 생성해 반환해주면 페이징 기능이 만들어진다!
이후, 검색 방식도 추가한 뒤에, 최종적인 테스트를 만들어보려고 한다.
일단, 검색 방식이 어떻게 있을까?
- 정확한 사람의 아이디를 가지고 검색을 할 경우
- 정확하진 않지만, 비슷한 아이디를 찾는 경우
로 나눌 수 있다.
이를 만들기 위해,
private BooleanExpression usernameEq(String username){
if(username == null || username.isEmpty() || username.isBlank()) return null;
return member.username.eq(username);
}
이렇게 있던 Eq들을 수정할 계획이다.
일단 enum타입 클래스를 만들어두었다.
public enum SearchType {
LIKE("like"), EXACT("exact");
private String type;
private SearchType(String type){
this.type = type;
}
public String getType(){
return this.type;
}
}
이렇게 enum타입을 만들어두고, 이를 활용하기로 했다.
private BooleanExpression usernameEq(String username, SearchType searchType){
if(username == null || username.isEmpty() || username.isBlank()) return null;
if(searchType.equals(CONTAINS)) return member.username.contains(username);
return member.username.eq(username);
}
만약, 검색값이 null이면 그냥 조회하고,
SearchType이 LIKE라면, contains쿼리를 보내게 했다.
다른 메서드들에도 다 추가를 해주었고, MemberCustomRepository 인터페이스에도 파라미터를 추가해주었다.
이후, 서비스도 파라미터를 추가했다.
@Transactional(readOnly = true)
public Page<SearchMemberDto> search(SearchMemberDto searchMemberDto, Pageable pageable, SearchType searchType){
return memberRepository.search(searchMemberDto, pageable, searchType);
}
이렇게 메서드에 Pageable와 SearchType을 추가했다.
이제 테스트를 해야하는데, 일단 기존의 테스트를 미리 수정해둔게 좀 있다.
기존의 테스트에 전부 Pageable, SearchType을 넣어두었는데,
private final PageRequest page = PageRequest.of(0, 3);
테스트를 위해 상수로 PageRequest를 만들어 썼으며,
memberService.search(searchMemberDto, page, EXACT)
모든 메서드를 EXACT로 테스트했다.
또한, 클래스명을 ~~~TEST_SEARCH_EXACT의 방식으로 클래스명을 수정했다.
지금의 기준으로는, 정확한 이름을 넣어 검색했기에 EXACT로 했으며, 후에 CONTAINS를 위한 테스트를 만들 계획이다.
그건 다음편에서~~
'스프링 공부 > 게시판 프로젝트 만들기' 카테고리의 다른 글
[스프링] 29. MemberRepository.search를 최적화시켜보자!! (0) | 2023.02.09 |
---|---|
[스프링] 28. MemberService까지 만들고의 회고, 그리고 search를 마지막까지 다듬어보자!! (0) | 2023.02.09 |
[스프링] 26. MemberService : 로그인 로직 만들기 (0) | 2023.02.08 |
[스프링] 25. 조회에 대한 서비스 로직 만들어 테스트하기...? (0) | 2023.02.07 |
[스프링] 24. Member 데이터 변경을 비즈니스 로직에 추가하기 (0) | 2023.02.07 |