实现了两种合同模板填充方式:
提供以下静态方法:
fillTemplateAndUpload(): 填充模板、转换PDF、上传到e签宝(一步完成)fillWordTemplate(): 仅填充Word模板,返回字节数组fillTemplateAndConvertToPdf(): 填充模板并转换为PDFfillTemplateAndSavePdf(): 填充模板并保存为PDF文件uploadDocument(): 上传文件到e签宝,返回fileIdcreateSignFlow(): 创建签署流程接口地址: POST /api/wechat/esign/flow/createFromTemplate
功能: 填充模板、上传文件、创建签署流程,一步完成
请求体示例:
{
"contractId": 123,
"caseId": 456,
"templatePath": "template1.docx",
"contractName": "浙江宝路同典当抵押合同",
"contract": {
"contractNo": "HT20250101001",
"name": "张三",
"idNumber": "330123199001011234",
"mobile": "13800138000",
"contractAmount": 100000.0,
"contractPeriod": 30,
"amountRate": 1.5,
"serviceCost": 2.0,
"loanRate": 3.0,
"bankName": "中国工商银行",
"bankAccount": "6222021234567890123",
"address": "杭州市西湖区文三路123号",
"collateralNumber": "101",
"collateralArea": "100平方米",
"contractType": "抵押合同",
"contractAttr": "不动产抵押",
"leastDay": 30,
"contactAddress1": "杭州市西湖区",
"contactAddress2": "杭州市西湖区",
"userMobile": "13900139000",
"signLocation1": "杭州",
"signLocation2": "杭州"
},
"customerName": "张三",
"customerMobile": "13800138000",
"customerIdNumber": "330123199001011234",
"businessName": "浙江宝路同典当有限公司",
"businessMobile": "13900139000",
"businessIdNumber": "",
"signDeadline": 1735632000000,
"remark": "测试合同"
}
响应示例:
{
"code": 200,
"message": "模板填充并创建签署流程成功",
"data": "flowId123456789"
}
接口地址: POST /api/wechat/esign/template/upload
功能: 仅填充模板并上传到e签宝,不创建签署流程
请求体: 与完整流程接口相同
响应示例:
{
"code": 200,
"message": "模板填充并上传成功",
"data": "fileId123456789"
}
接口地址: POST /api/wechat/esign/flow/create
功能: 使用已上传的文件ID创建签署流程
请求体示例:
{
"contractId": 123,
"caseId": 456,
"fileId": "fileId123456789",
"documentName": "浙江宝路同典当抵押合同.pdf",
"customerName": "张三",
"customerMobile": "13800138000",
"customerIdNumber": "330123199001011234",
"businessName": "浙江宝路同典当有限公司",
"businessMobile": "13900139000",
"signDeadline": 1735632000000
}
{{variableName}} 格式{{@pictureVariable}} 格式(用于签名图片)根据 ContractInformation 类,支持的变量包括:
| 变量名 | 说明 | 示例值 |
|---|---|---|
| contractNo | 合同编号 | HT20250101001 |
| customerName | 客户姓名 | 张三 |
| customerIdNumber | 客户身份证号 | 330123199001011234 |
| customerMobile | 客户手机号 | 13800138000 |
| contractType | 业务类型 | 抵押合同 |
| contractAttr | 业务属性 | 不动产抵押 |
| contractAmount | 合同金额 | 100000.0 |
| contractPeriod | 合同期限(天) | 30 |
| interestRate | 当金利率 | 1.5% |
| serviceCost | 综合服务费 | 2.0% |
| loanRate | 借款利率 | 3.0% |
| bankName | 客户银行 | 中国工商银行 |
| bankAccount | 客户银行账号 | 6222021234567890123 |
| collateralAddress | 押品地址 | 杭州市西湖区文三路123号 |
| numberAndArea | 押品编号和面积 | 101 100平方米 |
| contactAddress1 | 客户联系地址 | 杭州市西湖区 |
| contactAddress2 | 业务方联系地址 | 杭州市西湖区 |
| userMobile | 业务方手机号 | 13900139000 |
| signLocation1 | 客户签署地点 | 杭州 |
| signLocation2 | 业务方签署地点 | 杭州 |
| signature1 | 客户签名图片 | (图片) |
| signature2 | 业务方签名图片 | (图片) |
| startDateTime | 借款日期 | 2025-01-01 |
| endDateTime | 还款日期 | 2025-01-31 |
在Word模板中使用以下格式:
合同编号:{{contractNo}}
客户姓名:{{customerName}}
身份证号:{{customerIdNumber}}
合同金额:{{contractAmount}}元
合同期限:{{contractPeriod}}天
当金利率:{{interestRate}}
综合服务费:{{serviceCost}}
借款利率:{{loanRate}}
押品地址:{{collateralAddress}}
押品信息:{{numberAndArea}}
客户签名:{{@signature1}}
业务方签名:{{@signature2}}
system:
esign:
app-id: your-app-id
app-secret: your-app-secret
api-url: https://smlopenapi.esign.cn
project-id: your-project-id
enabled: true
upload:
templatePath: /app/upload/template/ # 模板文件路径
libreoffice:
remote-url: http://libreoffice-server:8080 # 或本地模式
office-home: "" # 留空使用远程模式
@Autowired
private EsignService esignService;
// 方式1: 使用工具类(推荐)
ContractInformation contract = new ContractInformation();
contract.setContractNo("HT20250101001");
contract.setName("张三");
// ... 设置其他字段
String templatePath = "/app/upload/template/template1.docx";
String fileId = EsignContractUtil.fillTemplateAndUpload(
templatePath,
contract,
"浙江宝路同典当抵押合同",
esignService
);
// 方式2: 分步执行
// 1. 填充模板
byte[] docxBytes = EsignContractUtil.fillWordTemplate(templatePath, contract);
// 2. 转换为PDF
byte[] pdfBytes = LibreOfficePdfUtil.convertDocxToPdf(docxBytes);
// 3. 上传到e签宝
String fileId = esignService.uploadDocument(pdfBytes, "合同.pdf", "application/pdf");
// 4. 创建签署流程
EsignCreateFlowDTO flowDTO = new EsignCreateFlowDTO();
flowDTO.setFileId(fileId);
flowDTO.setDocumentName("合同.pdf");
// ... 设置其他字段
String flowId = esignService.createSignFlow(flowDTO);
模板路径:
template1.docx),会自动拼接配置的 upload.templatePathPDF转换:
文件上传:
错误处理:
签名图片:
A: 检查Word模板中的变量格式是否正确,确保使用 {{variableName}} 格式。
A: 检查LibreOffice服务是否正常运行,查看日志中的错误信息。
A: 检查e签宝配置是否正确(app-id、app-secret),确保网络连接正常。
A: 修改 EsignContractUtil.fillWordTemplate() 方法中的变量映射部分。
在e签宝工作台创建模板:
了解模板控件ID:
接口地址: GET /api/wechat/esign/template/list
请求参数:
pageNum (可选): 页码,默认1pageSize (可选): 每页大小,默认20响应示例:
{
"code": 200,
"message": "获取模板列表成功",
"data": {
"list": [
{
"docTemplateId": "template123456",
"docTemplateName": "浙江宝路同典当抵押合同",
"docTemplateType": "DOCX",
"createTime": "2025-01-01 10:00:00"
}
],
"total": 10,
"pageNum": 1,
"pageSize": 20
}
}
接口地址: GET /api/wechat/esign/template/{templateId}
功能: 获取模板的详细信息,包括所有控件的配置
响应示例:
{
"code": 200,
"message": "获取模板详情成功",
"data": {
"docTemplateId": "template123456",
"docTemplateName": "浙江宝路同典当抵押合同",
"structComponents": [
{
"key": "contractNo",
"componentType": "TEXT",
"componentName": "合同编号"
},
{
"key": "customerName",
"componentType": "TEXT",
"componentName": "客户姓名"
}
]
}
}
接口地址: POST /api/wechat/esign/flow/createFromEsignTemplate
功能: 一步完成模板填充、文件生成、签署流程创建
请求体示例:
{
"contractId": 123,
"caseId": 456,
"templateId": "template123456",
"contractName": "浙江宝路同典当抵押合同",
"formFields": {
"contractNo": "HT20250101001",
"customerName": "张三",
"customerIdNumber": "330123199001011234",
"customerMobile": "13800138000",
"contractAmount": "100000",
"contractPeriod": "30",
"interestRate": "1.5",
"bankName": "中国工商银行",
"bankAccount": "6222021234567890123"
},
"customerName": "张三",
"customerMobile": "13800138000",
"customerIdNumber": "330123199001011234",
"businessName": "浙江宝路同典当有限公司",
"businessMobile": "13900139000",
"signDeadline": 1735632000000
}
请求体说明:
templateId: e签宝工作台中的模板ID(必填)formFields: 字段映射(key为模板控件ID,value为填充值)
formFields为空,可以传入contract对象,系统会自动映射常见字段customerName, customerMobile等: 用于创建签署流程的签署人信息响应示例:
{
"code": 200,
"message": "使用e签宝模板创建签署流程成功",
"data": "flowId123456789"
}
接口地址: POST /api/wechat/esign/template/fill
功能: 仅填充模板并生成文件,不创建签署流程
请求体: 与完整流程接口相同(但不创建流程)
响应示例:
{
"code": 200,
"message": "模板填充并生成文件成功",
"data": "fileId123456789"
}
如果您不想手动构建formFields,可以传入contract对象,系统会自动将常见字段映射到e签宝模板控件。
支持的自动映射字段:
| ContractInformation字段 | 映射到的模板控件ID |
|---|---|
| contractNo | contractNo, 合同编号 |
| name | customerName, 客户姓名, name |
| idNumber | customerIdNumber, 客户身份证号, idNumber |
| mobile | customerMobile, 客户手机号, mobile |
| contractAmount | contractAmount, 合同金额, 金额 |
| contractPeriod | contractPeriod, 合同期限, 期限 |
| amountRate | interestRate, 当金利率 |
| serviceCost | serviceCost, 综合服务费 |
| loanRate | loanRate, 借款利率 |
| bankName | bankName, 银行名称 |
| bankAccount | bankAccount, 银行账号 |
| address | collateralAddress, 押品地址, address |
| contractType | contractType, 业务类型 |
| contractAttr | contractAttr, 业务属性 |
| startDateTime | startDateTime, 借款日期 |
| endDateTime | endDateTime, 还款日期 |
使用示例:
{
"templateId": "template123456",
"contractName": "浙江宝路同典当抵押合同",
"contract": {
"contractNo": "HT20250101001",
"name": "张三",
"idNumber": "330123199001011234",
"mobile": "13800138000",
"contractAmount": 100000.0,
"contractPeriod": 30
},
"customerName": "张三",
"customerMobile": "13800138000",
"businessName": "浙江宝路同典当有限公司",
"businessMobile": "13900139000"
}
@Autowired
private EsignService esignService;
// 方式1: 使用手动字段映射
Map<String, String> formFields = new HashMap<>();
formFields.put("contractNo", "HT20250101001");
formFields.put("customerName", "张三");
formFields.put("contractAmount", "100000");
String fileId = esignService.fillTemplateAndGenerateFile(
"template123456",
"合同.pdf",
formFields
);
// 方式2: 使用自动字段映射
ContractInformation contract = new ContractInformation();
contract.setContractNo("HT20250101001");
contract.setName("张三");
// ... 设置其他字段
Map<String, String> formFields = EsignContractUtil.convertContractToTemplateFields(contract);
String fileId = esignService.fillTemplateAndGenerateFile(
"template123456",
"合同.pdf",
formFields
);
为了使用自动字段映射功能,建议在e签宝工作台中创建模板时,使用以下控件ID:
合同基本信息:
contractNo 或 合同编号contractAmount 或 合同金额contractPeriod 或 合同期限客户信息:
customerName 或 客户姓名 或 namecustomerIdNumber 或 客户身份证号 或 idNumbercustomerMobile 或 客户手机号 或 mobile利率信息:
interestRate 或 当金利率serviceCost 或 综合服务费loanRate 或 借款利率银行信息:
bankName 或 银行名称bankAccount 或 银行账号押品信息:
collateralAddress 或 押品地址 或 addressnumberAndArea 或 押品信息日期信息:
startDateTime 或 借款日期endDateTime 或 还款日期| 特性 | 本地Word模板 | e签宝工作台模板 |
|---|---|---|
| 模板管理 | 需要自行管理模板文件 | e签宝工作台统一管理 |
| 模板编辑 | 需要使用Word编辑器 | e签宝可视化编辑器 |
| 字段填充 | 使用变量名 {{variable}} |
使用控件ID(key) |
| PDF转换 | 需要LibreOffice服务 | e签宝自动转换 |
| 适用场景 | 开发和测试 | 生产环境(推荐) |
| 模板更新 | 需要重新上传文件 | 在e签宝工作台直接更新 |
模板ID获取:
控件ID(key):
字段映射:
formFields中的key必须与模板中的控件ID完全一致自动映射:
formFields模板更新:
contractNo、customerName)template123456步骤1:使用模板ID填充字段并创建签署流程
POST /api/wechat/esign/flow/createFromEsignTemplate
这个接口会一步完成以下操作:
templateId 填充模板字段(使用 formFields 或 contract)flowId请求示例:
{
"contractId": 123,
"caseId": 456,
"templateId": "template123456",
"contractName": "浙江宝路同典当抵押合同",
"formFields": {
"contractNo": "HT20250101001",
"customerName": "张三",
"customerMobile": "13800138000"
},
"customerName": "张三",
"customerMobile": "13800138000",
"businessName": "浙江宝路同典当有限公司",
"businessMobile": "13900139000"
}
响应示例:
{
"code": 200,
"message": "使用e签宝模板创建签署流程成功",
"data": "flowId123456789"
}
步骤2:获取签署链接
获取客户签署链接:
GET /api/wechat/esign/flow/{flowId}/customer/sign-url?mobile=13800138000&name=张三
获取业务方签署链接:
GET /api/wechat/esign/flow/{flowId}/business/sign-url?mobile=13900139000&name=公司名称
步骤3:启动签署流程
POST /api/wechat/esign/flow/{flowId}/start
启动后,签署人才能通过签署链接进行签署。
步骤4:签署和查询
GET /api/wechat/esign/flow/{flowId}/statusGET /api/wechat/esign/flow/{flowId}/download如果不想一步完成,可以分步执行:
步骤1:填充模板生成文件
POST /api/wechat/esign/template/fill
返回 fileId
步骤2:使用fileId创建签署流程
POST /api/wechat/esign/flow/create
传入 fileId,返回 flowId
步骤3-5:同方式一的步骤2-4
┌─────────────────────────────────────────────────────────────┐
│ 准备工作(一次性) │
│ ┌───────────────────────────────────────────────────────┐ │
│ │ 1. 在e签宝工作台创建模板 │ │
│ │ 2. 设置控件ID(如:contractNo, customerName) │ │
│ │ 3. 记录模板ID(templateId) │ │
│ └───────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ 业务流程(每次签署) │
│ ┌───────────────────────────────────────────────────────┐ │
│ │ 步骤1: 填充模板并创建签署流程 │ │
│ │ POST /api/wechat/esign/flow/createFromEsignTemplate │ │
│ │ 输入: templateId + formFields/contract │ │
│ │ 输出: flowId │ │
│ └───────────────────────────────────────────────────────┘ │
│ ↓ │
│ ┌───────────────────────────────────────────────────────┐ │
│ │ 步骤2: 获取签署链接 │ │
│ │ GET /api/wechat/esign/flow/{flowId}/customer/sign-url│ │
│ │ GET /api/wechat/esign/flow/{flowId}/business/sign-url│ │
│ └───────────────────────────────────────────────────────┘ │
│ ↓ │
│ ┌───────────────────────────────────────────────────────┐ │
│ │ 步骤3: 启动签署流程 │ │
│ │ POST /api/wechat/esign/flow/{flowId}/start │ │
│ └───────────────────────────────────────────────────────┘ │
│ ↓ │
│ ┌───────────────────────────────────────────────────────┐ │
│ │ 步骤4: 客户和业务方签署 │ │
│ │ 通过签署链接完成签署 │ │
│ └───────────────────────────────────────────────────────┘ │
│ ↓ │
│ ┌───────────────────────────────────────────────────────┐ │
│ │ 步骤5: 查询状态和下载 │ │
│ │ GET /api/wechat/esign/flow/{flowId}/status │ │
│ │ GET /api/wechat/esign/flow/{flowId}/download │ │
│ └───────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
templateId(模板ID):
flowId(流程ID):
fileId(文件ID):
createFromEsignTemplate 接口,fileId会自动处理,无需关心❌ 错误理解:
✅ 正确理解:
createFromEsignTemplate 接口时,传入templateId和要填充的数据模板填充和签署流程创建成功后,可以:
/api/wechat/esign/flow/{flowId}/customer/sign-url/api/wechat/esign/flow/{flowId}/start/api/wechat/esign/flow/{flowId}/status/api/wechat/esign/flow/{flowId}/download详细接口说明请参考 EsignController.java。