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

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

          實際案例:
          我們現在有一個畫面,假如從菜單中進入畫面的URI為“list.jsf”,畫面上有“新增”、“查詢”兩個Button,當點擊“查詢”這個Button時,查詢結果并顯示在“list.jsf”這個頁面上,當點擊“新增”這個Button時,跳轉到“add.jsf”這個頁面,新增畫面中還有一個“返回”Button。當我們點擊“新增”時,在Filter中得到的URI為“list.jsf”,實際上我們要跳轉到“add.jsf”這個頁面,當我們點擊“返回”Button時,Filter中得到URI的是“add.jsf”,這與我們實際要跳轉到的頁面“list.jsf”又不符。如果我們僅僅在Filter中根據URI來判斷權限,那么當一個用戶不具有新增權限時,就會出現可以操作新增功能的事情,這樣便未達到權限控制的目的。

          問題解決:
          JSF提供了自定義Application的可能,通過研究JSF的實現可以發現JSF控制頁面的跳轉都是在NavigationHandler中完成的。那么我們來試著實現一個自己的NavigationHandler,解決這一問題。先給出詳細的實現:
          ??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權限
          ?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

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

          context.setViewRoot(newRoot);

          當然別忘了在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中,當發現檢查URL權限未能通過時,千萬不要直接去修改當前的那個CaseStruts,因為JSF自己會緩存整個跳轉的配置,以提高執行效率,請使用viewHandler.createView()來創建一個新CaseStruts,否則會發生跳轉不正常的情況。
          posted on 2007-10-16 14:07 Robin's Programming World 閱讀(8697) 評論(6)  編輯  收藏 所屬分類: Java

          評論:
          # re: JSF深入--控制跳轉 2007-10-16 14:39 | cooky
          你好! 為什么不用飯否呢?
          just an advice :)  回復  更多評論
            
          # re: JSF深入--控制跳轉 2007-10-16 15:11 | Robin's Java World
          @cooky
          飯否?
          什么意思?沒明白。  回復  更多評論
            
          # re: JSF深入--控制跳轉 2007-10-16 17:46 | Robin's Java World
          @cooky
          明白了。飯否也還不錯。呵呵!  回復  更多評論
            
          # re: JSF深入--控制跳轉 2007-10-17 12:56 | Alexander.Yu
          一個跳轉就要寫500多行...暈倒.  回復  更多評論
            
          # re: JSF深入--控制跳轉 2007-10-18 12:05 | Robin's Java World
          @Alexander.Yu
          其實這是參照JSF官方實現來做的,大部分代碼都是原來的官方的代碼,沒有改動,只是改了記LOG的方式和一些關鍵的部分。
            回復  更多評論
            
          # re: JSF深入--控制跳轉 2008-04-01 18:05 | gembin
          關注JSF  回復  更多評論
            
          主站蜘蛛池模板: 苍溪县| 鲁山县| 河西区| 布尔津县| 土默特左旗| 姜堰市| 申扎县| 枣阳市| 寿阳县| 辉南县| 腾冲县| 香格里拉县| 涞源县| 朔州市| 江阴市| 大同市| 育儿| 大姚县| 佛冈县| 武汉市| 萍乡市| 峨边| 通道| 乡城县| 清镇市| 上饶县| 扎赉特旗| 陵川县| 新丰县| 克山县| 崇左市| 乌拉特后旗| 永年县| 东明县| 岐山县| 略阳县| 迭部县| 龙海市| 商水县| 永川市| 独山县|