# e签宝电子签署集成实现文档
## 一、概述
本文档详细说明如何在贷款管理系统中集成e签宝电子签署功能,实现合同的在线电子签署。系统采用前后端分离架构,后端使用Spring Boot,前端使用uniapp开发微信小程序。
## 二、准备工作
### 2.1 注册e签宝账号
1. 访问e签宝官网:https://www.esign.cn
2. 注册企业账号并完成实名认证
3. 创建应用,获取以下信息:
- AppId(应用ID)
- AppSecret(应用密钥)
- ProjectId(项目ID)
- API网关地址(生产环境:https://smlopenapi.esign.cn)
### 2.2 配置回调地址
在e签宝控制台配置回调地址:
- 回调URL:`https://your-domain.com/api/wechat/esign/callback`
- 回调方式:HTTP POST
- 回调内容:JSON格式
## 三、后端实现
### 3.1 依赖配置
已在`pom.xml`中添加e签宝SDK依赖:
```xml
com.esign
esign-sdk-java
3.6.0
```
### 3.2 配置文件
在`application-dev.yaml`中配置e签宝参数:
```yaml
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
```
### 3.3 核心类说明
#### 3.3.1 实体类
**EsignFlow** (`src/main/java/com/loan/system/domain/entity/EsignFlow.java`)
- 存储签署流程信息
- 包含流程ID、合同ID、签署状态等字段
#### 3.3.2 服务类
**EsignService** (`src/main/java/com/loan/system/service/EsignService.java`)
- 提供签署流程的创建、启动、查询等核心功能
**EsignServiceImpl** (`src/main/java/com/loan/system/service/Impl/EsignServiceImpl.java`)
- 实现e签宝API调用逻辑
- 处理签署流程状态同步
#### 3.3.3 控制器
**EsignController** (`src/main/java/com/loan/system/controller/wechat/EsignController.java`)
- 提供RESTful API接口
- 供前端调用
### 3.4 数据库表结构
系统会自动创建`esign_flow`表,主要字段:
```sql
CREATE TABLE `esign_flow` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`flow_id` varchar(100) NOT NULL COMMENT 'e签宝流程ID',
`contract_id` bigint(20) COMMENT '合同ID',
`case_id` bigint(20) COMMENT '案件ID',
`flow_status` int(11) COMMENT '流程状态:0-草稿 1-签署中 2-签署完成 3-签署失败 4-已撤销 5-已过期 6-已拒签',
`flow_status_desc` varchar(50) COMMENT '流程状态描述',
`document_id` varchar(100) COMMENT '签署文档ID',
`document_url` varchar(500) COMMENT '签署文档下载地址',
`document_name` varchar(200) COMMENT '签署文档名称',
`customer_account_id` varchar(100) COMMENT '客户签署人账号ID',
`business_account_id` varchar(100) COMMENT '业务方签署人账号ID',
`customer_sign_status` int(11) COMMENT '客户签署状态:0-待签署 1-已签署 2-已拒签 3-已过期',
`business_sign_status` int(11) COMMENT '业务方签署状态',
`customer_sign_time` varchar(50) COMMENT '客户签署时间',
`business_sign_time` varchar(50) COMMENT '业务方签署时间',
`create_time` varchar(50) COMMENT '创建时间',
`update_time` varchar(50) COMMENT '更新时间',
`is_delete` tinyint(1) DEFAULT 0 COMMENT '是否删除',
PRIMARY KEY (`id`),
UNIQUE KEY `idx_flow_id` (`flow_id`),
KEY `idx_contract_id` (`contract_id`),
KEY `idx_case_id` (`case_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
```
## 四、前端实现(uniapp)
### 4.1 签署流程页面
创建签署页面 `pages/contract/sign.vue`:
```vue
合同签署
{{ contractName }}
签署状态:{{ signStatusText }}
客户签署:{{ customerSignStatusText }}
业务方签署:{{ businessSignStatusText }}
```
### 4.2 WebView页面
创建WebView页面用于显示签署页面 `pages/webview/webview.vue`:
```vue
```
### 4.3 创建签署流程
在合同详情页面,添加创建签署流程的功能:
```javascript
// 创建签署流程
async createSignFlow() {
try {
uni.showLoading({
title: '创建中...'
});
// 获取合同信息
const contractInfo = this.contractDetail;
// 获取客户信息
const customerInfo = this.customerInfo;
const params = {
contractId: this.contractId,
caseId: this.caseId,
documentUrl: contractInfo.filePath, // 合同文件URL
documentName: contractInfo.contractName,
customerName: customerInfo.name,
customerMobile: customerInfo.mobile,
customerIdNumber: customerInfo.idNumber,
businessName: '业务方名称', // 从配置或用户信息获取
businessMobile: '业务方手机号',
signDeadline: Date.now() + 7 * 24 * 60 * 60 * 1000 // 7天后过期
};
const res = await this.$http.post('/wechat/esign/flow/create', params);
uni.hideLoading();
if (res.code === 200) {
uni.showToast({
title: '创建成功',
icon: 'success'
});
// 启动签署流程
await this.startSignFlow(res.data);
// 跳转到签署页面
uni.navigateTo({
url: `/pages/contract/sign?contractId=${this.contractId}`
});
} else {
uni.showToast({
title: res.msg || '创建失败',
icon: 'none'
});
}
} catch (error) {
uni.hideLoading();
console.error('创建签署流程失败', error);
uni.showToast({
title: '创建失败',
icon: 'none'
});
}
},
// 启动签署流程
async startSignFlow(flowId) {
try {
const res = await this.$http.post(`/wechat/esign/flow/${flowId}/start`);
if (res.code !== 200) {
console.error('启动签署流程失败', res);
}
} catch (error) {
console.error('启动签署流程失败', error);
}
}
```
## 五、完整签署流程
### 5.1 流程步骤
1. **创建签署流程**
- 前端调用 `/wechat/esign/flow/create` 接口
- 后端创建e签宝签署流程,返回flowId
- 保存流程信息到数据库
2. **启动签署流程**
- 前端调用 `/wechat/esign/flow/{flowId}/start` 接口
- 后端调用e签宝API启动流程
3. **获取签署链接**
- 前端调用 `/wechat/esign/flow/{flowId}/customer/sign-url` 接口
- 后端返回签署链接
4. **打开签署页面**
- 前端在WebView中打开签署链接
- 用户在e签宝页面完成签署
5. **查询签署状态**
- 前端轮询调用 `/wechat/esign/flow/{flowId}/status` 接口
- 后端同步e签宝流程状态
6. **签署完成**
- e签宝回调 `/wechat/esign/callback` 接口
- 后端更新流程状态
- 前端显示签署完成
7. **下载已签署文档**
- 前端调用 `/wechat/esign/flow/{flowId}/download` 接口
- 后端返回文档下载地址
### 5.2 时序图
```
前端 后端 e签宝
| | |
|--创建流程-------->| |
| |--创建流程--------->|
| |<--返回flowId------|
|<--返回flowId------| |
| | |
|--启动流程-------->| |
| |--启动流程--------->|
| |<--启动成功--------|
|<--启动成功--------| |
| | |
|--获取签署链接---->| |
| |--获取签署链接---->|
| |<--返回签署链接----|
|<--返回签署链接----| |
| | |
|--打开WebView-----| |
| | |
| |<--用户签署--------|
| | |
| |--回调通知--------->|
| | |
|--查询状态-------->| |
| |--查询状态--------->|
| |<--返回状态--------|
|<--返回状态--------| |
| | |
|--下载文档-------->| |
| |--获取下载地址----->|
| |<--返回下载地址----|
|<--返回下载地址----| |
```
## 六、API接口说明
### 6.1 创建签署流程
**接口地址:** `POST /wechat/esign/flow/create`
**请求参数:**
```json
{
"contractId": 123,
"caseId": 456,
"documentUrl": "https://example.com/contract.pdf",
"documentName": "借款合同",
"customerName": "张三",
"customerMobile": "13800138000",
"customerIdNumber": "110101199001011234",
"businessName": "业务方",
"businessMobile": "13900139000",
"businessIdNumber": "110101199001011235",
"signDeadline": 1640995200000,
"remark": "备注信息"
}
```
**返回结果:**
```json
{
"code": 200,
"msg": "创建签署流程成功",
"data": "flowId123456"
}
```
### 6.2 启动签署流程
**接口地址:** `POST /wechat/esign/flow/{flowId}/start`
**返回结果:**
```json
{
"code": 200,
"msg": "启动签署流程成功"
}
```
### 6.3 获取客户签署链接
**接口地址:** `GET /wechat/esign/flow/{flowId}/customer/sign-url`
**请求参数:**
- `mobile`: 手机号(必填)
- `name`: 姓名(必填)
- `accountId`: 账号ID(可选)
**返回结果:**
```json
{
"code": 200,
"msg": "获取成功",
"data": "https://esign.cn/sign/xxx"
}
```
### 6.4 查询流程状态
**接口地址:** `GET /wechat/esign/flow/{flowId}/status`
**返回结果:**
```json
{
"code": 200,
"msg": "查询成功",
"data": {
"flowStatus": 2,
"flowStatusDesc": "签署完成",
"signers": [...]
}
}
```
### 6.5 下载已签署文档
**接口地址:** `GET /wechat/esign/flow/{flowId}/download`
**返回结果:**
```json
{
"code": 200,
"msg": "获取下载地址成功",
"data": "https://esign.cn/download/xxx"
}
```
### 6.6 撤销签署流程
**接口地址:** `POST /wechat/esign/flow/{flowId}/revoke`
**请求参数:**
- `revokeReason`: 撤销原因(必填)
**返回结果:**
```json
{
"code": 200,
"msg": "撤销成功"
}
```
### 6.7 e签宝回调接口
**接口地址:** `POST /wechat/esign/callback`
**请求参数(e签宝回调):**
```json
{
"flowId": "flowId123456",
"action": "SIGN_FLOW_FINISH",
"flowStatus": 2,
"signerAccountId": "accountId123",
"timestamp": 1640995200000
}
```
## 七、注意事项
### 7.1 合同文件上传
在创建签署流程前,需要先将合同文件上传到e签宝:
1. 调用e签宝文件上传接口
2. 获取文件ID(fileId)
3. 使用fileId创建签署流程
### 7.2 签署位置配置
签署位置(坐标)需要根据实际合同模板调整:
- 在`EsignServiceImpl.createSignFields()`方法中配置
- 支持多页文档,需要指定页码
- 支持多个签署区域
### 7.3 错误处理
1. **网络错误**:实现重试机制
2. **API错误**:记录错误日志,返回友好提示
3. **签署超时**:设置合理的签署截止时间
4. **回调失败**:实现回调重试机制
### 7.4 安全性
1. **接口鉴权**:所有接口需要JWT认证
2. **参数校验**:验证手机号、身份证号格式
3. **回调验证**:验证e签宝回调签名
4. **数据加密**:敏感信息加密存储
### 7.5 性能优化
1. **状态轮询**:使用合理的轮询间隔(建议3-5秒)
2. **缓存机制**:缓存访问令牌,避免频繁获取
3. **异步处理**:回调处理使用异步方式
4. **数据库索引**:为flowId、contractId等字段建立索引
## 八、测试建议
### 8.1 单元测试
- 测试服务类方法
- 测试API接口
- 测试异常情况
### 8.2 集成测试
- 测试完整签署流程
- 测试回调处理
- 测试并发场景
### 8.3 沙箱环境
- 使用e签宝沙箱环境进行测试
- 验证各种签署场景
- 测试异常情况处理
## 九、常见问题
### 9.1 签署链接无法打开
- 检查URL是否正确编码
- 检查小程序是否配置了业务域名
- 检查网络连接
### 9.2 签署状态不同步
- 检查回调接口是否正常
- 检查轮询逻辑是否正确
- 检查数据库更新是否成功
### 9.3 文档下载失败
- 检查文档是否已签署完成
- 检查下载地址是否有效
- 检查文件权限
## 十、参考资料
- [e签宝开放平台文档](https://open.esign.cn/)
- [e签宝Java SDK文档](https://open.esign.cn/doc/detail?id=opendoc%2Fjava_sdk%2Fjava_sdk)
- [e签宝API参考](https://open.esign.cn/doc/detail?id=opendoc%2Fapi%2Fapi)
---
**文档版本:** v1.0
**最后更新:** 2024-01-01
**维护人员:** 开发团队