hapi-fhir-testpage-overlay
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
3. Tìm kiếm nâng cao
Công cụ tìm kiếm mạnh mẽ với giao diện trực quan:
Search Builder: UI để xây dựng truy vấn tìm kiếm phức tạp
Parameter Support: Hỗ trợ đầy đủ cho tất cả search parameter types
Chaining: Giao diện cho phép chaining và reverse chaining
Includes: Tích hợp _include và _revinclude
Pagination Controls: Điều khiển phân trang kết quả tìm kiếm
Export Options: Xuất kết quả tìm kiếm dưới dạng JSON/XML
4. Thực thi Operations
Giao diện để thực thi các operations FHIR:
Standard Operations: Hỗ trợ cho $everything, $validate, $meta
Custom Operations: Thực thi các operations tùy chỉnh
Parameters Builder: Giao diện xây dựng Parameters resources
Results Viewer: Xem kết quả operations dưới dạng định dạng có cấu trúc
5. Transaction Support
Giao diện cho việc xây dựng và thực thi FHIR transactions:
Bundle Builder: Tạo và chỉnh sửa FHIR Bundle resources
Transaction Editor: Thêm nhiều entries vào một transaction
Batch Editor: Xây dựng và thực thi batch operations
Response Analyzer: Phân tích kết quả bundle responses
6. History & Validation
Các tính năng khác bao gồm:
History Viewer: Xem lịch sử thay đổi của resources
Validation Tool: Validate resources theo profiles
Diff Tool: So sánh các phiên bản khác nhau của một resource
Formatting Options: Chuyển đổi giữa JSON, XML và các định dạng khác
Cài đặt và Tích hợp
1. Maven Dependency
Thêm TestPage Overlay vào dự án Maven:
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-testpage-overlay</artifactId>
<version>6.4.0</version>
</dependency>
2. Tích hợp với HAPI FHIR JPA Server
@Configuration
public class FhirServerConfig {
@Bean
public ServletRegistrationBean<RestfulServer> fhirServerServletRegistration() {
ServletRegistrationBean<RestfulServer> servletRegistrationBean = new ServletRegistrationBean<>();
RestfulServer fhirServlet = new RestfulServer();
// Cấu hình FHIR server
servletRegistrationBean.setServlet(fhirServlet);
servletRegistrationBean.addUrlMappings("/fhir/*");
return servletRegistrationBean;
}
@Bean
public ServletRegistrationBean<TestPageOverlay> overlayRegistrationBean() {
ServletRegistrationBean<TestPageOverlay> servletRegistrationBean = new ServletRegistrationBean<>();
TestPageOverlay overlayServlet = new TestPageOverlay();
// Cấu hình TestPage Overlay
servletRegistrationBean.setServlet(overlayServlet);
servletRegistrationBean.addUrlMappings("/testpage/*");
// Cấu hình tùy chọn
servletRegistrationBean.addInitParameter("serverId", "FHIR Server");
servletRegistrationBean.addInitParameter("serverBase", "/fhir");
servletRegistrationBean.addInitParameter("enableJsonEditor", "true");
return servletRegistrationBean;
}
}
3. Tích hợp với Spring Boot
@SpringBootApplication
public class FhirApplication {
public static void main(String[] args) {
SpringApplication.run(FhirApplication.class, args);
}
@Bean
public WebMvcConfigurer webMvcConfigurer() {
return new WebMvcConfigurer() {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
// Redirect root to testpage
registry.addViewController("/").setViewName("redirect:/testpage");
}
};
}
@Bean
public TestPageOverlay testPageServlet() {
TestPageOverlay overlay = new TestPageOverlay();
// Cấu hình Theme
overlay.setServerName("My FHIR Server");
overlay.setServerVersion("6.4.0");
overlay.setThemeName("default");
// Cấu hình bảo mật
overlay.setSecure(true);
overlay.setAuthorizationInterceptor(new TestPageAuthorizationInterceptor());
return overlay;
}
@Bean
public ServletRegistrationBean<TestPageOverlay> overlayServletRegistration(TestPageOverlay testPageServlet) {
ServletRegistrationBean<TestPageOverlay> bean = new ServletRegistrationBean<>(testPageServlet, "/testpage/*");
bean.setLoadOnStartup(1);
return bean;
}
}
4. Tích hợp với web.xml (Legacy)
<!-- Trong web.xml -->
<servlet>
<servlet-name>testPageOverlay</servlet-name>
<servlet-class>ca.uhn.fhir.to.TestPageOverlay</servlet-class>
<init-param>
<param-name>serverId</param-name>
<param-value>FHIR Server</param-value>
</init-param>
<init-param>
<param-name>serverBase</param-name>
<param-value>/fhir</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>testPageOverlay</servlet-name>
<url-pattern>/testpage/*</url-pattern>
</servlet-mapping>
Tùy chỉnh và Mở rộng
1. Theme Customization
TestPage Overlay có thể được tùy chỉnh theo thương hiệu tổ chức:
@Component
public class CustomTestPageConfig {
@Autowired
private TestPageOverlay testPageOverlay;
@PostConstruct
public void configureOverlay() {
// Cấu hình thông tin hiển thị
testPageOverlay.setServerName("Organization FHIR Server");
testPageOverlay.setServerVersion("Version 1.0");
testPageOverlay.setServerDescription("FHIR Server của Tổ chức Y tế Việt Nam");
// Theme configuration
Properties themeProps = new Properties();
themeProps.setProperty("primaryColor", "#007bff");
themeProps.setProperty("secondaryColor", "#6c757d");
themeProps.setProperty("backgroundColor", "#f8f9fa");
themeProps.setProperty("logoUrl", "/images/org-logo.png");
themeProps.setProperty("footerText", "© 2025 Tổ chức Y tế Việt Nam");
testPageOverlay.setThemeProperties(themeProps);
}
@Bean
public WebMvcConfigurer additionalResourceConfigurer() {
return new WebMvcConfigurer() {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/testpage/custom/**")
.addResourceLocations("classpath:/custom-testpage-assets/");
}
};
}
}
2. Bảo mật và Xác thực
Tích hợp bảo mật cho TestPage Overlay:
@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:
@Component
public class ResourceComparisonExtension implements ITestPageExtension {
@Override
public String getExtensionName() {
return "resource-comparison";
}
@Override
public String getExtensionDescription() {
return "So sánh các phiên bản FHIR resources hoặc giữa các resources khác nhau";
}
@Override
public String getExtensionUrl() {
return "comparison";
}
@Override
public String getExtensionHtml() {
return "<div class=\"container pt-3\">\n" +
" <h3>So sánh FHIR Resources</h3>\n" +
" <div class=\"row\">\n" +
" <div class=\"col-md-5\">\n" +
" <div class=\"form-group\">\n" +
" <label>Resource 1:</label>\n" +
" <select id=\"resource1-type\" class=\"form-control mb-2\"></select>\n" +
" <input id=\"resource1-id\" type=\"text\" class=\"form-control mb-2\" placeholder=\"ID\">\n" +
" <button id=\"load-resource1\" class=\"btn btn-primary\">Load</button>\n" +
" </div>\n" +
" <div id=\"resource1-container\" class=\"border p-2 mt-3\" style=\"min-height: 400px; max-height: 600px; overflow: auto;\">\n" +
" <pre id=\"resource1-json\"></pre>\n" +
" </div>\n" +
" </div>\n" +
" <div class=\"col-md-2 d-flex align-items-center justify-content-center\">\n" +
" <div class=\"text-center\">\n" +
" <button id=\"compare-btn\" class=\"btn btn-success mb-3\">Compare</button>\n" +
" <div>\n" +
" <div class=\"form-check\">\n" +
" <input class=\"form-check-input\" type=\"radio\" name=\"compare-mode\" id=\"compare-mode-visual\" checked>\n" +
" <label class=\"form-check-label\" for=\"compare-mode-visual\">Visual</label>\n" +
" </div>\n" +
" <div class=\"form-check\">\n" +
" <input class=\"form-check-input\" type=\"radio\" name=\"compare-mode\" id=\"compare-mode-detail\">\n" +
" <label class=\"form-check-label\" for=\"compare-mode-detail\">Detailed</label>\n" +
" </div>\n" +
" </div>\n" +
" </div>\n" +
" </div>\n" +
" <div class=\"col-md-5\">\n" +
" <div class=\"form-group\">\n" +
" <label>Resource 2:</label>\n" +
" <select id=\"resource2-type\" class=\"form-control mb-2\"></select>\n" +
" <input id=\"resource2-id\" type=\"text\" class=\"form-control mb-2\" placeholder=\"ID\">\n" +
" <button id=\"load-resource2\" class=\"btn btn-primary\">Load</button>\n" +
" </div>\n" +
" <div id=\"resource2-container\" class=\"border p-2 mt-3\" style=\"min-height: 400px; max-height: 600px; overflow: auto;\">\n" +
" <pre id=\"resource2-json\"></pre>\n" +
" </div>\n" +
" </div>\n" +
" </div>\n" +
" <div class=\"row mt-4\">\n" +
" <div class=\"col-12\">\n" +
" <h4>Kết quả so sánh</h4>\n" +
" <div id=\"comparison-result\" class=\"border p-3\" style=\"min-height: 200px;\">\n" +
" <p class=\"text-muted\">Chọn hai resources và nhấn Compare để xem sự khác biệt.</p>\n" +
" </div>\n" +
" </div>\n" +
" </div>\n" +
"</div>\n" +
"<script src=\"/testpage/static/js/resource-comparison.js\"></script>";
}
}
2. Batch Request Builder
TestPage có thể được mở rộng với batch request builder nâng cao:
@Component
public class BatchRequestBuilderExtension implements ITestPageExtension {
@Override
public String getExtensionName() {
return "batch-builder";
}
@Override
public String getExtensionDescription() {
return "Xây dựng và thực thi FHIR Batch/Transaction requests";
}
@Override
public String getExtensionUrl() {
return "batch-builder";
}
@Override
public String getExtensionHtml() {
return "<div class=\"container pt-3\">\n" +
" <h3>FHIR Batch/Transaction Builder</h3>\n" +
" <div class=\"form-group\">\n" +
" <label>Bundle Type:</label>\n" +
" <select id=\"bundle-type\" class=\"form-control\">\n" +
" <option value=\"batch\">Batch</option>\n" +
" <option value=\"transaction\">Transaction</option>\n" +
" </select>\n" +
" </div>\n" +
" <div class=\"row mb-3\">\n" +
" <div class=\"col-md-" <div class=\"col-md-12\">\n" +
" <button id=\"add-entry\" class=\"btn btn-primary\">Thêm Entry mới</button>\n" +
" <button id=\"clear-all\" class=\"btn btn-danger ml-2\">Xóa tất cả</button>\n" +
" </div>\n" +
" </div>\n" +
" <div id=\"entries-container\">\n" +
" <div class=\"card mb-3 entry-card\" id=\"entry-template\" style=\"display:none;\">\n" +
" <div class=\"card-header d-flex justify-content-between align-items-center\">\n" +
" <span>Entry <span class=\"entry-number\">1</span></span>\n" +
" <div>\n" +
" <button class=\"btn btn-sm btn-danger remove-entry\">Xóa</button>\n" +
" </div>\n" +
" </div>\n" +
" <div class=\"card-body\">\n" +
" <div class=\"form-group\">\n" +
" <label>HTTP Method:</label>\n" +
" <select class=\"form-control http-method\">\n" +
" <option value=\"GET\">GET</option>\n" +
" <option value=\"POST\">POST</option>\n" +
" <option value=\"PUT\">PUT</option>\n" +
" <option value=\"DELETE\">DELETE</option>\n" +
" </select>\n" +
" </div>\n" +
" <div class=\"form-group\">\n" +
" <label>URL:</label>\n" +
" <input type=\"text\" class=\"form-control entry-url\" placeholder=\"Patient/123 or Patient?name=Smith\">\n" +
" </div>\n" +
" <div class=\"form-group resource-container\" style=\"display:none;\">\n" +
" <label>Resource Body:</label>\n" +
" <div class=\"resource-editor\" style=\"height: 200px; border: 1px solid #ccc;\"></div>\n" +
" </div>\n" +
" </div>\n" +
" </div>\n" +
" </div>\n" +
" <div class=\"row mt-3\">\n" +
" <div class=\"col-md-12\">\n" +
" <button id=\"preview-bundle\" class=\"btn btn-info\">Preview Bundle</button>\n" +
" <button id=\"execute-bundle\" class=\"btn btn-success ml-2\">Execute</button>\n" +
" </div>\n" +
" </div>\n" +
" <div class=\"row mt-3\">\n" +
" <div class=\"col-md-12\">\n" +
" <div class=\"card\">\n" +
" <div class=\"card-header\">Bundle Preview</div>\n" +
" <div class=\"card-body\">\n" +
" <pre id=\"bundle-preview\" style=\"max-height: 400px; overflow: auto;\"></pre>\n" +
" </div>\n" +
" </div>\n" +
" </div>\n" +
" </div>\n" +
" <div class=\"row mt-3\">\n" +
" <div class=\"col-md-12\">\n" +
" <div class=\"card\">\n" +
" <div class=\"card-header\">Response</div>\n" +
" <div class=\"card-body\">\n" +
" <pre id=\"response-preview\" style=\"max-height: 400px; overflow: auto;\"></pre>\n" +
" </div>\n" +
" </div>\n" +
" </div>\n" +
" </div>\n" +
"</div>\n" +
"<script src=\"/testpage/static/js/batch-builder.js\"></script>";
}
}
3. SMART App Launcher
TestPage có thể được tích hợp với SMART on FHIR App Launcher:
@Component
public class SmartAppLauncherExtension implements ITestPageExtension {
@Autowired
private Environment env;
@Override
public String getExtensionName() {
return "smart-app-launcher";
}
@Override
public String getExtensionDescription() {
return "Khởi chạy và thử nghiệm SMART on FHIR Apps";
}
@Override
public String getExtensionUrl() {
return "smart-launcher";
}
@Override
public String getExtensionHtml() {
String authEndpoint = env.getProperty("fhir.smart.auth-endpoint", "http://localhost:8080/auth");
String tokenEndpoint = env.getProperty("fhir.smart.token-endpoint", "http://localhost:8080/token");
String fhirServerBase = env.getProperty("fhir.server.base-url", "http://localhost:8080/fhir");
return "<div class=\"container pt-3\">\n" +
" <h3>SMART on FHIR App Launcher</h3>\n" +
" <div class=\"row\">\n" +
" <div class=\"col-md-6\">\n" +
" <div class=\"card\">\n" +
" <div class=\"card-header bg-primary text-white\">App Configuration</div>\n" +
" <div class=\"card-body\">\n" +
" <div class=\"form-group\">\n" +
" <label>App Launch URL:</label>\n" +
" <input type=\"text\" id=\"app-url\" class=\"form-control\" placeholder=\"https://example.org/smart-app/launch.html\">\n" +
" </div>\n" +
" <div class=\"form-group\">\n" +
" <label>Client ID:</label>\n" +
" <input type=\"text\" id=\"client-id\" class=\"form-control\" placeholder=\"client_id\">\n" +
" </div>\n" +
" <div class=\"form-group\">\n" +
" <label>Scope:</label>\n" +
" <input type=\"text\" id=\"scope\" class=\"form-control\" value=\"patient/*.read launch/patient\">\n" +
" </div>\n" +
" <div class=\"form-group\">\n" +
" <label>Launch Type:</label>\n" +
" <select id=\"launch-type\" class=\"form-control\">\n" +
" <option value=\"patient\">Patient Context</option>\n" +
" <option value=\"provider\">Provider Context</option>\n" +
" <option value=\"standalone\">Standalone Launch</option>\n" +
" </select>\n" +
" </div>\n" +
" <div id=\"patient-context\" class=\"form-group\">\n" +
" <label>Patient:</label>\n" +
" <select id=\"patient-id\" class=\"form-control\"></select>\n" +
" </div>\n" +
" <div id=\"provider-context\" class=\"form-group\" style=\"display:none;\">\n" +
" <label>Provider:</label>\n" +
" <select id=\"provider-id\" class=\"form-control\"></select>\n" +
" </div>\n" +
" <button id=\"launch-app\" class=\"btn btn-success mt-3\">Launch App</button>\n" +
" </div>\n" +
" </div>\n" +
" </div>\n" +
" <div class=\"col-md-6\">\n" +
" <div class=\"card\">\n" +
" <div class=\"card-header bg-info text-white\">SMART Configuration</div>\n" +
" <div class=\"card-body\">\n" +
" <div class=\"form-group\">\n" +
" <label>FHIR Server Base URL:</label>\n" +
" <input type=\"text\" id=\"fhir-server-url\" class=\"form-control\" value=\"" + fhirServerBase + "\">\n" +
" </div>\n" +
" <div class=\"form-group\">\n" +
" <label>Authorization Endpoint:</label>\n" +
" <input type=\"text\" id=\"auth-endpoint\" class=\"form-control\" value=\"" + authEndpoint + "\">\n" +
" </div>\n" +
" <div class=\"form-group\">\n" +
" <label>Token Endpoint:</label>\n" +
" <input type=\"text\" id=\"token-endpoint\" class=\"form-control\" value=\"" + tokenEndpoint + "\">\n" +
" </div>\n" +
" <div class=\"alert alert-info\">\n" +
" <strong>Note:</strong> SMART on FHIR configuration should be enabled on your FHIR server for this launcher to work correctly.\n" +
" </div>\n" +
" </div>\n" +
" </div>\n" +
" <div class=\"card mt-3\">\n" +
" <div class=\"card-header bg-secondary text-white\">Recent Launches</div>\n" +
" <div class=\"card-body p-0\">\n" +
" <ul id=\"launch-history\" class=\"list-group list-group-flush\">\n" +
" <li class=\"list-group-item text-muted\">No recent launches</li>\n" +
" </ul>\n" +
" </div>\n" +
" </div>\n" +
" </div>\n" +
" </div>\n" +
" <div class=\"row mt-4\">\n" +
" <div class=\"col-12\">\n" +
" <div class=\"card\">\n" +
" <div class=\"card-header bg-dark text-white\">App Preview</div>\n" +
" <div class=\"card-body p-0\" style=\"height: 600px;\">\n" +
" <iframe id=\"app-frame\" style=\"width: 100%; height: 100%; border: none;\" src=\"about:blank\"></iframe>\n" +
" </div>\n" +
" </div>\n" +
" </div>\n" +
" </div>\n" +
"</div>\n" +
"<script src=\"/testpage/static/js/smart-launcher.js\"></script>";
}
}
Hướng dẫn Sử dụng
1. Resource Browsing và CRUD
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.
Last updated