1、前言
本文主要是通过实战演练,介绍各类个性化、自定义WebService及其方法的开发方法,以及相关技术,重点介绍Cordys NOM类型(底层基于C语言的XML对象解析),以及Java中Soap WebService的调用技术。
首先介绍本文所依赖的数据库设计,采用常用的主从表模式,包括:用户账号表“sm_account”、登录验证用户表“sm_auth_account”、租户账号表“sm_tenant_account ”,提供人员多重身份的流程能力(人员跨部门、跨租户)。
设计数据库查询SQL如下所示:
select a.user_name,a.acc_code,a.acc_name,a.create_time ,b.auth_account,c.org_id,c.tenant_account,c.tenant_name
from sm_account a ,sm_auth_account b,sm_tenant_account c
where a.acc_id=b.acc_id and a.acc_id=c.acc_id;
2.不依赖数据库创建自定义类和Webservice
此操作仍需在WS_AppServer Package界面来进行。
(1)创建自定义类及属性
按上图所示,操作鼠标点击(Create Model from Object Layout),在“Object
Layout Editor”输入Name为“C_USER”。此类与数据库表模型没有直接关系,是完全自主设计的新类。(注:多次实践验证后,示例代码的类名称替换为C_UserManger,WebService名称替换为C_UserManger,代码内容基本没有变)
如果关闭了“Object Layout Editor”界面,在次进入编辑,需要通过鼠标右键菜单“Edit Object Layout”来进行。注意:属性“Attributes”,必须通过此界面进行设置。
(2)添加方法
添加方法与普通方式一样,鼠标右键打开菜单添加。
(2.1)设置方法“Method”返回值等属性
上图中,“Occurrnce”选择框中,选“1”为返回单行记录,选“*”为返回多行记录。
注意:必须设置成SOAP方法,才能发布成可见的Webservice。
(2.2)添加方法参数
public static com.unicom.xiaoywwsappserverpackage.C_UserManager getC_UserObject(String v_tenantcount)
{
String sql="select a.user_name U_NAMENAME,b.auth_account U_ACOUNT,c.org_id ORG_ID,c.tenant_account U_TENANTACOUNT,c.tenant_name U_TENANTNAME";
sql = sql+ " from sm_account a ,sm_auth_account b,sm_tenant_account c ";
sql = sql + " where a.acc_id=b.acc_id and a.acc_id=c.acc_id and c.tenant_account = :v_tenantcount ";
QueryObject query = new QueryObject(sql);
query.addParameter("v_tenantcount", "sm_tenant_account.tenant_account", QueryObject.PARAM_STRING,v_tenantcount);//NOPMD
query.setResultClass(C_UserManager.class);
return (C_UserManager) query.getObject() ;
}
(注:培训老师要求,数据库查询语句的字段别名要与类的属性名称保持一致。)
3、开发时使用外部Jar包依赖
(1)上传Jar包
在项目中,新建“Jar”文件夹,通过鼠标右键菜单“Upload Document...”功能完成。
(2)添加依赖类包
(3)再发布Java代码
4、自定义XML解析
项目规范使用Cordys推荐的NOM类型进行XML处理,在此举例说明,输入NOM(自定义XML)。修改方法输入参数为NOM。
(1)重新生成Java代码。
(2)定义输入XML数据
<USER>
<ACCNAME>xiaoyw</ACCNAME>
<USERNAME>肖永威</USERNAME>
<ACCCODE>101</ACCCODE>
</USER>
<TENANTUSER>
<U_TENANTACCOUNT>manager</U_TENANTACCOUNT>
<U_TENANTNAME>项目经理</U_TENANTNAME>
<U_TENANTDN>o=harbin,cn=cordys,cn=expense,o=HL.CHINAUNICOM.CN</U_TENANTDN>
</TENANTUSER>
<TENANTUSER>
<U_TENANTACCOUNT>programer</U_TENANTACCOUNT>
<U_TENANTNAME>程序员</U_TENANTNAME>
<U_TENANTDN>o=harbin,cn=cordys,cn=expense,o=HL.CHINAUNICOM.CN</U_TENANTDN>
</TENANTUSER>
对应测试请求如下:
<SOAP:Envelope xmlns:SOAP="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP:Body>
<CreateUser xmlns="http://schemas.cordys.com/XiaoywWSAppServerPackage" preserveSpace="no" qAccess="0" qValues="">
<v_user>
<USER>
<ACCNAME>xiaoyw</ACCNAME>
<USERNAME>肖永威</USERNAME>
<ACCCODE>101</ACCCODE>
</USER>
<TENANTUSER>
<U_TENANTACCOUNT>manager</U_TENANTACCOUNT>
<U_TENANTNAME>项目经理</U_TENANTNAME>
<U_TENANTDN>o=harbin,cn=cordys,cn=expense,o=HL.CHINAUNICOM.CN</U_TENANTDN>
</TENANTUSER>
<TENANTUSER>
<U_TENANTACCOUNT>programer</U_TENANTACCOUNT>
<U_TENANTNAME>程序员</U_TENANTNAME>
<U_TENANTDN>o=harbin,cn=cordys,cn=expense,o=HL.CHINAUNICOM.CN</U_TENANTDN>
</TENANTUSER>
</v_user>
</CreateUser>
</SOAP:Body>
</SOAP:Envelope>
(3)主从表插入操作代码
/*自行管理数据库事务Demo代码,用于主从表插入操作,附代码演示插入主表后,获取自增长主键值,插入子表;方法属性中Transcation设置为NONE*/
public static void createUser(int v_user)
{
BSF.startTransaction();
long acc_id =0;
int accountXML = XPath.getFirstMatch("*[local-name()=‘USER‘]", null, v_user);
String accountName = Node.getDataWithDefault(XPath.getFirstMatch("*[local-name()=‘ACCNAME‘]", null, accountXML), "");
String userName = Node.getDataWithDefault(XPath.getFirstMatch("*[local-name()=‘USERNAME‘]", null, accountXML), "");
String accountCode = Node.getDataWithDefault(XPath.getFirstMatch("*[local-name()=‘ACCCODE‘]", null, accountXML), "");
sm_account ACCOUNT = new sm_account(BusObjectConfig.TRANSIENT);
try {
ACCOUNT.setAcc_code(accountCode);
ACCOUNT.setAcc_name(accountName);
ACCOUNT.setUser_name(userName);
ACCOUNT.setIs_admin((short)0);
ACCOUNT.insert();
BSF.commitTransaction();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
BSF.abortTransaction();
return;
} finally {
if (accountXML != 0){
Node.delete(accountXML);
accountXML = 0;
}
}
acc_id = ACCOUNT.getAcc_id();
BSF.startTransaction();
sm_auth_account AUTH_ACC = new sm_auth_account(BusObjectConfig.TRANSIENT);
try {
AUTH_ACC.setAcc_id(acc_id);
AUTH_ACC.setAuth_account(accountName);
AUTH_ACC.insert();
BSF.commitTransaction();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
BSF.abortTransaction();
return;
}
int[] usersXML = XPath.getMatchingNodes("*[local-name()=‘TENANTUSER‘]", null, v_user);
for(int userXML:usersXML)
{
BSF.startTransaction();
sm_tenant_account Tenant_Account = new sm_tenant_account(BusObjectConfig.TRANSIENT);
Tenant_Account.setAcc_id(acc_id);
Tenant_Account.setTenant_account(Node.getDataWithDefault(XPath.getFirstMatch("*[local-name()=‘U_TENANTACCOUNT‘]", null, userXML), ""));
Tenant_Account.setTenant_name(Node.getDataWithDefault(XPath.getFirstMatch("*[local-name()=‘U_TENANTNAME‘]", null, userXML), ""));
Tenant_Account.setTenant_dn(Node.getDataWithDefault(XPath.getFirstMatch("*[local-name()=‘U_TENANTDN‘]", null, userXML), ""));
Tenant_Account.setTenant_code("99");
Tenant_Account.setOrg_id(8);
Tenant_Account.setIs_default((short)0);
Tenant_Account.setStatus_sign((short)1);
try {
Tenant_Account.insert();
BSF.commitTransaction();
} catch (Exception e) {
e.printStackTrace();
BSF.abortTransaction();
return;
}finally {
if (userXML != 0){
Node.delete(userXML);
userXML = 0;
}
}
}
}
注意:在异常处理增加finally,用于处理清除NOM内存。“Node.delete(accountXML )”
5、使用Eclipse进行远程调试
-Xdebug
-Xnoagent
-Xrunjdwp:transport=dt_socket,server=y,address=8818,suspend=n
在Eclipse上配置调试
快速添加代码
6、调用外部Service
先建UDDI
7、调用外部Jar包,生成Webservices
要求代码中的方法写成static,可以发布成Webservice。由于时间紧迫,不等后续完成,先发布此文档,请关注后续,主要是解决使用MongoDB的解决方案。
8、整合SOAP,Java调用Soap
通过“Operation Test tools”工具测试,测试报文和结果如下:
<SOAP:Envelope xmlns:SOAP="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP:Body>
<GetNameByCode xmlns="http://schemas.cordys.com/XiaoywWSAppServerPackage" preserveSpace="no" qAccess="0" qValues="">
<v_code>manager</v_code>
</GetNameByCode>
</SOAP:Body>
</SOAP:Envelope>
通过Webservice方法调用SOAP代码如下:
import com.cordys.cpc.bsf.busobject.BSF;
import com.cordys.cpc.bsf.busobject.BusObjectConfig;
import com.cordys.cpc.bsf.busobject.BusObjectIterator;
import com.cordys.cpc.bsf.soap.SOAPRequestObject;
import com.eibus.xml.nom.Node;
import com.eibus.xml.xpath.XPath;
public static String getNameByCode(String v_code)
{
String[] paramNames = {"v_tenantcount"};
Object[] paramValues = {v_code};
String nameSpace = "http://schemas.cordys.com/XiaoywWSAppServerPackage";
String methodName = "GetC_UserObject";
SOAPRequestObject sro = new SOAPRequestObject(BSF.getOrganization(),nameSpace,methodName,paramNames,paramValues);
int response = 0;
String uname = null;
try{
response = sro.execute();
uname = Node.getData(XPath.getXPathInstance(".//U_TENANTNAME").firstMatch(response, null));
if (uname == null){
uname = "null";
}
} catch(Exception e) {
return e.getMessage();
} finally {
if (response !=0){
Node.delete(response);
response = 0;
}
}
// TODO implement body
return uname;
}
上文代码调用是前面开发的Webservices,方法是“GetC_UserObject”,命名空间“nameSpace”都在此方法请求报文中,如下图所示。
解析返回报文:
response = sro.execute();
uname = Node.getData(XPath.getXPathInstance(".//U_TENANTNAME").firstMatch(response, null));
草稿完成于2015年4月2日