0

0

Spring Boot中医生-患者关系的高效数据模型与安全实践

聖光之護

聖光之護

发布时间:2025-08-15 14:24:24

|

341人浏览过

|

来源于php中文网

原创

Spring Boot中医生-患者关系的高效数据模型与安全实践

本文探讨了在Spring Boot应用中构建复杂用户关系(如医生与患者)的数据模型和安全集成方案。通过采用共享的用户基类与特定角色实体的混合模式,我们能够清晰地分离通用用户属性与角色特有数据,有效管理多对多关系,并基于用户角色实现灵活的权限控制,同时避免了数据冗余和空值问题,提供了一种健壮且可扩展的解决方案。

在开发医疗管理系统时,如何高效地建模医生与患者之间的复杂关系,并在此基础上集成灵活的用户认证与授权机制,是常见的挑战。传统的解决方案往往面临两个主要困境:一是为医生和患者创建完全独立的实体,这导致在用户登录和权限管理时逻辑复杂;二是将所有属性集中到一个用户实体中,通过角色区分,但这可能导致大量空字段和不必要的业务逻辑分支。本教程将介绍一种更优的数据模型设计,并演示如何与spring security集成,以构建一个既清晰又功能强大的医生-患者关系管理系统。

核心数据模型设计

为了解决上述问题,我们采用一种混合模型:一个通用的User实体来存储所有用户的通用信息(如登录凭据、姓名),以及独立的Doctor和Patient实体来存储各自特有的属性和关系。这种设计通过@OneToOne和@MapsId注解将特定角色实体与User实体关联起来,确保了数据的一致性和模型的灵活性。

1. 用户实体 (User)

User实体作为所有用户的基类,包含通用的认证信息和基本身份属性。

import javax.persistence.*;
import lombok.Getter;
import lombok.Setter;

@Entity
@Table(name = "app_users") // 避免与数据库保留字冲突
@Getter
@Setter
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(unique = true, nullable = false)
    private String username; // 用户名,用于登录

    @Column(nullable = false)
    private String password; // 密码,应加密存储

    private String name;
    private String surname;

    @Enumerated(EnumType.STRING)
    @Column(nullable = false)
    private UserType userType; // 用户类型,如医生、患者
}
// UserType 枚举定义
public enum UserType {
    DOCTOR,
    PATIENT,
    ADMIN // 可根据需求扩展
}

2. 医生实体 (Doctor)

Doctor实体存储医生特有的信息,并通过@MapsId与User实体建立一对一关联。医生与患者之间存在多对多关系。

import javax.persistence.*;
import java.util.HashSet;
import java.util.Set;
import lombok.Getter;
import lombok.Setter;

@Entity
@Getter
@Setter
public class Doctor {
    @Id
    private Long id; // 与User的ID保持一致

    @OneToOne
    @MapsId // 表示Doctor的主键也是其关联User的外键
    @JoinColumn(name = "id") // 外键列名
    private User user;

    @ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
    @JoinTable(
        name = "doctor_patient", // 中间表名
        joinColumns = @JoinColumn(name = "doctor_id"), // 医生在中间表中的列名
        inverseJoinColumns = @JoinColumn(name = "patient_id") // 患者在中间表中的列名
    )
    private Set patients = new HashSet<>();

    // 辅助方法,用于维护双向关系
    public void addPatient(Patient patient) {
        this.patients.add(patient);
        patient.getDoctors().add(this);
    }

    public void removePatient(Patient patient) {
        this.patients.remove(patient);
        patient.getDoctors().remove(this);
    }
}

3. 患者实体 (Patient)

Patient实体存储患者特有的信息,同样通过@MapsId与User实体关联。患者可以拥有多位医生,并记录所服用的药物信息。

import javax.persistence.*;
import java.util.HashSet;
import java.util.Set;
import lombok.Getter;
import lombok.Setter;

@Entity
@Getter
@Setter
public class Patient {
    @Id
    private Long id; // 与User的ID保持一致

    @OneToOne
    @MapsId
    @JoinColumn(name = "id")
    private User user;

    @ManyToMany(mappedBy = "patients", fetch = FetchType.LAZY) // 由Doctor实体中的patients字段映射
    private Set doctors = new HashSet<>();

    @ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
    @JoinTable(
        name = "patient_medicine",
        joinColumns = @JoinColumn(name = "patient_id"),
        inverseJoinColumns = @JoinColumn(name = "medicine_id")
    )
    private Set medicines = new HashSet<>();

    // 辅助方法,用于维护双向关系
    public void addMedicine(Medicine medicine) {
        this.medicines.add(medicine);
        medicine.getPatients().add(this);
    }

    public void removeMedicine(Medicine medicine) {
        this.medicines.remove(medicine);
        medicine.getPatients().remove(this);
    }
}

4. 药物实体 (Medicine)

Medicine实体存储药物的基本信息,与Patient实体存在多对多关系。

NeuralText
NeuralText

Neural Text是一个使用机器学习自动生成文本的平台

下载
import javax.persistence.*;
import java.util.HashSet;
import java.util.Set;
import lombok.Getter;
import lombok.Setter;

@Entity
@Getter
@Setter
public class Medicine {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;

    @ManyToMany(mappedBy = "medicines", fetch = FetchType.LAZY) // 由Patient实体中的medicines字段映射
    private Set patients = new HashSet<>();
}

Spring Security 集成

这种数据模型为Spring Security的集成提供了清晰的路径。User实体将作为Spring Security进行认证的基石,而UserType则用于授权和区分不同角色的业务逻辑。

1. 实现 UserDetailsService

