有個金融領域的需求,有一段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是可能的,做後面這些就是天方夜談了。