VBMAN

VBMAN案例:某内部系统WEBAPI封装【源码】

这是一个客户的内部系统webapi对接需求,我搭建了mock模拟数据服务器做演示,已对数据进行脱敏处理,现分析该案例源码

源码在文章底部

源码

cApiTransport.cls

'这里是接口的封装类,目前只做了2个接口作为示例,实际接口有6个左右
'接口列表
Const API_LOGIN As String = "/v1/webapi/transport/auth/token"
Const API_NOTIFY_LIST As String = "/v1/webapi/transport/notification/list"
Const API_NOTIFY_UPDATE_STATUS As String = "/v1/webapi/transport/notification/updateStatusById"

'接口返回代码
Public Enum EnumApiResCode
    Success = 200
    ServerError = 500
    NotAuth = 401
    NotPerm = 403
    BadRequest = 400
End Enum

'解密对象实例
Dim Aes As New cAes
Dim HttpClient As New cHttpClient

Public ApiServer As String
Public Aeskey As String

'缓存用户名和密码,用于token过期后自动更新,因为该接口没有提供 refreshToken
Private Type TypeApiAuth
    HasAuth As Boolean
    Username As String
    Password As String                                                          '加密后的密码
    Token As String
    ExpiresIn  As Date
End Type
Private ApiAuth As TypeApiAuth

Public Enum EnumNotifyStatus
    初始 = 0
    生效 = 10
    执行中 = 20
    申请完成 = 30
    完成 = 40
    作废 = 90
End Enum
Public NotifyStatus As EnumNotifyStatus


'接口:登录授权
'参数:
'   Username            用户账号
'   Password             用户密码
'   IsAesEncode      【可选】是否aes加密后的密码 默认 false
'返回:cJson 对象
Public Function Login(Username As String, ByVal Password As String, Optional IsAesEncode As Boolean) As cJson
    '如果使用明文密码,需要先进行 aes 加密
    If IsAesEncode = False Then
        Password = Aes.Encode(Aeskey, Password)
    End If
    '构造请求体
    With New cJson
        .Item("systemId") = Username
        .Item("password") = Password
        Set Login = HttpRequest(ReqPost, API_LOGIN, .Encode())
        '如果登录成功,需要缓存 token
        With Login
            If .Item("code") = EnumApiResCode.Success Then
                '过期时长为毫秒,注意转换为秒,并减少60秒,提前更新
                Dim Span As Long: Span = .Item("data")("expiresIn")
                ApiAuth.Username = Username
                ApiAuth.Password = Password
                ApiAuth.Token = .Item("data")("token")
                ApiAuth.ExpiresIn = DateAdd("s", (Span / 1000 - 60), Now())
                ApiAuth.HasAuth = True
            End If
        End With
    End With
End Function

'接口:获取通知列表
'参数:【可选】IsFullSync 是否全量同步 默认 false
'返回:cJson 对象
Public Function NotifyList(Optional IsFullSync As Boolean) As cJson
    '构造请求体
    'syncType (string) 0:全量:1:增量
    With New cJson
        .Item("syncType") = IIf(IsFullSync, "0", "1")
        Set NotifyList = HttpRequest(ReqPost, API_NOTIFY_LIST, .Encode())
    End With
End Function

'接口:根据ID更新通知状态
'参数:
'   Code       拉运通知单号(业务唯一主键)
'   Total       实际完成总数(单位:吨)
'   Status      状态:00-初始 、10-生效(生效后给到运销)、20-执行中、30-申请完成、40完成(含部分完成)、90-作废
'返回:cJson 对象
Public Function NotifyStatusUpdate(Code As String, Total As Long, Status As EnumNotifyStatus) As cJson
    '构造请求体
    With New cJson
        .Item("shippingNoticeCode") = Code
        .Item("actualCompletionTotal") = CStr(Total)
        .Item("status") = Format$(Status, "00")
        Set NotifyStatusUpdate = HttpRequest(ReqPost, API_NOTIFY_UPDATE_STATUS, AesEncodePack(.Encode()))
    End With
End Function



'----------更多接口请自行参考前面2个函数扩展



'----------------------------------------------------------------------------------------------------------------------
'公用请求函数,每个接口都使用这个统一的请求和返回函数,减少冗余,确保接口函数是最轻量的,。
'返回值结构:
'{
'  "code": "500",
'  "data": {},
'  "msg": "查询失败: 未获取到系统Id"
'}
'如果 code 为 0 表示需要解密 data 值,200 表示成功,其他为失败
Private Function HttpRequest( _
    Method As VBMANLIB.EnumRequestMethod, _
    Path As String, _
    Data As String) As cJson
    If App.LogMode <> 0 Then On Error GoTo eee
    With HttpClient
        '设置请求头:授权token值
        .RequestHeaders("Authorization") = GetToken()
        'IDE下开启调试
        If App.LogMode = 0 Then .DebugStart = True
        '发起请求并获取结果
        .Fetch Method, ApiServer & Path, Data
        '返回Json对象
        Set HttpRequest = .ReturnJson()
        With HttpRequest
            If .Item("code") = 0 Then                                           '如果是 0 就解密
                Dim Miwen As String: Miwen = .Item("data")
                Dim Mingwen As String: Mingwen = Aes.Decode(Aeskey, Miwen)
                Dim Dat As New cJson                                            '转为json对象
                '此处转换 code 为 200,外部仅需要判断 200 就知道成功
                .Item("code") = EnumApiResCode.Success
                Set .Item("data") = Dat.Decode(Mingwen)
            End If
        End With
        'IDE下显示调试信息,查看:立即窗口
        If App.LogMode = 0 Then Debug.Print .DebugInfo.Encode(, 2, True)
    End With
    Exit Function