UserDetailsService是Spring Security的核心接口,用于加载用户详情。我们将通过username从User实体中加载用户信息,并根据UserType赋予相应的角色权限。

import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.stereotype.Service;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class CustomUserDetailsService implements UserDetailsService {

    private final UserRepository userRepository; // 假设您有一个UserRepository接口

    public CustomUserDetailsService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User user = userRepository.findByUsername(username)
                .orElseThrow(() -> new UsernameNotFoundException("用户未找到: " + username));

        // 根据UserType构建Spring Security的权限列表
        List authorities = Collections.singletonList(
            new SimpleGrantedAuthority("ROLE_" + user.getUserType().name())
        );

        // 返回Spring Security的User对象
        return new org.springframework.security.core.userdetails.User(
                user.getUsername(),
                user.getPassword(), // 密码应为加密后的形式
                authorities
        );
    }
}

注意: UserRepository需要您自行定义,例如:public interface UserRepository extends JpaRepository { Optional findByUsername(String username); }。同时,在实际应用中,User实体中的password字段应存储加密后的密码,并在注册用户时使用PasswordEncoder进行编码。

2. 授权管理

一旦用户通过认证,其UserType(通过ROLE_UserType形式的权限)就可以用于授权。您可以在控制器或服务层根据当前用户的角色来执行不同的业务逻辑,或者使用Spring Security的注解进行方法级别的权限控制。

import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import java.util.Optional;

@Service
public class HealthCareService {

    private final UserRepository userRepository;
    private final DoctorRepository doctorRepository; // 假设有DoctorRepository
    private final PatientRepository patientRepository; // 假设有PatientRepository

    public HealthCareService(UserRepository userRepository, DoctorRepository doctorRepository, PatientRepository patientRepository) {
        this.userRepository = userRepository;
        this.doctorRepository = doctorRepository;
        this.patientRepository = patientRepository;
    }

    // 医生特有操作:查看其所有患者
    @PreAuthorize

相关专题

更多
spring框架介绍
spring框架介绍

本专题整合了spring框架相关内容,想了解更多详细内容,请阅读专题下面的文章。

102

2025.08.06

spring boot框架优点
spring boot框架优点

spring boot框架的优点有简化配置、快速开发、内嵌服务器、微服务支持、自动化测试和生态系统支持。本专题为大家提供spring boot相关的文章、下载、课程内容,供大家免费下载体验。

135

2023.09.05

spring框架有哪些
spring框架有哪些

spring框架有Spring Core、Spring MVC、Spring Data、Spring Security、Spring AOP和Spring Boot。详细介绍:1、Spring Core,通过将对象的创建和依赖关系的管理交给容器来实现,从而降低了组件之间的耦合度;2、Spring MVC,提供基于模型-视图-控制器的架构,用于开发灵活和可扩展的Web应用程序等。

389

2023.10.12

Java Spring Boot开发
Java Spring Boot开发

本专题围绕 Java 主流开发框架 Spring Boot 展开,系统讲解依赖注入、配置管理、数据访问、RESTful API、微服务架构与安全认证等核心知识,并通过电商平台、博客系统与企业管理系统等项目实战,帮助学员掌握使用 Spring Boot 快速开发高效、稳定的企业级应用。

68

2025.08.19

Java Spring Boot 4更新教程_Java Spring Boot 4有哪些新特性
Java Spring Boot 4更新教程_Java Spring Boot 4有哪些新特性

Spring Boot 是一个基于 Spring 框架的 Java 开发框架,它通过 约定优于配置的原则,大幅简化了 Spring 应用的初始搭建、配置和开发过程,让开发者可以快速构建独立的、生产级别的 Spring 应用,无需繁琐的样板配置,通常集成嵌入式服务器(如 Tomcat),提供“开箱即用”的体验,是构建微服务和 Web 应用的流行工具。

32

2025.12.22

Java Spring Boot 微服务实战
Java Spring Boot 微服务实战

本专题深入讲解 Java Spring Boot 在微服务架构中的应用,内容涵盖服务注册与发现、REST API开发、配置中心、负载均衡、熔断与限流、日志与监控。通过实际项目案例(如电商订单系统),帮助开发者掌握 从单体应用迁移到高可用微服务系统的完整流程与实战能力。

114

2025.12.24

string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

315

2023.08.02

硬盘接口类型介绍
硬盘接口类型介绍

硬盘接口类型有IDE、SATA、SCSI、Fibre Channel、USB、eSATA、mSATA、PCIe等等。详细介绍:1、IDE接口是一种并行接口,主要用于连接硬盘和光驱等设备,它主要有两种类型:ATA和ATAPI,IDE接口已经逐渐被SATA接口;2、SATA接口是一种串行接口,相较于IDE接口,它具有更高的传输速度、更低的功耗和更小的体积;3、SCSI接口等等。

1018

2023.10.19

Java 桌面应用开发(JavaFX 实战)
Java 桌面应用开发(JavaFX 实战)

本专题系统讲解 Java 在桌面应用开发领域的实战应用,重点围绕 JavaFX 框架,涵盖界面布局、控件使用、事件处理、FXML、样式美化(CSS)、多线程与UI响应优化,以及桌面应用的打包与发布。通过完整示例项目,帮助学习者掌握 使用 Java 构建现代化、跨平台桌面应用程序的核心能力。

61

2026.01.14

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
SQL 教程
SQL 教程

共61课时 | 3.4万人学习

10分钟--Midjourney创作自己的漫画
10分钟--Midjourney创作自己的漫画

共1课时 | 0.1万人学习

Midjourney 关键词系列整合
Midjourney 关键词系列整合

共13课时 | 0.9万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号