일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- 스레드
- 도커 엔진
- 쿠버네티스
- LIST
- 김영한
- Collection
- Java IO
- java socket
- 시작하세요 도커 & 쿠버네티스
- 컨테이너
- 실전 자바 고급 1편
- 자바
- java network
- 동시성
- Thread
- container
- 리스트
- 자바 입출력 스트림
- Kubernetes
- 멀티 쓰레드
- 도커
- 인프런
- java
- 쓰레드
- Docker
- 자료구조
- 자바 io 보조스트림
- 알고리즘
- 스레드 제어와 생명 주기
- filewriter filereader
- Today
- Total
쌩로그
검색 조건을 가진 Condition클래스 작성시 바인딩 되지 않던 문제 해결 본문
목록
포스팅 개요
본론
2-1. 구성 클래스
2-2. 문제 살펴보기
2-3. 문제 해결하기
2-3-1. 번외 @Getter 사용해보기
2-3-2. @Setter로 진짜 문제 해결하기요약
1. 포스팅 개요
이번 프로젝트에서 동행 도메인 같은 경우,
쿼리스트링으로, 지역과 날짜(동행시작 날짜)를 검색해서 조회하는 기능을 구현했는데,
쿼리스트링으로 검색 조건을 넣더라도,
검색조건을 가지는 클래스(AccompanySearchCondition)의 필드와 바인딩 되지 않던 문제를 해결하는 포스팅이다.
결론부터 말하자면 @Setter를 쓰면 된다.
2. 본론
2-1. 구성 클래스
먼저 관련된 클래스 코드를 보면 다음과 같다.
Controller
// 동행 전체 조회(날짜, 지역)
@GetMapping
public ResponseEntity searchLocalAndDate(AccompanySearchCondition accompanySearchCondition,
@RequestParam(name = "page", defaultValue = "1") Integer page) throws ParseException {
return ResponseEntity.ok(accompanyService.findByLocalAndDate(accompanySearchCondition, page));
}
검색 조건 클래스
@AllArgsConstructor
@NoArgsConstructor
public class AccompanySearchCondition {
private String local;
@DateTimeFormat(pattern = "yyyy-MM-dd")
private LocalDate startDate;
public Local getLocal() {
return this.local == null ? null : Local.findByLocal(this.local);
}
public LocalDate getDate() {
return startDate;
}
}
검색 조건을 가지고 select 쿼리를 날리는 QueryDsl(with 페이지)
public PageResponseDto<AccompanyResponseListDto> searchByLocalAndDate(AccompanySearchCondition accompanySearchDto, Integer page) throws ParseException {
List<AccompanyResponseListDto> accompanyDtoList;
accompanyDtoList = queryFactory
.select(new QAccompanyResponseListDto(
accompany.accompanyId.as("accompanyId"),
accompany.nickname,
accompany.local.stringValue(),
accompany.accompanyMemberList.size().longValue(),
accompany.maxMemberNum,
accompany.accompanyStartDate,
accompany.accompanyEndDate,
accompany.title,
accompany.recruitComplete,
accompany.createdAt))
.from(accompany)
.where(
localEq(accompanySearchDto.getLocal()),
startDateEq(accompanySearchDto.getDate())
)
.offset(page*10-10) // 해당 페이지의 시작데이터
.limit(10)
.fetch();
Long totalElements = queryFactory
.select(accompany.count())
.from(accompany)
.where(
localEq(accompanySearchDto.getLocal()),
startDateEq(accompanySearchDto.getDate())
).fetchOne();
Long totalPage = (totalElements/10) + (totalElements%10 > 0 ? 1 : 0); // totalPage
// 마지막 페이지보다 작으면 10 아니라면, 총 요소갯수에서 % 10(페이지 사이즈)
Long currentPageElements = page < totalPage ? 10 : totalElements % 10;
return PageResponseDto.of(accompanyDtoList, totalPage, totalElements, currentPageElements, page);
}
// local이 있는지 확인 (AccompanySearchCondition으로부터 받아옴)
private BooleanExpression localEq(Local local) {
return Objects.nonNull(local) ? accompany.local.eq(local) : null;
}
// startDate가 있는지 확인 (AccompanySearchCondition으로부터 받아옴)
private BooleanExpression startDateEq(LocalDate startDate) {
return Objects.nonNull(startDate) ? accompany.accompanyStartDate.eq(startDate) : null;
}
2-2. 문제 살펴보기
2-1 처럼 클래스가 구성되어있을 때 어떻게 받아오는지 보자.
검색조건을 쿼리스트링으로 주면,
AccompanySearchCondition클래스에서
지역을 뜻하는 local, 여행시작날짜를 의미하는 필드인 startDate 필드가 검색조건으로 준 값(value)과 각각 바인딩되어 변수에 담겨야한다.
컨트롤러에는 쿼리스트링이 잘 받아오는지 확인하기 위해서@Slf4j
를 이용해서 log.info를 다음과 같이 발.라.놨다.

다음은 검색조건을 받는 클래스이다.

그리고 다음과 같이 데이터가 두 건 있다고 가정하자...
✅참고로 다른 데이터들 보다 검색조건을 받는 지역을 의미하는 local
과, 여행 시작날짜를 뜻하는 변수 accompanyStartDate
를 주목하자.

두 데이터 다 지역은 서울이다.
만약, 제주도를 검색하면 결과는 아무것도 없어야 한다.

하지만, 결과는 서울이 잘 나온다. ..;;;

음.. 그럼 서울로 검색하면 과연 값이 잘 들어갈까?