eee:
    Set HttpRequest = New cJson
    HttpRequest.Item("code") = Err.Number
    HttpRequest.Item("msg") = Err.Description
End Function

'打包加密请求体,有些请求的内容需要加密的,就用的这个加密函数,
Private Function AesEncodePack(Data As String) As String
    With New cJson
        .Item("data") = Aes.Encode(Aeskey, Data)
        AesEncodePack = .Encode()
    End With
End Function

'获取 token 值,如果过期则自动更新
Private Function GetToken() As String
    '判断是否已经缓存,避免循环调用
    If ApiAuth.HasAuth = False Then Exit Function
    If ApiAuth.ExpiresIn > Now() Then
        GetToken = ApiAuth.Token
        Exit Function
    End If
    '自动更新
    With Login(ApiAuth.Username, ApiAuth.Password, True)
        If .Item("code") <> EnumApiResCode.Success Then
            Err.Raise .Item("code"), "GetToken", .Item("msg")
        End If
    End With
End Function

Form1.frm

VERSION 5.00
Begin VB.Form Form1 
   BorderStyle     =   1  'Fixed Single
   Caption         =   "Form1"
   ClientHeight    =   7830
   ClientLeft      =   45
   ClientTop       =   390
   ClientWidth     =   12015
   LinkTopic       =   "Form1"
   MaxButton       =   0   'False
   ScaleHeight     =   7830
   ScaleWidth      =   12015
   StartUpPosition =   2  '屏幕中心
   Begin VB.CommandButton Command2 
      Caption         =   "接口2:更新状态"
      Height          =   495
      Left            =   2400
      TabIndex        =   3
      Top             =   240
      Width           =   2175
   End
   Begin VB.CommandButton Command1 
      Caption         =   "接口1:获取列表"
      Height          =   495
      Left            =   240
      TabIndex        =   2
      Top             =   240
      Width           =   2175
   End
   Begin VB.ListBox List2 
      Height          =   4740
      Left            =   240
      TabIndex        =   1
      Top             =   2640
      Width           =   11535
   End
   Begin VB.ListBox List1 
      Height          =   1860
      Left            =   240
      TabIndex        =   0
      Top             =   840
      Width           =   11535
   End
End
Attribute VB_Name = "Form1"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = False
Attribute VB_PredeclaredId = True
Attribute VB_Exposed = False
'接口服务器地址
Const API_SERVER As String = "https://mock.vb6.pro/m1/6567931-6272257-default"
'Const API_SERVER As String = "https://mip-test.cloud.chinacoal.com"
'接口实例
Dim ApiInst As New cApiTransport

Private Sub Form_Load()
    Me.Show
    '先登录
    VBMAN.Layer.msg "正在登录..."
    With ApiInst
        '配置接口方提供的aes加解密Key
        .Aeskey = "73qFpsvbjJuAZ7kEEyzNUOstoUOJ5XrJM7jB01okRlU="
        .ApiServer = API_SERVER
        With .Login("dengwei", "123456")
            If .Item("code") = EnumApiResCode.Success Then
                VBMAN.Layer.msg "登录成功"
            Else
                MsgBox .Item("msg")
            End If
        End With
    End With
End Sub

Private Sub Command1_Click()
    '显示一个提示框,参数2 为 0 秒代表不会消失
    VBMAN.Layer.msg "正在请求..."
    With ApiInst.NotifyList(True)
        If .Item("code") = EnumApiResCode.Success Then
            List1.Clear
            List2.Clear
            '以下演示2种使用方式,从 data 字段的数组遍历显示内容到 listbox
            Dim x As Variant, k As Variant, i As Long
            For Each x In .Item("data").Root
                '循环计数器
                i = i + 1
                '方式1,显示指定字段到 list1
                List1.AddItem Join(Array( _
                x("shippingNoticeCode"), _
                x("coalTypeName"), _
                x("settleCustomerName"), _
                x("shippingDeadlineStarttime"), _
                x("shippingDeadlineEndtime") _
                ), vbTab)
                '方式2,遍历每个数组的成员字段到 list2
                For Each k In x.Keys()
                    List2.AddItem "第 " & i & " 行的字段:" & k & " => " & x(k)
                Next
            Next
            '默认3秒消失
            VBMAN.Layer.msg "操作成功"
        Else
            MsgBox .Item("msg")
        End If
    End With
End Sub

'根据ID更新通知状态
Private Sub Command2_Click()
    '显示一个提示框,参数2 为 0 秒代表不会消失
    VBMAN.Layer.msg "正在请求..."
    With ApiInst.NotifyStatusUpdate("HT20240828-XS00001", 100, 申请完成)
        If .Item("code") = EnumApiResCode.Success Then
            '默认3秒消失
            VBMAN.Layer.msg "操作成功"
        Else
            MsgBox .Item("msg")
        End If
    End With
End Sub

封装类模块

业务调用

使用效果

下载

https://wwhs.lanzouo.com/iqKx82yphxwj

Hi, I’m 邓伟(woeoio)

本来无一物,何处惹尘埃

发表回复