国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

Petstore源碼追蹤記(3)-商業邏輯處理(五)

2019-11-18 16:21:43
字體:
來源:轉載
供稿:網友

  Web tier
當使用者輸入http://localhost:8080/petstore/customer.do,MainServlet接收到
Request,轉到doPRocess()函數:

private void doProcess(HttpServletRequest request, HttpServletResponse response)
                   throws IOException, ServletException {
    // set the locale of the user to default if not set
    if (request.getsession().getAttribute(WebKeys.LOCALE) == null) {
       request.getSession().setAttribute(WebKeys.LOCALE, defaultLocale);
    }
    try {
       getRequestProcessor().processRequest(request);
//進行轉導動作(forward)              
getScreenFlowManager().forwardToNextScreen(request,response);
    } catch (Throwable ex) {
       String className = ex.getClass().getName();
       String nextScreen = getScreenFlowManager().getExceptionScreen(ex);
       // put the exception in the request
       request.setAttribute("javax.servlet.jsp.jspException", ex);
       if (nextScreen == null) {
          // send to general error screen
          ex.printStackTrace();
          throw new ServletException("MainServlet: unknown exception: " +
className);
       }
          context.getRequestDispatcher(nextScreen).forward(request, response);
    }

}
請開啟
Petstore_home/src/waf/src/controller/com/sun/j2ee/blueprints/waf/controller/web/flow/ScreenFlowManager.java
,在約112列可找到forwardToNextScreen()函數:

