在使用 **go-zero** 框架来实现对接 **签宝** 的签名与验签、待签署文件管理、电子印章、配置签署场景与签署方式、签署流程管理的相关接口时,可以按照 **go-zero** 的最佳实践进行代码设计与分层。**go-zero** 提供了强大的工具支持,能够让你高效地开发和管理服务。
下面是基于 **go-zero** 架构进行分层设计的建议,并包含如何实现相关接口。
### 1. **项目目录结构**
```
/esign
/api # 表示层,处理 HTTP 请求与响应
/logic # 业务逻辑层
/model # 数据层,管理数据库模型和 API 请求响应模型
/service # 服务层,启动服务与接口注册
/config # 配置文件
/client # 对接 e签宝 API 的客户端
/utils # 工具类层,封装常用的功能
main.go # 启动文件
```
### 2. **各层的功能职责**
- **表示层(API)**:负责接收前端的请求,调用业务逻辑层,处理请求和响应。
- **业务逻辑层(Logic)**:处理核心业务逻辑,如签名、验签、获取待签署文件等,封装业务流程。
- **数据层(Model)**:定义与数据库交互的模型,保存签署流程等信息。
- **服务层(Service)**:启动服务、注册路由等。
- **工具类层(Utils)**:封装一些常用功能,如 HTTP 请求、日志等。
### 3. **具体代码实现**
#### 3.1 **工具类层:`utils/http.go`**
工具类负责发送 HTTP 请求到 e签宝 API,处理请求响应。```go
package utils
import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
)
// DoRequest 通用 HTTP 请求函数
func DoRequest(url, method string, headers map[string]string, body interface{}) ([]byte, error) {
var reqBody []byte
var err error
// 如果请求体存在,则进行 JSON 序列化
if body != nil {
reqBody, err = json.Marshal(body)
if err != nil {
return nil, fmt.Errorf("failed to marshal body: %v", err)
}
}
// 创建 HTTP 请求
req, err := http.NewRequest(method, url, bytes.NewBuffer(reqBody))
if err != nil {
return nil, fmt.Errorf("failed to create request: %v", err)
}
// 设置请求头
for key, value := range headers {
req.Header.Set(key, value)
}
// 发送请求
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return nil, fmt.Errorf("failed to execute request: %v", err)
}
defer resp.Body.Close()
// 读取响应体
respBody, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("failed to read response body: %v", err)
}
return respBody, nil
}
```
#### 3.2 **数据层(Model):`model/signature_model.go`**
定义与 e签宝相关的数据结构,便于与 API 交互。```go
package model
// 签署文件结构
type File struct {
FileID string `json:"file_id"`
FileName string `json:"file_name"`
FileURL string `json:"file_url"`
}
// 签署流程结构
type SignProcess struct {
ProcessID string `json:"process_id"`
FileID string `json:"file_id"`
SignerID string `json:"signer_id"`
Status string `json:"status"`
}
// API 响应结构
type APIResponse struct {
Code int `json:"code"`
Message string `json:"message"`
Data interface{} `json:"data"`
}
```
#### 3.3 **业务逻辑层(Logic):`logic/signature_logic.go`**
业务逻辑层负责封装业务流程,调用 e签宝 API 完成签署和验签等操作。```go
package logic
import (
"encoding/json"
"fmt"
"github.com/your_project/utils"
"github.com/your_project/model"
"github.com/your_project/client"
"github.com/zeromicro/go-zero/core/logx"
)
type SignatureLogic struct {
client *client.ESignClient
}
func NewSignatureLogic(client *client.ESignClient) *SignatureLogic {
return &SignatureLogic{client: client}
}
// 创建签署流程
func (logic *SignatureLogic) CreateSignProcess(fileID, signerID string) (*model.SignProcess, error) {
url := fmt.Sprintf("%s/v1/sign/processes", logic.client.BaseURL)
headers := map[string]string{
"Authorization": logic.client.APIKey,
}
body := map[string]interface{}{
"file_id": fileID,
"signer_id": signerID,
}
respData, err := utils.DoRequest(url, "POST", headers, body)
if err != nil {
logx.Errorf("Error creating sign process: %v", err)
return nil, err
}
var response model.APIResponse
if err := json.Unmarshal(respData, &response); err != nil {
logx.Errorf("Failed to parse response: %v", err)
return nil, err
}
if response.Code != 0 {
return nil, fmt.Errorf("error response from eSign API: %s", response.Message)
}
// 返回签署流程信息
signProcess := &model.SignProcess{
ProcessID: response.Data["process_id"].(string),
FileID: fileID,
SignerID: signerID,
Status: "created",
}
return signProcess, nil
}
```
#### 3.4 **客户端层(Client):`client/esign_client.go`**
封装与 e签宝的 API 通信,确保与外部服务的交互简单、清晰。```go
package client
import (
"fmt"
"github.com/your_project/utils"
)
// ESignClient 用于与 e签宝 API 的交互
type ESignClient struct {
BaseURL string
APIKey string
}
// NewESignClient 创建一个新的 eSign 客户端实例
func NewESignClient(baseURL, apiKey string) *ESignClient {
return &ESignClient{
BaseURL: baseURL,
APIKey: apiKey,
}
}
// 上传文件
func (client *ESignClient) UploadFile(filePath string) (string, error) {
url := fmt.Sprintf("%s/v1/files", client.BaseURL)
headers := map[string]string{
"Authorization": client.APIKey,
}
// 假设有一个工具函数处理文件上传(可以自行实现文件上传函数)
fileData, err := utils.UploadFile(filePath)
if err != nil {
return "", err
}
respData, err := utils.DoRequest(url, "POST", headers, fileData)
if err != nil {
return "", err
}
// 假设 API 返回的文件 ID 在 response 中
var result map[string]interface{}
if err := json.Unmarshal(respData, &result); err != nil {
return "", err
}
return result["file_id"].(string), nil
}
```
#### 3.5 **表示层(API):`api/signature_api.go`**
处理 HTTP 请求并调用相应的业务逻辑,返回结果给客户端。```go
package api
import (
"github.com/your_project/logic"
"github.com/your_project/model"
"github.com/zeromicro/go-zero/rest/httpx"
"net/http"
)
type SignatureAPI struct {
SignatureLogic *logic.SignatureLogic
}
func NewSignatureAPI(signatureLogic *logic.SignatureLogic) *SignatureAPI {
return &SignatureAPI{
SignatureLogic: signatureLogic,
}
}
func (api *SignatureAPI) CreateSignProcessHandler(w http.ResponseWriter, r *http.Request) {
var fileID, signerID string
// 解析请求 URL 参数等
signProcess, err := api.SignatureLogic.CreateSignProcess(fileID, signerID)
if err != nil {
httpx.Error(w, err)
return
}
httpx.OkJson(w, model.APIResponse{
Code: 0,
Message: "Success",
Data: signProcess,
})
}
```
#### 3.6 **启动服务:`main.go`**
在启动文件中,初始化各个模块,启动 HTTP 服务。```go
package main
import (
"github.com/your_project/client"
"github.com/your_project/logic"
"github.com/your_project/api"
"github.com/zeromicro/go-zero/rest"
"github.com/zeromicro/go-zero/zrpc"
)
func main() {
// 创建 eSign 客户端
client := client.NewESignClient("https://api.esign.com", "your_api_key")
// 创建逻辑层
signatureLogic := logic.NewSignatureLogic(client)
// 创建 API 层
signatureAPI := api.NewSignatureAPI(signatureLogic)
// 创建并启动 HTTP 服务
server := rest.MustNewServer(rest.RestConf{
Host: "localhost",
Port: 8080,
})
server.AddRoute(httpx.MethodPost, "/sign/{file_id}/{signer_id}", signatureAPI.CreateSignProcessHandler)
// 启动服务
defer server.Stop()
server.Start()
}
```
### 4. **总结**
- 通过 **go-zero** 的分层架构,可以使得代码的模块化程度更高,职责分明。
- **工具类层**(如 HTTP 请求封装)可以复用,避免了重复的代码。
- **业务逻辑层**封装了具体的操作,如签署流程的创建、文件上传等。
- **API 层**负责与外部交互,提供用户接口,保证业务逻辑的清晰性。
- 最终通过 **服务层** 启动 Web 服务,使得整个流程更加清晰和可维护。
这种架构和设计能够有效地支持可扩展性,方便后期的维护和功能扩展。