Tiện ích nền tảng
Thư viện tiện ích nền tảng dùng chung cho mọi service: context theo luồng, đọc cấu hình, sinh ID, xử lý JSON/ngày giờ/chuỗi, mã hoá AES, nén dữ liệu và các exception nền. Đây là thư viện tiện ích thuần Java, không tự đăng ký bean Spring — thêm dependency là dùng được ngay.
Khi nào sử dụng
- Cần bộ tiện ích chuẩn hoá (JSON, ngày giờ, chuỗi, số điện thoại, che dấu dữ liệu nhạy cảm) thay vì tự viết lại hoặc thêm thư viện riêng.
- Cần sinh định danh duy nhất (UUID, Snowflake, NanoId) cho entity hoặc tác vụ.
- Cần mang thông tin người dùng/tenant theo luồng xử lý để các tầng dưới đọc lại mà không phải truyền tham số qua nhiều lớp.
- Cần đọc cấu hình theo key qua lớp trừu tượng
Configuration(hoạt động khi classpath có implementation, thường đến từgovex-cloud-core). - Cần assertion với thông điệp lỗi rõ ràng, hoặc nén/giải nén payload trước khi lưu trữ hay truyền đi.
Cài đặt
Thêm dependency vào pom.xml — không cần khai báo version vì BOM đã quản lý:
<dependency>
<groupId>vn.govex.cloud</groupId>
<artifactId>govex-cloud-common</artifactId>
</dependency>
Hướng dẫn khai báo parent/BOM và Maven repository xem tại Cài đặt.
Cấu hình
Hai điểm cần biết:
- Việc đọc cấu hình qua
ConfigurationFactorychỉ hoạt động khi classpath có implementation SPI của interfaceConfiguration(mặc định dogovex-cloud-corecung cấp). - Muốn thay implementation mặc định (context theo luồng, đọc cấu hình, nén dữ liệu), đăng ký class mới bằng file
META-INF/servicestương ứng interface SPI kèm annotation@SPI.
Sử dụng
Context theo luồng
Gắn thông tin vào luồng xử lý hiện tại và luôn gỡ ra trong finally để tránh lộ dữ liệu sang request khác:
@Component
public class UserContextFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain chain) throws ServletException, IOException {
try {
String username = request.getHeader("X-User-Name");
if (username != null) {
RootContext.bindUserName(username);
}
chain.doFilter(request, response);
} finally {
RootContext.unbindUserName();
}
}
}
Đọc lại ở bất kỳ tầng nào:
String username = RootContext.getUserName();
String tenant = RootContext.getTenant();
Object value = RootContext.get("custom-key");
Đọc cấu hình theo key
Configuration configuration = ConfigurationFactory.getInstance();
int poolSize = configuration.getInt("govex.async.core-pool-size", 8);
long timeout = configuration.getLong("govex.request.timeout", 30_000L);
boolean enabled = configuration.getBoolean("govex.feature.enabled", false);
JSON
String json = JsonUtils.toJson(dto);
Dto parsed = JsonUtils.toObject(json, Dto.class);
List<Dto> items = JsonUtils.toList(json, Dto.class);
Map<String, Object> map = JsonUtils.toMap(json, String.class, Object.class);
String pretty = JsonUtils.toJsonPrettyString(dto);
Nếu cần gắn thêm Jackson module dùng chung cho tiện ích, gọi JsonUtils.registerModule(module).
Sinh ID và assertion
String uuid = IdUtil.randomUUID();
long snowflakeId = IdUtil.getSnowflakeNextId();
String nanoId = IdUtil.nanoId(12);
Asserts.isTrue(quantity > 0, "Số lượng phải lớn hơn 0");
Asserts.notBlank(code, "Mã không được để trống");
Asserts.notNull(entity, "Không tìm thấy dữ liệu");
Mã hoá AES và che dấu dữ liệu
String key = AesUtils.generateKey();
String encrypted = AesUtils.encrypt("noi-dung-can-bao-mat", key);
String decrypted = AesUtils.decrypt(encrypted, key);
String masked = DesensitizedUtil.mobilePhone("0987654321");
String emailMasked = DesensitizedUtil.email("thiennv@govex.vn");
Ngoài ra dependency còn có PhoneUtils để parse/chuẩn hoá số điện thoại quốc tế và CompressUtil để nén/giải nén dữ liệu nhị phân (các method parse/IO có thể ném checked exception — xử lý như bình thường khi gọi).
Lưu ý
- Trong ứng dụng Spring Boot,
govex-cloud-commonthường được kéo vào gián tiếp quagovex-cloud-core; chỉ khai báo trực tiếp khi ứng dụng không phụ thuộcgovex-cloud-core. RootContextlưu dữ liệu theo thread: khi chạy tác vụ ở thread khác, cần copy context (getCopyOfContextMap) nếu muốn giữ thông tin người dùng — async executor củagovex-cloud-coređã hỗ trợ việc này.JsonUtils.toObjectném exception runtime khi JSON sai định dạng — nên validate dữ liệu đầu vào trước khi parse.- File
META-INF/servicescủa SPI phải khớp đúng tên interface, nếu khôngEnhancedServiceLoadersẽ không tìm thấy implementation.