일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
Tags
- javascript
- 싱글톤
- codingtest
- 리눅스
- 시큐리티 로그아웃
- html
- 2차원배열
- java
- 로그인
- css
- input태그
- Spring boot
- 스프링 부트
- 프로그래머스
- gradle
- springSecurity
- security
- 시큐리티로그인
- springboot
- 반복문
- JAVA11
- 시큐리티 로그인
- sql
- 코딩테스트
- Linux
- 시큐리티
- StyleSheet
- programmers
- 목록
- 소스트리
Archives
- Today
- Total
JAVAIARY
JPQL로 검색하기 본문
1. Repository의 확장
- 쿼리메서드나 @Query 등으로 처리할 수 없는 기능은 별도의 인터페이스로 설계
- 별도의 인터페이스에 대한 구현 클래스를 작성합니다.
이 때 QuerydslRepositorySupport라는 클래스를 부모 클래스로 사용 - 구현 클래스에 인터페이스의 기능을 Q도메인 클래스와 JPQLQuery를 이용해서 구현
1) compileJava 실행
- Q도메인 클래스 생성 확인
2) search 패키지와 Repository 생성
public interface SearchBoardRepository {
Board search1();
}
@Log4j2
public class SearchBoardRepositoryImpl extends QuerydslRepositorySupport implements SearchBoardRepository {
public SearchBoardRepositoryImpl(){
super(Board.class);
}
@Override
public Board search1() {
log.info("search1................");
return null;
}
}
- QuerydslRepositorySupport 클래스를 상속해야함
- QuerydslRepositorySupport는 생성자가 존재하므로 클래스 내에서 super()를 이용하여 호출해야 함
💡 상속받는 자식 클래스의 인스턴스 생성시, 부모 클래스의 기본 생성자를 자동으로 호출 하게 됨.
그러나 매개변수가 있는 부모 클래스의 생성자는 자동으로 호출되지 않는다.
그러므로 super( ) 를 통해 부모 클래스 생성자를 호출하고 부모클래스의 생성자가 요구하는 매개변수를 넣어줌
* super( ) 는 반드시 자식 생성자의 첫 줄에 위치해야 함
- 도메인 클래스를 지정하는데 null 값을 넣을 수 없으므로 Board.class를 넣어줌
- BoardRepository 에서 SearchBoardRepository 를 상속하는 형태로 변경
2) test
@Test
public void testSearch1(){
boardRepository.search1();
}
log.info에서 동작 확인
2. JPQL Query객체
- Querydsl 라이브러리 내에 존재하는 JPQLQuery 인터페이스 활용
1) SearchBoardRepositoryImpl
@Override
public Board search1() {
log.info("search1................");
QBoard board = QBoard.board;
JPQLQuery<Board> jpqlQuery = from(board);
jpqlQuery.select(board).where(board.bno.eq(1L));
log.info("----------------------------");
log.info(jpqlQuery);
log.info("----------------------------");
List<Board> result = jpqlQuery.fetch();
return null;
}
- 실제 SQL문 실행
3. JPQLQuery의 leftJoin() / on()
- Board와 Reply Left (outer) join
@Override
public Board search1() {
log.info("search1......................................");
QBoard board = QBoard.board;
QReply reply = QReply.reply;
JPQLQuery<Board> jpqlQuery = from(board);
jpqlQuery.select(board).where(board.bno.eq(1L));
jpqlQuery.leftJoin(reply).on(reply.board.eq(board));
log.info("------------------------");
log.info(jpqlQuery);
log.info("------------------------");
List<Board> result = jpqlQuery.fetch();
return null;
}
4. Tuple 객체
- JPQLQUery의 leftJoin(), join()을 이용해서 Board, Member, Reply를 처리할 수 있고,
groupBy() 등을 이용해서 집계함수 처리 가능 - 정해진 엔티티 객체 단위가 아니라 각각의 데이터를 추출하는 경우에는 Tuple 객체를 사용
- Tuple은 JPQLQuery에서 데이터를 추출(projection)하는 용도로 제한적으로 사용
@Override
public Board search1(){
log.info("search1......................................");
QBoard board = QBoard.board;
QReply reply = QReply.reply;
QMember member = QMember.member;
JPQLQuery<Board> jpqlQuery = from(board);
jpqlQuery.leftJoin(member).on(board.writer.eq(member));
jpqlQuery.leftJoin(reply).on(reply.board.eq(board));
JPQLQuery<Tuple> tuple = jpqlQuery.select(board, member.email, reply.count()).groupBy(board);
log.info("------------------------");
log.info(jpqlQuery);
log.info("------------------------");
List<Board> result = jpqlQuery.fetch();
return null;
}
-JPQL
select board, member1.email, count(reply)
from Board board
left join Member member1 with board.writer = member1
left join Reply reply with reply.board = board
group by board, member1
-SQL
- Board 객체, 작성자 이메일, 댓글 개수 출력
5. JPQLQuery로 Page<Object[]> 처리
1) SearchPage 생성 및 테스트
- 가능하면 DTO를 Repository 영역에서 다루지 않도록 하기 위해
검색 타입(type), 키워드 (keyword), 페이지 정보 (Pageable)를 파라미터로 전달
@Override
public Page<Object[]> searchPage(String type, String keyword, Pageable pageable) {
log.info("searchPage..............................");
return null;
}
- SearchBoardRepositoryImpl 에서 구현
Test 추가
@Test
public void testSearchPage(){
Pageable pageable = PageRequest.of(0,10, Sort.by("bno").descending());
Page<Object[]> result = boardRepository.searchPage("t", "1", pageable);
}
2) SearchPage에 검색 조건 추가
@Override
public Page<Object[]> searchPage(String type, String keyword, Pageable pageable) {
log.info("searchPage..............................");
QBoard board = QBoard.board;
QReply reply = QReply.reply;
QMember member = QMember.member;
JPQLQuery<Board> jpqlQuery = from(board);
jpqlQuery.leftJoin(member).on(board.writer.eq(member));
jpqlQuery.leftJoin(reply).on(reply.board.eq(board));
//Select b, w, count(r) From Board b
//Left Join b.writer w Left Join Reply r On r.board= b
JPQLQuery<Tuple> tuple = jpqlQuery.select(board,member,reply.count());
BooleanBuilder booleanBuilder = new BooleanBuilder();
BooleanExpression expression = board.bno.gt(0L);
booleanBuilder.and(expression);
if(type != null){
String[] typeArr = type.split("");
//검색 조건 작성하기
BooleanBuilder conditionBuilder = new BooleanBuilder();
for(String t:typeArr){
switch (t){
case "t":
conditionBuilder.or(board.title.contains(keyword));
break;
case "w":
conditionBuilder.or(member.email.contains(keyword));
break;
case "c":
conditionBuilder.or(board.content.contains(keyword));
break;
}
}
booleanBuilder.and(conditionBuilder);
}
tuple.where(booleanBuilder);
tuple.groupBy(board);
List<Tuple> result = tuple.fetch();
log.info(result);
return null;
}

