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

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 ConfigurationFactory chỉ hoạt động khi classpath có implementation SPI của interface Configuration (mặc định do govex-cloud-core cung 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/services tươ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-common thường được kéo vào gián tiếp qua govex-cloud-core; chỉ khai báo trực tiếp khi ứng dụng không phụ thuộc govex-cloud-core.
  • RootContext lư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ủa govex-cloud-core đã hỗ trợ việc này.
  • JsonUtils.toObject né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/services của SPI phải khớp đúng tên interface, nếu không EnhancedServiceLoader sẽ không tìm thấy implementation.