본문 바로가기

boot_JPA 수업 정리

5일

검색기능 구현

 

- build.gradle 추가부분

	implementation 'com.querydsl:querydsl-jpa:5.0.0:jakarta'
	annotationProcessor "com.querydsl:querydsl-apt:${dependencyManagement.importedProperties['querydsl.version']}:jakarta"
	annotationProcessor "jakarta.annotation:jakarta.annotation-api"
	annotationProcessor "jakarta.persistence:jakarta.persistence-api"
def querydslSrcDir = 'src/main/generated'

clean{
	delete file(querydslSrcDir)
}

tasks.withType(JavaCompile){
	options.generatedSourceOutputDirectory = file(querydslSrcDir)
}

 

● 리스트페이지에 검색 화면 구성

<div class ="container-fluid">
    <form action="/board/list" class="d-flex" role="search" >
        <select class="form-select form-select-sm" id="inputGroupSelect01" name="type" style="width: 70%; margin-right: 20px">
            <option th:selected="${pgvo.type == null ? true : false}" >Choose...</option>
            <option th:value="t" th:selected="${pgvo.type == 't' ? true : false}" >title</option>
            <option th:value="w" th:selected="${pgvo.type == 'w' ? true : false}">writer</option>
            <option th:value="c" th:selected="${pgvo.type == 'c' ? true : false}">content</option>
            <option th:value="tw" th:selected="${pgvo.type == 'tw' ? true : false}" >title + writer</option>
            <option th:value="wc" th:selected="${pgvo.type == 'wc' ? true : false}">writer + content</option>
            <option th:value="tc" th:selected="${pgvo.type == 'tc' ? true : false}">title + content</option>
            <option th:value="twc" th:selected="${pgvo.type == 'twc' ? true : false}">all</option>
        </select>

        <input class="form-control me-2" name="keyword" type="search" placeholder="Search..." aria-label="Search" th:value="${pgvo.keyword }" >
        <input type="hidden" name="pageNo" value="1">
        <button type="submit" class="btn btn-success position-relative">
            Search
            <span class="position-absolute top-0 start-100 translate-middle badge rounded-pill bg-danger">
                [[${list.totalElements }]]
                <span class="visually-hidden">unread messages</span>
            </span>
        </button>

    </form>
</div>

 

● PagingVO에 타입 , 키워드를 추가해주고 생성자도 추가 

    private String type;
    private String keyword;
    public PagingVO(Page<BoardDTO> list, int pageNo, String type , String keyword){
        this(list,pageNo);
        this.type = type;
        this.keyword = keyword;
    }

 

● 컨트롤러 list부분에 type과 keyword를 파라미터로 받을 수 있도록하고 list와 pgvo에 추가해줌.

    @GetMapping("/list")
    public void list(Model model,
                     @RequestParam(value = "pageNo", defaultValue = "0", required = false) int pageNo,
                     @RequestParam(value = "type", required = false) String type,
                     @RequestParam(value = "keyword",required = false) String keyword){

        pageNo = (pageNo == 0  ? 0  : pageNo - 1);
        Page<BoardDTO> list = boardService.getList(pageNo,type,keyword); // type, keyword 추가해서 서비스임플로 보내기
        PagingVO pgvo = new PagingVO(list, pageNo,type,keyword);
        model.addAttribute("list", list);
        model.addAttribute("pgvo", pgvo);
    }

 

  type,keyword,pageable을 받아서  Page<Board> list를 리턴받는 BoardCustomRepository 인터페이스를 생성

public interface BoardCustomRepository {
    Page<Board> serachBoards(String type, String keyword, Pageable pageable);
}

 

- 구현 타입을 배열로만들어서 나눈다음 switch case를 이용해서 타입별 포함하는지 확인하는 구문구현

이후 구현한 조건문을 이용해서 페이징

public class BoardCustomRepositoryImpl implements BoardCustomRepository{
    private final JPAQueryFactory queryFactory;
    public BoardCustomRepositoryImpl(EntityManager em) {
        this.queryFactory = new JPAQueryFactory(em);
    }

    // 실제 구현
    @Override
    public Page<Board> serachBoards(String type, String keyword, Pageable pageable) {
        // 조건이 많을 경우
        // select * from baord where
        // isDel = 'n' and title like '% aaa %'
        // BooleanExpression condition = board.isDel.eq('N');
        BooleanExpression condition = null;

        // 동적 검색 조건 추가
        if(type != null && keyword != null){
            String[] typearr = type.split("");
            // 이전 선행 조건이 있다면...
            BooleanExpression dynamicCondition = null;
            for(String t : typearr){
                switch (t) {
                    case "t":
                        dynamicCondition = (dynamicCondition == null) ?
                                board.title.containsIgnoreCase(keyword) : dynamicCondition.or(board.title.containsIgnoreCase(keyword));
                        break;
                    case "w":
                        dynamicCondition = (dynamicCondition == null) ?
                                board.writer.containsIgnoreCase(keyword) : dynamicCondition.or(board.writer.containsIgnoreCase(keyword));
                        ;
                        break;
                    case "c":
                        dynamicCondition = (dynamicCondition == null) ?
                                board.content.containsIgnoreCase(keyword) : dynamicCondition.or(board.content.containsIgnoreCase(keyword));
                        break;
                }
            }
            if(dynamicCondition != null){
                condition = dynamicCondition;
            }
        }
        // 쿼리 작성 및 페이징 적용
        List<Board> result = queryFactory
                .selectFrom(board)
                .where(condition)
                .orderBy(board.bno.desc())
                .offset(pageable.getOffset())
                .limit(pageable.getPageSize())
                .fetch();
        // 검색된 데이터의 전체 개수 조합
        long total = queryFactory
                .selectFrom(board)
                .where(condition)
                .fetch().size();     // .fetchCount()

        return new PageImpl<>(result, pageable, total);
    }

 

● 생성한 type,keyword,pageable을 받아 Page list를 리턴하는 메서드를 이용해서 ServiceImpl 수정 검색기능을 구현.

    @Override
    public Page<BoardDTO> getList(int pageNo, String type, String keyword) {
        // pageNo = 0부터 시작
        // 0 => limit 0,10 , 1=> limit 10,10
        Pageable pageable = PageRequest.of(pageNo,10,Sort.by("bno").descending());
        // type, keyword , pageable 값을 주고, Page<Board> list 리턴 받는 메서드 생성
        Page<Board> list = boardRepository.serachBoards(type,keyword,pageable);
        Page<BoardDTO> boardDTOList = list.map(b -> convertEntityToDto(b));
        return boardDTOList;
    }

 

● 페이지네이션 th:href 부분에 추가 

type=${pgvo.type},keyword=${pgvo.keyword}

 

이러면 전체적인 CURD 게시판은 끝 

'boot_JPA 수업 정리' 카테고리의 다른 글

Boot_JPA 4일차  (1) 2024.11.25
Boot_JPA 3일차  (0) 2024.11.22
Boot_JPA 2일차  (3) 2024.11.21
Boot_JPA 1일  (1) 2024.11.20