隨筆-193  評(píng)論-715  文章-1  trackbacks-0
          B/S通常我們的權(quán)限控制包括以下幾個(gè)方面:1,Web層訪問權(quán)限控制(包括URL級(jí)或Button/Link級(jí));2,業(yè)務(wù)邏輯訪問控制,主要指業(yè)務(wù)邏輯中方法級(jí)的權(quán)限控制;3,數(shù)據(jù)訪問權(quán)限控制,主要指對(duì)Table, View的訪問控制,嚴(yán)格的控制會(huì)到Row級(jí),甚至是Field級(jí)。

          問題引入:
          我們通常的系統(tǒng)中僅僅做了Web層訪問權(quán)限控制,因?yàn)榇蠖嘞到y(tǒng)只有Web方式的UI做為人機(jī)交互的接口,不提供其它的客戶端,所以業(yè)務(wù)邏輯訪問控制一般可以不用控制,數(shù)據(jù)訪問方面由于一般系統(tǒng)的要求目前尚未達(dá)到這一權(quán)限控制的必要,也沒有完整的進(jìn)行控制。Web層的URL級(jí)控制通常采用J2EE規(guī)范中的Filter來解決,但由于JSF中的跳轉(zhuǎn)并不會(huì)重寫URL,默認(rèn)采用Forward的方式,一般不會(huì)采用Redirect的方式,而且采用Redirect的時(shí)候,開發(fā)時(shí)會(huì)很不方便,很多Request參數(shù)無法傳遞,所以我們實(shí)際上在Filter中獲得的URI往往都不是真實(shí)的地址。

          實(shí)際案例:
          我們現(xiàn)在有一個(gè)畫面,假如從菜單中進(jìn)入畫面的URI為“l(fā)ist.jsf”,畫面上有“新增”、“查詢”兩個(gè)Button,當(dāng)點(diǎn)擊“查詢”這個(gè)Button時(shí),查詢結(jié)果并顯示在“l(fā)ist.jsf”這個(gè)頁面上,當(dāng)點(diǎn)擊“新增”這個(gè)Button時(shí),跳轉(zhuǎn)到“add.jsf”這個(gè)頁面,新增畫面中還有一個(gè)“返回”Button。當(dāng)我們點(diǎn)擊“新增”時(shí),在Filter中得到的URI為“l(fā)ist.jsf”,實(shí)際上我們要跳轉(zhuǎn)到“add.jsf”這個(gè)頁面,當(dāng)我們點(diǎn)擊“返回”Button時(shí),F(xiàn)ilter中得到URI的是“add.jsf”,這與我們實(shí)際要跳轉(zhuǎn)到的頁面“l(fā)ist.jsf”又不符。如果我們僅僅在Filter中根據(jù)URI來判斷權(quán)限,那么當(dāng)一個(gè)用戶不具有新增權(quán)限時(shí),就會(huì)出現(xiàn)可以操作新增功能的事情,這樣便未達(dá)到權(quán)限控制的目的。

          問題解決:
          JSF提供了自定義Application的可能,通過研究JSF的實(shí)現(xiàn)可以發(fā)現(xiàn)JSF控制頁面的跳轉(zhuǎn)都是在NavigationHandler中完成的。那么我們來試著實(shí)現(xiàn)一個(gè)自己的NavigationHandler,解決這一問題。先給出詳細(xì)的實(shí)現(xiàn):
          ??1public?class?NavigationHandleWithAuthImpl?extends?NavigationHandler?{
          ??2
          ??3????/**
          ??4?????*?Field?DEBUGLOG.
          ??5?????*/

          ??6????private?static?final?Logger?DEBUGLOG?=?Logger.getLogger(Constant.LOG_DEBUG);
          ??7
          ??8????/**
          ??9?????*?Field?ERRORLOG.
          ?10?????*/

          ?11????private?static?final?Logger?ERRORLOG?=?Logger.getLogger(Constant.LOG_ERROR);
          ?12
          ?13????/**
          ?14?????*?Field?IGNORED_URI.
          ?15?????*/

          ?16????private?static?final?String?IGNORED_URI?=?"/login.faces;/send.faces;"
          ?17????????????+?"/mainlayout.faces;/backForward.faces";
          ?18
          ?19????/**
          ?20?????*?Application?associate?that?contains?navigation?mappings?loaded?from
          ?21?????*?configuration?file(s).
          ?22?????*/

          ?23????private?ApplicationAssociate?associate?=?null;
          ?24
          ?25????/**
          ?26?????*?This?constructor?uses?the?current?<code>Application</code>?instance?to
          ?27?????*?obtain?the?navigation?mappings?used?to?make?navigational?decisions.
          ?28?????*/

          ?29????public?NavigationHandleWithAuthImpl()?{
          ?30????????super();
          ?31????????if?(DEBUGLOG.isDebugEnabled())?{
          ?32????????????DEBUGLOG.debug("Created?NavigationHandler?instance?");
          ?33????????}

          ?34????????//?if?the?user?is?using?the?decorator?pattern,?this?would?cause
          ?35????????//?our?ApplicationAssociate?to?be?created,?if?it?isn't?already
          ?36????????//?created.
          ?37????????ApplicationFactory?aFactory?=?(ApplicationFactory)?FactoryFinder
          ?38????????????????.getFactory(FactoryFinder.APPLICATION_FACTORY);
          ?39????????aFactory.getApplication();
          ?40????????associate?=?ApplicationAssociate.getInstance(ConfigureListener
          ?41????????????????.getExternalContextDuringInitialize());
          ?42????}

          ?43
          ?44????/**
          ?45?????*?檢查URL權(quán)限
          ?46?????*?
          ?47?????*?@param?authList
          ?48?????*????????????List<FunctionVo>
          ?49?????*?@param?uri
          ?50?????*????????????String
          ?51?????*?@return?boolean
          ?52?????*/

          ?53????private?boolean?checkURL(List<FunctionVo>?authList,?String?uri)?{
          ?54????????if?(authList?==?null)?{
          ?55????????????return?false;
          ?56????????}

          ?57????????for?(FunctionVo?vo?:?authList)?{
          ?58????????????String?authUri?=?vo.getUrl();
          ?59????????????if?(authUri?!=?null?&&?!authUri.equals(""))?{
          ?60????????????????int?index?=?authUri.indexOf("?");
          ?61????????????????if?(index?>=?0)?{
          ?62????????????????????authUri?=?authUri.substring(0,?index);
          ?63????????????????}

          ?64????????????}

          ?65????????????if?(uri.equals("/"?+?authUri))?{
          ?66????????????????return?true;
          ?67????????????}

          ?68????????}

          ?69????????return?false;
          ?70????}

          ?71
          ?72????/**
          ?73?????*?Determine?the?next?view?based?on?the?current?view?
          ?74?????*?(<code>from-view-id</code>
          ?75?????*?stored?in?<code>FacesContext</code>),?<code>fromAction</code>?and
          ?76?????*?<code>outcome</code>.
          ?77?????*?
          ?78?????*?@param?context
          ?79?????*????????????The?<code>FacesContext</code>
          ?80?????*?@param?fromAction
          ?81?????*????????????the?action?reference?string
          ?82?????*?@param?outcome
          ?83?????*????????????the?outcome?string
          ?84?????*/

          ?85????public?void?handleNavigation(FacesContext?context,?String?fromAction,
          ?86????????????String?outcome)?{
          ?87????????if?(context?==?null)?{
          ?88????????????String?message?=?Util
          ?89????????????????????.getExceptionMessageString(Util.
          ?90????????????????????????????NULL_PARAMETERS_ERROR_MESSAGE_ID);
          ?91????????????message?=?message?+?"?context?"?+?context;
          ?92????????????throw?new?NullPointerException(message);
          ?93????????}

          ?94????????if?(outcome?==?null)?{
          ?95????????????if?(DEBUGLOG.isDebugEnabled())?{
          ?96????????????????DEBUGLOG.debug("No?navigation?rule?found?for?outcome?"
          ?97????????????????????????+?outcome?+?"and?viewId?"
          ?98????????????????????????+?context.getViewRoot().getViewId()
          ?99????????????????????????+?"?Explicitly?remain?on?the?current?view?");
          100????????????}

          101????????????return;?//?Explicitly?remain?on?the?current?view
          102????????}

          103????????CaseStruct?caseStruct?=?getViewId(context,?fromAction,?outcome);
          104????????ExternalContext?extContext?=?context.getExternalContext();
          105????????if?(caseStruct?!=?null)?{
          106????????????Object?obj?=?context.getExternalContext().getSessionMap().get(
          107????????????????????Constant.LOGIN_INFO_KEY);
          108????????????List?authList?=?null;
          109????????????if?(obj?!=?null)?{
          110????????????????authList?=?((LoginInfo)?obj).getAuthorityFunctionVoList();
          111????????????}

          112????????????String?uri?=?caseStruct.navCase.getToViewId().replace(".jsp",
          113????????????????????".faces");
          114????????????boolean?flag=true;
          115????????????if?(this.IGNORED_URI.indexOf(uri)?<?0)?{
          116????????????????if?(authList?!=?null?&&?!this.checkURL(authList,?uri))?{
          117????????????????????//?URI?is?invalid
          118????????????????????flag=false;
          119????????????????}

          120????????????}

          121
          122????????????ViewHandler?viewHandler?=?Util.getViewHandler(context);
          123????????????Util.doAssert(null?!=?viewHandler);
          124
          125????????????if?(caseStruct.navCase.hasRedirect())?{
          126????????????????//?perform?a?302?redirect.
          127????????????????String?newPath?=?viewHandler.getActionURL(context,
          128????????????????????????caseStruct.viewId);
          129
          130????????????????try?{
          131????????????????????if?(DEBUGLOG.isDebugEnabled())?{
          132????????????????????????DEBUGLOG.debug("Redirecting?to?path?"?+?newPath
          133????????????????????????????????+?"?for?outcome?"?+?outcome?+?"and?viewId?"
          134????????????????????????????????+?caseStruct.viewId);
          135????????????????????}

          136????????????????????extContext.redirect(newPath);
          137????????????????}
          ?catch?(java.io.IOException?ioe)?{
          138????????????????????String?message?=?"Redirect?to?"?+?newPath?+?"?failed.";
          139????????????????????ERRORLOG.error(message);
          140????????????????????throw?new?FacesException(message,?ioe);
          141????????????????}

          142????????????????context.responseComplete();
          143????????????????if?(DEBUGLOG.isDebugEnabled())?{
          144????????????????????DEBUGLOG
          145????????????????????????????.debug("Response?complete?for?"?
          146????????????????????????????????????+?caseStruct.viewId);
          147????????????????}

          148????????????}
          ?else?{
          149????????????????UIViewRoot?newRoot?=?null;
          150????????????????if?(flag)?{
          151????????????????????newRoot?=?viewHandler
          152????????????????????????.createView(context,?caseStruct.viewId);
          153????????????????}
          ?else?{
          154????????????????????newRoot?=?viewHandler.createView(context,
          155????????????????????????"/backForward.jsp");
          156????????????????}

          157????????????????context.setViewRoot(newRoot);
          158????????????????if?(DEBUGLOG.isDebugEnabled())?{
          159????????????????????DEBUGLOG.debug("Set?new?view?in?FacesContext?for?"
          160????????????????????????+?caseStruct.viewId);
          161????????????????}

          162????????????}

          163????????}

          164????}

          165
          166????/**
          167?????*?This?method?uses?helper?methods?to?determine?the?new?<code>view</code>
          168?????*?identifier.?Refer?to?section?7.4.2?of?the?specification?for?more?details.
          169?????*?
          170?????*?@param?context
          171?????*????????????The?Faces?Context
          172?????*?@param?fromAction
          173?????*????????????The?action?reference?string
          174?????*?@param?outcome
          175?????*????????????The?outcome?string
          176?????*?@return?The?<code>view</code>?identifier.
          177?????*/

          178????private?CaseStruct?getViewId(FacesContext?context,?String?fromAction,
          179????????????String?outcome)?{
          180????????//?String?nextViewId?=?null;
          181????????String?viewId?=?context.getViewRoot().getViewId();
          182????????CaseStruct?caseStruct?=?null;
          183
          184????????synchronized?(this)?{
          185????????????caseStruct?=?findExactMatch(viewId,?fromAction,?outcome);
          186
          187????????????if?(caseStruct?==?null)?{
          188????????????????caseStruct?=?findWildCardMatch(viewId,?fromAction,?outcome);
          189????????????}

          190
          191????????????if?(caseStruct?==?null)?{
          192????????????????caseStruct?=?findDefaultMatch(fromAction,?outcome);
          193????????????}

          194????????}

          195????????return?caseStruct;
          196????}

          197
          198????/**
          199?????*?This?method?finds?the?List?of?cases?for?the?current?<code>view</code>
          200?????*?identifier.?After?the?cases?are?found,?the?<code>from-action</code>?and
          201?????*?<code>from-outcome</code>?values?are?evaluated?to?determine?the?new
          202?????*?<code>view</code>?identifier.?Refer?to?section?7.4.2?of?the
          203?????*?specification?for?more?details.
          204?????*?
          205?????*?@param?viewId
          206?????*????????????The?current?<code>view</code>?identifier.
          207?????*?@param?fromAction
          208?????*????????????The?action?reference?string.
          209?????*?@param?outcome
          210?????*????????????The?outcome?string.
          211?????*?@return?The?<code>view</code>?identifier.
          212?????*/

          213
          214????private?synchronized?CaseStruct?findExactMatch(String?viewId,
          215????????????String?fromAction,?String?outcome)?{
          216????????//?String?returnViewId?=?null;
          217????????//?if?the?user?has?elected?to?replace?the?Application?instance
          218????????//?entirely
          219????????if?(null?==?associate)?{
          220????????????return?null;
          221????????}

          222????????Map?caseListMap?=?associate.getNavigationCaseListMappings();
          223????????Util.doAssert(null?!=?caseListMap);
          224????????List?caseList?=?(List)?caseListMap.get(viewId);
          225????????if?(caseList?==?null)?{
          226????????????return?null;
          227????????}

          228????????//?We've?found?an?exact?match?for?the?viewId.?Now?we?need?to?evaluate
          229????????//?from-action/outcome?in?the?following?order:
          230????????//?1)?elements?specifying?both?from-action?and?from-outcome
          231????????//?2)?elements?specifying?only?from-outcome
          232????????//?3)?elements?specifying?only?from-action
          233????????//?4)?elements?where?both?from-action?and?from-outcome?are?null
          234????????return?determineViewFromActionOutcome(caseList,?fromAction,?outcome);
          235????}

          236
          237????/**
          238?????*?This?method?traverses?the?wild?card?match?List?(containing
          239?????*?<code>from-view-id</code>?strings?and?finds?the?List?of?cases?for?each
          240?????*?<code>from-view-id</code>?string.?Refer?to?section?7.4.2?of?the
          241?????*?specification?for?more?details.
          242?????*?
          243?????*?@param?viewId
          244?????*????????????The?current?<code>view</code>?identifier.
          245?????*?@param?fromAction
          246?????*????????????The?action?reference?string.
          247?????*?@param?outcome
          248?????*????????????The?outcome?string.
          249?????*?@return?The?<code>view</code>?identifier.
          250?????*/

          251????private?synchronized?CaseStruct?findWildCardMatch(String?viewId,
          252????????????String?fromAction,?String?outcome)?{
          253????????CaseStruct?result?=?null;
          254
          255????????//?if?the?user?has?elected?to?replace?the?Application?instance
          256????????//?entirely
          257????????if?(null?==?associate)?{
          258????????????return?null;
          259????????}

          260
          261????????Map?caseListMap?=?associate.getNavigationCaseListMappings();
          262????????Util.doAssert(null?!=?caseListMap);
          263????????TreeSet?wildcardMatchList?=?associate.getNavigationWildCardList();
          264????????Util.doAssert(null?!=?wildcardMatchList);
          265
          266????????Iterator?iter?=?wildcardMatchList.iterator();
          267????????String?fromViewId;
          268????????List?caseList;
          269????????String?wcFromViewId?=?null;
          270????????while?(iter.hasNext())?{
          271????????????fromViewId?=?(String)?iter.next();
          272????????????//?See?if?the?entire?wildcard?string?(without?the?trailing?"*"?is
          273????????????//?contained?in?the?incoming?viewId.?Ex:?/foobar?is?contained?with
          274????????????//?/foobarbaz
          275????????????//?If?so,?then?we?have?found?our?largest?pattern?match..
          276????????????//?If?not,?then?continue?on?to?the?next?case;
          277
          278????????????if?(viewId.indexOf(fromViewId,?0)?==?-1)?{
          279????????????????continue;
          280????????????}

          281????????????//?Append?the?trailing?"*"?so?we?can?do?our?map?lookup;
          282????????????wcFromViewId?=?fromViewId?+?"*";
          283????????????caseList?=?(List)?caseListMap.get(wcFromViewId);
          284
          285????????????if?(caseList?==?null)?{
          286????????????????return?null;
          287????????????}

          288
          289????????????//?If?we've?found?a?match,?then?we?need?to?evaluate
          290????????????//?from-action/outcome?in?the?following?order:
          291????????????//?1)?elements?specifying?both?from-action?and?from-outcome
          292????????????//?2)?elements?specifying?only?from-outcome
          293????????????//?3)?elements?specifying?only?from-action
          294????????????//?4)?elements?where?both?from-action?and?from-outcome?are?null
          295
          296????????????result?=?determineViewFromActionOutcome(caseList,?fromAction,
          297????????????????????outcome);
          298????????????if?(result?!=?null)?{
          299????????????????break;
          300????????????}

          301????????}

          302????????return?result;
          303????}

          304
          305????/**
          306?????*?This?method?will?extract?the?cases?for?which?a?<code>from-view-id</code>
          307?????*?is?an?asterisk?"*".?Refer?to?section?7.4.2?of?the?specification?for?more
          308?????*?details.
          309?????*?
          310?????*?@param?fromAction
          311?????*????????????The?action?reference?string.
          312?????*?@param?outcome
          313?????*????????????The?outcome?string.
          314?????*?@return?The?<code>view</code>?identifier.
          315?????*/

          316
          317????private?synchronized?CaseStruct?findDefaultMatch(String?fromAction,
          318????????????String?outcome)?{
          319????????//?String?returnViewId?=?null;
          320????????//?if?the?user?has?elected?to?replace?the?Application?instance
          321????????//?entirely
          322????????if?(null?==?associate)?{
          323????????????return?null;
          324????????}

          325
          326????????Map?caseListMap?=?associate.getNavigationCaseListMappings();
          327????????Util.doAssert(null?!=?caseListMap);
          328
          329????????List?caseList?=?(List)?caseListMap.get("*");
          330
          331????????if?(caseList?==?null)?{
          332????????????return?null;
          333????????}

          334
          335????????//?We?need?to?evaluate?from-action/outcome?in?the?follow
          336????????//?order:?1)elements?specifying?both?from-action?and?from-outcome
          337????????//?2)?elements?specifying?only?from-outcome
          338????????//?3)?elements?specifying?only?from-action
          339????????//?4)?elements?where?both?from-action?and?from-outcome?are?null
          340
          341????????return?determineViewFromActionOutcome(caseList,?fromAction,?outcome);
          342????}

          343
          344????/**
          345?????*?This?method?will?attempt?to?find?the?<code>view</code>?identifier?based
          346?????*?on?action?reference?and?outcome.?Refer?to?section?7.4.2?of?the
          347?????*?specification?for?more?details.
          348?????*?
          349?????*?@param?caseList
          350?????*????????????The?list?of?navigation?cases.
          351?????*?@param?fromAction
          352?????*????????????The?action?reference?string.
          353?????*?@param?outcome
          354?????*????????????The?outcome?string.
          355?????*?@return?The?<code>view</code>?identifier.
          356?????*/

          357????private?synchronized?CaseStruct?determineViewFromActionOutcome(
          358????????????List?caseList,?String?fromAction,?String?outcome)?{
          359
          360????????String?cncFromAction?=?null;
          361????????String?fromOutcome?=?null;
          362????????String?toViewId?=?null;
          363????????CaseStruct?result?=?new?CaseStruct();
          364????????int?size=caseList.size();
          365????????ConfigNavigationCase?cnc?=?null;
          366????????for?(int?i?=?0;?i?<?size;?i++)?{
          367????????????cnc?=?(ConfigNavigationCase)?caseList.get(i);
          368????????????cncFromAction?=?cnc.getFromAction();
          369????????????fromOutcome?=?cnc.getFromOutcome();
          370????????????toViewId?=?cnc.getToViewId();
          371????????????if?((cncFromAction?!=?null)?&&?(fromOutcome?!=?null))?{
          372????????????????if?((cncFromAction.equals(fromAction))
          373????????????????????????&&?(fromOutcome.equals(outcome)))?{
          374????????????????????result.viewId?=?toViewId;
          375????????????????????result.navCase?=?cnc;
          376????????????????????return?result;
          377????????????????}

          378????????????}

          379????????}

          380????????for?(int?i?=?0;?i?<?size;?i++)?{
          381????????????cnc?=?(ConfigNavigationCase)?caseList.get(i);
          382????????????cncFromAction?=?cnc.getFromAction();
          383????????????fromOutcome?=?cnc.getFromOutcome();
          384????????????toViewId?=?cnc.getToViewId();
          385????????????if?((cncFromAction?==?null)?&&?(fromOutcome?!=?null))?{
          386????????????????if?(fromOutcome.equals(outcome))?{
          387????????????????????result.viewId?=?toViewId;
          388????????????????????result.navCase?=?cnc;
          389????????????????????return?result;
          390????????????????}

          391????????????}

          392????????}

          393
          394????????for?(int?i?=?0;?i?<?size;?i++)?{
          395????????????cnc?=?(ConfigNavigationCase)?caseList.get(i);
          396????????????cncFromAction?=?cnc.getFromAction();
          397????????????fromOutcome?=?cnc.getFromOutcome();
          398????????????toViewId?=?cnc.getToViewId();
          399????????????if?((cncFromAction?!=?null)?&&?(fromOutcome?==?null))?{
          400????????????????if?(cncFromAction.equals(fromAction))?{
          401????????????????????result.viewId?=?toViewId;
          402????????????????????result.navCase?=?cnc;
          403????????????????????return?result;
          404????????????????}

          405????????????}

          406????????}

          407
          408????????for?(int?i?=?0;?i?<?size;?i++)?{
          409????????????cnc?=?(ConfigNavigationCase)?caseList.get(i);
          410????????????cncFromAction?=?cnc.getFromAction();
          411????????????fromOutcome?=?cnc.getFromOutcome();
          412????????????toViewId?=?cnc.getToViewId();
          413????????????if?((cncFromAction?==?null)?&&?(fromOutcome?==?null))?{
          414????????????????result.viewId?=?toViewId;
          415????????????????result.navCase?=?cnc;
          416????????????????return?result;
          417????????????}

          418????????}

          419
          420????????return?null;
          421????}

          422
          423????/**
          424?????*?@author?robin
          425?????*/

          426????class?CaseStruct?{
          427
          428????????/**
          429?????????*?Field?viewId.
          430?????????*/

          431????????protected?String?viewId;
          432
          433????????/**
          434?????????*?Field?navCase.
          435?????????*/

          436????????protected?ConfigNavigationCase?navCase;
          437????}

          438
          439}

          440

          來看看其中的關(guān)鍵部分,149行起:
          UIViewRoot?newRoot?=?null;
          if?(flag)?{?????
          ?????
          //當(dāng)檢查URL通過時(shí),使用CaseStruct,即faces-config.xml中的配置跳轉(zhuǎn)
          ????newRoot?=?viewHandler
          ????????.createView(context,?caseStruct.viewId);
          }
          ?else?{??????
          ????
          //未通過URL檢查時(shí),直接到權(quán)限不足頁面或你指定的頁面
          ????newRoot?=?viewHandler.createView(context,
          ????????
          "/backForward.jsp");
          }

          context.setViewRoot(newRoot);

          當(dāng)然別忘了在faces-config.xml中加入自定義Application Navigation的配置,如下:
          ?1<faces-config>
          ?2????<application>
          ?3????????<navigation-handler?id="navigationWithAuth">
          ?4????????????com.***.framework.NavigationHandleWithAuthImpl
          ?5????????</navigation-handler>
          ?6????</application>
          ?7
          ?8
          ?9
          10
          11</faces-config>


          注意:
          在NavigationHandler中,當(dāng)發(fā)現(xiàn)檢查URL權(quán)限未能通過時(shí),千萬不要直接去修改當(dāng)前的那個(gè)CaseStruts,因?yàn)镴SF自己會(huì)緩存整個(gè)跳轉(zhuǎn)的配置,以提高執(zhí)行效率,請(qǐng)使用viewHandler.createView()來創(chuàng)建一個(gè)新CaseStruts,否則會(huì)發(fā)生跳轉(zhuǎn)不正常的情況。
          posted on 2007-10-16 14:07 Robin's Programming World 閱讀(8699) 評(píng)論(6)  編輯  收藏 所屬分類: Java

          評(píng)論:
          # re: JSF深入--控制跳轉(zhuǎn) 2007-10-16 14:39 | cooky
          你好! 為什么不用飯否呢?
          just an advice :)  回復(fù)  更多評(píng)論
            
          # re: JSF深入--控制跳轉(zhuǎn) 2007-10-16 15:11 | Robin's Java World
          @cooky
          飯否?
          什么意思?沒明白。  回復(fù)  更多評(píng)論
            
          # re: JSF深入--控制跳轉(zhuǎn) 2007-10-16 17:46 | Robin's Java World
          @cooky
          明白了。飯否也還不錯(cuò)。呵呵!  回復(fù)  更多評(píng)論
            
          # re: JSF深入--控制跳轉(zhuǎn) 2007-10-17 12:56 | Alexander.Yu
          一個(gè)跳轉(zhuǎn)就要寫500多行...暈倒.  回復(fù)  更多評(píng)論
            
          # re: JSF深入--控制跳轉(zhuǎn) 2007-10-18 12:05 | Robin's Java World
          @Alexander.Yu
          其實(shí)這是參照J(rèn)SF官方實(shí)現(xiàn)來做的,大部分代碼都是原來的官方的代碼,沒有改動(dòng),只是改了記LOG的方式和一些關(guān)鍵的部分。
            回復(fù)  更多評(píng)論
            
          # re: JSF深入--控制跳轉(zhuǎn) 2008-04-01 18:05 | gembin
          關(guān)注JSF  回復(fù)  更多評(píng)論
            
          主站蜘蛛池模板: 兴文县| 新竹市| 呼伦贝尔市| 微山县| 五指山市| 阆中市| 射洪县| 哈尔滨市| 怀来县| 温泉县| 黄大仙区| 洮南市| 长葛市| 富阳市| 清镇市| 城固县| 吐鲁番市| 葫芦岛市| 定结县| 吕梁市| 遂平县| 涞源县| 隆化县| 绥德县| 永善县| 大港区| 宕昌县| 琼海市| 南澳县| 驻马店市| 商丘市| 清徐县| 贞丰县| 牡丹江市| 天祝| 蚌埠市| 衡阳市| 克东县| 正阳县| 高雄市| 永和县|