public void forwardToNextScreen(HttpServletRequest request, HttpServletResponse 
response) throws java.io.IOException, FlowHandlerException,
javax.servlet.ServletException {
      // set the presious screen
      String fullURL = request.getRequestURI();
      // get the screen name
      String selectedURL = defaultScreen;
      int lastPathSeparator = fullURL.lastIndexOf("/") + 1;
      if (lastPathSeparator != -1) {
          selectedURL = fullURL.substring(lastPathSeparator, fullURL.length());
      }
      //請加入偵察碼,以本例來說,selectedURL=customer.do
      System.out.println("selectURL="+ selectedURL);
      String currentScreen = "";
      URLMapping urlMapping = getURLMapping(selectedURL);
      if (urlMapping != null) {
            if (!urlMapping.useFlowHandler()) {
                currentScreen = urlMapping.getScreen();
        //請加入偵察碼,以本例來說,currentScreen =customer.screen
                System.out.println("currentScreen="+currentScreen);
            } else {
                // load the flow handler
                FlowHandler handler = null;
                String flowHandlerString = urlMapping.getFlowHandler();
                try {
                    handler = (FlowHandler)getClass().getClassLoader()
                       .loadClass(flowHandlerString).newInstance();
                    // invoke the processFlow(HttpServletRequest)
                    handler.doStart(request);
                    String flowResult = handler.processFlow(request);
                    handler.doEnd(request);
                    currentScreen = urlMapping.getResultScreen(flowResult);
                    // if there were no screens by the id then assume that the
result was
                    //the screen itself
                    if (currentScreen == null) currentScreen = flowResult;
               } catch (Exception ex) {
                   System.err.println("ScreenFlowManager caught loading
handler: " + ex);
               }
            }
        }
        if (currentScreen == null) {
            System.err.println("ScreenFlowManager: Screen not found for " +
selectedURL);
            throw new RuntimeException("Screen not found for " + selectedURL);
        }
        //進行轉導動作(forward)
        System.out.println("forward to "+ currentScreen);
        context.getRequestDispatcher("/" + currentScreen).forward(request,
response);

}

我們知道它會轉導至customer.screen,從screendefinitions_en_US.xml,可找到對應各畫面區塊:

<screen name="customer">
  <parameter key="title" value="Customer" direct="true"/>
  <parameter key="banner" value="/banner.jsp" />
  <parameter key="sidebar" value="/sidebar.jsp" />
  <parameter key="body" value="/customer.jsp" />
  <parameter key="mylist" value="/mylist.jsp" />
  <parameter key="footer" value="/footer.jsp" />
</screen>


其實大部份與main.screen都相同,唯一差異部份就是主體區塊(body),開啟
customer.jsp瞧它的內容,位置在Petstore_home/src/apps/petstore/src/docroot
,在約50列:

<table cellpadding="5" cellspacing="0" width="100%" border="0">
<tr>
<td colspan="3"><p class="petstore_title">Contact Information</p></td>
</tr>
<tr>
<td class="petstore_form" align="right"><b>First Name</b></td>

<td class="petstore_form" align="left"
colspan="2"><c:out value="${customer.account.contactInfo.givenName}"/></td>
</tr>
以下略...

以上程序代碼作用要將使用者名稱(First Name)顯示出現,它利用JSTL Tags要
資料打印出來,可是問題來了,資料是如何得來的?答案就是本文前頭所提到的四個隱形角色之一-SignOnNotifier Attribute Listener。


SignOnNotifier
請讀者回想前頭所提,當使用者身分驗證成功后,SignOnFilter會將SIGNED_ON_USER對應變量設定真值(true),存入Session:

hreq.getSession().setAttribute(SIGNED_ON_USER, new Boolean(true));

此時便會觸發SignOnNotifier,請開啟:
Petstore_home/src/apps/petstore/src/com/sun/j2ee/blueprints/petstore/controller/web/SignOnNotifier.java
,在約89列:

/**
 * Process an attribute added
 *屬性新增后
 */
public void attributeAdded(HttpSessionBindingEvent se) {
   processEvent(se);
}

/**
* Process the update
*屬性覆蓋后
*/
public void attributeReplaced(HttpSessionBindingEvent se) {
   processEvent(se);
}

private void processEvent(HttpSessionBindingEvent se) {
   HttpSession session = se.getSession();
   String name = se.getName();

   /* check if the value matches the signon attribute
   * if a macth fire off an event to the ejb tier that the user
   * has signed on and load the account for the user
   */
   //判別新增或覆蓋屬性為”SIGNED_ON_USER”則進行處理,否則略過
   if (name.equals(SignOnFilter.SIGNED_ON_USER)) {
      boolean aSignOn  = ((Boolean)se.getValue()).booleanValue();
      if (aSignOn) {
          String userName =
(String)session.getAttribute(SignOnFilter.USER_NAME);
//請加入偵察碼
System.out.println("SignOnNotifier() userName="+userName);
          // look up the model manager and webclient controller
          PetstoreComponentManager sl =
(PetstoreComponentManager)session.getAttribute(PetstoreKeys.COMPONENT_MANAGER);
          WebController wc =  sl.getWebController(session);
          SignOnEvent soe = new SignOnEvent(userName);
          // set the EJBAction on the Event
          EventMapping em = getEventMapping(session.getServletContext(), soe);
          if (em != null) {
             soe.setEJBActionClassName(em.getEJBActionClassName());
System.out.println("EJBActionClassName="+
   em.getEJBActionClassName());
          }

          try {
             //更新資料時會用到,以本例來說只需讀取,所以沒有作用
             wc.handleEvent(soe, session);
          } catch (EventException e) {
             System.err.println("SignOnNotifier Error handling event " + e);
          }
          //取得Customer EJB Local Interface Reference
          CustomerLocal customer =  sl.getCustomer(session);
          // ensure the customer object is put in the session
          //將Customer EJB Local Interface存入Session
          if (session.getAttribute(PetstoreKeys.CUSTOMER) == null) {
             session.setAttribute(PetstoreKeys.CUSTOMER, customer);
          }
          // set the language to the preferred language and other preferences
          ProfileLocal profile = sl.getCustomer(session).getProfile();
          Locale locale =
I18nUtil.getLocaleFromString(profile.getPreferredLanguage());
          session.setAttribute(PetstoreKeys.LOCALE, locale);
      }
   }
}
以下略...

     SignOnNotifier會透過PetstoreComponentManager取得ShoppingClientFacade
reference,ShoppingClientFacade是Petstore在EJB tier的代理接口,Web tier所
有Request均需透過它來存取所需資料,這個Design Pattern的好處是可以降低EJB tier與Web tier間的藕合性,將商業邏輯集中控管在EJB tier。


PetstoreComponentManager,源碼
D:/petstore1.3.1/src/apps/petstore/src/com/sun/j2ee/blueprints/petstore/controller/web/ 
PetstoreComponentManager.java,約110列:

public CustomerLocal  getCustomer(HttpSession session) {
   ShoppingControllerLocal scEjb = getShoppingController(session);
   try {
   //取得ShoppingClientFacade reference
      ShoppingClientFacadeLocal scf = scEjb.getShoppingClientFacade();
      //scf.setUserId(userId);
      //取得CustomerLocal reference
      return scf.getCustomer();
   } catch (FinderException e) {
      System.err.println("PetstoreComponentManager finder error: " + e);
   } catch (Exception e) {
      System.err.println("PetstoreComponentManager error: " + e);
   }
  return null;
}

ShoppingClientFacadeLocalEJB為Session Bean,源碼在
D:/petstore1.3.1/src/apps/petstore/src/com/sun/j2ee/blueprints/petstore/controller/ejb/
ShoppingClientFacadeLocalEJB.java,約101列:

/*
* Asume that the customer userId has been set
*/
public CustomerLocal getCustomer() throws FinderException {
   //請加入偵察碼
   System.out.println("ShoppingClientFacadeLocalEJB.getCustomer()");
   if (userId == null) {
      throw new GeneralFailureException("ShoppingClientFacade: failed to look
up name of customer: userId is not set" );
   }
   try {
       ServiceLocator sl = new ServiceLocator();
       CustomerLocalHome home =(CustomerLocalHome)
           sl.getLocalHome(JNDINames.CUSTOMER_EJBHOME);
       customer = home.findByPrimaryKey(userId);
    } catch (ServiceLocatorException slx) {
       throw new GeneralFailureException("ShoppingClientFacade: failed to look
up name of customer: caught " + slx);
    }
    return customer;
}

CustomerEJB為Entity Bean,它與AccountEJB有一對一關系,AccountEJB也與ContactInfoEJB有一對一關系,三者皆為Entity Bean,直接對應資料庫資料表CustomerEJBTable, AccountEJBTable, ContactInfoEJBTable,源碼在D:/petstore1.3.1/src/components/customer/src/com/sun/j2ee/blueprints/customer/
目錄下,因Entity Bean無特別之處,故不再說明。

圖24 Entity Beans間的關系(Relation)

所以<c:out value="${customer.account.contactInfo.givenName}"/>即是從
Session取出CustomerLocal,再透過CMR字段(即前面所提關系)取得最底層givenName字段顯示出來。


將程序重新編譯及部署,可得如下預期結果:

圖25 SignOnNotifier取得CustomerLocal

結語

筆者將整個使用者基本數據瀏覽流程做一總整理,繪制成合作圖,幫助讀者更容易了解:

圖25 使用者基本資料瀏覽合作圖

1.使用者進入首頁。
2.點選右上角Account連結(customer.do),欲進入使用者基本資料瀏覽畫面,
Request中途被SignOnNotifier攔截。
3.SignOnFilter讀取signon-config.xml設定。
4. SignOnFilter依據signon-config.xml設定,發現customer.do是受保護的資源,
且使用者尚未進行登入動作,所以轉導至signon.screen畫面。
5.使用者輸入帳號及密碼,按”Sumit”后,Request再度被SignOnFilter攔截,透過SignOnEJB Session Bean進行驗證。
6.SignOnEJB Session Bean透過UserEJB比對密碼是否正確。
7.密碼驗證無誤后,會在Session寫入使用者已登入標記,此時會觸發SignOnNotifier。8.SignOnNotifier透過PetstoreComponentManager,
PetstoreComponentManager是Petstore在Web tier的接口。SignOnNotifier經過
后面9至13步驟取得CustomerEJB對應CustomerLocal,并存入Session。
9.PetstoreComponentManager透過ShoppingControllerEJB,ShoppingControllerEJB是Petstore在EJB tier的接口。
10.ShoppingControllerEJB透過ShoppingClientFacadeEJB,ShoppingClientFacadeEJB是Petstore在EJB tier關于前端購物所有功能統一提供接口。
11.ShoppingClientFacadeEJB取得CustomerEJB Entity Bean,CustomerEJB代表
CustomerEJBTable資料表。
12.CustomerEJB Entity Bean對AccountEJB Entity Bean有一對一關系,AccountEJB代表AccountEJBTable資料表。
13. AccountEJB Entity Bean對ContactInfoEJB Entity Bean有一對一關系,
ContactInfoEJB代表ContactInfoEJBTable資料表。
14.SignOnFilter在第7步驟驗證無誤后,則將Request(customer.do)放行。
15.Request(customer.do)由MainServlet接收,MainServlet負責處理*.do的Request。
16.MainServlet讀取mappings.xml相關設定,找出customer.do所對應的web action class(在web tier欲執行工作,以本例來說,只有瀏覽,所以沒有對應的工作)及screen(結果呈現畫面)。
17.MainServlet將screen交給ScreenFlowManager,它負責轉導工作。
18. screen對應值為customer.screen,所以轉導至customer.screen。

     寫到這里筆者已經快昏了!第一次寫這么長的文章,不過還是要強打精神
做個Endding,由這三期探討Petstore架構,一個完整的J2EE framework已然成形,在J2EE所提到的大部份技術幾乎都用上了,也見到了各種技術該如何整合
運用,這就是所謂的Design Pattern,也許讀者會想這樣的架構能不能直接套用
在我們實際要開發的項目上?當然是可以,不過在Web tier的架構已有更完整
、更套裝化的framework出現,就是struts,網址在http://jakarta.apache.org/struts/index.Html
,它是Apache Jakarta下的一個子項目(Jakarta最有名的子項目就是Tomcat),一個免費且會持續升級的framework,目前是當紅炸子雞,它整個架構與Petstore類似,只是它提的solution只在Web tier,筆者建議可運用struts來開發我們的項目,當我們已了解Petstore的架構,學習struts必能事半功倍,且能補上struts在EJB tier缺乏的framework。若讀者有任何問題或意見歡迎與筆者討論,E-Mail:senshaw@ms4.hinet.net。

注1:Petstore_home代表您的Petstore安裝目錄。
注2:deploytool的開啟方式及將pestore.ear加載deploytool請參閱本系列第一篇文章。
注3:DAO產生過程與本系列第二篇CatalogDAO產生方式相似,筆者不再贅述。
注4:讀者若想觀察cloudscape數據庫中相關資料表,筆者在此提供一個方法,可利用JBuilder之Database Pilot來觀察:
a.請開啟JBuilder,點選menu bar之”Tools” > “Enterprise Setup”,請選擇”
Database Drivers”頁,按”add”鈕,請新增一個library將cloudscape相關jar文件,位置在j2ee安裝目錄/lib/cloudscape下三個檔案選進來后按”ok”鈕,此時JBuilder會要求您重新激活JBuiler,將JBuilder關閉。
b.開啟Database Pilot,點選menu bar之”File” > “New”,會出現一窗口要您輸入
Driver及URL,請依下列值輸入:
Driver:COM.cloudscape.core.RmiJdbcDriver
URL:jdbc:cloudscape:rmi:PetStoreDB;create=true
c.點選左半邊增加出來的URL,點選兩下會要求您輸入username及passWord
直接略過按”ok”,會發現所有資料表都出現啦!

d.Database Pilot詳細操作請參考JBuiler相關文件。


bill-轉自:csdn

(出處:http://m.survivalescaperooms.com)



發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 婺源县| 吉安县| 泊头市| 布拖县| 台北市| 搜索| 禄劝| 兴仁县| 宝兴县| 武邑县| 德庆县| 文成县| 高清| 杨浦区| 衡阳市| 玉树县| 青海省| 玉屏| 景德镇市| 兴化市| 金门县| 瓦房店市| 庆安县| 万荣县| 平邑县| 明水县| 广丰县| 苏尼特右旗| 霸州市| 沛县| 泸溪县| 彰化市| 永丰县| 北票市| 关岭| 博罗县| 个旧市| 安国市| 宁乡县| 静海县| 余干县|