Petstore原始碼追蹤記(3)-商業邏輯處理(二) (轉)

worldblog發表於2007-12-15
Petstore原始碼追蹤記(3)-商業邏輯處理(二) (轉)[@more@]使用者基本資料瀏覽流程
=======================
現在讓我們進入主題-Petstore商業邏輯,筆者以使用者基本資料瀏覽流程為例,請啟用cloudscape:
cloudscape –start

圖1 啟用資料庫

接著啟用RI Application Server(應用):
–verbose

圖2 啟用RI

Petstore啟用無誤後,請開啟,輸入
">

圖3 進入Petstore系統

進入系統看到那大大的鸚鵡頭,請點選右上角的”Account”連結,
進入使用者登入流程:

圖4 Petstore首頁

我們會看到登入畫面,直接使用預設的使用者(j2ee)及密碼(j2ee),
點選”Sign In”鈕:

圖5 登入畫面

看到以下顯示個人資訊畫面就表示我們已登入成功啦!


圖6 個人資訊畫面

若此時我們按瀏覽器之”上一頁”鈕返回首頁:


圖7 再返回首頁

再按右上角”Account”連結,會發現畫面直接跳至個人資訊畫面:

圖8 個人資訊畫面

  請注意圖4 Petstore首頁畫面左下角出現的

URL:http://localhost:8080/petstore/customer.do,它其實就是圖6個人資訊畫面,但系統並沒有直接從圖4跳至圖6,而先換成圖5登入畫面,要求我們做登入動作,輸入帳號及密碼,驗證成功後才跳至圖6;若是再次從首頁進入個人資訊,系統並不會再次要求登入,在這裡有兩個重點要提:
1.SignOnFilter:若使用者進入的頁面是受到保護的,則系統會先將畫面轉至登入畫面,要求登入。
2.customer.do:它代表的是一個動作加一個畫面的組合,以本例來說,從資料庫讀取個人資訊,組成完整HTML畫面顯示。

SignOnFilter
  筆者將使用者進入使用者基本資料瀏覽畫面的流程分為三個階段:
1.使用者欲進入使用者基本資料瀏覽畫面(customer.do),因未登入過,被SignOnFilter攔截,轉至登入畫面(signon.screen)。
2.使用者輸入帳號及密碼按”sumit”後,再度由SignOnFilter攔截,SignOnFilter亦負責帳號、密碼檢核工作,確認無誤後,則將網頁轉導(forward)至第一階段使用者欲進入之使用者基本資料瀏覽畫面(customer.do)。
3.重複第一階段動作,SignOnFilter檢查使用者已登入過,放行轉導至使用者基本資料瀏覽畫面(customer.do)。

第一階段
欲觀察 Filter,先要了解它的影響範圍,請開啟deploytool(注2),滑鼠點選PetstoreWAR,選擇右邊Filter Map頁,會發現此Filter的影響範圍是所有網頁。

圖9 Filter影響範圍

也可在.看到設定,請參考前面敘述,接下來請開啟SignOnFilter.
,它的原始碼位置在
Petstore_homesrccomponentssignonsrccomsunj2eeblueprintssignonwebSignOnFilter.java

先看SignOnFilter初始動作,約在87列:
public void init(FilterConfig config) throws ServletException {
  this.config = config;
  URL protectedResURL = null;
  try {
  //謮取signon-config.xml
  protectedResourcesURL =
config.getServletContext().getResource("/WEB-INF/signon-config.xml");
  SignOnDAO dao = new SignOnDAO(protectedResourcesURL);
  //讀取登入失敗畫面(signon_error.screen)
  signOnErrorPage = dao.getSignOnErrorPage();
  //讀取登入畫面(signon.screen)
  signOnPage = dao.getSignOnPage();
  //讀取所有欲保護畫面,組成HashMap
  protectedResources = dao.getProtectedResources();
  } catch (java.MalformedURLException ex) {
  System.err.println("SignonFilter: malformed URL exception: " + ex);
  }
}