- Tuple 에 기본 조회 속성 및 조인처리를 해 준 뒤,
- BooleanBuilder를 통해 Where 절을 검색 조건에 맞게 작성해 준다.
- 검색조건이 변경되면 where절도 함께 변경됨
- tuple에 where 절 추가 및 groupBy 지정
- fetch() : List 형식으로 변환하여
- 미리 작성해 놓은 Test 코드를 통해 확인
3) sort / count 처리
- JPQL에서는 Sort 객체를 지원하지 않음
- OrderSpecifier<Textends Comparable> 를 파라미터로 처리 필요
//order by
Sort sort = pageable.getSort();
//tuple.orderBy(board.bno.desc());
sort.stream().forEach(order -> {
Order direction = order.isAscending()? Order.ASC : Order.DESC;
String prop = order.getProperty();
PathBuilder orderByExpression = new PathBuilder(Board.class, "board");
tuple.orderBy(new OrderSpecifier(direction, orderByExpression.get(prop)));
});
tuple.groupBy(board, member);
//page 처리
tuple.offset(pageable.getOffset());
tuple.limit(pageable.getPageSize());
List<Tuple> result = tuple.fetch();
log.info(result);
long count = tuple.fetchCount();
log.info("COUNT:" + count);
return new PageImpl<Object[]>(result.stream().
map(t -> t.toArray()).collect(Collectors.toList()), pageable, count);
- searchPage()의 where절 이하 변경
- and() 를 이용하여 고의적으로 중첩되는 정렬 조건 추가
6. 목록화면에서 검색 처리
1) BoardServiceImpl 클래스 getList 수정
@Override
public PageResultDTO<BoardDTO, Object[]> getList(PageRequestDTO pageRequestDTO) {
log.info(pageRequestDTO);
Function<Object[], BoardDTO> fn = (en -> entityToDTO((Board)en[0], (Member)en[1], (Long)en[2]));
// Page<Object[]> result = repository.getBoardWithReplyCount(pageRequestDTO
// .getPageable(Sort.by("bno").descending()));
Page<Object[]> result = repository.searchPage(pageRequestDTO.getType(),
pageRequestDTO.getKeyword(), pageRequestDTO.getPageable(Sort.by("bno").descending()));
return new PageResultDTO<>(result, fn);
}
- 타입, 키워드, 정렬조건을 받도록 변경
- 검색 키워드를 넣고 정상적으로 검색 결과가 출력되는 것 확인~
'Project > 2023.02~ ) Study toy 프로젝트' 카테고리의 다른 글
자잘한 이슈 고치기! (0) | 2023.03.13 |
---|---|
@RestController와 JSON처리 (0) | 2023.03.13 |
컨트롤러와 화면 처리 (0) | 2023.03.06 |
프로젝트 적용하기(Board) (0) | 2023.03.06 |
N:1(다대일) 연관 관계 2 - JPQL과 LEFT(OUTER) JOIN (0) | 2023.03.05 |