Skip to content

Commit

Permalink
Merge pull request #46 from Sirius506775/develope
Browse files Browse the repository at this point in the history
Querydsl를 이용한 검색과 페이징 기능 구현
  • Loading branch information
jyp-on authored Mar 28, 2023
2 parents 48a4474 + 935a8d4 commit 6ec534f
Show file tree
Hide file tree
Showing 17 changed files with 297 additions and 41 deletions.
26 changes: 26 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@

buildscript { //gradle이 특정 task를 실행할 때 사용
ext {
queryDslVersion = "5.0.0"
}
}

plugins {
id 'java'
id 'org.springframework.boot' version '2.7.9'
Expand Down Expand Up @@ -57,9 +64,28 @@ dependencies {
/* Thumbnail 파일 처리를 위한 의존성 */
implementation 'net.coobird:thumbnailator:0.4.17'

/* 동적 쿼리를 사용한 페이징과 검색 처리를 위해 querydsl 의존성 추가*/
implementation "com.querydsl:querydsl-jpa:${queryDslVersion}"

annotationProcessor(

"javax.persistence:javax.persistence-api",

"javax.annotation:javax.annotation-api",

"com.querydsl:querydsl-apt:${queryDslVersion}:jpa")


}

tasks.named('test') {
useJUnitPlatform()
}

sourceSets {
main {
java {
srcDirs = ["$projectDir/src/main/java", "$projectDir/build/generated"]
}
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
package com.hallym.festival.domain.booth.controller;

import com.hallym.festival.domain.booth.dto.BoothDTO;
import com.hallym.festival.domain.booth.entity.Booth;
import com.hallym.festival.domain.booth.dto.PageRequestDTO;
import com.hallym.festival.domain.booth.dto.PageResponseDTO;
import com.hallym.festival.domain.booth.service.BoothService;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
Expand All @@ -10,7 +11,6 @@
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import java.util.List;
import java.util.Map;
import javax.validation.Valid;

Expand All @@ -23,8 +23,13 @@ public class BoothController {
private final BoothService boothService;

@GetMapping(value = "/list", produces = MediaType.APPLICATION_JSON_VALUE)
public List<Booth> getAllBooths() {
return boothService.getList();
public PageResponseDTO<BoothDTO> list(PageRequestDTO pageRequestDTO){

PageResponseDTO<BoothDTO> responseDTO = boothService.list(pageRequestDTO);

log.info(responseDTO);

return responseDTO;
}

@GetMapping("/{bno}")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,20 +27,20 @@ public class PageRequestDTO {

private String keyword;

public String[] getTypes(){
public String[] getTypes(){ //boardRepository에서 String[]으로 반환하기 때문에 배열 반환
if(type == null || type.isEmpty()){
return null;
}
return type.split("");
}

public Pageable getPageable(String...props) {
public Pageable getPageable(String...props) { //페이징 처리를 위해 Pageable 타입 반환
return PageRequest.of(this.page -1, this.size, Sort.by(props).descending());
}

private String link;

public String getLink() {
public String getLink() { //검색 조건과 페이징 조건 들을 문자열로 구성

if(link == null){
StringBuilder builder = new StringBuilder();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

@Getter
@ToString
public class PageResponseDTO<E> {
public class PageResponseDTO<E> { //다른 도메인에서도 페이징 처리를 할 수 있게 제네릭 처리

private int page;
private int size;
Expand All @@ -27,7 +27,7 @@ public class PageResponseDTO<E> {
private List<E> dtoList;

@Builder(builderMethodName = "withAll")
public PageResponseDTO(PageRequestDTO pageRequestDTO, List<E> dtoList, int total){
public PageResponseDTO(PageRequestDTO pageRequestDTO, List<E> dtoList, int total){ //여러 정보를 생성자를 이용해서 받아서 처리하는 것이 안전

if(total <= 0){
return;
Expand All @@ -39,17 +39,17 @@ public PageResponseDTO(PageRequestDTO pageRequestDTO, List<E> dtoList, int total
this.total = total;
this.dtoList = dtoList;

this.end = (int)(Math.ceil(this.page / 10.0 )) * 10;
this.end = (int)(Math.ceil(this.page / 10.0 )) * 10; //마지막 페이지

this.start = this.end - 9;
this.start = this.end - 9; //시작 페이지

int last = (int)(Math.ceil((total/(double)size)));
int last = (int)(Math.ceil((total/(double)size))); //마지막 페이지 전체 개수

this.end = end > last ? last: end;
this.end = end > last ? last: end; //마지막 페이지가 last 값보다 작은 경우에 last값이 end

this.prev = this.start > 1;
this.prev = this.start > 1; //이전 페이지는 시작 페이지가 1이 아니라면 무조건 true

this.next = total > this.end * this.size;
this.next = total > this.end * this.size; //마지막 페이지와 페이지당 개수를 곱한 값보다 전체 개수가 많은가?

}
}
14 changes: 9 additions & 5 deletions src/main/java/com/hallym/festival/domain/booth/entity/Booth.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import com.fasterxml.jackson.annotation.JsonManagedReference;
import com.hallym.festival.domain.comment.entity.Comment;
import com.hallym.festival.domain.likes.entity.Likes;
import com.hallym.festival.domain.menu.entity.Menu;
import com.hallym.festival.global.baseEntity.BaseTimeEntity;
import lombok.*;
import org.hibernate.annotations.ColumnDefault;
Expand Down Expand Up @@ -80,12 +82,14 @@ public void clearImages() {
}


// @JsonManagedReference
// @OneToMany(mappedBy = "booth")
// private List<Menu> menus = new ArrayList<>();
@Builder.Default
@JsonManagedReference
@OneToMany(mappedBy = "booth")
private List<Menu> menus = new ArrayList<>();

// @OneToMany(mappedBy = "booth")
// private List<Like> likes = new ArrayList<>();
@Builder.Default
@OneToMany(mappedBy = "booth")
private List<Likes> likes = new ArrayList<>();

//test를 위한 change 함수
public void change(String booth_title, String booth_content, String writer, BoothType booth_type, boolean active){
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.hallym.festival.domain.booth.repository;

import com.hallym.festival.domain.booth.entity.Booth;
import com.hallym.festival.domain.booth.repository.boothSearch.BoothSearch;
import org.springframework.data.jpa.repository.EntityGraph;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
Expand All @@ -9,10 +10,12 @@
import java.util.Optional;

@Repository
public interface BoothRepository extends JpaRepository<Booth, Long> {
public interface BoothRepository extends JpaRepository<Booth, Long>, BoothSearch {
//EntityGraph를 이용해서 lazy 로딩이여도 한 번에 join 처리 후, select 실행
@EntityGraph(attributePaths = {"imageSet"}) //imageSet 속성을 같이 로딩
@Query("select b from Booth b where b.bno =:bno")
Optional<Booth> findByIdWithImages(Long bno);



}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.hallym.festival.domain.booth.repository.boothSearch;

import com.hallym.festival.domain.booth.entity.Booth;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;

public interface BoothSearch {

Page<Booth> search1(Pageable pageable);

Page<Booth> searchAll(String[] types, String keyword, Pageable pageable);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
package com.hallym.festival.domain.booth.repository.boothSearch;

import com.hallym.festival.domain.booth.entity.Booth;
import com.hallym.festival.domain.booth.entity.QBooth;
import com.querydsl.core.BooleanBuilder;
import com.querydsl.jpa.JPQLQuery;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.support.QuerydslRepositorySupport;

import java.util.List;

public class BoothSearchImpl extends QuerydslRepositorySupport implements BoothSearch {

public BoothSearchImpl(){
super(Booth.class);
}

@Override
public Page<Booth> search1(Pageable pageable) {

QBooth booth = QBooth.booth;

JPQLQuery<Booth> query = from(booth); //@Query로 생성했던 JPQL을 코드로 생성

BooleanBuilder booleanBuilder = new BooleanBuilder(); // (

booleanBuilder.or(booth.booth_title.contains("11")); // title like ...

booleanBuilder.or(booth.booth_content.contains("11")); // content like ....

query.where(booleanBuilder);
query.where(booth.bno.gt(0L)); //bno가 0보다 큰 조건


//paging
this.getQuerydsl().applyPagination(pageable, query);

List<Booth> list = query.fetch(); //JPQLQuery 실행

long count = query.fetchCount(); //fetchCount()로 count 쿼리 실행


return null;

}

@Override
public Page<Booth> searchAll(String[] types, String keyword, Pageable pageable) {

QBooth booth = QBooth.booth;
JPQLQuery<Booth> query = from(booth);

if( (types != null && types.length > 0) && keyword != null ){ //검색 조건과 키워드가 있다면

BooleanBuilder booleanBuilder = new BooleanBuilder(); // (

for(String type: types){

switch (type){
case "t":
booleanBuilder.or(booth.booth_title.contains(keyword));
break;
case "c":
booleanBuilder.or(booth.booth_content.contains(keyword));
break;
case "w":
booleanBuilder.or(booth.writer.contains(keyword));
break;
}
}//end for
query.where(booleanBuilder);
}//end if

//bno > 0
query.where(booth.bno.gt(0L));

//paging
this.getQuerydsl().applyPagination(pageable, query);

List<Booth> list = query.fetch();

long count = query.fetchCount();

return new PageImpl<>(list, pageable, count);
//페이징의 최종 처리는 Page<T>타입을 반환합니다. (실제 목록 데이터, 페이지 정보를 가진 객체, 전체개수)

}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package com.hallym.festival.domain.booth.service;

import com.hallym.festival.domain.booth.dto.BoothDTO;
import com.hallym.festival.domain.booth.dto.PageRequestDTO;
import com.hallym.festival.domain.booth.dto.PageResponseDTO;
import com.hallym.festival.domain.booth.entity.Booth;

import java.util.List;
Expand All @@ -11,7 +13,7 @@ public interface BoothService {

BoothDTO getOne(Long bno);

List<Booth> getList();
PageResponseDTO<BoothDTO> list(PageRequestDTO pageRequestDTO);

void modify(BoothDTO boothDTO);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,22 @@
package com.hallym.festival.domain.booth.service;

import com.hallym.festival.domain.booth.dto.BoothDTO;
import com.hallym.festival.domain.booth.dto.PageRequestDTO;
import com.hallym.festival.domain.booth.dto.PageResponseDTO;
import com.hallym.festival.domain.booth.entity.Booth;
import com.hallym.festival.domain.booth.entity.BoothType;
import com.hallym.festival.domain.booth.repository.BoothRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.modelmapper.ModelMapper;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;

import javax.transaction.Transactional;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

@Service
@Transactional
Expand All @@ -22,8 +27,23 @@ public class BoothServiceImpl implements BoothService{
private final BoothRepository boothRepository;
private final ModelMapper modelMapper;

public List<Booth> getList() {
return boothRepository.findAll();
public PageResponseDTO<BoothDTO> list(PageRequestDTO pageRequestDTO) {
String[] types = pageRequestDTO.getTypes();
String keyword = pageRequestDTO.getKeyword();
Pageable pageable = pageRequestDTO.getPageable("bno");

Page<Booth> result = boothRepository.searchAll(types, keyword, pageable);

List<BoothDTO> dtoList = result.getContent().stream()
.map(booth -> modelMapper.map(booth,BoothDTO.class)).collect(Collectors.toList());


return PageResponseDTO.<BoothDTO>withAll()
.pageRequestDTO(pageRequestDTO)
.dtoList(dtoList)
.total((int)result.getTotalElements())
.build();

}

public Long register(BoothDTO boothDTO){ //등록
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
import java.util.List;

public interface CommentRepository extends JpaRepository<Comment, Long> {
// @Query("select r from Comment r where r.booth.bno = :bno") //게시물 삭제 시 댓글들 삭제를 위한 쿼리
List<Comment> findByBooth_BnoAndActiveOrderByRegDateDesc(Long bno, Boolean active);

void deleteByBooth_Bno(Long bno);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
package com.hallym.festival.domain.visitComment.controller;


import com.hallym.festival.domain.visitComment.dto.VisitCommentRequestDto;
import com.hallym.festival.domain.visitComment.dto.VisitCommentResponseDto;
import com.hallym.festival.domain.visitComment.service.VisitCommentService;
import com.hallym.festival.domain.visitComment.dto.VisitCommentResponseDTO;
import lombok.RequiredArgsConstructor;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
Expand All @@ -21,12 +20,12 @@ public class VisitCommentController {
private final VisitCommentService visitCommentService;

@GetMapping(value = "list", produces = MediaType.APPLICATION_JSON_VALUE)
public List<VisitCommentResponseDto> getVisitCommentList() {
public List<VisitCommentResponseDTO> getVisitCommentList() {
return visitCommentService.getAll();
}
@PostMapping("/create")
public Map<String, String> createVisitComment
(@Valid @RequestBody VisitCommentRequestDto visitCommentRequestDto, HttpServletRequest request){
(@Valid @RequestBody com.hallym.festival.domain.visitComment.dto.VisitCommentRequestDTO visitCommentRequestDto, HttpServletRequest request){
visitCommentService.create(visitCommentRequestDto, request);
return Map.of("result", "create success");
}
Expand Down
Loading

0 comments on commit 6ec534f

Please sign in to comment.