Demo
esign-helper-demo 是一个“调用方示例工程”,它的意义不是承载核心逻辑,而是演示:
- 一个普通业务系统如何引入
esign-helper-starter - 如何通过 Web 接口调用 starter
- 如何复用 starter 默认表和默认归档能力
- 如何在本地快速验证流程创建、查询和回调链路
- 如何把真实生产里常见的盖章/签署动作组织成可落地的请求
1. 模块定位
这个模块主要服务三类人:
- 第一次接入 starter 的开发者
- 想快速跑通联调链路的同学
- 想理解“业务系统应该怎么接 starter”的维护者
它不是:
- 生产级业务系统模板
- 核心能力承载模块
- 未来要持续堆复杂业务逻辑的地方
2. 一个最重要的原则
demo 当前遵循一个非常明确的原则:
尽量薄,但示例要尽量贴近生产
也就是说:
- 核心逻辑在 starter
- demo 只保留示例调用层
- 不在 demo 里再复制一套领域层、编排层、持久化逻辑
- 场景差异主要通过
requestPayload透传表达
这里的 requestPayload 很关键:
- demo 的
/api/esign/flows/file和/api/esign/flows/template最终会把requestPayload里的扩展字段透传到 e签宝请求体 - 因此它很适合承载生产里高频出现但暂时还没有完全建模的字段
- 比如签署方、签署顺序、通知策略、经办人信息、盖章区、关键字定位结果、抄送人、业务附加字段等
这也是 demo 能覆盖“尽可能多生产常见盖章场景”的关键原因。
补充说明:
- 下文示例里的
requestPayload字段名,主要用于表达常见生产编排方式 - 真正联调时,请按你们租户所使用的 e签宝官方接口字段要求校准
3. 模块结构
esign-helper-demo
├─ README.md
├─ pom.xml
└─ src它本质上是一个普通 Spring Boot 应用,只不过依赖了:
esign-helper-starterspring-boot-starter-webspring-boot-starter-validation
4. 当前 demo 暴露的接口
4.1 发起文件流程
POST /api/esign/flows/file适合:
- 已经有
fileId的合同发起签署 - 采购合同、销售合同、补充协议、对账单、确认函等文件类签署
- 企业公章、法人章、经办人签字等组合签署场景
4.2 发起模板流程
POST /api/esign/flows/template适合:
- 劳动合同
- 入职文件包
- 标准加盟协议
- 经常复用固定模板的签署场景
4.3 查询流程
GET /api/esign/flows/{signFlowId}
GET /api/esign/flows?businessId=...&tenantCode=...&systemCode=...适合:
- 业务单据回查
- 流程追踪
- 多租户隔离查询
4.4 回调入口
POST /esign/callback/sign-notify适合:
- 签署完成更新流程状态
- 节点签署更新任务状态
- 用回调补档签署人信息
5. demo 当前重点覆盖的生产常见盖章场景
| 场景 | 推荐入口 | 典型业务 |
|---|---|---|
| 劳动合同/入职协议标准模板签署 | /api/esign/flows/template | HR、共享服务中心 |
| 采购合同/销售合同/框架协议文件签署 | /api/esign/flows/file | ERP、CRM、SRM |
| 平台统一代发起签署流程 | /api/esign/flows/file | 中台、多租户 SaaS |
| 企业公章 + 经办人签字 | /api/esign/flows/file | B2B 合同、付款协议 |
| 法人章、财务章、合同专用章等多印章编排 | /api/esign/flows/file | 财务、法务、供应链 |
| 关键字盖章、指定页盖章、骑缝章 | starter 直调 contractFile() | 法务定稿、复杂版式合同 |
| 已发起流程补章/补签/追加签署区 | starter 直调 appendSignFields() | 补签、加签、漏章修正 |
| 解约、撤销、终止协议 | starter 直调 createRescissionUrl() | 人事离职、业务终止 |
| 已签完成后申请出证报告 | starter 直调 contractManagement() | 审计、法务、归档 |
| 企业印章、成员、模板的准备与查询 | starter 直调 seal() / member() / enterpriseConsole() | 平台初始化、组织治理 |
6. 场景举例 + 代码
6.1 入职劳动合同模板签署
这是最典型的模板流程场景:
- 模板固定
- 签署方固定
- 只替换员工、公司、入职日期、薪资等业务参数
Demo 请求示例:
POST /api/esign/flows/template
Content-Type: application/json
{
"tenantCode": "TENANT_HR",
"systemCode": "HR",
"businessId": "EMP-OFFER-20260420-001",
"businessType": "EMPLOYMENT_CONTRACT",
"contractName": "张三-劳动合同",
"signTemplateId": "TPL_EMPLOYMENT_2026",
"companyId": "COMPANY-001",
"companyName": "示例科技有限公司",
"initiator": "hr-admin",
"requestPayload": {
"autoStart": true,
"signers": [
{
"signerType": "PERSON",
"thirdPartyUserId": "EMP-10001",
"psnAccount": "13800138000"
},
{
"signerType": "ORGANIZATION",
"orgId": "ORG-HQ-001",
"sealId": "SEAL-COMPANY-001"
}
],
"notifyUrl": "https://hr.example.com/esign/callback/sign-notify"
}
}Starter 内直接调用示例:
Map<String, Object> payload = new LinkedHashMap<String, Object>();
payload.put("autoStart", true);
payload.put("signers", Arrays.asList(
new LinkedHashMap<String, Object>() {{
put("signerType", "PERSON");
put("thirdPartyUserId", "EMP-10001");
put("psnAccount", "13800138000");
}},
new LinkedHashMap<String, Object>() {{
put("signerType", "ORGANIZATION");
put("orgId", "ORG-HQ-001");
put("sealId", "SEAL-COMPANY-001");
}}
));
CreateEsignFlowCommand command = new CreateEsignFlowCommand()
.setTenantCode("TENANT_HR")
.setSystemCode("HR")
.setBusinessId("EMP-OFFER-20260420-001")
.setBusinessType("EMPLOYMENT_CONTRACT")
.setContractName("张三-劳动合同")
.setSignTemplateId("TPL_EMPLOYMENT_2026")
.setCompanyId("COMPANY-001")
.setCompanyName("示例科技有限公司")
.setInitiator("hr-admin")
.setRequestPayload(payload);
EsignFlowRecord record = integrationService.createTemplateFlow(command);6.2 采购合同/销售合同文件发起签署
这是最典型的文件流程场景:
- 合同 PDF 已由业务系统生成
- 系统已经拿到了
fileId - 需要按业务单据号发起签署并做本地归档
Demo 请求示例:
POST /api/esign/flows/file
Content-Type: application/json
{
"tenantCode": "TENANT_SRM",
"systemCode": "SRM",
"businessId": "PO-20260420-9527",
"businessType": "PURCHASE_CONTRACT",
"esignPactNo": "PACT-PO-9527",
"contractName": "采购框架协议-供应商A",
"contractCode": "PO-CONTRACT-9527",
"initiator": "buyer-001",
"companyId": "ORG-BUYER-001",
"companyName": "采购中心",
"fileId": "FILE-PO-9527",
"requestPayload": {
"autoStart": true,
"deadline": "2026-04-30 23:59:59",
"signers": [
{
"signerType": "ORGANIZATION",
"orgId": "ORG-BUYER-001",
"sealId": "SEAL-CONTRACT-001"
},
{
"signerType": "ORGANIZATION",
"orgId": "ORG-SUPPLIER-009",
"sealId": "SEAL-SUPPLIER-009"
}
]
}
}Starter 门面直接调用示例:
ContractFileModels.CreateByFileRequest request = new ContractFileModels.CreateByFileRequest()
.setFlowName("采购框架协议-供应商A")
.setDocs(Collections.singletonList(
new ContractFileModels.DocumentInfo().setFileId("FILE-PO-9527")
))
.putExtraField("autoStart", true)
.putExtraField("deadline", "2026-04-30 23:59:59")
.putExtraField("signers", Arrays.asList(
new LinkedHashMap<String, Object>() {{
put("signerType", "ORGANIZATION");
put("orgId", "ORG-BUYER-001");
put("sealId", "SEAL-CONTRACT-001");
}},
new LinkedHashMap<String, Object>() {{
put("signerType", "ORGANIZATION");
put("orgId", "ORG-SUPPLIER-009");
put("sealId", "SEAL-SUPPLIER-009");
}}
));
EsignResponse<ContractFileModels.SignFlowCreateData> response =
esignApiFacade.contractFile().createByFile(request);6.3 平台统一代发起,多租户隔离回查
这个场景在线上非常常见:
- 一个共享平台给多个租户、多套业务系统代发起签署
- 业务侧经常按
tenantCode + systemCode + businessId回查
发起示例:
POST /api/esign/flows/file
Content-Type: application/json
{
"tenantCode": "TENANT_B",
"systemCode": "CRM",
"businessId": "OPPORTUNITY-20260420-08",
"businessType": "SALES_CONTRACT",
"contractName": "华东区销售合同",
"fileId": "FILE-SALES-008"
}回查示例:
GET /api/esign/flows?businessId=OPPORTUNITY-20260420-08&tenantCode=TENANT_B&systemCode=CRM这种写法可以直接复用 starter 默认归档表,不需要业务系统自己再维护一套签署流程索引。
6.4 企业公章 + 经办人签字
很多生产合同不是“单纯盖一个章”,而是:
- 企业盖章
- 再由经办人签字
- 或者先经办人签字,再企业盖章
Demo 请求示例:
POST /api/esign/flows/file
Content-Type: application/json
{
"tenantCode": "TENANT_FINANCE",
"systemCode": "FIN",
"businessId": "PAY-AGREEMENT-20260420-11",
"businessType": "PAYMENT_AGREEMENT",
"contractName": "付款协议-四月批次",
"fileId": "FILE-PAY-011",
"requestPayload": {
"autoStart": true,
"signOrder": true,
"signers": [
{
"signerType": "ORGANIZATION",
"orgId": "ORG-PAYER-001",
"sealId": "SEAL-FINANCE-001",
"transactor": {
"psnId": "PSN-TRANS-001",
"psnAccount": "13900000001"
}
},
{
"signerType": "PERSON",
"psnId": "PSN-VENDOR-002",
"psnAccount": "13900000002"
}
]
}
}这个模式尤其适合:
- B2B 合同
- 对账确认单
- 付款确认函
- 供应商承诺书
6.5 关键字盖章、指定页盖章、骑缝章
这是法务场景里非常高频的一类动作,通常做法是:
- 先查关键字坐标
- 再按坐标追加签署区
- 必要时再配置骑缝章、多页章
Starter 直调示例:
ContractFileModels.KeywordPositionQueryRequest keywordRequest =
new ContractFileModels.KeywordPositionQueryRequest()
.putExtraField("keyword", "甲方盖章");
EsignResponse<ContractFileModels.KeywordPositionData> keywordResponse =
esignApiFacade.contractFile().queryKeywordPositions("FILE-PO-9527", keywordRequest);
ContractFileModels.AppendSignFieldsRequest appendRequest =
new ContractFileModels.AppendSignFieldsRequest()
.putExtraField("signFields", Arrays.asList(
new LinkedHashMap<String, Object>() {{
put("sealId", "SEAL-CONTRACT-001");
put("pageNum", 3);
put("posX", 420);
put("posY", 580);
}}
))
.putExtraField("acrossPageSeal", true);
esignApiFacade.contractFile().appendSignFields("FLOW-PO-9527", appendRequest);适合:
- 关键字“甲方盖章”“乙方签字”
- 每页盖章
- 首页盖章 + 尾页签字
- 骑缝章
6.6 已发起流程补章、补签、加签
生产环境里经常出现:
- 合同定稿后新增一个审批节点
- 原来漏了一个盖章位置
- 需要给经办人补签
Starter 直调示例:
ContractFileModels.AppendSignFieldsRequest request =
new ContractFileModels.AppendSignFieldsRequest()
.putExtraField("signFields", Arrays.asList(
new LinkedHashMap<String, Object>() {{
put("signerType", "PERSON");
put("psnId", "PSN-LEGAL-009");
put("pageNum", 5);
put("posX", 180);
put("posY", 680);
}}
));
esignApiFacade.contractFile().appendSignFields("FLOW-LEGAL-20260420-09", request);这个场景是很多“上线后才发现还要多加一个章/签字”的救火动作。
6.7 解约、撤销、终止协议
生产里常见于:
- 劳动合同解除
- 渠道协议终止
- 供应商合作解约
Starter 直调示例:
ContractFileModels.RescissionUrlRequest request =
new ContractFileModels.RescissionUrlRequest()
.putExtraField("initiatorType", "ORG")
.putExtraField("operatorId", "hr-admin")
.putExtraField("reason", "试用期不通过,发起解约");
EsignResponse<ContractFileModels.SignUrlData> response =
esignApiFacade.contractFile().createRescissionUrl("FLOW-EMP-0008", request);如果是“续签/补充协议”,通常还是重新走:
- 模板流程:
/api/esign/flows/template - 文件流程:
/api/esign/flows/file
6.8 已签完成后申请出证报告
适合:
- 法务归档
- 争议留证
- 审计留痕
Starter 直调示例:
EvidenceModels.ApplyReportRequest request =
new EvidenceModels.ApplyReportRequest().setSignFlowId("FLOW-PO-9527");
EsignResponse<EvidenceModels.ApplyReportData> response =
esignApiFacade.contractManagement().applyEvidenceReport(request);6.9 回调更新流程、任务和本地档案
demo 已经把这条链路串起来了。
回调示例:
POST /esign/callback/sign-notify
Content-Type: application/json
{
"action": "SIGN_FLOW_COMPLETE",
"signFlowId": "FLOW002",
"signOrderId": "TASK-001",
"operatorId": "PSN-001",
"operatorName": "张三",
"operatorMobile": "13800138000",
"signResult": "2"
}回调后可直接查询:
GET /api/esign/flows/FLOW002这条链路适合做:
- 业务状态回写
- 回调补档
- 签署节点审计
6.10 企业印章、成员、模板准备
很多系统在正式“发合同”前,先要把企业侧基础资源准备好。
Starter 直调示例:
esignApiFacade.seal().createOrganizationTemplateSeal(
new SealModels.CreateOrganizationTemplateSealRequest()
.setOrgId("ORG-HQ-001")
.setSealName("合同专用章")
);
esignApiFacade.seal().listOrganizationOwnSeals("ORG-HQ-001", 1, 20);
esignApiFacade.member().listMembers("ORG-HQ-001", 1, 20);
esignApiFacade.flowTemplate().listTemplates("ORG-HQ-001", 1, 20, null);
esignApiFacade.enterpriseConsole().workspace("ORG-HQ-001", 1, 20);这类场景在线上常见于:
- 新租户开通
- 新公司主体接入
- 印章治理
- 模板和经办人初始化
7. 怎么运行
7.1 运行命令
mvn -q -f esign-helper-starter/pom.xml install
mvn -q -f esign-helper-demo/pom.xml spring-boot:run7.2 测试命令
mvn -q -f esign-helper-starter/pom.xml install
mvn -q -f esign-helper-demo/pom.xml test补充说明:
demo和starter在同一个仓库里维护,但不是 Maven 父子 module 关系- 运行、测试和打包都应直接基于
esign-helper-demo/pom.xml执行 - 如果本地还没有安装
starter,需要先把esign-helper-starter安装到本地 Maven 仓库
8. 你应该从 demo 学到什么
你真正要学的是:
- 怎么引 starter
- 怎么配置 starter
- 怎么调 starter 暴露的服务
- 怎么复用 starter 默认表
- 怎么把常见盖章动作组织成
requestPayload
而不是把 demo 当成未来生产系统的模板直接复制。
适合:
- 新同学 onboarding
- 接入预演
- Mock 联调
- 回归验证
- 梳理常见盖章动作的请求组织方式
不适合:
- 继续往里堆复杂业务
- 再造一套 starter 能力
- 当正式平台服务发布
9. 和 starter 的关系
demo 与 starter 的关系是:
starter是产品核心demo是接入范例
所以遇到任何设计问题,优先原则永远是:
能力应该下沉到 starter,而不是堆在 demo
10. 推荐阅读顺序
建议按下面顺序看:
- 先看 esign-helper-starter/README.md
- 再看本 README 的“场景举例 + 代码”
- 再运行 demo
- 再看 Controller 和测试
关键代码:
- EsignFlowCommandController.java
- EsignFlowQueryController.java
- CreateEsignFlowRequest.java
- EsignDemoIntegrationTest.java
11. 产品化视角下 demo 的价值
从产品化角度看,demo 不是“给仓库凑一个示例模块”,而是:
- 降低新接入方的理解成本
- 降低 starter 的学习门槛
- 让团队内部能快速验证 starter 的升级是否破坏接入方式
- 把生产环境里最常见的盖章动作沉淀成可讨论、可复用的示例
所以它更像 starter 的“开发者体验层”和“接入教学层”。
12. 结论
如果一句话概括:
esign-helper-demo 不是生产系统本身,而是一套尽量贴近生产常见盖章操作的接入样例,用来证明 starter 在真实业务系统里的使用姿势。