- 新增 MD/specs/IRON_RULES.md — 执行铁律汇总(v2.0, 8条铁律) - 新增 MD/specs/BACKEND_DEVELOPMENT_STANDARD.md — 后端开发规范 - 新增 MD/specs/FRONTEND_DEVELOPMENT_STANDARD.md — 前端开发规范 - 新增 healthlink-his-ui/AGENTS.md — 前端铁律引用 - 更新 healthlink-his-server/AGENTS.md — 同步规范文档引用 - 修复10个文档缺失的元数据(文档类型标签) - 全部30个文档通过命名规范和元数据检查
368 lines
10 KiB
Markdown
368 lines
10 KiB
Markdown
# HealthLink-HIS 后端开发规范
|
||
|
||
> **文档类型**: 技术规范
|
||
> **适用范围**: 后端 Java 开发
|
||
> **版本**: v1.0
|
||
> **编制日期**: 2026-06-06
|
||
> **最后更新**: 2026-06-06
|
||
|
||
---
|
||
|
||
## 一、技术栈
|
||
|
||
| 组件 | 版本 | 说明 |
|
||
|------|------|------|
|
||
| JDK | 25 | OpenJDK 25 (LTS) |
|
||
| Spring Boot | 4.0.6 | 框架核心 |
|
||
| MyBatis-Plus | 3.5.16 | ORM框架 |
|
||
| PostgreSQL | 15+ | 主数据库 |
|
||
| Redis | 7.x | 缓存/会话 |
|
||
| Maven | 3.9+ | 构建工具 |
|
||
|
||
---
|
||
|
||
## 二、项目结构
|
||
|
||
```
|
||
healthlink-his-server/
|
||
├── healthlink-his-common/ # 公共模块(枚举、常量、工具类)
|
||
├── healthlink-his-domain/ # 领域层(实体、Mapper、Flyway迁移)
|
||
├── healthlink-his-application/ # 应用层(Controller、Service、业务逻辑)
|
||
├── core-common/ # 若依公共核心
|
||
├── core-system/ # 若依系统模块
|
||
├── core-framework/ # 若依框架核心
|
||
├── core-quartz/ # 定时任务
|
||
├── core-generator/ # 代码生成
|
||
├── core-flowable/ # 工作流
|
||
└── core-admin/ # 管理后台
|
||
```
|
||
|
||
---
|
||
|
||
## 三、分层架构规范
|
||
|
||
### 3.1 Controller 层
|
||
- 路径:`com.healthlink.his.web.{module}.controller`
|
||
- 职责:接收请求、参数校验、调用AppService、返回统一结果
|
||
- 禁止:直接操作数据库、编写业务逻辑
|
||
|
||
```java
|
||
@RestController
|
||
@RequestMapping("/api/v1/registration")
|
||
@Api(tags = "挂号管理")
|
||
public class RegistrationController {
|
||
|
||
@Autowired
|
||
private IRegistrationAppService registrationAppService;
|
||
|
||
@GetMapping("/list")
|
||
@PreAuthorize("@ss.hasPermi('registration:list')")
|
||
public TableDataInfo list(RegistrationQueryDto query) {
|
||
startPage();
|
||
List<RegistrationDto> list = registrationAppService.selectList(query);
|
||
return getDataTable(list);
|
||
}
|
||
}
|
||
```
|
||
|
||
### 3.2 AppService 层(应用服务)
|
||
- 路径:`com.healthlink.his.web.{module}.appservice`
|
||
- 职责:编排业务流程、协调多个Service、事务管理
|
||
- 命名:`XxxAppService`(接口)+ `XxxAppServiceImpl`(实现)
|
||
|
||
### 3.3 Service 层
|
||
- 路径:`com.healthlink.his.web.{module}.service`
|
||
- 职责:单表CRUD、基础业务逻辑
|
||
- 命名:`IXxxService`(接口)+ `XxxServiceImpl`(实现)
|
||
|
||
### 3.4 Mapper 层
|
||
- 路径:`com.healthlink.his.web.{module}.mapper`
|
||
- 职责:数据访问、SQL映射
|
||
- 命名:`XxxMapper`(接口)+ `XxxMapper.xml`(XML映射)
|
||
|
||
### 3.5 Entity/Domain 层
|
||
- 路径:`com.healthlink.his.domain.{module}`
|
||
- 职责:实体定义、数据库表映射
|
||
- 命名:`Xxx`(实体类)
|
||
|
||
### 3.6 DTO 层
|
||
- 路径:`com.healthlink.his.web.{module}.dto`
|
||
- 职责:数据传输对象、查询参数、返回结果
|
||
|
||
---
|
||
|
||
## 四、命名规范
|
||
|
||
### 4.1 包命名
|
||
```
|
||
com.healthlink.his.web.{模块名}.{层级}
|
||
```
|
||
|
||
### 4.2 类命名
|
||
| 类型 | 命名规则 | 示例 |
|
||
|------|---------|------|
|
||
| Controller | `XxxController` | `RegistrationController` |
|
||
| AppService接口 | `IXxxAppService` | `IRegistrationAppService` |
|
||
| AppService实现 | `XxxAppServiceImpl` | `RegistrationAppServiceImpl` |
|
||
| Service接口 | `IXxxService` | `IRegistrationService` |
|
||
| Service实现 | `XxxServiceImpl` | `RegistrationServiceImpl` |
|
||
| Mapper | `XxxMapper` | `RegistrationMapper` |
|
||
| Entity | `Xxx` | `Registration` |
|
||
| DTO | `XxxDto` / `XxxQueryDto` | `RegistrationDto` |
|
||
| Enum | `XxxEnum` / `XxxType` | `ItemType` |
|
||
|
||
### 4.3 方法命名
|
||
| 场景 | 命名规则 | 示例 |
|
||
|------|---------|------|
|
||
| 查询列表 | `selectList` / `queryList` | `selectList(query)` |
|
||
| 查询详情 | `selectById` / `getById` | `selectById(id)` |
|
||
| 新增 | `insert` / `save` / `add` | `insert(dto)` |
|
||
| 修改 | `update` / `modify` | `update(dto)` |
|
||
| 删除 | `delete` / `remove` | `deleteById(id)` |
|
||
| 批量操作 | `batchXxx` | `batchInsert(list)` |
|
||
|
||
### 4.4 数据库命名
|
||
| 类型 | 命名规则 | 示例 |
|
||
|------|---------|------|
|
||
| 表名 | `{模块}_{功能}` 小写下划线 | `reg_registration` |
|
||
| 字段名 | 小写下划线 | `patient_id`, `create_time` |
|
||
| 主键 | `id` 或 `{表名}_id` | `registration_id` |
|
||
| 外键 | `{关联表}_id` | `patient_id` |
|
||
| 时间字段 | `create_time`, `update_time` | — |
|
||
| 软删除 | `del_flag` | — |
|
||
| 租户 | `tenant_id` | — |
|
||
|
||
---
|
||
|
||
## 五、编码规范
|
||
|
||
### 5.1 Controller 规范
|
||
```java
|
||
// ✅ 正确
|
||
@RestController
|
||
@RequestMapping("/api/v1/patient")
|
||
@Api(tags = "患者管理")
|
||
@Slf4j
|
||
public class PatientController {
|
||
|
||
@Autowired
|
||
private IPatientAppService patientAppService;
|
||
|
||
@GetMapping("/{id}")
|
||
@PreAuthorize("@ss.hasPermi('patient:query')")
|
||
public AjaxResult getInfo(@PathVariable Long id) {
|
||
return success(patientAppService.selectById(id));
|
||
}
|
||
|
||
@PostMapping
|
||
@PreAuthorize("@ss.hasPermi('patient:add')")
|
||
public AjaxResult add(@Validated @RequestBody PatientDto dto) {
|
||
return toAjax(patientAppService.insert(dto));
|
||
}
|
||
}
|
||
|
||
// ❌ 错误 - Controller里写业务逻辑
|
||
public AjaxResult add(@RequestBody PatientDto dto) {
|
||
// 不应该在这里写验证逻辑
|
||
if (dto.getName() == null) {
|
||
return error("名称不能为空");
|
||
}
|
||
// 不应该在这里写数据库操作
|
||
patientMapper.insert(patient);
|
||
return success();
|
||
}
|
||
```
|
||
|
||
### 5.2 Service 规范
|
||
```java
|
||
// ✅ 正确 - 事务注解
|
||
@Transactional(rollbackFor = Exception.class)
|
||
public int insert(PatientDto dto) {
|
||
Patient patient = BeanUtils.copyProperties(dto, Patient.class);
|
||
patient.setCreateTime(new Date());
|
||
patient.setCreateBy(SecurityUtils.getUsername());
|
||
return patientMapper.insert(patient);
|
||
}
|
||
|
||
// ❌ 错误 - 自调用导致事务失效
|
||
public void batchProcess(List<PatientDto> list) {
|
||
for (PatientDto dto : list) {
|
||
this.insert(dto); // 自调用,事务不生效!
|
||
}
|
||
}
|
||
```
|
||
|
||
### 5.3 Mapper 规范
|
||
```java
|
||
// ✅ 正确 - 使用LambdaQueryWrapper
|
||
public List<Patient> selectList(PatientQueryDto query) {
|
||
LambdaQueryWrapper<Patient> wrapper = new LambdaQueryWrapper<>();
|
||
wrapper.like(StringUtils.isNotBlank(query.getName()), Patient::getName, query.getName())
|
||
.eq(Patient::getDelFlag, "0")
|
||
.orderByDesc(Patient::getCreateTime);
|
||
return patientMapper.selectList(wrapper);
|
||
}
|
||
|
||
// ❌ 错误 - 字符串拼接SQL
|
||
public List<Patient> selectList(String name) {
|
||
String sql = "SELECT * FROM patient WHERE name = '" + name + "'";
|
||
return jdbcTemplate.queryForList(sql, Patient.class);
|
||
}
|
||
```
|
||
|
||
### 5.4 统一返回格式
|
||
```java
|
||
// 成功
|
||
return AjaxResult.success(data);
|
||
return AjaxResult.success("操作成功", data);
|
||
|
||
// 失败
|
||
return AjaxResult.error("患者不存在");
|
||
return AjaxResult.error(MessageUtils.message("patient.not.found"));
|
||
|
||
// 列表
|
||
TableDataInfo dataPage = getDataTable(list);
|
||
```
|
||
|
||
---
|
||
|
||
## 六、异常处理规范
|
||
|
||
### 6.1 业务异常
|
||
```java
|
||
throw new ServiceException("患者编号不能为空");
|
||
throw new ServiceException(MessageUtils.message("patient.id.required"));
|
||
```
|
||
|
||
### 6.2 全局异常处理
|
||
- 使用 `@RestControllerAdvice` + `@ExceptionHandler`
|
||
- 不在 Controller 中 try-catch 后返回错误
|
||
- 所有异常最终返回统一格式 `{code, msg, data}`
|
||
|
||
### 6.3 日志规范
|
||
```java
|
||
// ✅ 正确
|
||
log.info("患者挂号成功: patientId={}, registrationId={}", patientId, regId);
|
||
log.error("挂号失败: patientId={}", patientId, e);
|
||
|
||
// ❌ 错误
|
||
log.info("患者身份证号: " + idCard); // 敏感信息泄露
|
||
System.out.println("debug"); // 不使用System.out
|
||
```
|
||
|
||
---
|
||
|
||
## 七、安全规范
|
||
|
||
### 7.1 数据脱敏
|
||
- 患者身份证号:`***` 掩码
|
||
- 患者手机号:前3后4,中间 `****`
|
||
- 密码:BCrypt 加密,不可逆
|
||
|
||
### 7.2 SQL注入防护
|
||
- 所有查询使用参数化查询
|
||
- 禁止字符串拼接 SQL
|
||
- 使用 MyBatis-Plus 的 `QueryWrapper` / `LambdaQueryWrapper`
|
||
|
||
### 7.3 权限控制
|
||
- 所有接口标注 `@PreAuthorize`
|
||
- 数据级权限校验(医生只能访问本科室患者)
|
||
- 敏感操作需二次确认
|
||
|
||
---
|
||
|
||
## 八、测试规范
|
||
|
||
### 8.1 测试类型
|
||
| 类型 | 工具 | 覆盖范围 |
|
||
|------|------|---------|
|
||
| 单元测试 | JUnit 5 + Mockito | Service/工具类 |
|
||
| 接口测试 | MockMvc + SpringBootTest | Controller接口 |
|
||
| 白盒测试 | Maven编译 | 全量代码 |
|
||
| 黑盒测试 | 手动/自动化 | 核心业务流程 |
|
||
|
||
### 8.2 接口测试规范
|
||
```java
|
||
@SpringBootTest
|
||
@AutoConfigureMockMvc
|
||
public class PatientApiTest {
|
||
|
||
@Test
|
||
public void testGetPatientInfo() throws Exception {
|
||
mockMvc.perform(get("/healthlink-his/api/v1/patient/{id}", 1L)
|
||
.header("Authorization", "Bearer " + token))
|
||
.andExpect(status().isOk())
|
||
.andExpect(jsonPath("$.code").value(200))
|
||
.andExpect(jsonPath("$.data").isNotEmpty())
|
||
.andExpect(jsonPath("$.data.name").isNotEmpty());
|
||
}
|
||
}
|
||
```
|
||
|
||
### 8.3 测试数据要求
|
||
- 测试数据必须基于业务逻辑设计
|
||
- 验证业务返回内容(非仅HTTP状态码)
|
||
- 覆盖正常流程和异常流程
|
||
- 包含边界条件测试
|
||
|
||
---
|
||
|
||
## 九、性能规范
|
||
|
||
### 9.1 数据库查询
|
||
- 无N+1查询问题(使用 `JOIN` 或批量查询)
|
||
- 大表查询必须有分页限制
|
||
- 慢查询已优化(执行时间 < 500ms)
|
||
- 索引已覆盖高频查询条件
|
||
|
||
### 9.2 接口性能
|
||
- 核心接口响应时间 < 1秒
|
||
- 列表接口支持分页,无全量返回
|
||
- 大文件下载使用流式传输
|
||
|
||
### 9.3 缓存使用
|
||
- 频繁查询的字典数据使用Redis缓存
|
||
- 缓存必须设置过期时间
|
||
- 数据变更时主动清除相关缓存
|
||
|
||
---
|
||
|
||
## 十、Git提交规范
|
||
|
||
### Commit Message 格式
|
||
```
|
||
<type>(<scope>): <subject>
|
||
|
||
<body>
|
||
|
||
<footer>
|
||
```
|
||
|
||
### Type 类型
|
||
| Type | 说明 |
|
||
|------|------|
|
||
| feat | 新功能 |
|
||
| fix | Bug修复 |
|
||
| docs | 文档变更 |
|
||
| style | 代码格式(不影响功能) |
|
||
| refactor | 重构 |
|
||
| test | 测试相关 |
|
||
| chore | 构建/工具变更 |
|
||
|
||
### 示例
|
||
```
|
||
feat(registration): 新增患者过敏史管理功能
|
||
|
||
- 新增 PatientAllergy 实体和 Mapper
|
||
- 新增 IRegistrationAppService.getPatientAllergy()
|
||
- 新增 /api/v1/registration/allergy 接口
|
||
- Flyway迁移脚本: V2.0.1__add_patient_allergy.sql
|
||
|
||
Co-authored-by: zhangsan <zhangsan@healthlink.com>
|
||
```
|
||
|
||
---
|
||
|
||
> **文档版本**: v1.0
|
||
> **最后更新**: 2026-06-06
|