Cordys BOP 4平臺開發入門實戰演練——Webservices開發(高階)

肖永威發表於2015-04-02

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)新增依賴類包


         注:滑鼠選中“xiaoywWSAppServerPackage”(上圖中樹狀目錄com下的Jar包),再滑鼠右鍵彈出“WS-AppServer Java Archive Definiton”視窗。

        (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日


相關文章