Microsoft Office软件作为办公软件系统,已成为人们日常工作的必备工具,而其中的Excel更是各类人员的得力工具,
本文介绍基于Office VBA生成Web Service的客户端代理程序,使VBA程序能够调用Web Service。
基于的系统配置如下:
- Window XP
- Office 2003
- MS Office2003 WebServices Tools
- SOAP Toolkit3.0
- OC4J 10.1.3.3.0
一、使用MS Office2003 WebServices Tools
MS Office2003 WebServices Tools工具是为了简化在VBA中编写Web Services代理程序代码而设计的一个辅助工具,
它根据Web Services的wsdl描述文件生成对应的代理类以及用户自定义的类型结构类。
在 Office 应用程序中,单击“Visual Basic 编辑器”的“工具”菜单中的“Web 服务引用”即可启动 Microsoft Office 2003 Web Services Toolkit。
该工具提供了可用于下列用途的界面:
- 发现 Web 服务
- 选择所需的服务
- 创建为引用这些服务的 Visual Basic for Applications (VBA) 项目充当 Web 服务代理的类。
选择“Web服务URL(U)”,输入wsdl的URL地址,如
http://ORACLE:8888/aronehome/UserListInfoSoapHttpPort
点击搜索按钮,右边会显示出Web Services拥有的方法,点击“添加”按钮创建各种类。
根据wsdl的描述内容,它会创建几个类型的类文件:
| 类前缀 |
类类型 |
说明 |
| clsof_Factory_ |
对象工厂 |
如果有用户定义的类型结构则产生 |
| clsws_ |
Web 服务代理 |
Web Service的代理类,任何时候都产生 |
| struct_ |
用户定义的类型结构 |
非基本类型,用户自定义的类型则会产生,如PL/SQL中用户定义的Type或者Table都会产生 |
如上面的UserListInfo Web Services会产生如下的3个VBA类模块:
- clsof_Factory_UserListInfo
- clsws_UserListInfo
- struct_AronehomeDemoWs2User:对应的是PL/SQL中声明的user_type自定义类型
二、服务代理类模块描述
Web服务代理类模块主要完成以下工作:
- 实例化类(Class_Initialize),按照wsdl要求的类型创建一个SoapClient30对象实例
- 通过实例化的SoapClient30对象调用方法(wsm_getUserList(),wsm_updateUserInfo(ByVal ar_pUserList As Variant))
- 结束调用(Class_Terminate),释放资源
下面是clsws_UserListInfo服务的代理类模块的代码片段:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
| Private sc_UserListInfo As SoapClient30
Private Const c_WSDL_URL As String = "http://oracle:8888/aronehome/UserListInfoSoapHttpPort?wsdl"
Private Const c_SERVICE As String = "UserListInfo"
Private Const c_PORT As String = "UserListInfoSoapHttpPort"
Private Const c_SERVICE_NAMESPACE As String = "http://com/aronehome/demo/UserListInfo.wsdl"
Private Sub Class_Initialize()
Dim str_WSML As String
str_WSML = ""
str_WSML = str_WSML & ""
str_WSML = str_WSML & ""
str_WSML = str_WSML & ""
str_WSML = str_WSML & ""
str_WSML = str_WSML & ""
str_WSML = str_WSML & ""
str_WSML = str_WSML & ""
Set sc_UserListInfo = New SoapClient30
sc_UserListInfo.MSSoapInit2 c_WSDL_URL, str_WSML, c_SERVICE, c_PORT, c_SERVICE_NAMESPACE
'Use the proxy server defined in Internet Explorer's LAN settings by
'setting ProxyServer to
sc_UserListInfo.ConnectorProperty("ProxyServer") = ""
'Autodetect proxy settings if Internet Explorer is set to autodetect
'by setting EnableAutoProxy to True
sc_UserListInfo.ConnectorProperty("EnableAutoProxy") = True
Set sc_UserListInfo.ClientProperty("GCTMObjectFactory") = New clsof_Factory_UserListInfo
End Sub
Private Sub Class_Terminate()
'Error Trap
On Error GoTo Class_TerminateTrap
Set sc_UserListInfo = Nothing
Exit Sub
Class_TerminateTrap:
UserListInfoErrorHandler ("Class_Terminate")
End Sub
Private Sub UserListInfoErrorHandler(str_Function As String)
'SOAP Error
If sc_UserListInfo.FaultCode <> "" Then
Err.Raise vbObjectError, str_Function, sc_UserListInfo.FaultString
'Non SOAP Error
Else
Err.Raise Err.Number, str_Function, Err.Description
End If
End Sub
Public Function wsm_getUserList() As Variant
'Error Trap
On Error GoTo wsm_getUserListTrap
wsm_getUserList = sc_UserListInfo.getUserList()
Exit Function
wsm_getUserListTrap:
UserListInfoErrorHandler "wsm_getUserList"
End Function
Public Sub wsm_updateUserInfo(ByVal ar_pUserList As Variant)
'Error Trap
On Error GoTo wsm_updateUserInfoTrap
sc_UserListInfo.updateUserInfo ar_pUserList
Exit Sub
wsm_updateUserInfoTrap:
UserListInfoErrorHandler "wsm_updateUserInfo"
End Sub |
这样VBA程序或者VBA宏就可以调用服务代理类中的方法来调用Web Service了
三、编写VBA宏代码调用代理类方法来调用Web Service
上面通过MS Office2003 WebServices Tools工具已经生成了调用Web Service的VBA代理类,下面编写VBA宏代码来调用它们
1,调用结果返回自定义复杂类型
上面的PL/SQL函数示例声明中看到,get_user_list函数返回一个基于自定义类型user_type的Table类型user_tbl,
对应的是通过MS Office2003 WebServices Tools工具可以生成的代理类clsws_UserListInfo中的wsm_getUserList()方法
下面是VBA宏代码调用的片段:
1
2
3
4
5
6
7
8
9
10
11
| Dim clsUserListInfo As clsws_UserListInfo
Dim objCurUserListArray() As struct_AronehomeDemoWs2User
Dim objCurUser As struct_AronehomeDemoWs2User
Set clsUserListInfo = New clsws_UserListInfo
objCurUserListArray = clsUserListInfo.wsm_getUserList
For i = 0 To UBound(objCurUserListArray)
Set objCurUser = objCurUserListArray(i)
MsgBox objCurUser.username + "" + objCurUser.password
Next |
2,提供复杂数据类型参数调用WebServices
上面的PL/SQL函数示例声明中看到,update_user_info函数返回一个基于自定义类型user_type的Table类型user_tbl,
对应的是通过MS Office2003 WebServices Tools工具可以生成的代理类clsws_UserListInfo中的wsm_getUserList()方法
下面是VBA宏代码调用的代码片段:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| Dim lines As Integer
Dim clsUpdateUserInfo As clsws_UserListInfo
Dim objCurUserInfoArrary() As struct_AronehomeDemoWs2User
Dim objCurUserInfo As struct_AronehomeDemoWs2User
lines = 3
ReDim objCurUserInfoArrary(lines) As struct_AronehomeDemoWs2User
For i = 1 To 3
Set objCurUserInfo = New struct_AronehomeDemoWs2User
objCurUserInfo.userid = i
objCurUserInfo.username = "a" + i
objCurUserInfo.password = "b" + i
Set objCurUserInfoArray(i) = objCurUserInfo
Next
Set clsUpdateUserInfo = New clsws_UserListInfo
clsUpdateUserInfo.wsm_updateUserInfo objCurUserInfoArray |
注:上面传给Web Service的Table为objCurUserInfoArray,而PL/SQL在接收到这个Table时的count数要比实际的多一行,多出的一行全是空值,
是由于SOAP在进行序列化的过程中添加的,因此在PL/SQL代码中,需要将传入的Table变量的count数减去1,可能有的同学已经注意到PLSQL update_user_info方法中的“p_user_list.count -1”了。
三、执行VBA程序
如果上面的Web Service按照前期的课题中一样添加的安全性配置,那通过上面的代码在VBA程序中调用Web Services是执行不成功的,报出如下的错误:
ERROR OWS-04005: Missing <wsse:Security> in SOAP Header
和我们使用OC4J自带的测试页面进行测试时一样的错误,是由于没有提供安全验证信息到SOAP Header中。
而通过MS Office2003 WebServices Tools工具为我们产生的Web Services代理类中没有安全验证相关的内容,我们需要自己编写程序来产生SOAP Header的内容
下一篇文章将描述如何在VBA调用中添加认证信息以支持Web Service的认证
–