它在初始化時會先讀取
Petstore_homesrcappspetstoresrcdocWEB-INFsignon-config.xml
,並組成Data Access (DAO),以方便後續存取(注3),此xml檔案主
要功用記錄登入畫面、登入失敗畫面及所有需登入才能使用的畫面之URL,以下是signon-config.xml片段:


<!-- FoSign On Page(登入畫面)--&gt

  signon.screen

<!-- Error Page When Sign On fails(登入失敗畫面)--&gt

  signon_error.screen


<!-- A Protected Resource--&gt

 
  Customer Screen
  customer.screen
 



<!-- A Protected Resource(本例之保護畫面)--&gt

 
  Customer Action
  customer.do
 



接著請看SignOnFilter實際運作的主要函式doFilter(),約在107列:

public  void doFilter(ServletRequest request, ServletResponse  response,
FilterChain chain)  throws IOException, ServletException {
  HttpServletRequest hreq = (HttpServletRequest)request;
  String currentURI = hreq.getRequestURL().toString();
  String currentURL = hreq.getRequestURI();
  // get everything after the context root
  int firstSlash = currentURL.indexOf("/",1); // jump past the starting slash
  String targetURL = null;
  //取得使用者欲前往之URL,以本例來說,即是customer.do
  if (firstSlash != -1) targetURL = currentURL.substring(firstSlash + 1,
currentURL.length());
  //判斷使用者從登入畫面(signon.screen)進行驗證工作
   
  if ((targetURL != null) && targetURL.equals(FORM_SIGNON_URL)) {
  validateSignOn(request, response, chain);
  // jump out of this method
  return;
  }

  // check if the user is signed on
  //檢查使用者是否登入過,從Session取出登入標記,作為判斷之用
  boolean signedOn = false;
  if (hreq.getSession().getAttribute(SIGNED_ON_USER) != null) {
  signedOn
=((Boolean)hreq.getSession().getAttribute(SIGNED_ON_USER)).booleanValue();
  } else {
  hreq.getSession().setAttribute(SIGNED_ON_USER, new Boolean(false));
  }
  // jump to the resource if signed on
  //若已登入過,則結束此Filter工作,進入Filter chain,以本例來說,它為Filter chain中最後一個Filter,所以就是不做任何事,讓使用者進入他的目的畫面
  if (signedOn) {
  chain.doFilter(request,response);
  return;
  }
  // find out if the patterns match the target URL
  //將使用者欲前往之URL與所有保護畫面URL做比對,若符合則匯入登入畫面
(signon.screen)
  Iterator it = protectedResources.keySet().iterator();
  while (it.hasNext()) {
  String protectedName = (String)it.next();
  ProtectedResource resource  =
(ProtectedResource)protectedResources.get(protectedName);
  String urlPattern = resource.getURLPattern();

  // now check agains the targetURL
  //若符合則將目的URL存入Session,並轉導至登入畫面,結束Filter工作
  if (urlPattern.equals(targetURL)) {
  // put the orginal url in the session so others can access
  hreq.getSession().setAttribute(ORIGINAL_URL,  targetURL);
  config.getServletContext().getRequestDispatcher("/" +
signOnPage).forward(request, response);
  // Jump out of the filter and go to the next page
  return;
  }
  }
  // No matches if we made it to here
  chain.doFilter(request,response);
}

SignOnFilter先取得使用者的目的URL(customer.do),判斷使用者並未登入,開始比對目的URL是否在保護畫面中,發現customer.do為保護畫面,將customer.do此目的URL存入Session,將request轉導至登入畫面(signon.screen),要求使用者進行登入動作。


