Excel用VBA傳數據到服務器

有個金融領域的需求,有一段excel的vba代碼可以自動生成金融產品數據,要把這些數據在網頁上(其實是微信公衆號)展示,於是就需要把生成的數據發送到服務器並保存給網頁用。

vba裏面可以發送Http請求,筆者先把需要的數據拼成了1個Json字符串。真的是拼的,最好的方式肯定是序列化類實例,不過筆者以爲vba不支持類,可能記糊塗了。不過後來發現vba居然支持類,但沒有現成的json序列化方法,那麼跟自己拼也沒啥區別,就這麼用了。ps,寫vba真是浪費時間,比C#效率低多了,也沒用vs這種強大的IDE。

Sub MakeJson()

Dim result, duedates, lists As String
Dim currentdate As String

Dim target As Range
Set target = Sheets("publish").Range("A1")

result = "["


Do


'開始處理標的
duedates = ""
lists = ""

If Len(result) <> 1 Then
    result = result + ","
End If

result = result + "{"
result = result + """exchange_code"":""" + target.Offset(1, 7).Value + ""","
result = result + """product_code"":""" + target.Offset(1, 8).Value + ""","
result = result + """link_contract"":""" + target.Offset(1, 0).Value + ""","

Do
    Set target = target.Offset(1, 0)

    If currentdate <> target.Offset(0, 1).Value Then
        If duedates <> "" Then
            duedates = duedates + ","
        End If
        currentdate = target.Offset(0, 1).Value
        duedates = duedates + "\""" + currentdate + "\"""
    End If

    If lists <> "" Then
        lists = lists + ","
    End If

    lists = lists & _
    "{\""due_date\"":\""" & target.Offset(0, 1).Value & _
    "\"",\""upward_buy\"":\""" & target.Offset(0, 2).Value & _
    "\"",\""upward_delta\"":\""" & (target.Offset(0, 3).Value * 100) & _
    "%\"",\""Kprice\"":\""" & target.Offset(0, 4).Value & _
    "\"",\""weaker_buy\"":\""" & target.Offset(0, 5).Value & _
    "\"",\""weaker_delta\"":\""" & (target.Offset(0, 6).Value * 100) & "%\""}"

Loop While target.Value = target.Offset(1, 0).Value


result = result + """link_contract_duedates"":""[" + duedates + "]"","
result = result + """link_contract_list"":""[" + lists + "]"""
result = result + "}"



'檢查是否換交易所了
If target.Offset(0, 7).Value <> target.Offset(1, 7).Value Then
    'post val
    result = result + "]"
    Call UploadJson(target.Offset(0, 7).Value, result)
    result = "["
End If

'檢查還有沒有行
Loop While target.Offset(1, 0).Value <> ""



End Sub

這個excel的表裏面有個名叫publish的sheet,這個函數讀取sheet的內容並拼接成1串筆者需要格式的json,這裏只是個例子,具體根據自己的需要來拼。結尾部分用到一個函數UploadJson是用來把拼出來的json字符串上傳到服務器的。

Sub UploadJson(exname, result)
    'itemp = itemp + 1
    'Sheets("setup").Range("E20").Offset(itemp, 0).Value = result
    'Sheets("setup").Range("E20").Offset(itemp, 1).Value = Len(result)
    'Dim MyData As New DataObject
    'MyData.SetText result
    'MyData.PutInClipboard
    '上面的代碼爲debug時候顯示json內容

  Dim http
  Set http = CreateObject("Microsoft.XMLHTTP")
  http.Open "POST", "http://你的接收地址", False
  http.send "excode=" & exname & "&jsons=" & result
  If http.Status = 200 Then
    MsgBox "上傳" & exname & "交易所成功"
  Else
    MsgBox "上傳" & exname & "失敗,錯誤代碼:" & http.Status
  End If
End Sub

這就是上傳代碼,把json值和一些別的參數post到自己的api地址。值得一提的是上面註釋掉的部分代碼,把字符串顯示在excel的表格單元裏查看結果,不過筆者的json字符串結果比較長,有200k的長度,而單元格只能存下32767個字符(很容易理解,32位整型範圍),於是乎,就有了後面把字符串內容拷貝到剪貼板的代碼,需要注意的是要先引用Microsoft Forms 2.0 Object Library,具體操作是工具-引用-瀏覽,選擇C:\Windows\System32\FM20.dll

好了,數據上傳了我們需要在服務器端接收,看看代碼

            Stopwatch watch1 = new Stopwatch();
            watch1.Start();
            JavaScriptSerializer serializer = new JavaScriptSerializer();
            NameValueCollection req = PublicClass.FillFromEncodedBytes(base.Request.BinaryRead(base.Request.ContentLength), Encoding.UTF8);

            try
            {
                if (req["excode"].Length > 0)
                {
                    exjsonsBll eb = new exjsonsBll();
                    Model.exjsons exj = eb.getexjsonsbyExCode(req["excode"]);
                    if (exj == null)
                    {
                        exj = new Model.exjsons();
                        exj.exchange_code = req["excode"];
                        exj.jsons = req["jsons"];
                        exj.CreatedTime = exj.LastUpdate = DateTime.Now;
                        eb.Add(exj);
                    }

                    Response.Write("Success");
                }
                else
                {
                    Response.Write("Failed");
                }
            }
            catch (Exception ex)
            {
                new Thread(() => errorBll.log("interface_ExchangeData", ex.ToString(), "")).Start();
                Response.Write("Failed");
            }

            watch1.Stop();
            new Thread((ThreadStart)(() => log_interfaceBll.add("wx_recExData", Convert.ToInt32(watch1.ElapsedMilliseconds)))).Start();
        public static NameValueCollection FillFromEncodedBytes(byte[] bytes, Encoding encoding)
        {
            NameValueCollection values = new NameValueCollection();
            int num = (bytes != null) ? bytes.Length : 0;
            for (int i = 0; i < num; i++)
            {
                string str;
                string str2;
                int offset = i;
                int num4 = -1;
                while (i < num)
                {
                    byte num5 = bytes[i];
                    if (num5 == 0x3d)
                    {
                        if (num4 < 0)
                        {
                            num4 = i;
                        }
                    }
                    else if (num5 == 0x26)
                    {
                        break;
                    }
                    i++;
                }
                if (num4 >= 0)
                {
                    str = HttpUtility.UrlDecode(bytes, offset, num4 - offset, encoding);
                    str2 = HttpUtility.UrlDecode(bytes, num4 + 1, (i - num4) - 1, encoding);
                }
                else
                {
                    str = null;
                    str2 = HttpUtility.UrlDecode(bytes, offset, i - offset, encoding);
                }
                values.Add(str, str2);
                if ((i == (num - 1)) && (bytes[i] == 0x26))
                {
                    values.Add(null, string.Empty);
                }
            }
            return values;
        }

上面有2段代碼,第一段是接收頁面的入口,裏面設置了Stopwatch來監控這個接口的處理時間,做移動開發的時候還是很有用的信息,可以很好的計算出一個操作一共需要花費多少時間。最後用了ThreadStart來把處理時間寫入數據庫,線程的使用也很必要,不能耽誤返回的時間。處理過程替換成自己的就行了。
第2段代碼是前面用到的用來提取post過來的數據的函數,筆者放進標準類裏面的,直接使用就行,不要深究。

好了,這時候可以在excel放一個按鈕,點擊以後執行vba代碼,自動上傳數據到服務器。你可能會問爲什麼要這麼操作excel操作vba,嘿嘿,因爲你可以把你的核心算法隔離出來,因爲讓金融人士寫vba是可能的,做後面這些就是天方夜談了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章