Skip to content

엔티티 정의

@QfEntity 기본 선언

엔티티는 클래스에 @QfEntity 어노테이션을 선언하여 정의합니다.

java
@QfEntity(
    appKey = "app",   // 클라이언트 앱 키 (선택 사항; 단일 @QfClientApp이 선언된 경우 자동 사용)
    name = @QfI18n(
        defaultMessage = "Product",
        texts = { @QfI18nText(locale = "ko", message = "상품") }
    )
)
public class ProductEntity {
    // 필드 선언...
}

@QfEntity 주요 속성

속성타입필수설명기본값
appKeyString소속 클라이언트 앱 키"" (선언된 단일 앱 사용)
name@QfI18n다국어 표시명@QfI18n(texts = {})
autoHistoryEnabledboolean자동 변경 이력 활성화false
treePolicy@QfTreePolicy트리 구조 설정@QfTreePolicy (비활성)
organizationPolicy@QfOrganizationPolicy조직 기반 데이터 필터링@QfOrganizationPolicy(enabled = false)
deletePolicy@QfCrudPolicy삭제 작업 정책@QfCrudPolicy(enabled = false)
capabilityKeyString접근 제어용 Capability 키"" (클래스명에서 도출)
excelDownloadablebooleanExcel 내보내기 활성화true
excelUploadablebooleanExcel 가져오기 활성화true

속성 선언

필드에 화면 및 동작 어노테이션을 직접 선언하여 관리합니다. @QfField 마커 어노테이션은 존재하지 않으며 — 각 어노테이션이 특정 기능을 제어합니다.

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

    // 목록 + 상세 + 등록 + 수정
    @QfListAttribute(sortable = true)
    @QfDetailAttribute
    @QfCreateAttribute(requiredOn = @QfRequiredOn(always = true))
    @QfUpdateAttribute
    @QfDisplayLabel(text = "Product Name")
    private String name;

    // 목록 + 상세 전용 (읽기 전용 가격)
    @QfListAttribute
    @QfDetailAttribute
    @QfDisplayLabel(text = "Price")
    private Integer price;

    // 상세 + 등록 + 수정 (textarea 컨트롤)
    @QfDetailAttribute
    @QfCreateAttribute
    @QfUpdateAttribute
    @QfControlType(QfControlType.Type.textarea)
    @QfDisplayLabel(text = "Description")
    private String description;
}

화면 노출 어노테이션

어노테이션설명
@QfListAttribute목록 화면에 컬럼으로 표시
@QfDetailAttribute상세 조회 화면에 표시
@QfCreateAttribute등록 폼에 입력 필드로 표시
@QfUpdateAttribute수정 폼에 입력 필드로 표시
@QfSearch목록 화면에서 검색 조건으로 활성화
@QfDisplayLabel표시 레이블 설정 (i18n 조회 키 또는 리터럴 텍스트)

필수 필드

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

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

// type == 'BUSINESS'인 경우에만 필수
@QfCreateAttribute(
    requiredOn = @QfRequiredOn(
        conditions = @QfConditionExpr(expr = "type == 'BUSINESS'")
    )
)
@QfDisplayLabel(text = "Business Registration Number")
private String businessNumber;

@QfCrypto 암호화

민감 데이터 필드에 @QfCrypto를 선언하면 저장/조회 시 자동으로 암호화/복호화가 처리됩니다.

java
@QfDetailAttribute
@QfCreateAttribute
@QfCrypto                    // 자동 암호화
@QfControlType(QfControlType.Type.email)
@QfDisplayLabel(text = "Email")
private String email;

@QfDetailAttribute
@QfCreateAttribute
@QfUpdateAttribute
@QfCrypto
@QfDisplayLabel(text = "Phone")
private String phone;

암호화 필드 제약

@QfCrypto가 선언된 필드는 @QfSearch(검색)와 함께 사용할 수 없습니다. 암호화된 데이터는 서버 사이드 LIKE 검색이 불가하기 때문입니다. 컴파일 시점에 오류로 처리됩니다.


조직 정책

조직 기반 데이터 필터링은 엔티티의 organizationPolicy에서 설정하며, 조직 식별자를 보유하는 속성을 지정합니다.

java
@QfEntity(
    name = @QfI18n(defaultMessage = "Order", texts = {}),
    organizationPolicy = @QfOrganizationPolicy(
        enabled = true,
        attribute = "orgId"   // 조직 ID를 담고 있는 필드명
    )
)
public class OrderEntity {

    private String orgId;    // 조직 필터 대상 (organizationPolicy.attribute에 선언)

    @QfListAttribute
    @QfDisplayLabel(text = "Order Number")
    private String orderNumber;

    @QfListAttribute
    @QfDisplayLabel(text = "Order Amount")
    private Long amount;
}

조직 정책이 활성화된 엔티티는:

  • 조회 시 현재 사용자의 조직 범위에 해당하는 데이터만 자동 반환
  • 등록 시 현재 사용자의 조직 ID 자동 설정
  • 별도의 WHERE 절 작성 불필요

Capability 키

capabilityKey를 설정하여 엔티티를 Capability에 연결합니다:

java
@QfEntity(
    name = @QfI18n(defaultMessage = "Product", texts = {}),
    capabilityKey = "product-management"   // @QfCapability의 key와 일치해야 함
)
public class ProductEntity {
    // ...
}

마스터-디테일 관계

masterRelation을 통해 엔티티가 마스터 엔티티의 디테일임을 선언합니다:

java
// 주문 항목 (Detail 엔티티)
@QfEntity(
    name = @QfI18n(defaultMessage = "Order Item", texts = {}),
    masterRelation = @QfMasterRelation(
        enabled = true,
        masterEntityFqcn = "com.example.OrderEntity",  // 마스터 클래스의 전체 패키지명
        masterKeyAttribute = "orderId",                 // 마스터 ID를 담는 이 엔티티의 속성
        onMasterDelete = QfMasterRelation.OnMasterDelete.CASCADE_DELETE
    )
)
public class OrderItemEntity {

    private String orderId;   // 마스터의 ID

    @QfListAttribute
    @QfCreateAttribute(requiredOn = @QfRequiredOn(always = true))
    @QfDisplayLabel(text = "Product Name")
    private String productName;

    @QfListAttribute
    @QfCreateAttribute(requiredOn = @QfRequiredOn(always = true))
    @QfDisplayLabel(text = "Quantity")
    private Integer quantity;
}

onMasterDelete 옵션:

  • CASCADE_DELETE — 마스터 삭제 시 디테일 레코드 자동 삭제
  • RESTRICT — 디테일이 존재하면 마스터 삭제 거부
  • IGNORE — 디테일 레코드를 고아 상태로 유지

이력 관리 활성화

java
@QfEntity(
    name = @QfI18n(defaultMessage = "Product", texts = {}),
    autoHistoryEnabled = true    // 자동 변경 이력 활성화
)
public class ProductEntity {
    // ...
}

autoHistoryEnabled = true로 설정하면:

  • 모든 수정/삭제 작업의 변경 이력 자동 기록
  • 이력 조회 엔드포인트 자동 생성

트리 구조 엔티티

treePolicy를 통해 트리 동작을 설정합니다:

java
@QfEntity(
    name = @QfI18n(defaultMessage = "Category", texts = {}),
    treePolicy = @QfTreePolicy
)
public class CategoryEntity {

    @QfParent
    private String parentId;   // 부모 노드 ID

    @QfTreeDepth
    private Integer depth;     // 깊이 레벨

    @QfListAttribute(isTreeNodeTitle = true)
    @QfDisplayLabel(text = "Category Name")
    private String name;
}

트리 정책이 설정되면 트리 조회 엔드포인트가 자동으로 생성됩니다.


전체 예시: 복합 엔티티

java
@QfEntity(
    name = @QfI18n(
        defaultMessage = "Employee",
        texts = { @QfI18nText(locale = "ko", message = "직원") }
    ),
    organizationPolicy = @QfOrganizationPolicy(
        enabled = true,
        attribute = "orgId"
    ),
    autoHistoryEnabled = true,
    deletePolicy = @QfCrudPolicy(enabled = true),
    capabilityKey = "hr-management"
)
public class EmployeeEntity {

    // 조직 범위 — 자동 필터링
    private String orgId;

    // 사원번호
    @QfListAttribute(sortable = true)
    @QfDetailAttribute
    @QfCreateAttribute(requiredOn = @QfRequiredOn(always = true))
    @QfSearch(type = QfSearch.Type.text)
    @QfDisplayLabel(text = "Employee Number")
    private String employeeNumber;

    // 성명
    @QfListAttribute(sortable = true)
    @QfDetailAttribute
    @QfCreateAttribute(requiredOn = @QfRequiredOn(always = true))
    @QfUpdateAttribute(requiredOn = @QfRequiredOn(always = true))
    @QfSearch(type = QfSearch.Type.text)
    @QfDisplayLabel(text = "Full Name")
    private String fullName;

    // 주민등록번호 — 암호화, 검색 불가
    @QfDetailAttribute
    @QfCreateAttribute
    @QfCrypto
    @QfDisplayLabel(text = "SSN")
    private String ssn;

    // 연락처 — 암호화 + 정규식 검증
    @QfDetailAttribute
    @QfCreateAttribute
    @QfUpdateAttribute
    @QfCrypto
    @QfValidationRule(
        rule = QfValidationRule.Rule.regex,
        params = "^(?:\\+82[-\\s]?)?(?:0?1[0-9])[-\\s]?\\d{3,4}[-\\s]?\\d{4}$"
    )
    @QfDisplayLabel(text = "Phone")
    private String phone;

    // 직급 — 코드 그룹
    @QfListAttribute
    @QfDetailAttribute
    @QfCreateAttribute
    @QfUpdateAttribute
    @QfCodeGroup(code = "EMPLOYEE_RANK")
    @QfDisplayLabel(text = "Rank")
    private String rank;

    // 입사일
    @QfListAttribute
    @QfDetailAttribute
    @QfCreateAttribute
    @QfDisplayLabel(text = "Join Date")
    private LocalDate joinDate;
}

다음 단계

Released under the Apache 2.0 License.