第一階段驗證
口說無憑,我們可加入偵察程式程式碼來驗證程式是否如筆者所述般執行,
請在SignOnFilter.init()加入兩行程式:
public void init(FilterConfig config) throws ServletException {
  this.config = config;
  URL protectedResourcesURL = null;
  try {
  //謮取signon-config.xml
  protectedResourcesURL =
config.getServletContext().getResource("/WEB-INF/signon-config.xml");
  SignOnDAO dao = new SignOnDAO(protectedResourcesURL);
  //讀取登入失敗畫面(signon_error.screen)
  signOnErrorPage = dao.getSignOnErrorPage();
  //讀取登入畫面(signon.screen)
  signOnPage = dao.getSignOnPage();
  //請加入偵察程式程式碼
    System.out.println("signOnPage="+signOnPage);
    System.out.println("signErrorPage="+signOnErrorPage);
  //讀取所有欲保護畫面,組成HashMap
  protectedResources = dao.getProtectedResources();
  } catch (java.net.MalformedURLException ex) {
  System.err.println("SignonFilter: malformed URL exception: " + ex);
  }
}

doFilter()亦加入偵察程式程式碼:

public  void doFilter(ServletRequest request, ServletResponse  response,
FilterChain chain)  throws IOException, ServletException {
  HttpServletRequest hreq = (HttpServletRequest)request;
  String currentURI = hreq.getRequestURL().toString();
  String currentURL = hreq.getRequestURI();
  // get everything after the context root
  int firstSlash = currentURL.indexOf("/",1); // jump past the starting slash
  String targetURL = null;
  //取得使用者欲前往之URL,以本例來說,即是customer.do
  if (firstSlash != -1) targetURL = currentURL.substring(firstSlash + 1,
currentURL.length());
  //請加入偵察程式程式碼
  System.out.println("targetURL="+targetURL);
  //判斷使用者從登入畫面(signon.screen)進行驗證工作
  if ((targetURL != null) && targetURL.equals(FORM_SIGNON_URL)) {
  validateSignOn(request, response, chain);
  // jump out of this method
  return;
  }

  // check if the user is signed on
  //檢查使用者是否登入過,從Session取出登入標記,作為判斷之用
  boolean signedOn = false;
  if (hreq.getSession().getAttribute(SIGNED_ON_USER) != null) {
  signedOn
=((Boolean)hreq.getSession().getAttribute(SIGNED_ON_USER)).booleanValue();
  } else {
  hreq.getSession().setAttribute(SIGNED_ON_USER, new Boolean(false));
  }
  // jump to the resource if signed on
  //若已登入過,則結束此Filter工作,進入Filter chain,以本例來說,它為
Filter chain中最後一個Filter,所以就是不做任何事,讓使用者進入他的目的畫面
  if (signedOn) {
  chain.doFilter(request,response);
  return;
  }
  // find out if the patterns match the target URL
  //將使用者欲前往之URL與所有保護畫面URL做比對,若符合則匯入登入畫面
(signon.screen)
  Iterator it = protectedResources.keySet().iterator();
  while (it.hasNext()) {
  String protectedName = (String)it.next();
  ProtectedResource resource  =
(ProtectedResource)protectedResources.get(protectedName);
  String urlPattern = resource.getURLPattern();

  // now check agains the targetURL
  //若符合則將目的URL存入Session,並轉導至登入畫面,結束Filter工作
  if (urlPattern.equals(targetURL)) {
       //請加入偵察程式程式碼
       System.out.println("URL Matched! urlPattern="+urlPattern);
  // put the orginal url in the session so others can access
  hreq.getSession().setAttribute(ORIGINAL_URL,  targetURL);
  config.getServletContext().getRequestDispatcher("/" +
signOnPage).forward(request, response);
  // Jump out of the filter and go to the next page
  return;
  }
  }
  // No matches if we made it to here
  chain.doFilter(request,response);
}

接著請重新編譯及部署新的程式程式碼,在命令下:切換至Petstore_home srcsappspetstoresrc目錄如:cd D:petstore1.3.1srcwebservicesappspetstoresrc

重新編譯程式
如:build all



來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-993965/,如需轉載,請註明出處,否則將追究法律責任。

相關文章