Java+MySQL开发在线心理咨询平台(语音通话+病历加密存储)
·
技术选型与架构设计
后端采用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技术栈建立点对点连接:
- 信令服务器基于Spring WebSocket实现
- 客户端使用SimplePeer.js库
- 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)
);
安全防护措施
-
实施OWASP TOP10防护:
- 使用PreparedStatement防止SQL注入
- 密码使用BCrypt哈希存储
- 启用CSRF保护
- 配置CORS白名单
-
病历数据双重加密:
- 传输层使用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编排:
- 前端Nginx容器
- 后端Spring Boot应用容器
- MySQL主从集群
- Redis缓存集群
- 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}
测试策略
- 单元测试:JUnit5 + Mockito
- 集成测试:TestContainers
- 压力测试:JMeter模拟100并发通话
- 安全测试:OWASP ZAP扫描
- 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);
}
更多推荐
所有评论(0)