뭔가... 잘 들어간 것 처럼 보인다.
하지만 로그를 보면... null이 나온다.

;;;;;

흠... 그럼 날짜 조회는 어떨까?
아까 두 개의 데이터는
지역은 서울,
날짜는 2023-07-18
이다.
2023-07-20으로 조회해보자.

20일로 조회했지만, 18일이 나온다..
로그를 확인해보자.

결과는 null이다.
2-3. 문제 해결하기
그럼 과연 어떤 것이 문제일까?
포스팅 개요에서 말했지만, 다시 말하자면 @Setter
를 쓰면 된다.
@Setter를 넣어주지 않으면, 쿼리스트링으로 받는 값과 클래스의 각 필드가 바인딩되지 않는다.
2-3-1. 번외 @Getter 사용해보기
@Setter
를 사용하기 이전에 @Getter
를 넣어보자
참고로 그리도 유용한 @Getter가 여기선 쓸모없지만,
그냥 실험차 보는 것이다.

위와 같이 @Setter
는 주석처리하고, @Getter
만 적어줬다.
데이터는 다음과 같이 있다.

이번엔 3개의 데이터다.
이번에도 제주도로 검색해보자.

서울로만 3개인데, 제주도로 검색하니깐 서울 3개가 나왔다.(사실 위의 3개의 데이터는 제주도로 검색한 결과였다..그래서 스샷이 같음;;)

로그는 다음과 같다...

예상했지만, 역시 null이다.
2-3-2. @Setter로 진짜 문제 해결하기
이제 @Setter
로 가자@Getter
는 쓸모없으니 지우자.

이번엔 '서울', '2023-07-18'만 4개를 넣어놨다.
(accompanyId가 4이다.포스트맨 send 광클)

@Setter
로 바꾼 이후,
'서울', '2023-07-18'만 4개있을 때
지역으로 '제주도'를 검색하면,,?
이야아!!!!

이야아!!!!

오...아무것도 뜨지 않는다!!!
(참고로 지금 나오는 결과 값들은 페이지 네이션 정보들이다.)
드디어 성공!!!!

다시 살펴보자.

하나도 나오지 않는다.
안 나오는 게 맞다.
왜냐하면 우리에게 있는 데이터는 '서울','2023-07-18' 만 4건 있다.
이제 로그도 한번 보자.

크...잘 들어간다~
그리고 서울로 한 번 검색해보겠다.

지역을 서울로 검색하면 4건의 데이터가 다 나온다.
그럼 왜 다 나올까??
다 나오는 게 맞다... 아까 말했지만,우리에게 있는 데이터는 '서울','2023-07-18' 만 4건 있다.
로그를 보자.

역시 잘 들어간다.
그럼 날짜도 잘 들어갈까?

데이터가 나오지 않는다.
왜냐하면 검색은 17일로 했지만, 우리에게 있는 데이터는 4건 모두 18일이다.
로그를 확인하면,

로그에도 값이 잘 들어왔다고 알려준다.
이제 Id가 2,3인 데이터를 수정해보려고 한다.
Id 2는 부산, 08-01,
Id 3은 제주도 08-01
이렇게 수정해보겠다.
수정을 한 결과다.

4건의 데이터는 다음과 같다.
Id | 지역 | 날짜 |
---|---|---|
1 | 서울 | 07-18 |
2 | 부산 | 08-01 |
3 | 제주도 | 08-01 |
4 | 서울 | 07-18 |
이제 조회 결과를 보자.
'부산'으로 조회해보자.

부산에 해당하는 데이터가 잘 나온다.
다음은 '제주도'로 검색해보자.

제주도에 해당하는 데이터도 잘 나온다.
이제 '서울'로 조회해보자

크... 서울에 해당하는 데이터 역시 잘 나온다.
이제 날짜다.
날짜 '7월18일'을 조회해보자.

여행 시작날짜가 7월 18일에 해당하는 데이터가 잘 나온다.
다음은 '8월 1일' 조회

날짜가 8월 1일에 해당하는 데이터도 잘 나온다.
다음은 지역과 날짜를 같이 조회해보자!
'부산', '7월20일'로 조회하려고 한다.
결과는 나오지 않아야 정상이다.

나오지 않는다.
왜냐하면, '부산', '7월20일'에 해당하는 데이터가 당연히 없기 때문이다.
(갑자기 든 생각이다. 지금 조건은 and 조건인데, 만약 or 조건으로는..?
나중에 해봐야겠다.)

이제 '부산', '8월1일'로 검색해보자.
당연하게도 잘 나올 것이다.

캬...
로그는 어떻게 되있을까??


3. 요약
검색 조건을 쿼리스트링으로 받아서 검색 조건을 가지는 클래스를 생성하려고 할 때,
값이 바인딩되지 않던 문제를 마주하게 되었고,@Setter
를 사용함으로 이를 해결한 것에 대한 포스팅이다.
(요약에 비해선 스크롤이 긴거 같기도...;;)
'TroubleShooting & 고민 > BE' 카테고리의 다른 글
전체조회시 QueryDSL 사용 (3) | 2023.08.03 |
---|---|
Test코드 작성시 Post를 작성한다면, Map을 사용해보자. (0) | 2023.07.24 |
@Builder는 잘 써야 좋다. (0) | 2023.07.11 |
AOP는 필요없었다...(feat. Spring Security는 진짜 좋은 프레임워크다.) (0) | 2023.07.09 |
AOP로 AccessToken 검증(빡쳐서 만듬) (5) | 2023.07.05 |