쌩로그

검색 조건을 가진 Condition클래스 @Setter 빼기 본문

TroubleShooting & 고민/BE

검색 조건을 가진 Condition클래스 @Setter 빼기

.쌩수. 2023. 8. 15. 15:33
반응형

목록

  1. 포스팅 개요
  2. 본론
  3. 요약

1. 포스팅 개요

저번에 검색 조건을 가진 Condition클래스 작성시 바인딩 되지 않던 문제 해결이라는 주제로 포스팅을 했었습니다.

당시 검색조건을 필드로 가지던 클래스로 생성된 인스턴스를
계층별로 넘겨서 Repository 계층에서 받고,
인스턴스의 필드 값을 판별해서 데이터 조회결과를 반환하도록 했었습니다.

당시 그냥 구현에만 신경쓰다가 검색 조건 클래스에 @Setter를 무작정 쓰고,
"와~ 됬다!"만 하고 끝냈었습니다.

그런데 @Setter를 쓰면, 객체의 변경 가능성의 여지를 열어두기 때문에, 다른 방법을 찾아봤어야 함에도 불구하고, 되었다고 기분이 좋아서 그냥 그대로 사용했었는데요.

이번에 @Setter를 제거하면서 객체의 변경가능성을 다시 닫고,
GET매핑시 쿼리스트링으로 받은 값으로도 충분히 객체가 생성되는 것을 알아보겠습니다.

2. 본론

Controller
Controller의 메서드를 보겠습니다.

// 동행 전체 조회(날짜, 지역)  
@GetMapping  
public ResponseEntity searchLocalAndDate(AccompanySearchCondition accompanySearchCondition,  
                                         @RequestParam(name = "page", defaultValue = "1") Integer page) throws ParseException {  
    return ResponseEntity.ok(accompanyService.findByLocalAndDate(accompanySearchCondition, page));  
}

매개변수로 들어가는 AccompanySearchCondition 클래스입니다.

@AllArgsConstructor  
@NoArgsConstructor
@Setter
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;  
    }  
}

당시 저는 이렇게 문제를 해결했습니다.

@Setter를 사용하면, 쿼리스트링으로 받은 값을 프로퍼티 접근법을 통해서 값이 변경되도록 되어있습니다.
그리고 @Getter만 있었을 때는 값을 줘도 값이 들어가지 않아 null 이 나왔습니다.

그런데 Setter를 사용하지 않고도, 충분히 객체의 필드에 값을 받을 수 있는 방법이 있었습니다.

바로 initDirectFieldAccess를 사용하는 것이었습니다.
해당 메서드를 사용하면, 쿼리스트링으로 받은 값이 setter로 접근하는 것이 아니라, 필드에 직접 접근하게 됩니다.

참고 블로그는 다음과 같습니다.
향로님 블로그인데요

그대로 나와있습니다.
config 패키지에 다음과 같이 선언만 해주고, AccompanySearchCondition(검색조건 클래스)에서는 @Setter를 빼주면 됩니다.

@Slf4j // 저는 뺏습니다.
@ControllerAdvice  
public class WebControllerAdvice {  

    @InitBinder  
    public void initBinder(WebDataBinder binder) {  
        binder.initDirectFieldAccess();  
    }  
}

AccompanySearchCondition는 다음과 같습니다.

@AllArgsConstructor  
@NoArgsConstructor
@Setter
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;  
    }  
}

결과를 한번 보도록 하겠습니다.

이렇게 데이터가 있다고 가정해봅시다.

날짜를 7월 28일로 검색하면,
1개의 데이터가 나와야하고,

18일로 검색한다면 2개의 데이터가 나와야 합니다

이제 날짜를 관련없는 30일을 검색해보도록 하겠습니다.
아무것도 나오지 않아야합니다.

다음은 지역입니다.

지역은 제주도를 검색했을 때, 1개
서울을 검색했을 때 2개,
부산을 검색했을 때는 아무것도 나오지 않아야 합니다.

먼저 제주도입니다.

다음은 서울입니다.

다음은 부산입니다.

더 많은 예시가 있지만, 중요한 부분은 아니기에 이만 생략하겠습니다.
중요한 건 Setter를 제거해서 객체의 변경 가능성을 열어두지 않으면서,
GET매핑시 쿼리파라미터로 받은 값으로 충분히 객체를 생성하여,
검색조건을 가지는 인스턴스를 생성할 수 있습니다.

컨트롤러 코드에 @RequestParam을 많이 사용하기보단,
앞으로 이 방법으로 코드를 줄여보길 기대합니다.

3. 요약

@Slf4j // 저는 뺏습니다.
@ControllerAdvice  
public class WebControllerAdvice {  

    @InitBinder  
    public void initBinder(WebDataBinder binder) {  
        binder.initDirectFieldAccess();  
    }  
}

해당 코드를 사용해서 필드에 직접 접근하여, @Setter를 지양하자!

@Setter가 없이도 충분히 쿼리스트링의 값으로 객체를 생성할 수 있다!

가 될 수 있겠는데요.

사실 최근 프로젝트에 리팩터링 요소가 많습니다.
다음에는 리팩토링을 진행하면서 괜찮은 주제로 또 찾아오겠습니다!

참고블로그 : 향로님블로그

728x90
Comments