當(dāng)柳上原的風(fēng)吹向天際的時(shí)候...

          真正的快樂(lè)來(lái)源于創(chuàng)造

            BlogJava :: 首頁(yè) :: 聯(lián)系 :: 聚合  :: 管理
            368 Posts :: 1 Stories :: 201 Comments :: 0 Trackbacks
          在交易系統(tǒng)的C/S體系中,C只負(fù)責(zé)數(shù)據(jù)的輸入和顯示,相當(dāng)于MVC中的View部分,S負(fù)責(zé)數(shù)據(jù)的操作和持久化,兩者是通過(guò)WebService進(jìn)行聯(lián)系的,具體來(lái)說(shuō)聯(lián)系的方式是這樣:C端將指定S端負(fù)責(zé)處理的Service類(lèi)名,具體負(fù)責(zé)處理的函數(shù)名和函數(shù)的參數(shù)打包成一個(gè)XML傳送到S端,S端解析后通過(guò)反射找到具體的函數(shù)進(jìn)行處理,處理的結(jié)果會(huì)轉(zhuǎn)化成XML形式的字符串傳回。這就是設(shè)計(jì)梗概一中提到的內(nèi)容。

          如果這個(gè)過(guò)程交給負(fù)責(zé)具體業(yè)務(wù)的程序員自行完成的話(huà),那無(wú)疑會(huì)給系統(tǒng)帶來(lái)許多混亂和無(wú)序,程序員也無(wú)法將主要精力集中在業(yè)務(wù)上;另外,他們也無(wú)需了解每個(gè)細(xì)節(jié)是怎么完成的,他們真正需要的是框架提供好的接口,知道怎么調(diào)用取得結(jié)果就可以了。他們希望最好能像調(diào)用普通函數(shù)一樣調(diào)用S中的方法并取得想要的結(jié)果,舉例來(lái)說(shuō),如果客戶(hù)端需要查詢(xún)姓名以H開(kāi)頭的所有雇員,他們只需調(diào)用一個(gè)search函數(shù)就能得到查詢(xún)出來(lái)的雇員集合,中間發(fā)生的組裝請(qǐng)求XML,WebService調(diào)用,業(yè)務(wù)處理,從數(shù)據(jù)庫(kù)查詢(xún)數(shù)據(jù),將數(shù)據(jù)轉(zhuǎn)為XML傳回和在客戶(hù)端解析傳回的XML再變成領(lǐng)域?qū)ο蠹系榷紤?yīng)該由框架來(lái)完成。這并不過(guò)分,而是很合理的需求,就像RMI曾經(jīng)就是這樣做的。

          那么,客戶(hù)端與服務(wù)器端的交互會(huì)有幾種形式呢,從業(yè)務(wù)上來(lái)說(shuō)無(wú)外乎下面五種形式:
          1.調(diào)用S端的一個(gè)函數(shù),只想知道這個(gè)函數(shù)是否正確運(yùn)行了。典型例子如對(duì)象的刪除操作。
          2.調(diào)用S端的一個(gè)函數(shù),想得到函數(shù)執(zhí)行后返回的一個(gè)對(duì)象。典型例子如對(duì)象的添加操作,用戶(hù)需要取回添加好的對(duì)象的ID。
          3.調(diào)用S端的一個(gè)函數(shù),想得到返回對(duì)象的集合列表。典型例子如對(duì)象的查詢(xún)。
          4.調(diào)用S端的一個(gè)函數(shù),想得到分頁(yè)后的某一頁(yè)對(duì)象集合。典型例子如分頁(yè)查詢(xún)。
          5.調(diào)用S端的一個(gè)函數(shù),只想得到一個(gè)字符串。典型例子如改變一種商品的目錄,得到某種商品的介紹文字等。
          框架需要做的,就是把這五種形式做成通用的函數(shù)提供給負(fù)責(zé)業(yè)務(wù)的程序員,讓他們僅需要這五個(gè)函數(shù)就能完成與WebService服務(wù)器的交互。這五種形式以第二種最為典型,也最為基礎(chǔ),完成了它其它的就可以依樣畫(huà)葫蘆,下面請(qǐng)看具體過(guò)程:

          首先,規(guī)定具體函數(shù)的形制為
          public static BaseDomainObj fetchObject(String url,String serviceName,String mothodName,String[] args,Class<?> cls);
          公有靜態(tài)自不必說(shuō),BaseDomainObj是客戶(hù)端領(lǐng)域?qū)ο蟮幕?lèi),fetchObject是函數(shù)名,接下來(lái)是四個(gè)參數(shù),前三個(gè)分別是WebService所在URL,服務(wù)器上服務(wù)類(lèi)注冊(cè)在Spring上下文中的beanName,服務(wù)類(lèi)具體的方法名,最后一個(gè)是取得對(duì)象的類(lèi)型,在函數(shù)體中,會(huì)根據(jù)類(lèi)型用反射生成一個(gè)實(shí)例,再通過(guò)實(shí)例的FromXML方法給實(shí)例的屬性賦值,完成后就得到了負(fù)責(zé)業(yè)務(wù)的程序員想要的結(jié)果。

          其次,fetchObject內(nèi)部需要做的事情有:
          1.將serviceName,mothodName,args三項(xiàng)組合成一段XML文本。此項(xiàng)工作由WSRequest類(lèi)完成。
          2.向位于url上的WebService服務(wù)器端發(fā)起請(qǐng)求,獲得返回的文本。此項(xiàng)工作由WSInvoker類(lèi)來(lái)完成。
          3.將返回的文本轉(zhuǎn)化出來(lái),這一步是要檢測(cè)服務(wù)器端函數(shù)執(zhí)行是否順暢,有無(wú)拋出異常等。因?yàn)榉?wù)器端如果發(fā)生異常是無(wú)法通過(guò)WebService傳回的,只能變成文本后回傳,那么客戶(hù)端就需要解析一次,有問(wèn)題就報(bào)出來(lái),沒(méi)問(wèn)題再往下走。這一步是堅(jiān)決不能忽視的。
          4.通過(guò)反射得到對(duì)象,此時(shí)對(duì)象的屬性還是原始狀態(tài),需要再通過(guò)反射注入相應(yīng)的值,最后,客戶(hù)端需要的對(duì)象就產(chǎn)生了。

          具體的過(guò)程請(qǐng)參考下面的代碼:
          /**
           * 調(diào)用遠(yuǎn)程WebService端,將返回的XML轉(zhuǎn)化為一個(gè)對(duì)象,最終返回.這種調(diào)用的典型例子是getById,add等
           * 
          @param url WebService所在URL
           * 
          @param serviceName 服務(wù)名,此名在appCtx.xml中定義
           * 
          @param mothodName 方法名
           * 
          @param args 方法的參數(shù)
           * 
          @param cls 要返回的對(duì)象類(lèi)型
           * 
          @return
           
          */
          public static BaseDomainObj fetchObject(String url,String serviceName,String mothodName,String[] args,Class<?> cls){
              
          // 得到客戶(hù)端請(qǐng)求XML文本
              WSRequest request=new WSRequest(serviceName,mothodName,args);
              String requestXML
          =request.toXML();
              logger.info(
          "準(zhǔn)備向位于'"+url+"'發(fā)送的請(qǐng)求XML為'"+requestXML+"'.");
              
              
          try{
                  
          // 調(diào)用遠(yuǎn)端WebService上的方法,得到返回的XML文本
                  WSInvoker invoker=new WSInvoker(url);
                  String responseXML
          =invoker.getResponseXML(requestXML);
                  logger.info(
          "得到位于'"+url+"'響應(yīng)XML為'"+responseXML+"'.");
                  
                  
          // 轉(zhuǎn)化響應(yīng)
                  WSResponse response=new WSResponse(responseXML);
                  logger.info(response);
                  
                  
          // 如果在調(diào)用過(guò)程中如通不過(guò)檢測(cè)而被中斷的話(huà)
                  if(response.isBreaked()){
                      String errTxt
          ="遠(yuǎn)程方法被中斷,具體原因是"+response.getRemark();
                      logger.error(errTxt);
                      
          throw new WSBreakException(errTxt+".(WSE05)");
                  }
                  
                  
          // 如果在調(diào)用過(guò)程中出現(xiàn)異常的話(huà)
                  if(response.hasException()){
                      String errTxt
          ="調(diào)用遠(yuǎn)程方法返回了異常,具體信息是"+response.getRemark();
                      logger.error(errTxt);
                      
          throw new WSException(errTxt+".(WSE04)");
                  }
                  
                  
          try{
                      
          // 通過(guò)反射得到對(duì)象
                      BaseDomainObj obj= (BaseDomainObj)cls.newInstance();
                      
                      
          // 通過(guò)反射得到方法
                      Method method = cls.getMethod("fromXML"new Class[] {String.class});
                      
                      
          // 通過(guò)反射調(diào)用對(duì)象的方法
                      method.invoke(obj, new Object[] {response.getMethodResonseXML()});
                      
                      
          return obj;
                  }
                  
          catch(Exception ex){
                      String errTxt
          ="無(wú)法將"+response.getMethodResonseXML()+"轉(zhuǎn)化為"+cls.getName()+"對(duì)象.(WSE06)";
                      logger.error(errTxt);
                      
          throw new WSException(errTxt);
                  }
              }
              
          catch(MalformedURLException e){
                  String errTxt
          ="無(wú)法調(diào)用'"+url+"'上的服務(wù),因?yàn)樗腔蔚?(WSE01)";
                  logger.error(errTxt);    
                  
          throw new WSException(errTxt);
              }
              
          catch(XFireRuntimeException e){
                  String errTxt
          ="無(wú)法調(diào)用'"+url+"'上的服務(wù).(WSE02)";
                  logger.error(errTxt);    
                  
          throw new WSException(errTxt);
              }
              
          catch(DocumentException e){
                  String errTxt
          ="無(wú)法解析從服務(wù)器端'"+url+"'返回的XML文本.(WSE03)";
                  logger.error(errTxt);    
                  
          throw new WSException(errTxt);
              }
          }


          我們?cè)倏纯赐ㄟ^(guò)關(guān)鍵的注入屬性值的fromXML函數(shù)做了些什么:
          public void fromXML(String xml) throws DocumentException{
              Document doc
          =DocumentHelper.parseText(xml);        
              
              Element root
          =doc.getRootElement();        
              List
          <Element> elms=root.elements();
              
              
          for(Element elm:elms){
                  
          try {
                      
          // 借助于BeanUtils,給對(duì)象的屬性賦值
                      BeanUtils.setProperty(this,elm.getName(),elm.getText());
                  } 
          catch (IllegalAccessException e) {
                      e.printStackTrace();
                  } 
          catch (InvocationTargetException e) {
                      e.printStackTrace();
                  }
              }
          }


          最后,我們可以看看負(fù)責(zé)業(yè)務(wù)的程序員需要書(shū)寫(xiě)的代碼示例:
          public Tmp add(String name,String age,String salary,String picture){
              String url
          =CommonUtil.WebService_Url;
              String serviceName
          ="TmpService";
              String methodName
          ="add";
              String[] args
          =new String[]{name,age,salary,picture};
              
              
          try{
                  
          return (Tmp)WSUtil.fetchObject(url, serviceName, methodName, args, Tmp.class);
              }
              
          catch(WSBreakException ex){
                  DlgUtil.popupWarningDialog(ex.getMessage());
              }
              
          catch(WSException ex){
                  DlgUtil.popupErrorDialog(ex.getMessage());
              }
              
              
          return null;
          }


          小結(jié):
          一.負(fù)責(zé)業(yè)務(wù)程序員不需要了解的細(xì)節(jié),框架應(yīng)該將它們隱藏起來(lái)。
          二.負(fù)責(zé)業(yè)務(wù)程序員需要了解的接口,框架應(yīng)該使它們盡量簡(jiǎn)單。
          三.框架能做到的,就不該再讓負(fù)責(zé)業(yè)務(wù)的程序員再重復(fù)的發(fā)明車(chē)輪。
          posted on 2010-05-21 00:18 何楊 閱讀(199) 評(píng)論(0)  編輯  收藏

          只有注冊(cè)用戶(hù)登錄后才能發(fā)表評(píng)論。


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 祥云县| 会东县| 罗山县| 宜川县| 海城市| 馆陶县| 泸水县| 玉山县| 甘德县| 壶关县| 宁德市| 龙口市| 兴安县| 镇远县| 石屏县| 宜君县| 开阳县| 会泽县| 普宁市| 尉氏县| 霍邱县| 隆林| 洛隆县| 聊城市| 民县| 历史| 远安县| 恭城| 乐业县| 唐海县| 莱西市| 肃宁县| 蓬溪县| 汾西县| 晋江市| 昌邑市| 重庆市| 安西县| 托克托县| 东山县| 浦城县|