[회사일] DateRange 추가
오른쪽에 보이는 검색 필드를 MemberSearchingParam에 추가하는데 아무래도 이런 범위 검색 필드는 자주 사용될 것 같더군요.
그래서 별도의 클래스로 분리했습니다.
public class DateRange {
@DateTimeFormat(iso= DateTimeFormat.ISO.DATE)
private Date from;
@DateTimeFormat(iso= DateTimeFormat.ISO.DATE)
private Date to;
...
}
나머진 요다(?) 조다(?) 라이브러리만 넣어두면 기본 포매터가 동작해서 잘 바인딩 해 줍니다. 아.. 암튼 이번엔 바인딩 얘기가 아니라.. 저 클래스 DateRange 얘기입니다.
MemberSearchParam을 MemberDao코드에 적용합니다.
@Repository
public class MemberDaoImpl extends GenericDaoImpl<Member, MemberSearchParam> implements MemberDao {
protected void applySearchParam(Criteria c, MemberSearchParam searchParam) {
CriteriaUtils.addOptionalLike(c, "loginId", searchParam.getLoginId());
CriteriaUtils.addOptionalLike(c, "name", searchParam.getName());
CriteriaUtils.addOptionalLike(c, "email", searchParam.getEmail());
CriteriaUtils.addOptionalLike(c, "phoneNumber", searchParam.getPhoneNumber());
CriteriaUtils.addOptionalLike(c, "jobTiTle", searchParam.getJobTitle());
CriteriaUtils.addOptionaBetween(c, "birthDay", searchParam.getBirthDayRange());
}
}
이게 DAO 코드 전부입니다.
유틸 코드로 가야겠네요.
@Test
public void testOptionalBetween() {
String dateRangeSearchingFiled = "birthDay";
CriteriaUtils.addOptionaBetween(c, dateRangeSearchingFiled, null);
verify(c, times(0)).add(any(Criterion.class));
reset(c);
DateRange dateRange = new DateRange();
CriteriaUtils.addOptionaBetween(c, dateRangeSearchingFiled, dateRange);
verify(c, times(0)).add(any(Criterion.class));
reset(c);
dateRange.setFrom(new Date());
CriteriaUtils.addOptionaBetween(c, dateRangeSearchingFiled, dateRange);
verify(c, times(1)).add(Restrictions.ge(any(String.class), dateRange.getFrom()));
reset(c);
dateRange.setTo(new Date());
CriteriaUtils.addOptionaBetween(c, dateRangeSearchingFiled, dateRange);
verify(c, times(1)).add(Restrictions.between(any(String.class), dateRange.getFrom(), dateRange.getTo()));
reset(c);
dateRange.setFrom(null);
CriteriaUtils.addOptionaBetween(c, dateRangeSearchingFiled, dateRange);
verify(c, times(1)).add(Restrictions.le(any(String.class), dateRange.getTo()));
}
장황해 보이지만 별거 없는 테스트 입니다.
public static void addOptionaBetween(Criteria c, String fieldName, DateRange dateRange) {
if(dateRange == null)
return;
if(dateRange.getFrom() != null && dateRange.getTo() != null){
c.add(Restrictions.between(fieldName, dateRange.getFrom(), dateRange.getTo()));
}
if(dateRange.getFrom() != null && dateRange.getTo() == null){
c.add(Restrictions.ge(fieldName, dateRange.getFrom()));
}
if(dateRange.getFrom() == null && dateRange.getTo() != null){
c.add(Restrictions.le(fieldName, dateRange.getTo()));
}
}
이 코드를 테스트하고 있죠. 그런데 코드가 좀;; Don't Tell, Ask가 생각나더군요. 저런 조건 문을 inline 뭐시기 리팩토링으로 분리할 수도 있지만 그보다 일단 if 조건문에 들어있는 내용이 들어있어야 할 위치가... DateRange가 되어야 할 것 같단 생각이 듭니다.
머 일단 if안에 있는 조건문 들을 extract method 리팩토링으로 빼냅니다. 이런 리팩토링을 인라인 머시기 리팩토링이라고 했던것 같은데 잊어버렸네요. @_@;;
public static void addOptionaBetween(Criteria c, String fieldName, DateRange dateRange) {
if(dateRange == null)
return;
if(hasFromAndTo(dateRange)){
c.add(Restrictions.between(fieldName, dateRange.getFrom(), dateRange.getTo()));
}
if(hasFromOnly(dateRange)){
c.add(Restrictions.ge(fieldName, dateRange.getFrom()));
}
if(hasToOnly(dateRange)){
c.add(Restrictions.le(fieldName, dateRange.getTo()));
}
}
private static boolean hasToOnly(DateRange dateRange) {
return dateRange.getFrom() == null && dateRange.getTo() != null;
}
private static boolean hasFromOnly(DateRange dateRange) {
return dateRange.getFrom() != null && dateRange.getTo() == null;
}
private static boolean hasFromAndTo(DateRange dateRange) {
return dateRange.getFrom() != null && dateRange.getTo() != null;
}
그럼 이렇게 되는데 여기서 아래 세개의 static 메서드를 DateRange 쪽 멤버 메서드로 옯겨줍니다.
public class DateRange {
@DateTimeFormat(iso= DateTimeFormat.ISO.DATE)
private Date from;
@DateTimeFormat(iso= DateTimeFormat.ISO.DATE)
private Date to;
...
public boolean hasToOnly(DateRange dateRange) {
return dateRange.getFrom() == null && dateRange.getTo() != null;
}
public boolean hasFromOnly(DateRange dateRange) {
return dateRange.getFrom() != null && dateRange.getTo() == null;
}
public boolean hasFromAndTo(DateRange dateRange) {
return dateRange.getFrom() != null && dateRange.getTo() != null;
}
}
그리고 CriteriaUtils 코드를 수정해주면 되죠.
public static void addOptionaBetween(Criteria c, String fieldName, DateRange dateRange) {
if(dateRange == null)
return;
if(dateRange.hasFromAndTo(dateRange)){
c.add(Restrictions.between(fieldName, dateRange.getFrom(), dateRange.getTo()));
}
if(dateRange.hasFromOnly(dateRange)){
c.add(Restrictions.ge(fieldName, dateRange.getFrom()));
}
if(dateRange.hasToOnly(dateRange)){
c.add(Restrictions.le(fieldName, dateRange.getTo()));
}
}
마지막으로 테스트 한번 돌려주면 깔끔하게 끝~