Spring CRUD无法将Patient实体保存至H2数据库求助
Spring应用无法向H2数据库添加数据排查
问题描述
我的Spring应用无法向已连接的H2数据库添加任何数据,且createOrUpdatePatient控制器方法甚至没有输出日志信息,修改控制器和服务层后仍未解决,请求排查原因。
Patient实体类
package medical.Model; import jakarta.persistence.*; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; @Entity @Table(name = "PATIENTS") public class Patient { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column(name = "name") @NotBlank(message = "Imię pacjenta jest wymagane") private String name; @Column(name = "surname") @NotBlank(message = "Nazwisko pacjenta jest wymagane") private String surname; @Column(name = "age") @NotNull(message = "Wiek pacjenta jest wymagany") private int age; @Column(name = "description") @NotBlank(message = "Opis zdrowotny pacjenta jest wymagany") private String description; public Patient(String name, String surname, int age, String description) { this.name = name; this.surname = surname; this.age = age; this.description = description; } public Patient() { } public Long getId() { return id; } public void setId(long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getSurname() { return surname; } public void setSurname(String surname) { this.surname = surname; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } @Override public String toString() { return "Patient{" + "id=" + id + name = '" + name + '\'' + surname = '" + surname + '\ '' + age = " + age + description='" + description + '\'' + '}'; } }
控制器类
package medical.Controller; import medical.Model.Patient; import jakarta.validation.Valid; import medical.Service.UserManageService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.validation.BindingResult; import org.springframework.web.bind.annotation.*; import org.springframework.ui.Model; import java.util.List; import java.util.Optional; import medical.exception.RecordNotFoundException; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; @Controller @RequestMapping("/") public class UserManageController { @Autowired UserManageService service; @RequestMapping public String getAllEmployees(Model model) { System.out.println("getAllEmployees"); List<Patient> list = service.getAllPatients(); model.addAttribute("employees", list); return "list-employees"; } @RequestMapping(path = {"/edit", "/edit/{id}"}) public String editPatientById(Model model, @PathVariable("id") Optional<Long> id) throws RecordNotFoundException { System.out.println("editPatientById" + id); if (id.isPresent()) { Patient patient = service.getPatientById(id.get()); model.addAttribute("patient", patient); else{ model.addAttribute("patient", new Patient()); } return "add-edit-patient"; } @RequestMapping(path = "/delete/{id}") public String deleteEmployeeById (Model model, @PathVariable("id") Long id) throws RecordNotFoundException { System.out.println("deleteEmployeeById" + id); service.deletePatientById(id); return "redirect:/"; } @PostMapping("/createOrUpdatePatient") public String createOrUpdatePatient (@Valid Patient patient, BindingResult bindingResult, Model model){ if (bindingResult.hasErrors()) { In case of validation errors,return to the form with errors return "add-edit-patient"; } System.out.println("Create or update patient"); service.createOrUpdatePatient(patient); return "redirect:/list-employees"; } } }
服务层类
package medical.Service; import medical.Model.Patient; import medical.Repository.UserManageRepo; import medical.exception.RecordNotFoundException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.ArrayList; import java.util.List; import java.util.Optional; @Service public class UserManageService { @Autowired UserManageRepo repository; public List<Patient> getAllPatients() { System.out.println("getAllPatients"); List<Patient> result = (List<Patient>) repository.findAll(); if (result.size() > 0) { return result; else{ return new ArrayList<>(); } } public Patient getPatientById (Long id) throws RecordNotFoundException { System.out.println("getPatientById"); Optional<Patient> patient = repository.findById(id); if (patient.isPresent()) { return patient.get(); else{ throw new RecordNotFoundException("No patient record exist for given id"); } } public Patient createOrUpdatePatient (Patient patient){ System.out.println("createOrUpdatePatient"); Create new entry if (patient.getId() == null) { patient = repository.save(patient); return patient; else{ update existing entry Optional<Patient > patientOptional = repository.findById(patient.getId()); if (patientOptional.isPresent()) { Patient existingPatient = patientOptional.get(); existingPatient.setName(patient.getName()); existingPatient.setSurname(patient.getSurname()); existingPatient.setAge(patient.getAge()); existingPatient.setDescription(patient.getDescription()); existingPatient = repository.save(existingPatient); return existingPatient; else{ patient = repository.save(patient); return patient; } } } public void deletePatientById (Long id) throws RecordNotFoundException { System.out.println("deletePatientById"); Optional<Patient> patient = repository.findById(id); if (patient.isPresent()) { repository.deleteById(id); else{ throw new RecordNotFoundException("No patient record exist for given id"); } } } }
Thymeleaf页面
<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="utf-8"> <meta http-equiv="x-ua-compatible" content="ie=edge"> <title>Add Employee</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css"> <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.4.1/css/all.css"> </head> <body> <nav class="navbar navbar-expand-lg navbar-dark bg-dark static-top"> <div class="container"> <a class="navbar-brand" href="/">Springboot H2 DB @OKAYCOMPUTING</a> <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarResponsive" aria-controls="navbarResponsive" aria-expanded="false" aria-label="Toggle navigation"> <span class="navbar-toggler-icon"></span> </button> <div class="collapse navbar-collapse" id="navbarResponsive"> <ul class="navbar-nav ml-auto"> <li class="nav-item active"> <a class="nav-link" href="#">Home <span class="sr-only">(current)</span> </a> </li> <li class="nav-item"> <a class="nav-link" href="#">About</a> </li> <li class="nav-item"> <a class="nav-link" href="#">Services</a> </li> <li class="nav-item"> <a class="nav-link" href="#">Contact</a> </li> </ul> </div> </div> </nav> <div class="container my-5" style="padding-top: 30px;"> <h3> Add Employee</h3> <div class="card"> <div class="card-body"> <div class="col-md-10"> <!--/*@thymesVar id="patient" type="medical.Model.Patient"*/--> <form th:action="@{/createOrUpdatePatient}" th:object="${patient}" method="post"> <div class="row"> <div class="form-group col-md-8"> <label for="name" class="col-form-label">Name</label> <input type="text" th:field="*{name}" class="form-control" id="name" placeholder="name" /> </div> <div class="form-group col-md-8"> <label for="surname" class="col-form-label">Surname</label> <input type="text" th:field="*{surname}" class="form-control" id="surname" placeholder="surname" /> </div> <div class="form-group col-md-8"> <label for="age" class="col-form-label">Age</label> <input type="number" th:field="*{age}" class="form-control" id="age" placeholder="Age" /> </div> <div class="form-group col-md-8"> <label for="description" class="col-form-label">Description</label> <input type="text" th:field="*{description}" class="form-control" id="description" placeholder="Description" /> </div> <div class="col-md-6"> <input type="submit" class="btn btn-primary" value=" Submit "> </div> <input type="hidden" id="id" th:field="*{id}"> </div> </form> </div> </div> </div> </div> </body> </html>
核心问题与修复方案
1. 控制器方法嵌套定义(最关键原因)
deleteEmployeeById和createOrUpdatePatient方法被错误嵌套在editPatientById方法内部,Spring无法扫描到这两个方法的请求映射,导致表单提交时根本不会触发createOrUpdatePatient方法,自然没有日志输出。
修复:将这两个方法移出,作为控制器的独立方法:
@Controller @RequestMapping("/") public class UserManageController { @Autowired UserManageService service; @RequestMapping public String getAllEmployees(Model model) { System.out.println("getAllEmployees"); List<Patient> list = service.getAllPatients(); model.addAttribute("employees", list); return "list-employees"; } @RequestMapping(path = {"/edit", "/edit/{id}"}) public String editPatientById(Model model, @PathVariable("id") Optional<Long> id) throws RecordNotFoundException { System.out.println("editPatientById" + id); if (id.isPresent()) { Patient patient = service.getPatientById(id.get()); model.addAttribute("patient", patient); } else { model.addAttribute("patient", new Patient()); } return "add-edit-patient"; } @RequestMapping(path = "/delete/{id}") public String deleteEmployeeById (Model model, @PathVariable("id") Long id) throws RecordNotFoundException { System.out.println("deleteEmployeeById" + id); service.deletePatientById(id); return "redirect:/"; } @PostMapping("/createOrUpdatePatient") public String createOrUpdatePatient (@Valid Patient patient, BindingResult bindingResult, Model model){ if (bindingResult.hasErrors()) { return "add-edit-patient"; } System.out.println("Create or update patient"); service.createOrUpdatePatient(patient); return "redirect:/"; } }
2. 代码语法错误
- Patient类toString方法:字符串拼接语法错误,会导致编译失败,修正后:
@Override public String toString() { return "Patient{" + "id=" + id + ", name='" + name + '\'' + ", surname='" + surname + '\'' + ", age=" + age + ", description='" + description + '\'' + '}'; } - 服务层createOrUpdatePatient方法:注释与代码混合、语法错误,修正后:
public Patient createOrUpdatePatient(Patient patient) { System.out.println("createOrUpdatePatient"); if (patient.getId() == null) { patient = repository.save(patient); return patient; } else { Optional<Patient> patientOptional = repository.findById(patient.getId()); if (patientOptional.isPresent()) { Patient existingPatient = patientOptional.get(); existingPatient.setName(patient.getName()); existingPatient.setSurname(patient.getSurname()); existingPatient.setAge(patient.getAge()); existingPatient.setDescription(patient.getDescription()); existingPatient = repository.save(existingPatient); return existingPatient; } else { patient = repository.save(patient); return patient; } } } - 控制器验证逻辑:代码混乱导致编译错误,已在控制器修复中修正。
3. 其他细节问题
- 重定向路径错误:
createOrUpdatePatient方法应重定向到/而非/list-employees,因为根路径映射已关联列表页面。 - 确保
UserManageRepo继承JpaRepository<Patient, Long>,否则无法使用Spring Data JPA的持久化方法。 - 检查H2数据库配置,确保
spring.jpa.hibernate.ddl-auto=update,保证实体类能正确生成数据库表。
内容的提问来源于stack exchange,提问作者Adrian M
相关产品推荐
相关产品推荐

