Chuyển tới nội dung chính

Dữ liệu động theo entity

Dựng danh mục/trang động theo mô hình entity–field definition: khai báo entity và field qua REST API rồi lưu bản ghi theo mô hình EAV, không cần viết entity/repository/controller mới. Dùng khi cần bổ sung loại danh mục mới thường xuyên mà không muốn sửa code.

Khi nào sử dụng

  • Cần thêm danh mục mới (chức danh, dân tộc, loại văn bản...) cấu hình được qua API thay vì deploy code.
  • Cần một REST API chung cho nhiều entity động với cùng nghiệp vụ CRUD, tìm kiếm, phân trang và cây phân cấp.
  • Cần sinh form nhập liệu từ schema (uiSchemaJson) cho frontend.
  • Cần kiểm tra quyền theo từng entity (public, yêu cầu đăng nhập, hoặc yêu cầu permission riêng).

Cài đặt

<dependency>
<groupId>vn.govex.cloud</groupId>
<artifactId>govex-cloud-dynamic</artifactId>
</dependency>

Version do BOM quản lý — xem Cài đặt.

Cấu hình

PropertyMô tảMặc định
govex.dynamic.enabledBật dependency; phải đặt true thì auto-configuration mới chạy.false
govex.dynamic.api-prefixTiền tố API chung; path bản ghi là {api-prefix}/dynamic/{entityCode}./api/v1
govex.dynamic.permission-prefixTiền tố quyền khi kiểm tra permission dạng {permission-prefix}:{apiPath}:{action}.
govex.dynamic.table-prefixTiền tố tên bảng động (khai báo sẵn, hiện chưa áp dụng — xem Lưu ý).DYN_

Sử dụng

Bước 1 — bật dependency:

govex:
dynamic:
enabled: true
api-prefix: /api/v1
permission-prefix: qtdm

Bước 2 — tạo định nghĩa entity bằng API quản trị (POST /api/v1/entity-definitions) với code, name, apiPath, cờ requireAuth/requirePermissionuiSchemaJson:

{
"code": "DM_CHUC_DANH",
"name": "Danh mục chức danh",
"apiPath": "dm-chuc-danh",
"requireAuth": true,
"requirePermission": true,
"uiSchemaJson": "{\"type\":\"object\",\"properties\":{...}}"
}

Field definition được đồng bộ tự động từ uiSchemaJson (Formily ISchema) xuống bảng DYN_FIELD_DEFINITION; có thể cập nhật schema qua PUT /api/v1/entity-definitions/code/{code}/schema.

Bước 3 — thao tác dữ liệu qua các endpoint dùng chung:

MethodPathMô tả
GET{api-prefix}/dynamic/{entityCode}Danh sách có phân trang (page, size), tìm kiếm theo tham số.
GET{api-prefix}/dynamic/{entityCode}/{id}Chi tiết bản ghi (response phẳng).
POST{api-prefix}/dynamic/{entityCode}Tạo mới, body là map field-code → giá trị.
PUT{api-prefix}/dynamic/{entityCode}/{id}Cập nhật.
DELETE{api-prefix}/dynamic/{entityCode}/{id}Xoá mềm.
GET{api-prefix}/dynamic/{entityCode}/treeCây phân cấp (entity có hierarchical).
GET{api-prefix}/dynamic/{entityCode}/schemaSchema để frontend render form.

Bước 4 — cấu hình security. Với entity requireAuth=false, đăng ký các path public do DynamicSecurityConfigurer.getPublicPaths() trả về vào SecurityFilterChain:

@Bean
SecurityFilterChain securityFilterChain(HttpSecurity http,
DynamicSecurityConfigurer dynamicSecurityConfigurer) throws Exception {
http.authorizeHttpRequests(auth -> auth
.requestMatchers(dynamicSecurityConfigurer.getPublicPaths().toArray(String[]::new)).permitAll()
.anyRequest().authenticated());
return http.build();
}

Khi requirePermission=true, hệ thống kiểm tra permission qua PermissionEvaluator với target {permission-prefix}:{apiPath} và action view, add, edit, delete.

Lưu ý

  • Điều kiện tiên quyết: JPA + datasource; các bảng DYN_ENTITY_DEFINITION, DYN_FIELD_DEFINITION, DYN_RECORD, DYN_FIELD_VALUE do ứng dụng tạo bằng migration/DDL.
  • govex.dynamic.table-prefix hiện chỉ được khai báo trong properties, chưa dùng để đặt tên bảng (entity dùng tên cố định DYN_*).
  • Khi requireAuth=true cần Spring Security trong ứng dụng; kiểm tra permission chỉ chạy khi có bean PermissionEvaluator.
  • Sự kiện đồng bộ menu phát qua Kafka topic dynamic-entity-definition chỉ khi có govex-cloud-mq; nếu thiếu, dependency vẫn phát sự kiện nội bộ.
  • apiPath là phần đường dẫn sau {api-prefix}, dùng cho cả endpoint bản ghi lẫn path public/permission.