Categories
웹개발/Spring
Apache Commons StringUtils DateUtils 사용법, null 문자열과 날짜 처리 기준
문자열 null 체크와 날짜 계산 코드가 반복되면 먼저 Apache Commons StringUtils DateUtils로 줄일 수 있는 부분을 확인한다. 이 글은 공백 문자열, Date 계산, 검색 조건 처리 기준을 정리한다.
Apache Commons Lang은 대단한 프레임워크라기보다, Java 기본 API로 매번 직접 작성하던 자잘한 처리를 줄여 주는 유틸 모음에 가깝다. 특히 StringUtils는 null과 공백 문자열 처리에, DateUtils는 오래된 Date, Calendar 기반 프로젝트의 날짜 계산에 자주 쓰인다.
핵심 결론: StringUtils는 null-safe 문자열 체크에 강하고, DateUtils는 레거시 Date/Calendar 코드에서 날짜 더하기, 절삭, 파싱을 단순하게 만든다.
확인 순서: commons-lang3 의존성 추가 → StringUtils 공백 기준 확인 → DateUtils 날짜 기준 확인 → 프로젝트 날짜 타입과 혼용 여부 점검.
Apache Commons Lang은 언제 쓰나
Apache Commons Lang은 Java 표준 라이브러리만으로 처리하기 애매하거나 반복되는 작업을 줄여 주는 유틸 라이브러리다. 문자열, 숫자, 날짜, 객체 비교, 예외 처리, 배열 처리 같은 기능이 들어 있다.
요즘 Java에는 java.time, Objects, Optional 같은 좋은 API가 많다. 그래도 공공 SI나 오래된 Spring MVC 프로젝트에서는 Date, Calendar, JSP, MyBatis, Java 8 이전 스타일 코드가 섞여 있는 경우가 많다. 이런 환경에서는 commons-lang3가 여전히 자주 보인다.
Spring 프로젝트에서 라이브러리를 추가하고 정적 리소스나 설정 파일 경로까지 같이 만지는 상황이라면 MVC 설정 흐름도 같이 확인해 두면 좋다. 유틸 라이브러리 자체는 단순하지만, 실제 프로젝트에서는 의존성, 빌드, 배포 설정과 함께 움직이기 때문이다.
의존성 추가 방법
Maven 설정
Maven 프로젝트라면 pom.xml에 commons-lang3 의존성을 추가한다. 버전은 프로젝트의 Java 버전, 사내 저장소, 기존 라이브러리 정책에 맞게 조정한다.
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.x.x</version>
</dependency>
Gradle 설정
Gradle이라면 아래처럼 추가한다.
dependencies {
implementation 'org.apache.commons:commons-lang3:3.x.x'
}
의존성을 넣은 뒤에는 IDE에서 import가 되는지 먼저 확인한다. StringUtils는 org.apache.commons.lang3.StringUtils, DateUtils는 org.apache.commons.lang3.time.DateUtils 패키지에 있다.
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils;
StringUtils는 null-safe 문자열 처리에 쓴다
isEmpty와 isBlank 차이
StringUtils에서 가장 많이 헷갈리는 메서드는 isEmpty()와 isBlank()다. 둘 다 문자열이 비어 있는지 확인하지만, 공백 문자열을 어떻게 볼 것인지가 다르다.
| 값 | isEmpty | isBlank | 실무 판단 |
|---|---|---|---|
null | true | true | 값 없음 |
"" | true | true | 값 없음 |
" " | false | true | 입력값으로 보기 어려움 |
"abc" | false | false | 값 있음 |
사용자가 화면에서 스페이스만 입력한 값을 빈 값으로 처리하려면 isBlank()가 더 자연스럽다. 반대로 공백도 의미 있는 값으로 인정해야 한다면 isEmpty() 기준을 쓸 수 있다.
String userName = request.getParameter("userName");
if (StringUtils.isBlank(userName)) {
throw new IllegalArgumentException("사용자 이름은 필수입니다.");
}
isNotBlank로 조건을 읽기 쉽게 만든다
조건문을 작성할 때는 부정 연산자를 겹쳐 쓰는 것보다 isNotBlank()가 읽기 쉽다.
if (StringUtils.isNotBlank(searchKeyword)) {
params.put("searchKeyword", searchKeyword.trim());
}
이 코드는 검색어가 null이 아니고, 빈 문자열도 아니고, 공백만 있는 문자열도 아닐 때만 파라미터에 넣는다. 검색 조건 조립, MyBatis 동적 쿼리 파라미터 구성, 컨트롤러 입력값 검증에서 자주 쓰는 형태다.
defaultString으로 null 표시를 막는다
JSP나 로그에서 null이 그대로 찍히는 것을 막고 싶을 때는 defaultString()을 쓸 수 있다.
String displayName = StringUtils.defaultString(member.getName(), "이름 없음");
다만 이 메서드를 남용하면 실제 null과 기본값을 구분하기 어려워진다. 화면 표시용으로는 유용하지만, DB 저장 전 핵심 값 검증에는 명시적인 validation을 두는 편이 낫다.
StringUtils 사용 시 자주 하는 실수
trim을 무조건 같이 쓰는 경우
isBlank()는 공백 문자열을 이미 빈 값으로 판단한다. 그래서 단순 검증에서 StringUtils.isBlank(value.trim())처럼 쓰면 value가 null일 때 오히려 NullPointerException이 난다.
// 좋지 않은 예
if (StringUtils.isBlank(value.trim())) {
return;
}
// null-safe 처리
if (StringUtils.isBlank(value)) {
return;
}
equals 비교를 직접 하는 경우
상수와 문자열을 비교할 때는 "Y".equals(flag)처럼 쓰면 null-safe하다. 하지만 두 변수 모두 null 가능성이 있거나 대소문자 무시 비교가 필요하면 StringUtils.equals(), equalsIgnoreCase()를 쓸 수 있다.
if (StringUtils.equalsIgnoreCase(useYn, "Y")) {
// 사용 처리
}
단, 팀 컨벤션이 이미 Java 표준 방식으로 통일되어 있다면 굳이 모든 비교를 StringUtils로 바꿀 필요는 없다. StringUtils는 반복되는 null-safe 처리를 줄이는 도구이지, 모든 문자열 코드를 대체하는 규칙은 아니다.
DateUtils는 Date와 Calendar 기반 코드에서 쓴다
날짜 더하기와 빼기
DateUtils는 Date 객체에 날짜, 시간, 분을 더하거나 빼는 코드를 간단하게 만든다. 오래된 프로젝트에서 java.util.Date를 계속 쓰고 있다면 유용하다.
Date today = new Date();
Date tomorrow = DateUtils.addDays(today, 1);
Date yesterday = DateUtils.addDays(today, -1);
Date nextMonth = DateUtils.addMonths(today, 1);
이런 코드를 직접 Calendar로 작성하면 인스턴스 생성, 필드 변경, 다시 Date로 변환하는 코드가 반복된다. DateUtils는 그 반복을 줄여 준다.
날짜 절삭 truncate
날짜 비교에서 시분초가 섞여 문제가 생길 때는 truncate()를 자주 쓴다. 예를 들어 오늘 날짜만 비교하고 싶다면 시, 분, 초, 밀리초를 제거한다.
Date now = new Date();
Date todayStart = DateUtils.truncate(now, Calendar.DATE);
이렇게 하면 현재 시간이 언제든 해당 날짜의 00:00:00 기준으로 맞춰진다. Oracle에서 날짜 조건을 걸 때도 시분초 때문에 조회 결과가 달라지는 일이 많다. DB 쪽 날짜 조건이 문제라면 날짜 조건 문제도 함께 확인하는 편이 좋다.
같은 날짜인지 비교하기
두 Date가 같은 날인지 비교할 때 단순 equals()를 쓰면 시분초까지 모두 같아야 한다. 날짜만 같으면 되는 업무에서는 isSameDay()가 더 의도를 잘 드러낸다.
if (DateUtils.isSameDay(startDate, endDate)) {
// 같은 날짜로 처리
}
단, 시간대가 중요한 시스템에서는 서버 타임존, DB 타임존, 사용자 지역 기준을 따로 봐야 한다. DateUtils가 업무 기준까지 대신 정해 주지는 않는다.
StringUtils와 DateUtils를 함께 쓰는 예제
검색 조건 파라미터 정리
게시판이나 관리자 목록 화면에서는 검색어와 날짜 조건이 함께 들어온다. 이때 StringUtils로 검색어를 검증하고, DateUtils로 날짜 범위를 정리할 수 있다.
public SearchCondition buildCondition(String keyword, Date searchDate) {
SearchCondition condition = new SearchCondition();
if (StringUtils.isNotBlank(keyword)) {
condition.setKeyword(keyword.trim());
}
if (searchDate != null) {
Date from = DateUtils.truncate(searchDate, Calendar.DATE);
Date to = DateUtils.addDays(from, 1);
condition.setFromDate(from);
condition.setToDate(to);
}
return condition;
}
이렇게 만들면 검색어는 공백만 있는 값을 제외하고, 날짜는 하루 범위로 정리된다. DB 쿼리에서는 fromDate <= created_at, created_at < toDate처럼 쓰면 시분초 조건을 비교적 안정적으로 처리할 수 있다.
MyBatis 파라미터로 넘길 때
MyBatis를 쓰는 프로젝트라면 컨트롤러에서 받은 값을 그대로 Mapper에 넘기기보다 서비스 계층에서 정리한 뒤 넘기는 편이 낫다. 파라미터 이름, resultMap, resultType이 헷갈리는 경우는 인코딩이나 유틸 문제가 아니라 매핑 문제일 수 있다. 이런 경우에는 조회 매핑 기준을 먼저 보는 것이 빠르다.
Map<String, Object> params = new HashMap<>();
if (StringUtils.isNotBlank(condition.getKeyword())) {
params.put("keyword", condition.getKeyword());
}
params.put("fromDate", condition.getFromDate());
params.put("toDate", condition.getToDate());
java.time과 DateUtils 중 무엇을 써야 하나
신규 코드는 java.time을 우선한다
Java 8 이후 신규 코드라면 LocalDate, LocalDateTime, ZonedDateTime 같은 java.time API를 우선 고려하는 것이 좋다. 타입 자체가 날짜와 시간을 더 명확하게 표현하고, 불변 객체라 실수도 줄어든다.
LocalDate today = LocalDate.now();
LocalDate tomorrow = today.plusDays(1);
그렇다고 기존 프로젝트의 모든 DateUtils 사용을 바로 없애야 한다는 뜻은 아니다. 레거시 코드가 Date와 Calendar를 기준으로 돌아가고 있다면, DateUtils는 여전히 현실적인 선택이다.
레거시 프로젝트에서는 혼용 기준을 정한다
실무에서 문제는 혼용이다. 컨트롤러는 LocalDate, 서비스는 Date, Mapper는 Timestamp를 쓰면 변환 코드가 여기저기 흩어진다. 팀 기준을 정해 어느 계층에서 변환할지 고정하는 편이 낫다.
| 상황 | 권장 기준 | 이유 |
|---|---|---|
| 신규 Java 8+ 코드 | java.time | 타입이 명확하고 불변 객체라 안전함 |
| 기존 Date 기반 프로젝트 | DateUtils | 기존 타입을 유지하면서 반복 코드를 줄임 |
| DB 날짜 조건 | from/to 범위 | 시분초 포함 여부를 명확히 처리 |
| 화면 입력값 검증 | StringUtils + 명시적 validation | null, 빈 값, 공백 입력을 구분하기 쉬움 |
실무에서 자주 하는 실수
StringUtils로 검증을 끝냈다고 생각하는 경우
isBlank()는 값이 비었는지 확인할 뿐이다. 이메일 형식, 날짜 형식, 길이 제한, 허용 문자 같은 업무 검증을 대신하지 않는다. 예를 들어 사용자 ID가 필수인지 확인하는 것과, 사용자 ID가 정책에 맞는지 확인하는 것은 다른 문제다.
DateUtils가 타임존 문제를 해결한다고 생각하는 경우
DateUtils는 날짜 계산을 편하게 해 주지만, 타임존 정책을 대신 정해 주지 않는다. 서버 시간이 KST인지 UTC인지, DB에는 어떤 기준으로 저장하는지, 화면에서는 어떤 기준으로 보여 줄지 정해야 한다.
유틸 라이브러리를 너무 많이 섞는 경우
StringUtils, Spring의 StringUtils, Java 표준 API가 섞이면 팀원이 코드를 읽을 때 기준이 흐려진다. 프로젝트에서 Apache Commons Lang을 쓰기로 했다면 주로 쓰는 메서드와 금지할 패턴을 간단히 정해 두는 것이 좋다.
실무에서 바로 쓰는 팁
- 필수 문자열 검증에는 isBlank를 우선한다. 사용자가 공백만 입력한 값도 빈 값으로 볼 수 있다.
- 표시용 기본값과 저장용 기본값을 구분한다. defaultString은 화면 표시에는 편하지만 데이터 의미를 숨길 수 있다.
- DateUtils는 Date 기반 레거시 코드에 적합하다. 신규 코드는 java.time을 우선 검토한다.
- 날짜 검색은 하루 끝 시간을 만들기보다 다음 날 미만 조건을 쓴다. 밀리초와 DB 타입 차이를 줄일 수 있다.
- 의존성 추가 후 배포 환경을 확인한다. 로컬에는 jar가 있는데 운영 빌드에 빠지는 경우가 있다.
자주 묻는 질문
- Q. StringUtils는 Java 기본 String 메서드보다 항상 좋은가요? A. 아닙니다. null-safe 처리가 필요하거나 공백 기준이 중요할 때 유용합니다. 단순 문자열 길이나 contains 정도는 Java 기본 메서드로 충분할 수 있습니다.
- Q. isEmpty와 isBlank 중 무엇을 써야 하나요? A. 사용자 입력값 검증은 보통 isBlank가 더 자연스럽습니다. 공백만 입력한 값을 빈 값으로 처리할 수 있기 때문입니다.
- Q. DateUtils는 java.time보다 좋은가요? A. 신규 코드라면 java.time을 우선합니다. DateUtils는 Date, Calendar 기반 레거시 프로젝트에서 반복 코드를 줄이는 데 유용합니다.
- Q. commons-lang3를 Spring 프로젝트에 넣어도 되나요? A. 가능합니다. 다만 이미 프로젝트에서 쓰는 유틸 라이브러리와 중복되지 않는지, 버전 충돌이 없는지 확인해야 합니다.
- Q. DateUtils.truncate는 DB 날짜 조건을 완전히 해결하나요? A. 아닙니다. Java 쪽 날짜 기준을 정리하는 데 도움을 줄 뿐이고, DB 컬럼 타입과 SQL 조건은 별도로 확인해야 합니다.
- Q. StringUtils.defaultString을 저장 전에도 써도 되나요? A. 저장 전 기본값 치환은 신중해야 합니다. 실제 null인지, 사용자가 빈 값을 입력한 것인지 구분이 사라질 수 있습니다.
정리
Apache Commons StringUtils DateUtils는 Java와 Spring 프로젝트에서 반복되는 문자열 null 체크와 날짜 계산 코드를 줄여 준다. StringUtils는 isBlank, isNotBlank, defaultString처럼 null-safe 문자열 처리에 유용하고, DateUtils는 addDays, truncate, isSameDay처럼 Date 기반 날짜 처리를 단순하게 만든다.
다만 유틸 라이브러리는 업무 기준을 대신하지 않는다. 빈 값과 공백을 어떻게 볼지, 날짜 검색 범위를 어떻게 잡을지, java.time과 Date를 어느 계층에서 변환할지 정해야 한다. 신규 코드는 java.time을 우선하고, 레거시 Date 기반 프로젝트에서는 DateUtils를 현실적인 도구로 쓰는 식으로 기준을 잡으면 된다.
유틸 메서드는 코드를 짧게 만드는 도구이지, 검증 기준과 날짜 정책을 대신 정해 주는 도구는 아니다.
'웹개발 > Spring' 카테고리의 다른 글
| Spring Security 없이 권한 체크 구현하기 정리 (0) | 2026.07.05 |
|---|---|
| Spring Security 4.x XML 설정 정리 (공공 SI 기준) (0) | 2026.07.05 |
| 인터셉터 로그인 체크와 login.do 리다이렉트 처리 정리 (0) | 2026.07.04 |
| session attribute에 loginUserVO 담고 꺼내기 정리 (1) | 2026.07.04 |
| Session 기반 로그인 HttpSession 동작 흐름 정리 (0) | 2026.07.03 |