You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 23:09:51