在使用 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 请求到 签宝 API,处理请求响应。
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 交互。
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 完成签署和验签等操作。
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 通信,确保与外部服务的交互简单、清晰。
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 请求并调用相应的业务逻辑,返回结果给客户端。
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 服务。
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 服务,使得整个流程更加清晰和可维护。
这种架构和设计能够有效地支持可扩展性,方便后期的维护和功能扩展。