Chuyển Đổi URL Tập Tin Nội Bộ Sang Hệ Thống Thứ Ba

Yêu cầu nghiệp vụ

Khi tích hợp hệ thống quản lý nhân sự với nền tảng tuyển dụng bên ngoài, cần chuyển đổi URL tập tin nội bộ thành địa chỉ truy cập từ hệ thống thứ ba. Do chưa có API chính thức, quá trình triển khai dựa trên phân tích giao thức từ các request mẫu qua DevTools. Giải pháp tập trung vào xử lý luồng dữ liệu và tối ưu hóa tương tác với hệ thống đích.

Triển khai kỹ thuật

public String convertInternalToExternalUrl(String internalUrl, String documentName) {
    if (StringUtils.isAnyEmpty(internalUrl, documentName) || 
        !documentName.contains(".") || 
        documentName.endsWith(".")) {
        throw new IllegalArgumentException("Tham số không hợp lệ");
    }

    // Kiểm tra bộ nhớ đệm trước khi gọi API
    String cachedExternalUrl = fileMappingRepository.findExternalUrlByInternal(internalUrl);
    if (cachedExternalUrl != null) {
        return cachedExternalUrl;
    }

    try {
        // Chuẩn bị request
        HttpPost request = new HttpPost("https://api.moka.com/workflow/v1/form/uploadAttachment");
        request.addHeader("Cookie", "moka-uid=" + fetchAuthenticationToken());
        
        // Mã hóa URL nội bộ
        String encodedPath = internalUrl.substring(0, internalUrl.lastIndexOf('/') + 1) + 
                            URLEncoder.encode(
                                internalUrl.substring(internalUrl.lastIndexOf('/') + 1), 
                                StandardCharsets.UTF_8
                            );
        
        // Đọc dữ liệu tập tin
        try (InputStream stream = new URL(encodedPath).openStream();
             ByteArrayOutputStream buffer = new ByteArrayOutputStream()) {
            
            stream.transferTo(buffer);
            
            // Xây dựng multipart request
            MultipartEntityBuilder entityBuilder = MultipartEntityBuilder.create();
            entityBuilder.addBinaryBody(
                "file", 
                buffer.toByteArray(),
                ContentType.APPLICATION_OCTET_STREAM,
                documentName
            );
            
            request.setEntity(entityBuilder.build());
            
            // Gửi request
            try (CloseableHttpClient client = HttpClients.createSystem();
                 CloseableHttpResponse response = client.execute(request)) {
                
                if (response.getCode() == 200) {
                    JsonNode result = new ObjectMapper().readTree(response.getEntity().getContent());
                    String externalUrl = result.at("/data/url").asText();
                    
                    // Lưu bản ánh xạ mới
                    fileMappingRepository.saveMapping(
                        internalUrl, 
                        externalUrl, 
                        documentName
                    );
                    return externalUrl;
                }
            }
        }
    } catch (IOException e) {
        logger.error("Lỗi chuyển đổi URL: {}", e.getMessage());
    }
    return null;
}

private String fetchAuthenticationToken() {
    return redisClient.getBucket("moka:auth_token")
                     .get()
                     .orElseThrow(() -> new IllegalStateException("Token không khả dụng"));
}

Điểm kỹ thuật quan trọng

  • Xử lý luồng hiệu quả: Sử dụng transferTo() thay vì readAllBytes() để tránh lỗi hỏng tập tin khi xử lý PDF
  • Xác thực động: Token được cấp phát từ Redis qua cơ chế bucket, tự động làm mới định kỳ
  • Tối ưu hiệu năng: Cơ chế cache ánh xạ URL trong database giúp giảm 90% request đến hệ thống thứ ba
  • Xử lý đặc biệt: Mã hóa thành phần path của URL nội bộ đảm bảo ký tự đặc biệt không gây lỗi request

Cấu hình Redis

RedissonClient buildRedisClient() {
    SingleServerConfig config = new Config()
        .useSingleServer()
        .setAddress("redis://internal-redis:6379")
        .setPassword("secure_password")
        .setDatabase(3);
    
    return Redisson.create(config);
}

Thẻ: Java Apache HttpClient Redisson Multipart Upload URL Mapping

Đăng vào ngày 26 tháng 5 lúc 04:44