Skip to content

검증 (Validation)

Q-Framework의 검증은 선언 기반으로 동작합니다. 검증 로직을 직접 작성하지 않고, 어노테이션으로 규칙을 선언하면 프레임워크가 자동으로 처리합니다.

필수 필드

필수 규칙은 requiredOn을 통해 @QfCreateAttribute 또는 @QfUpdateAttribute 안에 선언합니다:

java
// 항상 필수
@QfCreateAttribute(requiredOn = @QfRequiredOn(always = true))
@QfUpdateAttribute(requiredOn = @QfRequiredOn(always = true))
@QfDisplayLabel(text = "Name")
private String name;

// 조건부 필수
@QfCreateAttribute(
    requiredOn = @QfRequiredOn(
        conditions = @QfConditionExpr(expr = "memberType == 'BUSINESS'")
    )
)
@QfDisplayLabel(text = "Business Registration Number")
private String businessNumber;

@QfRequiredOn@QfCreateAttribute / @QfUpdateAttribute 안에서 사용하는 요소 어노테이션(독립 사용 불가)입니다:

형태설명
@QfRequiredOn(always = true)항상 필수
@QfRequiredOn(conditions = ...)조건이 일치할 때 필수
@QfRequiredOn (기본값)필수 아님

@QfValidationRule

@QfValidationRule은 단일 검증 어노테이션입니다. 반복 선언 가능 — 하나의 필드에 여러 규칙을 중첩할 수 있습니다.

java
@QfEntity(name = @QfI18n(defaultMessage = "Member", texts = {}))
public class MemberEntity {

    // 로그인 ID — 커스텀 정규식 패턴
    @QfListAttribute(sortable = true)
    @QfCreateAttribute(requiredOn = @QfRequiredOn(always = true))
    @QfValidationRule(
        rule = QfValidationRule.Rule.login_id   // 설정된 로그인 ID 정규식 사용
    )
    @QfDisplayLabel(text = "Login ID")
    private String loginId;

    // 이메일 — 컨트롤 타입으로 형식 선언; 암호화 적용
    @QfDetailAttribute
    @QfCreateAttribute
    @QfCrypto
    @QfControlType(QfControlType.Type.email)
    @QfDisplayLabel(text = "Email")
    private String email;

    // 전화번호 — 커스텀 정규식
    @QfDetailAttribute
    @QfCreateAttribute
    @QfUpdateAttribute
    @QfCrypto
    @QfValidationRule(
        rule = QfValidationRule.Rule.regex,
        params = "^(?:\\+82[-\\s]?)?(?:0?1[0-9])[-\\s]?\\d{3,4}[-\\s]?\\d{4}$",
        invalidValueMessageKey = "validation.message.phone.invalid"
    )
    @QfDisplayLabel(text = "Phone")
    private String phone;

    // 비밀번호 — 설정된 비밀번호 정책 사용
    @QfCreateAttribute(requiredOn = @QfRequiredOn(always = true))
    @QfCrypto
    @QfValidationRule(rule = QfValidationRule.Rule.user_pwd)
    @QfDisplayLabel(text = "Password")
    private String password;
}

검증 규칙 타입

규칙설명params
Rule.regex커스텀 정규식params[0] = 패턴 문자열
Rule.unique서버 측 중복 검사params[0] = 검사 URL (선택)
Rule.login_id로그인 ID 형식 (설정에서 가져옴)없음
Rule.user_pwd비밀번호 정책 (설정에서 가져옴)없음

검증 오류 메시지

메시지 키 또는 인라인 i18n 메시지를 제공할 수 있습니다:

java
// 메시지 키 사용 (메시지 리소스에서 조회)
@QfValidationRule(
    rule = QfValidationRule.Rule.regex,
    params = "^[A-Za-z0-9_]+$",
    invalidValueMessageKey = "validation.message.loginId.invalid"
)

// 인라인 메시지 사용
@QfValidationRule(
    rule = QfValidationRule.Rule.regex,
    params = "^[A-Za-z0-9_]+$",
    invalidValueMessages = @QfI18n(
        defaultMessage = "Only alphanumeric and underscore allowed",
        texts = { @QfI18nText(locale = "ko", message = "영문, 숫자, 밑줄(_)만 허용됩니다") }
    )
)

컨트롤 타입과 검증

@QfControlType은 필드의 렌더링 방식을 선언하며, 프레임워크는 이 타입을 기반으로 클라이언트 측 검증 동작을 추론합니다:

java
@QfControlType(QfControlType.Type.email)   // 클라이언트에서 이메일 형식 검증
@QfDisplayLabel(text = "Email")
private String email;

검증과 관련된 주요 컨트롤 타입:

타입효과
email이메일 형식 검사
text일반 텍스트 (형식 제약 없음)
number숫자 입력
date날짜 선택기
textarea여러 줄 텍스트

컴파일 시점 Fail-Fast

Q-Framework는 잘못된 어노테이션 조합을 컴파일 시점에 즉시 감지합니다.

암호화 + 검색 — 컴파일 오류

java
@QfCrypto
@QfSearch   // 컴파일 오류 — 암호화 필드는 서버 측 검색 불가
private String email;
ERROR: @QfCrypto와 @QfSearch는 함께 사용할 수 없습니다.
       암호화된 필드는 서버 사이드 검색을 지원하지 않습니다.
       → MemberEntity.email

AI가 생성한 코드

Q-Framework의 컴파일 시점 검증은 AI가 생성한 코드에서도 동일하게 적용됩니다. AI가 잘못된 어노테이션 조합을 생성하더라도 빌드가 거부됩니다.


런타임 검증 오류 처리

검증 실패 시 Q-Framework는 표준화된 오류 응답을 반환합니다.

json
{
  "success": false,
  "code": "Q_RUNTIME_000002",
  "message": "입력값 검증에 실패했습니다.",
  "errors": [
    {
      "field": "loginId",
      "message": "영문, 숫자, 밑줄(_)만 허용됩니다",
      "rejectedValue": "invalid user!"
    }
  ]
}

@QfOn 훅을 이용한 커스텀 검증

어노테이션으로 표현할 수 없는 복잡한 비즈니스 규칙은 @QfOn 훅으로 처리합니다.

java
@QfOn(
    phase = QfOnPhase.BEFORE,
    layer = QfOnLayer.DOMAIN,
    op = QfOnOp.CREATE
)
public void validateUniqueLoginId(/* hook parameters */) {
    // 중복 아이디 검사
    if (memberRepository.existsByLoginId(loginId)) {
        throw new QfManagedException(MemberResultCode.DUPLICATE_LOGIN_ID);
    }
}

INFO

어노테이션으로 표현할 수 없는 복잡한 검증은 @QfOn 훅에서 처리합니다. 훅 안의 로직은 SSOT가 아닙니다 — 어노테이션 선언이 구조 규칙의 SSOT입니다.


다음 단계

Released under the Apache 2.0 License.