技术选型与架构设计

后端采用Spring Boot框架,简化配置并提供RESTful API支持。数据库使用MySQL 8.0+,支持JSON字段和窗口函数。实时通信采用WebSocket协议,结合STUN/TURN服务器实现P2P语音通话。病历加密使用AES-256算法,密钥由RSA非对称加密保护。

核心功能模块实现

用户认证模块

@PostMapping("/login")
public ResponseEntity<JwtResponse> authenticateUser(@RequestBody LoginRequest request) {
    Authentication authentication = authenticationManager.authenticate(
        new UsernamePasswordAuthenticationToken(request.getUsername(), request.getPassword()));
    SecurityContextHolder.getContext().setAuthentication(authentication);
    String jwt = jwtUtils.generateJwtToken(authentication);
    return ResponseEntity.ok(new JwtResponse(jwt));
}

病历加密存储

public String encryptMedicalRecord(String plainText, PublicKey publicKey) throws Exception {
    // 生成随机的AES密钥
    KeyGenerator keyGen = KeyGenerator.getInstance("AES");
    keyGen.init(256);
    SecretKey aesKey = keyGen.generateKey();
    
    // 用AES加密病历
    Cipher aesCipher = Cipher.getInstance("AES/GCM/NoPadding");
    aesCipher.init(Cipher.ENCRYPT_MODE, aesKey);
    byte[] iv = aesCipher.getIV();
    byte[] encryptedRecord = aesCipher.doFinal(plainText.getBytes(StandardCharsets.UTF_8));
    
    // 用RSA加密AES密钥
    Cipher rsaCipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding");
    rsaCipher.init(Cipher.ENCRYPT_MODE, publicKey);
    byte[] encryptedKey = rsaCipher.doFinal(aesKey.getEncoded());
    
    // 组合成单一数据包
    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
    outputStream.write(iv);
    outputStream.write(encryptedKey);
    outputStream.write(encryptedRecord);
    
    return Base64.getEncoder().encodeToString(outputStream.toByteArray());
}

实时语音通信实现

使用WebRTC技术栈建立点对点连接:

  1. 信令服务器基于Spring WebSocket实现
  2. 客户端使用SimplePeer.js库
  3. NAT穿透使用Coturn服务器

关键信令处理代码:

@MessageMapping("/offer")
public void handleOffer(SignalMessage message) {
    messagingTemplate.convertAndSendToUser(
        message.getTargetUser(),
        "/queue/signal",
        new SignalMessage("offer", message.getSender(), message.getData()));
}

数据库设计

核心表结构

CREATE TABLE users (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    username VARCHAR(50) UNIQUE NOT NULL,
    password_hash VARCHAR(100) NOT NULL,
    role ENUM('PATIENT', 'CONSULTANT', 'ADMIN') NOT NULL,
    is_active BOOLEAN DEFAULT TRUE
);

CREATE TABLE medical_records (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    patient_id BIGINT NOT NULL,
    encrypted_data TEXT NOT NULL,
    iv_and_key TEXT NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY (patient_id) REFERENCES users(id) ON DELETE CASCADE
);

CREATE TABLE consultations (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    patient_id BIGINT NOT NULL,
    consultant_id BIGINT NOT NULL,
    start_time DATETIME NOT NULL,
    end_time DATETIME,
    status ENUM('SCHEDULED', 'ONGOING', 'COMPLETED', 'CANCELLED') NOT NULL,
    FOREIGN KEY (patient_id) REFERENCES users(id),
    FOREIGN KEY (consultant_id) REFERENCES users(id)
);

安全防护措施

  1. 实施OWASP TOP10防护:

    • 使用PreparedStatement防止SQL注入
    • 密码使用BCrypt哈希存储
    • 启用CSRF保护
    • 配置CORS白名单
  2. 病历数据双重加密:

    • 传输层使用TLS 1.3
    • 存储层使用AES-256-GCM
    • 密钥轮换策略每周自动执行

性能优化方案

数据库优化

ALTER TABLE medical_records ADD INDEX idx_patient_created (patient_id, created_at DESC);

缓存策略

@Cacheable(value = "userProfile", key = "#userId")
public UserProfile getUserProfile(Long userId) {
    return userRepository.findProfileById(userId);
}

连接池配置

spring.datasource.hikari.maximum-pool-size=20
spring.datasource.hikari.idle-timeout=30000
spring.datasource.hikari.connection-timeout=2000

部署架构

采用Docker Swarm或Kubernetes编排:

  1. 前端Nginx容器
  2. 后端Spring Boot应用容器
  3. MySQL主从集群
  4. Redis缓存集群
  5. Coturn穿透服务器

部署文件示例:

version: '3.8'
services:
  app:
    image: registry.example.com/counseling-platform:${TAG}
    environment:
      - SPRING_PROFILES_ACTIVE=prod
    deploy:
      replicas: 3
    depends_on:
      - mysql
      - redis

  mysql:
    image: mysql:8.0
    volumes:
      - mysql_data:/var/lib/mysql
    environment:
      - MYSQL_ROOT_PASSWORD=${DB_ROOT_PASS}

测试策略

  1. 单元测试:JUnit5 + Mockito
  2. 集成测试:TestContainers
  3. 压力测试:JMeter模拟100并发通话
  4. 安全测试:OWASP ZAP扫描
  5. E2E测试:Selenium自动化脚本

测试示例代码:

@Test
@DisplayName("病历加密解密完整性测试")
void testMedicalRecordEncryption() throws Exception {
    KeyPair keyPair = generateRSAKeyPair();
    String originalText = "患者主诉:焦虑症状持续2周";
    
    String encrypted = encryptionService.encryptMedicalRecord(originalText, keyPair.getPublic());
    String decrypted = encryptionService.decryptMedicalRecord(encrypted, keyPair.getPrivate());
    
    assertEquals(originalText, decrypted);
}

更多推荐