JPA 와 Querydsl 를 활용하는 연습을 진행하고 있다.
오늘의 간단한 목표는OrderBy
정렬을 사용하는 것이다.
@Entity
@Getter
@Builder
public class Post extends BaseEntity
{
@Id
@GeneratedValue
@Column(name = "post_pid")
private Long pid;
private String title;
@Builder.Default
private Integer view = 0;
@Column(columnDefinition="TEXT")
private String contents;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "auth_pid")
private Auth auth;
}
@Entity
@Getter
@Builder
@AllArgsConstructor
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Table(uniqueConstraints = @UniqueConstraint(columnNames = {"loginId"}))
public class Auth extends BaseEntity
{
@Id @GeneratedValue
@Column(name = "auth_pid")
private Long pid;
private String loginId;
private String password;
@OneToOne(fetch = FetchType.LAZY,cascade = CascadeType.DETACH)
@JoinColumn(name = "refresh_token_pid")
private RefreshToken refreshToken;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "member_pid")
private Member member;
public void linkMember(Member member)
{
this.member = member;
member.getAuths().add(this);
}
@OneToMany(mappedBy = "auth")
@Builder.Default
private List<Post> posts = new ArrayList<>();
@OneToMany(mappedBy = "auth")
@Builder.Default
private List<RoleAndAuth> roleAndAuths = new ArrayList<>();
}
@Entity
@Getter
@Builder
@AllArgsConstructor
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Table(uniqueConstraints = @UniqueConstraint( columnNames = {"userEmail","userNick"}))
public class Member extends BaseEntity
{
@Id @GeneratedValue
@Column(name = "member_pid")
private Long pid;
private String userName;
private int age;
private String userEmail;
private String phone;
private String userNick;
@Embedded
private Address address;
@OneToMany(mappedBy = "member")
@Builder.Default
private List<Auth> auths = new ArrayList<>();
}
--
@Data
public class SearchPostDto {
private String authorNick ;
private String title ;
private String contents ;
private boolean isAsc ;
}
POST
에 대한 정보를 조회 할 때 사용한다.
@Data
@ToString
public class SearchPostResultDto {
private String authorNick ;
private String title ;
private String contents ;
private Integer views ;
}
POST
정보 요청에 대한 반환 값 DTO
public class PostRepositoryImpl implements PostRepositoryCustom{
private final JPAQueryFactory queryFactory;
public PostRepositoryImpl(EntityManager em)
{
queryFactory = new JPAQueryFactory(em);
}
@Override
public Page<SearchPostResultDto> getSearchPost(SearchPostDto request, Pageable pageable) {
List<SearchPostResultDto> searchPostReq =
queryFactory.select(
Projections.fields(
SearchPostResultDto.class,
member.userNick.as("authorNick"),
post.title.as("title"),
post.contents.as("contents"),
post.view.as("views"))
)
.from(post)
.join(post.auth , auth)
.join(auth.member, member)
.where(
authorNickEq(request.getAuthorNick()),
postTitleEq(request.getTitle()),
postContentsEq(request.getContents())
)
.orderBy(request.isAsc() ? post.view.asc() : post.view.desc())
.offset(pageable.getOffset())
.limit(pageable.getPageSize())
.fetch();
System.out.println("ABLE");
return new PageImpl<>(searchPostReq,pageable,searchPostReq.size());
}
private BooleanExpression postTitleEq(String title){
return hasText(title) ? post.title.like("%" + title + "%") : null;
}
private BooleanExpression postContentsEq(String contents){
return hasText(contents) ? post.contents.like("%" + contents + "%") : null;
}
private BooleanExpression authorNickEq(String authorNick){
return hasText(authorNick) ? member.userNick.like("%" + authorNick + "%") : null;
}
}
private final JPAQueryFactory queryFactory;
public PostRepositoryImpl(EntityManager em)
{
queryFactory = new JPAQueryFactory(em);
}
추후 Spring DATA JPA 의 Save Method 를 사용하지 않고 엔티티를 저장하는 메소드를 작성하기 위해
queryFactory.select(
Projections.fields(
SearchPostResultDto.class,
member.userNick.as("authorNick"),
post.title.as("title"),
post.contents.as("contents"),
post.view.as("views"))
Query 결과 값을 DTO 에 받으려고 한다. 많은 방식 들 중 fields 에 직접 받는 방식을 사용하였다. 필드이름이 다르기 때문에
as
메소드를 활용하여 매핑하였다.
private BooleanExpression postTitleEq(String title){
return hasText(title) ? post.title.like("%" + title + "%") : null;
}
private BooleanExpression postContentsEq(String contents){
return hasText(contents) ? post.contents.like("%" + contents + "%") : null;
}
private BooleanExpression authorNickEq(String authorNick){
return hasText(authorNick) ? member.userNick.like("%" + authorNick + "%") : null;
}
다이나믹 서치 기능을 생각해보면 글자를 포함하는 경우까지 들고오는 것을 생각 할 수 있다.
검색 조건은게시글 ( POST )
의제목 ( title )
,내용 ( contents )
,작성자 닉네임 ( authorNick )
을 사용했다.
orderBy(request.isAsc() ? post.view.asc() : post.view.desc())
isAsc
필드 값이true
이면조회 수 ( view 필드 )
를 기준으로 오름차순 아닐 경우 내림차순이 되도록 설정 했다.
@Autowired
PostRepository postRepository;
@Autowired
CreateUpdateMemberService createUpdateMemberService;
@Autowired
AuthRepository authRepository;
@BeforeEach
void beforeSetting()
{
MemberInfoDto memberInfoDto = MemberInfoDto.builder()
.age(10)
.city("경기도 성남시")
.phone("010-1234-5678")
.loginId("testLoginId01")
.password("Qwer!234")
.street("대왕판교로")
.userEmail("testLoginId01@naver.com")
.userName("테스트01")
.userNick("TEST01")
.zipcode("12345")
.build();
long test01Pid = createUpdateMemberService.createMember(memberInfoDto);
MemberInfoDto memberInfoDto2 = MemberInfoDto.builder()
.age(10)
.city("경기도 성남시")
.phone("010-1234-5679")
.loginId("testLoginId02")
.password("Qwer!234")
.street("대왕판교로")
.userEmail("testLoginId02@naver.com")
.userName("테스트02")
.userNick("TEST02")
.zipcode("12345")
.build();
long test02Pid = createUpdateMemberService.createMember(memberInfoDto2);
Auth auth01 = authRepository.findById(test01Pid).orElseThrow(NotFoundLoginId::new);
Auth auth02 = authRepository.findById(test02Pid).orElseThrow(NotFoundLoginId::new);
Post post1 = Post.builder()
.title("abcde")
.contents("가나다라마")
.view(0)
.auth(auth01).build();
Post post2 = Post.builder()
.title("stuvw")
.contents("바사아자")
.view(100)
.auth(auth01).build();
Post post3 = Post.builder()
.title("kkkkkk")
.contents("가나다라마")
.view(20)
.auth(auth02).build();
Post post4 = Post.builder()
.title("kkka")
.contents("바사아자")
.view(1200)
.auth(auth02).build();
List<Post> postList = new ArrayList<>();
postList.add(post1);
postList.add(post2);
postList.add(post3);
postList.add(post4);
postRepository.saveAll(postList);
}
@Test
void find_Post_BY_Search()
{
SearchPostDto request = new SearchPostDto();
request.setAsc(true);
Page<SearchPostResultDto> searchPost = postRepository.getSearchPost(request, PageRequest.of(0, 4));
for (SearchPostResultDto searchPostResultDto : searchPost) {
System.out.println("searchPostResultDto : "+searchPostResultDto.toString() );
}
}
조회 수 기준으로 오름차순 정렬하는 결과 값을 요청
ABLE
searchPostResultDto : SearchPostResultDto(authorNick=TEST01, title=abcde, contents=가나다라마, views=0)
searchPostResultDto : SearchPostResultDto(authorNick=TEST02, title=kkkkkk, contents=가나다라마, views=20)
searchPostResultDto : SearchPostResultDto(authorNick=TEST01, title=stuvw, contents=바사아자, views=100)
searchPostResultDto : SearchPostResultDto(authorNick=TEST02, title=kkka, contents=바사아자, views=1200)
조회 수 기준으로 오름차순 정렬을 return 받은 것을 확인할 수 있다.