Tutorial 4: Patient CRUD Operations¶
Pages: 2
📖 Page 1: Service Layer + CREATE/READ¶
Create PatientService¶
Create src/main/java/com/healthcare/pms/service/PatientService.java:
package com.healthcare.pms.service;
import ca.uhn.fhir.rest.api.MethodOutcome;
import ca.uhn.fhir.rest.client.api.IGenericClient;
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
import com.healthcare.pms.dto.PatientDTO;
import com.healthcare.pms.mapper.PatientMapper;
import lombok.RequiredArgsConstructor;
import org.hl7.fhir.r4.model.*;
import org.springframework.stereotype.Service;
import java.util.*;
import java.util.stream.Collectors;
@Service
@RequiredArgsConstructor
public class PatientService {
private final IGenericClient fhirClient;
private final PatientMapper patientMapper;
// CREATE
public PatientDTO createPatient(PatientDTO dto) {
Patient fhirPatient = patientMapper.toFhirResource(dto);
MethodOutcome outcome = fhirClient.create()
.resource(fhirPatient)
.execute();
Patient created = (Patient) outcome.getResource();
return patientMapper.toDTO(created);
}
// READ
public PatientDTO getPatientById(String id) {
try {
Patient patient = fhirClient.read()
.resource(Patient.class)
.withId(id)
.execute();
return patientMapper.toDTO(patient);
} catch (ResourceNotFoundException e) {
throw new RuntimeException("Patient not found: " + id);
}
}
// GET ALL (for list page)
public List<PatientDTO> getAllPatients() {
Bundle bundle = fhirClient.search()
.forResource(Patient.class)
.returnBundle(Bundle.class)
.execute();
List<PatientDTO> patients = new ArrayList<>();
for (Bundle.BundleEntryComponent entry : bundle.getEntry()) {
if (entry.getResource() instanceof Patient) {
patients.add(patientMapper.toDTO((Patient) entry.getResource()));
}
}
return patients;
}
}
📖 Page 2: UPDATE/DELETE/SEARCH¶
Add Remaining Operations¶
Add to PatientService.java:
// UPDATE
public PatientDTO updatePatient(String id, PatientDTO dto) {
dto.setId(id);
Patient fhirPatient = patientMapper.toFhirResource(dto);
fhirClient.update()
.resource(fhirPatient)
.withId(id)
.execute();
return getPatientById(id);
}
// DELETE
public void deletePatient(String id) {
fhirClient.delete()
.resourceById("Patient", id)
.execute();
}
// SEARCH by name
public List<PatientDTO> searchPatients(String name) {
if (name == null || name.trim().isEmpty()) {
return getAllPatients();
}
Bundle bundle = fhirClient.search()
.forResource(Patient.class)
.where(Patient.NAME.matches().value(name))
.returnBundle(Bundle.class)
.execute();
return bundle.getEntry().stream()
.map(entry -> (Patient) entry.getResource())
.map(patientMapper::toDTO)
.collect(Collectors.toList());
}
// FILTER (we'll add in Tutorial 6)
public List<PatientDTO> filterPatients(String gender, String bloodGroup,
Boolean active) {
List<PatientDTO> patients = getAllPatients();
return patients.stream()
.filter(p -> gender == null || gender.isEmpty() ||
p.getGender().equalsIgnoreCase(gender))
.filter(p -> bloodGroup == null || bloodGroup.isEmpty() ||
bloodGroup.equals(p.getBloodGroup()))
.filter(p -> active == null || active.equals(p.getActive()))
.collect(Collectors.toList());
}
Test Service¶
Create test method in Application.java:
@SpringBootApplication
public class Application implements CommandLineRunner {
@Autowired
private PatientService patientService;
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
@Override
public void run(String... args) {
// Create test patient
PatientDTO dto = new PatientDTO();
dto.setFirstName("John");
dto.setLastName("Doe");
dto.setBirthDate(LocalDate.of(1990, 5, 15));
dto.setGender("male");
dto.setEmail("john@example.com");
dto.setActive(true);
PatientDTO created = patientService.createPatient(dto);
System.out.println("Created patient: " + created.getId());
// Read it back
PatientDTO retrieved = patientService.getPatientById(created.getId());
System.out.println("Retrieved: " + retrieved.getFullName());
}
}
Run and check console!
✅ CRUD Complete¶
- CREATE -
createPatient() - READ -
getPatientById(),getAllPatients() - UPDATE -
updatePatient() - DELETE -
deletePatient() - SEARCH -
searchPatients() - FILTER -
filterPatients()
🚀 Next¶
Service layer done! Now let's add web interface.
→ Tutorial 5: Controller & UI
💡 Quick Tips¶
Error Handling
Wrap FHIR calls in try-catch for production
Pagination
getAllPatients() returns all - we'll paginate in Tutorial 7
Bundle
FHIR search returns Bundle (collection of resources)