개발꿀팁
spring 기간 조회 동적으로 처리하기
프로젝트 중 기간조회 기능이 필요해 작성하는 포스팅을 작성했었는데 코드를 더 동적으로 작성하자는 리뷰를 받고 수정해보았습니다
기존 코드
게시글 기간 조회
예시 이미지
Controller
날짜 조회를 위한 시작 날짜와 끝날짜 설정을 위해 requestParam으로 시작날짜와 마지막 날짜를 받습니다.
날짜를 입력하지 않을 때는 자동으로 입력될 수 있도록 defaultValue 값을 줍니다.
@DateTimeFormat으로 입력받을 형식을 지정해줍니다.
날짜만 받기 때문에 형식은 LocalDate입니다.
저는 페이징을 위해 Pageable도 넣었습니다
@RestController
@RequiredArgsConstructor
@RequestMapping("/api")
public class PostController {
private final PostService postService;
@GetMapping("/post")
public PageImpl<PostResponseDto> getPostList(@RequestParam(value = "searchStartDate", required = false, defaultValue = "19000101") @DateTimeFormat(pattern = "yyyyMMdd") LocalDate searchStartDate,
@RequestParam(value = "searchEndDate", required = false, defaultValue = "99991231") @DateTimeFormat(pattern = "yyyyMMdd") LocalDate searchEndDate,
@PageableDefault Pageable pageable
) {
return postService.getPostList(searchStartDate, searchEndDate, pageable));
}
}
Service
저는 보다 동적으로 처리하기 위해 Querydsl을 사용하였습니다
@Service
@Transactional
@AllArgsConstructor
public class PostService {
private final PostRepositorySupport postRepositorySupport;
public PageImpl<PostResponseDto> getPostList(String searchStartDate, String searchEndDate, Pageable pageable) {
return postQueryRepository.filter(startDateTime, endDateTime, pageable);
}
}
Repository
searchDateFilter라는 메서드를 별로도 만들어 조건문에 넣어줬습니다
여기서 특이점은 searchDateFilter메서드 안에 Querydsl 문법(goe, loe)입니다
post.createdAt.goe(LocalDateTime.of(searchStartDate, LocalTime.MIN))에서 goe는 .goe의 앞의 값이. goe 뒤 괄호 안의 값보다 크거나 같다는 것을 뜻합니다. (loe는 반대, 예시는 코드 아래 기록하였습니다)
또한 createdAt의 타입은 LocalDateTime으로 controller에서는 파라미터로 LocalDate만 받았기 때문에 LocalDateTime.of로 날짜와 시간을 입력해줍니다. 여기서 시간은 LocalTime.MIN으로 해서 최소시간(00:00)으로 해줍니다
LocalDateTime.of(searchEndDate, LocalTime.MAX).withNano(0)에서 .withNano(0)를 붙이는 이유는 LocalTime.MAX의 값이 '23:59:59.999999999'이기 때문에 그대로 사용하면 올림이 되어 '00:00'이 되어 버린다.... 뒤에 .withNano(0)를 붙여줌으로써 밀리세컨드 단위가 지워집니다
@Repository
public class PostQueryRepository extends QuerydslRepositorySupport {
private final JPAQueryFactory queryFactory;
public PostQueryRepository(JPAQueryFactory factory) {
super(Post.class);
this.queryFactory = factory;
}
public PageImpl<PostResponseDto> filter(LocalDateTime searchStartDate, LocalDateTime searchEndDate, Pageable pageable) {
JPQLQuery<PostResponseDto> result = queryFactory
.select(Projections.fields(PostResponseDto.class,
post.id, post.title, post.cont, post.created_at))
.from(post)
// 조건문
.where(searchDateFilter(searchStartDate, searchEndDate))
.orderBy(post.id.desc());
long totalCnt = result.fetchCount();
List<PostResponseDto> list = getQuerydsl().applyPagination(pageable, result).fetch();
return new PageImpl<PostResponseDto.ListDto>(list, pageable, totalCnt);
}
// 날짜 필터
private BooleanExpression searchDateFilter(LocalDate searchStartDate, LocalDate searchEndDate) {
//goe, loe 사용
BooleanExpression isGoeStartDate = post.createdAt.goe(LocalDateTime.of(searchStartDate, LocalTime.MIN));
BooleanExpression isLoeEndDate = post.createdAt.loe(LocalDateTime.of(searchEndDate, LocalTime.MAX).withNano(0));
return Expressions.allOf(isGoeStartDate, isLoeEndDate);
}
}
Querydsl 문법
<범위 체크 사용 예시>
- x.goe(y); (x >= y)
- x.gt(y); (x > y)
- x.loe(y); (x <= y)
- x.lt(y); (x < y)
확실히 먼저 기록했던 코드보다 깔끔해지기도 했고, 동적 쿼리를 활용해 더욱 효율적인 코드가 완성된 듯하네요! 만족 만족 대만족!
저 혼자였으면 앞선 코드에 만족했을 텐데 선임 개발자분이 조금 더 동적으로 작성해보라는 리뷰가 있어 더 찾아보고 작성했는데 모르고 넘어갔을 querydsl문법도 알게 된 좋은 기회였습니다!
다음에는 querydsl문법을 정리해보는 포스팅도 작성하면 좋을 것 같네요👍
'개발 하나둘셋 > Java & Spring' 카테고리의 다른 글
SpringBoot 슬랙 Slack알림보내기 ChatPostMessageRequest (0) | 2022.06.15 |
---|---|
SpringBoot SMTP서버를 활용한 메일 보내기 (0) | 2022.06.07 |
spring 게시판 기간조회 방법! String -> LocalDateTime 변환 (0) | 2022.04.25 |
스프링 DI ,IOC, AOP (0) | 2022.04.11 |
Spring에서 Redis Sorted set으로 인기검색어 순위 나타내기 (4) | 2022.01.15 |