Cordys BOP 4平台开发入门实战演练——Webservices开发(2)

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日


郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。