Files
workspace/code/g3soft-erp/server/README.md
T
oneao ae3ca3cfa1 feat(server): 后端从原型 fms-api 迁入并重整包结构
迁移:包名 cn.g3soft.fmsapi → cn.g3soft.erp;artifactId/name fms-api → erp-api;启动类 FmsApiApplication → ErpApiApplication;配置前缀 fms.* → erp.*;FMS_JWT_SECRET → ERP_JWT_SECRET;未带入流程引擎(service/workflow、WorkflowController*)、数据库迁移脚本(config/migrations、tools/migration)与 data/files;一并迁入 Maven Wrapper、config/dbconfigs、config/legacy-tls.security、start.cmd。

重构:拆解 utils.DbUtils(1470 行)为 common.util.SqlText + database.{MetadataReader,RowReader,RowWriter} + database.model(5 个 record);认证专用账号查询移出访问层到 service.auth.UserAccountReader;新建 common/(ApiResponse + exception 6 + util 5 + util/snowflake 9);database/ 分 org/(多机构连接)与 model/(纯数据载体);JwtUtils 与客户端信息采集簇归入 service.auth。

清理:删除迁移带入的空目录、HELP.md,及 pom 中 Initializr 留下的空 url/licenses/developers/scm;修正 OrgDataSourceFactoryTests 的陈旧断言(停留在 2026-07 的旧策略,实现已于 2026-08 反转为继续重试、不停建连线程、不 failFast)。

验证:mvn test 80/80 通过;另有 2 个 @SpringBootTest 需真实 SQL Server。本次仅提交 server/;根 .gitignore、根 .gitattributes 与 docs/ 的同步改动不在本次范围内。
2026-10-12 20:04:52 +08:00

103 lines
5.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# server —— 后端
后端服务(Maven + Spring Boot)。现有代码是从原型 `fms-api` 迁入的元数据驱动引擎实现:
包名 `cn.g3soft.erp`,artifactId `erp-api`,启动类 `ErpApiApplication`。
构建 `mvnw.cmd test`;启动 `start.cmd`(`spring-boot:run`,默认 8088、context-path `/api`)。
> 迁入时**未带入**三项:流程引擎(`service/workflow`、`WorkflowController`、
> `WorkflowRuntimeController`)、数据库迁移脚本(`config/migrations`、`tools/migration`)、
> 本地文件存储数据(`data/files`)。
## 已定的技术栈
| 项 | 选型 |
|---|---|
| 框架 | Spring Boot 4.1.0 |
| 语言 | Java 21 |
| Web | spring-boot-starter-webmvc |
| 持久层 | spring-boot-starter-jdbc(**无 ORM**) |
| 连接池 | Druid 1.2.18 |
| 数据库 | **SQL Server**(mssql-jdbc) |
| 鉴权 | JJWT 0.12.6 |
| Excel | Apache Fesod 2.0.2-incubating |
| 其他 | ip2region、ua-parser |
| 构建 | Maven |
## IP 归属地
登录日志里的 IP 归属地走**本地 `ip2region` 库**,不联网。实测:加载 5~7ms,单次查询 1~4 微秒,
所以它不构成启动瓶颈(应用自身启动约 1.2~1.7s)。
> **部署须知**:`ip2region.xdb`(约 11MB)被 `.gitignore` 排除,不在仓库里,部署时必须手工放到
> `src/main/resources/`。漏放**不会导致启动失败**,只会让所有归属地静默变成「未知」。
内网 / 保留地址(RFC1918、回环、链路本地、IPv6 ULA)直接记「内网」,不外呼。
## 数据访问层(`cn.g3soft.erp.database`)
`database` 下分两块,**两者零互相引用**(一边管"连接怎么来",一边管"拿到连接后怎么读写"):
| 包 / 类 | 职责 |
|---|---|
| `database/`(根) | 通用数据访问,方法都走 JDBC、无 ORM |
| `database.MetadataReader` | 表结构内省:`loadTableMetadata` / `getColumn` / `describeColumns`;列名归一化也在这里 |
| `database.RowReader` | 只读查询与分页:`loadData` / `loadDataBySql` / `page`;唯一持有默认数据源 |
| `database.RowWriter` | 通用写入与条件更新语义:`insert` / `update` / `delete`、`$original` / `$expr` / guard、零行原因定位 |
| `database.model` | 纯数据载体,无任何逻辑:`TableMetadata` / `ColumnMetadata` / `PageResult` / `GuardCondition` / `ZeroRowCause` |
| `database.org` | 多机构数据库连接:`OrgContext`(请求级机构/用户上下文)、`OrgDatabaseProperties` / `OrgDatabaseConfig*`(配置与热加载)、`OrgDataSourceFactory` / `OrgDataSourceManager` / `OrgRoutingDataSource`(装配与路由) |
| `common.util.SqlText` | SQL 文本与安全校验:标识符校验与加引号、只读 SQL 校验、排序子句构建;纯静态 |
三条约定:
1. `SqlText` 不依赖任何人,所以依赖方向固定为 `service → database → common`,不成环。
2. `RowReader` 之外的方法都接收调用方传入的 `Connection`(不自己开事务),事务边界留在服务层。
3. 认证要按 `orgId` 取该机构连接(登录时机构上下文尚未建立),所以那条查询在
`service.auth.UserAccountReader` 里,**不在**访问层。
## 分割现状与规划
**现状**(迁入的原型代码,已按职责归过一轮):
```
cn.g3soft.erp
├── common/ # 通用返回、异常、纯静态工具
│ ├── ApiResponse.java # HTTP 响应外壳 + 全部错误码常量
│ ├── exception/ # 6 个异常与 GlobalExceptionHandler
│ └── util/ # ParamUtils / SqlText / StringUtils / TimeUtils /
│ # UuidV7Generator + snowflake/(内嵌的雪花 ID 生成器)
├── config/ # AuthProperties / FileStorageProperties / JacksonConfig / JwtAuthFilter
├── controller/ # 6 个 Controller
├── database/ # 数据访问层(见上):RowReader / RowWriter / MetadataReader + model/ + org/
└── service/
├── auth/ # 登录、会话、登录日志、JwtUtils,以及 client/(客户端信息采集)
├── data/ # 通用保存 / 删除 / 查询编排
├── export/ file/ formula/ permission/
```
**规划**(新代码按此落位,老代码后续按域重构):
```
cn.g3soft.erp
├── common/ # 通用返回、异常、工具 —— 已建
├── engine/ # 元数据驱动引擎(查询 / 保存 / 权限)—— 未设计;
│ # 现在的 database + service/{data,formula,permission} 是它的雏形
└── module/
├── ocean/ # 海运
├── air/ # 空运
├── container/ # 箱管
├── finance/ # 财务
├── crm/ # CRM
└── system/ # 系统管理
```
## 与前端的关系
**唯一契约是 HTTP 接口。** 前端不读后端源码,后端不管前端怎么调。
同仓的三条纪律(见根 `README.md`):
1. **独立构建** —— `mvn package` 不触发前端构建,反之亦然
2. **独立版本** —— tag 分开打(`api-v1.2.0` / `web-v1.2.0`)
3. **接口契约写进 `docs/`** 并版本化