HAPI FHIR TestPage Overlay: Giao diện Web hiệu quả để truy cập và kiểm thử FHIR Server
Giới thiệu
hapi-fhir-testpage-overlay là một thành phần của hệ sinh thái HAPI FHIR cung cấp giao diện web đơn giản, trực quan cho phép nhà phát triển và người dùng tương tác, kiểm thử và khám phá FHIR server. Thành phần này được thiết kế như một overlay có thể dễ dàng tích hợp vào bất kỳ HAPI FHIR server nào, cung cấp giao diện người dùng đồ họa (GUI) mạnh mẽ để thực hiện và kiểm tra các thao tác FHIR RESTful.
Khác với các công cụ dòng lệnh hoặc API clients đòi hỏi kiến thức lập trình, TestPage Overlay cho phép người dùng với các trình độ kỹ thuật khác nhau tương tác với FHIR server thông qua giao diện web thân thiện, làm cho việc khám phá, phát triển và gỡ lỗi ứng dụng FHIR trở nên dễ dàng hơn nhiều.
Tính năng chính
1. Giao diện khám phá server
TestPage Overlay cung cấp giao diện để khám phá các tính năng của FHIR server:
Conformance Statement Viewer: Hiển thị chi tiết CapabilityStatement (metadata) của server
Resource Type Explorer: Xem danh sách tất cả resource types được hỗ trợ
Search Parameters: Hiển thị các parameters được hỗ trợ cho mỗi resource type
Operations Explorer: Khám phá các operations có sẵn trên server
2. CRUD Operations UI
Giao diện trực quan cho các thao tác CRUD (Create, Read, Update, Delete):
Create Resource: Form tạo resource mới với JSON/XML editor
Read Resource: Truy xuất resource theo ID
Update Resource: Cập nhật resource hiện có
Delete Resource: Xóa resource từ server
Versioning: Xem và khôi phục các phiên bản trước của resource
@Component
public class TestPageAuthorizationInterceptor implements ITestPageAuthorizationInterceptor {
@Autowired
private UserService userService;
@Override
public boolean authorizeRequest(HttpServletRequest request, HttpServletResponse response) {
// Kiểm tra session attribute cho người dùng đã xác thực
Object authenticatedUser = request.getSession().getAttribute("authenticatedUser");
if (authenticatedUser != null) {
return true;
}
// Nếu không có request login, chuyển hướng đến trang login
if (!request.getRequestURI().endsWith("/testpage/login")) {
try {
response.sendRedirect(request.getContextPath() + "/testpage/login");
return false;
} catch (IOException e) {
throw new RuntimeException("Error redirecting to login", e);
}
}
// Logic xác thực cho request login
if (request.getMethod().equals("POST")) {
String username = request.getParameter("username");
String password = request.getParameter("password");
if (userService.authenticate(username, password)) {
request.getSession().setAttribute("authenticatedUser", username);
// Chuyển hướng đến trang chính
try {
response.sendRedirect(request.getContextPath() + "/testpage/home");
return false;
} catch (IOException e) {
throw new RuntimeException("Error redirecting after login", e);
}
} else {
// Login thất bại, hiển thị form login với thông báo lỗi
request.setAttribute("loginError", "Invalid username or password");
return true;
}
}
// Allow access to the login page itself
return true;
}
@Override
public String getCustomLoginPage(HttpServletRequest request) {
String error = (String) request.getAttribute("loginError");
StringBuilder loginPage = new StringBuilder();
loginPage.append("<!DOCTYPE html>\n")
.append("<html>\n")
.append("<head>\n")
.append(" <title>Login - FHIR TestPage</title>\n")
.append(" <link rel=\"stylesheet\" href=\"https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css\">\n")
.append(" <style>\n")
.append(" body { background-color: #f5f5f5; }\n")
.append(" .login-container { max-width: 400px; margin: 100px auto; }\n")
.append(" </style>\n")
.append("</head>\n")
.append("<body>\n")
.append(" <div class=\"container login-container\">\n")
.append(" <div class=\"card\">\n")
.append(" <div class=\"card-header bg-primary text-white\">\n")
.append(" <h4 class=\"m-0\">FHIR TestPage Login</h4>\n")
.append(" </div>\n")
.append(" <div class=\"card-body\">\n");
if (error != null) {
loginPage.append(" <div class=\"alert alert-danger\">")
.append(error)
.append("</div>\n");
}
loginPage.append(" <form method=\"POST\" action=\"")
.append(request.getContextPath())
.append("/testpage/login\">\n")
.append(" <div class=\"form-group\">\n")
.append(" <label for=\"username\">Username</label>\n")
.append(" <input type=\"text\" class=\"form-control\" id=\"username\" name=\"username\" required>\n")
.append(" </div>\n")
.append(" <div class=\"form-group\">\n")
.append(" <label for=\"password\">Password</label>\n")
.append(" <input type=\"password\" class=\"form-control\" id=\"password\" name=\"password\" required>\n")
.append(" </div>\n")
.append(" <button type=\"submit\" class=\"btn btn-primary btn-block\">Login</button>\n")
.append(" </form>\n")
.append(" </div>\n")
.append(" </div>\n")
.append(" </div>\n")
.append("</body>\n")
.append("</html>");
return loginPage.toString();
}
}
3. Custom Operations UI
Tạo giao diện tùy chỉnh cho custom operations:
@Component
public class CustomOperationsProvider implements ITestPageCustomOperationProvider {
@Override
public List<CustomOperation> provideOperations() {
List<CustomOperation> operations = new ArrayList<>();
// Thêm custom operation cho Patient
CustomOperation patientRiskAssessment = new CustomOperation();
patientRiskAssessment.setResourceType("Patient");
patientRiskAssessment.setName("risk-assessment");
patientRiskAssessment.setDescription("Đánh giá rủi ro bệnh lý cho bệnh nhân");
// Thêm parameters
List<CustomOperationParam> params = new ArrayList<>();
CustomOperationParam patientIdParam = new CustomOperationParam();
patientIdParam.setName("patientId");
patientIdParam.setType("string");
patientIdParam.setRequired(true);
patientIdParam.setDescription("ID của bệnh nhân cần đánh giá");
params.add(patientIdParam);
CustomOperationParam assessmentTypeParam = new CustomOperationParam();
assessmentTypeParam.setName("assessmentType");
assessmentTypeParam.setType("code");
assessmentTypeParam.setRequired(true);
assessmentTypeParam.setDescription("Loại đánh giá rủi ro (CARDIAC, DIABETES, STROKE)");
params.add(assessmentTypeParam);
patientRiskAssessment.setParameters(params);
operations.add(patientRiskAssessment);
// Thêm custom operation ở mức system
CustomOperation bulkExport = new CustomOperation();
bulkExport.setResourceType("$system");
bulkExport.setName("bulk-export");
bulkExport.setDescription("Export dữ liệu số lượng lớn từ server");
List<CustomOperationParam> exportParams = new ArrayList<>();
CustomOperationParam sinceParam = new CustomOperationParam();
sinceParam.setName("_since");
sinceParam.setType("date");
sinceParam.setRequired(false);
sinceParam.setDescription("Chỉ export dữ liệu đã thay đổi từ ngày này");
exportParams.add(sinceParam);
CustomOperationParam typesParam = new CustomOperationParam();
typesParam.setName("_type");
typesParam.setType("string");
typesParam.setRequired(false);
typesParam.setDescription("Danh sách các resource types cần export");
exportParams.add(typesParam);
bulkExport.setParameters(exportParams);
operations.add(bulkExport);
return operations;
}
}
Trường hợp sử dụng thực tế
1. Môi trường phát triển
TestPage Overlay được sử dụng rộng rãi trong môi trường phát triển:
@Configuration
@Profile("development")
public class DevEnvironmentConfig {
@Bean
public ServletRegistrationBean<TestPageOverlay> devTestPageOverlay() {
TestPageOverlay overlay = new TestPageOverlay();
// Cấu hình cho môi trường dev
overlay.setSecure(false); // Vô hiệu hóa bảo mật trong dev
overlay.setServerName("FHIR Dev Server");
overlay.setShowRequestUrl(true); // Hiển thị URL đầy đủ
overlay.setShowStackTraceInErrorPage(true); // Hiện thông tin debug
// Cấu hình môi trường dev khác
Properties devProps = new Properties();
devProps.setProperty("defaultResourceCount", "20");
devProps.setProperty("enableConsole", "true");
overlay.setProperties(devProps);
// Đăng ký servlet
ServletRegistrationBean<TestPageOverlay> bean =
new ServletRegistrationBean<>(overlay, "/dev/testpage/*");
bean.setLoadOnStartup(1);
return bean;
}
@Bean
public WebMvcConfigurer devConfigurer() {
return new WebMvcConfigurer() {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/dev").setViewName("redirect:/dev/testpage");
}
};
}
}
2. Hỗ trợ đào tạo
TestPage được sử dụng trong đào tạo FHIR cho nhân viên y tế:
@Controller
@RequestMapping("/training")
public class FhirTrainingController {
@Autowired
private TestPageOverlay trainingOverlay;
@PostConstruct
public void configureTrainingOverlay() {
// Cấu hình TestPage cho đào tạo
trainingOverlay.setServerName("FHIR Training Environment");
trainingOverlay.setSimplifiedMode(true); // UI đơn giản hóa
trainingOverlay.setShowExamples(true); // Hiển thị ví dụ
// Thêm resources mẫu
trainingOverlay.addSampleResource("Patient", "/samples/patient-example.json");
trainingOverlay.addSampleResource("Observation", "/samples/observation-example.json");
trainingOverlay.addSampleResource("Encounter", "/samples/encounter-example.json");
}
@GetMapping("/intro")
public String trainingIntroduction(Model model) {
model.addAttribute("courseTitle", "FHIR for Healthcare Professionals");
model.addAttribute("testPageUrl", "/training/testpage");
return "training/intro";
}
@GetMapping("/exercises")
public String trainingExercises(Model model) {
List<TrainingExercise> exercises = getTrainingExercises();
model.addAttribute("exercises", exercises);
return "training/exercises";
}
private List<TrainingExercise> getTrainingExercises() {
List<TrainingExercise> exercises = new ArrayList<>();
// Exercise 1: Create Patient
TrainingExercise ex1 = new TrainingExercise();
ex1.setTitle("Tạo hồ sơ bệnh nhân");
ex1.setDescription("Sử dụng TestPage để tạo một resource Patient mới");
ex1.setTestPageLink("/training/testpage?resource=Patient&action=create");
exercises.add(ex1);
// Exercise 2: Search Patient
TrainingExercise ex2 = new TrainingExercise();
ex2.setTitle("Tìm kiếm bệnh nhân");
ex2.setDescription("Thực hành tìm kiếm bệnh nhân theo tên và ngày sinh");
ex2.setTestPageLink("/training/testpage?resource=Patient&action=search");
exercises.add(ex2);
// More exercises...
return exercises;
}
public static class TrainingExercise {
private String title;
private String description;
private String testPageLink;
// Getters and setters
}
}
3. Monitoring và Debugging
TestPage là công cụ hữu ích trong monitoring và debugging FHIR server:
@Configuration
public class TestPageMonitoringConfig {
@Autowired
private TestPageOverlay monitoringOverlay;
@PostConstruct
public void configureMonitoringOverlay() {
// Cấu hình TestPage cho việc monitoring
monitoringOverlay.setSecure(true);
monitoringOverlay.setServerName("FHIR Monitoring Console");
// Kích hoạt các tính năng monitoring
Properties monitoringProps = new Properties();
monitoringProps.setProperty("showServerMetrics", "true");
monitoringProps.setProperty("showActiveTransactions", "true");
monitoringProps.setProperty("refreshInterval", "10000"); // 10 seconds
monitoringProps.setProperty("enableLogging", "true");
monitoringOverlay.setProperties(monitoringProps);
// Register monitoring interceptor
monitoringOverlay.addInterceptor(new MonitoringInterceptor());
}
@Component
public static class MonitoringInterceptor implements ITestPageInterceptor {
private static final Logger logger = LoggerFactory.getLogger(MonitoringInterceptor.class);
@Override
public void interceptRequest(HttpServletRequest request, String serverBaseUrl,
String resourceName, String resourceId, String operation) {
// Log admin operations in monitoring console
String user = getCurrentUser(request);
logger.info("Monitoring: User {} performed {} on {}/{} via TestPage Console",
user, operation, resourceName, resourceId);
// Record monitoring metrics
updateMetrics(user, resourceName, operation);
}
private String getCurrentUser(HttpServletRequest request) {
// Get current authenticated user
Object user = request.getSession().getAttribute("authenticatedUser");
return user != null ? user.toString() : "anonymous";
}
private void updateMetrics(String user, String resourceType, String operation) {
// Implementation of metrics collection
// ...
}
}
@RestController
@RequestMapping("/admin/monitoring")
public class MonitoringController {
@GetMapping("/metrics")
public ResponseEntity<Map<String, Object>> getMetrics() {
// Get current server metrics
Map<String, Object> metrics = collectServerMetrics();
return ResponseEntity.ok(metrics);
}
private Map<String, Object> collectServerMetrics() {
// Implementation of server metrics collection
Map<String, Object> metrics = new HashMap<>();
// Populate metrics
return metrics;
}
}
}
Tính năng nâng cao
1. Resource Comparison
TestPage Overlay hỗ trợ so sánh các phiên bản FHIR resources:
TestPage Overlay cho phép người dùng dễ dàng duyệt và sử dụng các resources:
Browse Resources: Xem danh sách resource types hỗ trợ từ trang chủ
Create Resource:
Chọn resource type
Nhấp vào "Create"
Điền thông tin trong editor
Nhấp "Save" để tạo resource
Read Resource:
Nhập ID của resource
Nhấp "Read" để xem resource
Update Resource:
Đọc resource
Sửa đổi trong editor
Nhấp "Update" để lưu thay đổi
Delete Resource:
Đọc resource
Nhấp "Delete" để xóa resource
2. Search Interface
Thực hiện tìm kiếm nâng cao:
Basic Search:
Chọn resource type
Nhấp "Search"
Nhập các parameters cơ bản
Nhấp "Run Search"
Advanced Search:
Thêm nhiều search parameters
Sử dụng modifiers (eq, ne, gt, lt, etc.)
Kết hợp với AND/OR operators
Cấu hình _include và _revinclude
Sorting và Pagination:
Thiết lập _sort parameter
Cấu hình _count để kiểm soát số lượng kết quả
Sử dụng paginated navigation
3. Thực hiện Operations
Gọi standard và custom operations:
Operations Menu:
Xem danh sách operations có sẵn
Chọn type: instance, type hoặc system
Parameters:
Cung cấp parameters cần thiết
Thêm/xóa parameter để tùy chỉnh
Execution:
Nhấp "Execute" để chạy operation
Xem kết quả dưới dạng JSON/XML
Xem logs và response headers
Kết luận
hapi-fhir-testpage-overlay là một thành phần thiết yếu trong hệ sinh thái HAPI FHIR, cung cấp giao diện trực quan và mạnh mẽ để tương tác với FHIR server. Đây là công cụ vô giá cho nhà phát triển, quản trị viên hệ thống và thậm chí người dùng cuối để khám phá, thử nghiệm và sử dụng các tính năng của FHIR server.
Các lợi ích chính của TestPage Overlay bao gồm:
Giao diện thân thiện với người dùng: Giảm bớt đường cong học tập của FHIR
Khám phá trực quan: Dễ dàng hiểu cấu trúc và tính năng của server
Tính linh hoạt: Có thể tùy chỉnh và mở rộng theo nhu cầu cụ thể
Hỗ trợ phát triển: Công cụ thiết yếu trong quá trình phát triển và gỡ lỗi
Hỗ trợ đào tạo: Lý tưởng cho việc đào tạo người dùng về FHIR
Với khả năng tùy chỉnh cao và khả năng tích hợp dễ dàng, hapi-fhir-testpage-overlay là công cụ không thể thiếu trong bộ công cụ của bất kỳ nhà phát triển FHIR nào, giúp rút ngắn thời gian phát triển, tăng cường hiểu biết về FHIR và cải thiện chất lượng triển khai.