空間站

          北極心空

            BlogJava :: 首頁 :: 聯系 :: 聚合  :: 管理
            15 Posts :: 393 Stories :: 160 Comments :: 0 Trackbacks

          Restlet是一個Java下的輕量級REST框架。通過擁抱RESTREST是一種Web架構風格)它模糊了Web站點和Web服務之間的界限,從而幫助開發人員構建Web應用。每一個主要的REST概念(REST concept)都有一個對應的Java類。你的REST化的Web設計和你的代碼之間的映射是非常簡單直接的。

          為什么有必要創建另一種框架?難道Servlet API還不夠好用嗎?

          Servlet AIP1998年發布,從那個時候起它的核心設計一直沒有很大的變化。它是Java EE的眾多API中最成功的一個,但是它的幾個設計缺陷和一些限制損害了它。舉個例子,URI模式和它的處理者(handler)之間的映射是受限制的,而且其配置都集中在一個配置文件中。還有,它把socket流的控制直接交給了應用系統開發人員,Servlet容器阻礙了我們充分使用NIO特性對IO操作進行優化。另一個主要問題就是Servlet API鼓勵應用開發者在應用或者用戶會話級別直接將session狀態保存于內存中,盡管這看上去不錯,但它造成了Servlet容器擴展性和高可用性的主要問題。為了克服這些問題,就必須實現復雜的負載均衡session復制、持久化機制。這導致了可擴展性必然成為災難。

          如何看待別的框架中對REST的支持(例如Axis2,或者CXF/XFire)?

          這些支持非常有效,但是作用非常有限。我的主要觀點是設計這些項目是為了符合WS-*/SOAP Stack,它們與REST世界并不非常契合。在REST世界里,定義了一個全新的范例:面向資源的設計,而非通過遠程方法調用這樣的范例。例如Axis2僅僅支持GETPOST兩種HTTP方法,它需要遠程方法的傳遞需要一個URI參數。這在REST中式不允許的,這種做法也不能被稱之為REST化。XFire1.2不支持REST,但是它發布了一個項目用于將POJO映射到REST化的Web服務。這有點類似最近發布的JSR-311,此JSR試圖基于一套annotation和助手類標準化這種映射。

          REST與HTTP協議

          REST軟件架構是由Roy Thomas Fielding博士在2000年首次提出的。他為我們描繪了開發基于互聯網網絡軟件的藍圖。REST軟件架構是一個抽象的概念,是一種為了實現這一互聯網的超媒體分布式系統的行動指南。利用任何的技術都可以實現這種理念。而實現這一軟件架構最著名的就是HTTP協議。通常我們把REST也寫作為REST/HTTP,在實際中往往把REST理解為基于HTTP的REST軟件架構,或者更進一步把REST和HTTP看作為等同的概念。今天,HTTP是互聯網上應用最廣泛的計算機協議。HTTP不是一個簡單的運載數據的協議,而是一個具有豐富內涵的網絡軟件的協議。它不僅僅能夠對于互聯網資源進行唯一定位,而且還能告訴我們對于該資源進行怎樣運作。這也是REST軟件架構當中最重要的兩個理念。而REST軟件架構理念是真正理解HTTP協議而形成的。有了REST軟件架構理念出現,才使得軟件業避免了對HTTP協議的片面理解。只有正確的理論指導,才能避免在軟件開發的實際工作過程中少走彎路。

          REST與URI(資源定位)
          REST軟件架構之所以是一個超媒體系統,是因為它可以把網絡上所有資源進行唯一的定位,不管你的文件是圖片、文件Word還是
          視頻文件,也不管你的文件是txt文件格式、xml文件格式還是其它文本文件格式。它利用支持HTTP的TCP/IP協議來確定互聯網上的資源。

          REST與CRUD原則
          REST軟件架構遵循了CRUD原則,該原則告訴我們對于資源(包括網絡資源)只需要四種行為:創建(Create)、獲取(Read)、更新(Update)和銷毀(DELETE)就可以完成對其操作和處理了。其實世界萬物都是遵循這一規律:生、變、見、滅。所以計算機世界也不例外。這個原則是源自于我們對于數據庫表的數據操作:insert(生)、select(見)、update(變)和delete(滅),所以有時候CRUD也寫作為RUDI,其中的I就是insert。這四個操作是一種原子操作,即一種無法再分的操作,通過它們可以構造復雜的操作過程,正如數學上四則運算是數字的最基本的運算一樣。
           
          REST與網絡服務
          盡管在Java語言世界中網絡服務目前是以SOAP技術為主,但是REST將是是網絡服務的另一選擇,并且是真正意義上的網絡服務。基于REST思想的網絡服務不久的將來也會成為是網絡服務的主流技術。REST不僅僅把HTTP作為自己的數據運輸協議,而且也作為直接進行數據處理的工具。而當前的網絡服務技術都需要使用其它手段來完成數據處理工作,它們完全獨立于HTTP協議來進行的,這樣增加了大量的復雜軟件架構設計工作。REST的思想充分利用了現有的HTTP技術的網絡能力。在德國電視臺上曾經出現過一個這樣的五十萬歐元智力題:如何實現網絡服務才能充分利用現有的HTTP協議?該問題給出了四個答案:去問微軟;WSDL2.0/SOAP1.2;WS-Transfer;根本沒有。這個問題告訴我們HTTP并不是一個簡單的數據傳來傳去的協議,而是一個聰明的會表現自己的協議,這也許是REST = Representational State Transfer的真正含義。實際上目前很多大公司已經采用了REST技術作為網絡服務,如Google、Amazon等。在Java語言中重要的兩個以SOAP技術開始的網絡服務框架XFire和Axis也把REST作為自己的另一種選擇。它們的新的項目分別是
          Apache CXFAxis2。Java語言也制定關于REST網絡服務規范:JAX-RS: Java API for RESTful Web Services (JSR 311)。相信還會出現更多與REST相關的激動人心的信息。

          REST與AJAX技術
          盡管AJAX技術的出現才不到兩年時間,但是AJAX技術遵循了REST的一些重要原則。AJAX技術充分利用了HTTP來獲取網絡資源并且實現了HTTP沒有的對于異步數據進行傳輸的功能。AJAX技術還使得軟件更好地實現分布性功能,在一個企業內只要一個人下載了AJAX引擎,其它企業內部的人員,就可以共享該資源了。AJAX技術遵守REST準則的應用程序中簡單和可伸縮的架構,凡是采用AJAX技術的頁面簡潔而又豐富,一個頁面表現了豐富多彩的形態。AJAX技術還使用了一種不同于XML格式的JSON文件格式,這個意義在哪里呢?在REST軟件架構下我們不能對于XML文件進行序列化處理,這樣程序員必須要使用自己的XML綁定框架。而以序列化的JavaScript對象為基礎的JSON已經獲得了廣泛認可,它被認為能以遠比XML更好的方式來序列化和傳輸簡單數據結構,而且它更簡潔。這對REST是一個極大貢獻和補充。當前的網絡應用軟件還違背了REST的“無狀態
          服務器”約束。REST服務器只知道自己的狀態。REST不關心客戶端的狀態,客戶端的狀態自己來管理,這是AJAX技術的應用之地。通過AJAX技術,可以發揮有狀態網絡客戶機的優勢。而REST的服務器關心的是從所有網絡客戶端發送到服務器操作的順序。這樣使得互聯網這樣一個巨大的網絡得到有序的管理。

          REST與Rails框架
          Ruby on Rails框架(簡稱Rails或者Rails框架)是一個基于Ruby語言的越來越流行的網絡應用軟件開發框架。它提供了關于REST最好的支持,也是當今應用REST最成功的一個軟件開發框架。Rails框架(從版本1.2.x起)成為了第一個引入REST作為核心思想的主流網絡軟件開發框架。在Rails框架的充分利用了REST軟件架構之后,人們更加堅信REST的重要性和必要性。Rails利用REST軟件架構思想對網絡服務也提供了一流的支持。從最直觀的角度看待REST,它是網絡服務最理想的手段,但是Rails框架把REST帶到了網絡應用軟件開發框架。這是一次飛躍,讓REST的思想從網絡服務的應用提升到了網絡應用軟件開發。利用REST思想的simply_restful插件已經成為了Rails框架的核心內容。

          REST
          安全
          我們把現有基于SOAP的網絡服務和基于REST/HTTP網絡服務作個比喻,前者是一種傳統的寄信方式,而后者是現代網絡的電子郵件方式。要是是寄信和電子郵件都有病毒存在的話,傳統的寄信被送到對方就很危險,而電子郵件是開發的,電子郵件供應商比如Google為我們檢查了電子郵件是否有病毒。這里并不是說明SOAP網絡服務消息包含義病毒,而是說明HTTP是無法處理SOAP信息包究竟好不好,需要額外的軟件工具
          解決這一問題,包括防火墻也用不上和管不了。

          REST/HTTP網絡服務的信息包可以被防火墻理解和控制。你可以按照操作和鏈接進行過濾信息包,如你可以規定從外部來的只能讀取(GET操作)自己服務器的資源。這樣對于系統管理員而言使得軟件管理更為簡單。REST的安全性還可以利用傳輸安全協議SSL/TLS、基本和摘要式認證(Basic und Digest Authentication)。除了這些REST自身的安全性功能外,還可以利用像基于信息的Web Services Security(JSR 155)作為REST不錯的補充。

          Restlet第一步:

          這篇文章讓你在10分鐘內嘗試簡單的Restlet框架。告訴你如何創建一個說“hello, world”的Resource。
          1.我需要什么?
          2.“hello, world”應用
          3.在Servlet容器中運行
          4.作為一個單獨的Java應用運行
          5.結尾

          1.我需要什么?
          我們假設你已經有了一個可以馬上使用的開發環境,并且你已經安裝了JRE1.5(或更高)。如果你還沒有下載Restlet,請選擇最新的
          Restlet Framework 1.0發行版。

          2.“hello, world”
          程序
          讓我們從REST應用的核心---資源開始入手。下面的代碼是這個程序涉及的唯一資源。拷貝/粘貼代碼到“HelloWorldResource”類中。

          Java代碼

          01packagefirstSteps;
          02
          03importorg.restlet.Context;
          04importorg.restlet.data.MediaType;
          05importorg.restlet.data.Request;
          06importorg.restlet.data.Response;
          07importorg.restlet.resource.Representation;
          08importorg.restlet.resource.Resource;
          09importorg.restlet.resource.StringRepresentation;
          10importorg.restlet.resource.Variant;
          11
          12/**
          13* Resource which has only one representation.
          14*
          15*/
          16publicclassHelloWorldResourceextendsResource {
          17
          18publicHelloWorldResource(Context context, Request request,
          19 Response response) {
          20super(context, request, response);
          21
          22// This representation has only one type of representation.
          23 getVariants().add(newVariant(MediaType.TEXT_PLAIN));
          24 }
          25
          26/**
          27* Returns a full representation for a given variant.
          28*/
          29 @Override
          30publicRepresentation getRepresentation(Variant variant) {
          31 Representation representation =newStringRepresentation(
          32 "hello, world", MediaType.TEXT_PLAIN);
          33returnrepresentation;
          34 }
          35 }

          然后創建應用例子。我們創建名為“FirstStepsApplication”的類并拷貝/粘貼下面的代碼:

          01packagefirstSteps;
          02
          03importorg.restlet.Application;
          04importorg.restlet.Context;
          05importorg.restlet.Restlet;
          06importorg.restlet.Router;
          07
          08publicclassFirstStepsApplicationextendsApplication {
          09
          10publicFirstStepsApplication(Context parentContext) {
          11super(parentContext);
          12 }
          13
          14/**
          15* Creates a root Restlet that will receive all incoming calls.
          16*/
          17 @Override
          18publicsynchronizedRestlet createRoot() {
          19// Create a router Restlet that routes each call to a
          20// new instance of HelloWorldResource.
          21 Router router =newRouter(getContext());
          22
          23// Defines only one route
          24 router.attachDefault(HelloWorldResource.class);
          25
          26returnrouter;
          27 }
          28 }

          3.在Servlet容器中運行
          你可能更熟悉Servlets,我們建議你在你喜歡的Servlet容器里運行Restlet應用。像往常一樣創建一個新的Servlet應用,把下面列出的jar包放入lib目錄。
          org.restlet.jar
          com.noelios.restlet.jar
          com.noelios.restlet.ext.servlet_2.4.jar
          然后按下面的配置修改“web.xml”配置文件:

          01 <?xml version="1.0" encoding="UTF-8"?>
          02<web-appid="WebApp_ID" version="2.4"
          03 xmlns="
          http://java.sun.com/xml/ns/j2ee"
          04 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          05 xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
          06http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
          07<display-name>first steps servlet</display-name>
          08<!-- Application class name -->
          09<context-param>
          10<param-name>org.restlet.application</param-name>
          11<param-value>
          12 firstSteps.FirstStepsApplication
          13</param-value>
          14</context-param>
          15
          16<!-- Restlet adapter -->
          17<servlet>
          18<servlet-name>RestletServlet</servlet-name>
          19<servlet-class>
          20 com.noelios.restlet.ext.servlet.ServerServlet
          21</servlet-class>
          22</servlet>
          23
          24<!-- Catch all requests -->
          25<servlet-mapping>
          26<servlet-name>RestletServlet</servlet-name>
          27<url-pattern>/*</url-pattern>
          28</servlet-mapping>
          29</web-app>

          最后,將程序打包成一個war文件,例如“firstStepsServlet.war”,并部署到你的Servlet容器里。啟動Servlet容器后,打開你喜歡的瀏覽器,輸入URL:“http://<你的服務器名>:<端口號>/firstStepsServlet”。服務器將很高興地用“hello, world”歡迎你。

          4.作為一個單獨的Java應用運行
          Restlet應用并不是只能運行在Servlet容器里,也可以使用下面幾個Jar包所為一個獨立應用運行:
          org.restlet.jar
          com.noelios.restlet.jar
          com.noelios.restlet.ext.simple.jar
          org.simpleframework.jar
          如果你想要理解后面兩個Jar包的意義,你可以參考連接器(
          http://www.restlet.org/documentation/1.0/connectors)。
          創建一個主類,拷貝/粘貼下面的代碼。建立一個新的HTTP服務器監聽端口8182并委托所有的請求給“FirstStepsApplication”。

          代碼:

          01packagefirstSteps;
          02importorg.restlet.Component;
          03importorg.restlet.data.Protocol;
          04
          05publicclassFirstStepsMain {
          06
          07publicstaticvoidmain(String[] args) {
          08try{
          09// Create a new Component.
          10 Component component =newComponent();
          11// Add a new HTTP server listening on port 8182.
          12 component.getServers().add(Protocol.HTTP, 8182);
          13
          14// Attach the sample application.
          15 component.getDefaultHost().attach(
          16newFirstStepsApplication(component.getContext()));
          17
          18// Start the component.
          19 component.start();
          20 }catch(Exception e) {
          21// Something is wrong.
          22 e.printStackTrace();
          23 }
          24 }
          25 }
          啟動Main對象,打開你喜歡的瀏覽器,輸入URL:“http://localhost:8182/,服務器將高興地用“hello, world”歡迎你。否則,確認Classpath正確且沒有其他應用占用8182端口。

          RestLet第二步:晉級篇

          這里說明Resource如何處理GET,POST,PUT和DELETE方法。
          1.引言
          2.示例程序
          3.實現Items Resource
          4.實現Item Resource
          5.實現Base Resource
          6.運行應用
          7.客戶端應用
          8.總結

          1.      引言
          在開始開發前,我們需要簡單介紹一下Restlet框架的Resource概念。REST告訴我們,Resource根據URI進行辨認,同時能夠有一種或多種表現(也被稱作變量),用以響應方法調用。
          在Restlet框架中,服務器連接器(server connectors)收到的調用最終由Resource的實例對象處理。一個Resource負責聲明支持的表現方式列表(Variant對象的實例)和實現你想要支持的REST方法。
           GET依賴可更改的“variants”列表和“getRepresentation(Variant)”方法。
           POST依賴“allowPost”方法和“post(Representation)”方法。
           DELETE依賴“allowPut”方法和“put(Representation)”方法。
          DELETE依賴“allowDelete”方法和“delete()”方法。
          還有,每一個到達的響應由一個專門的Resource實例處理,你不需要操心這些方法的線程安全問題。
          我們假設你已經讀過“第一步”,并且有了一些元件和應用的概念。

          2.示例程序

          一個Item列表用來管理創建,讀取,更新,和刪除活動,如一個典型的CRUD應用。一個Item包含名字和描述。在簡短的分析后,我們定義了兩個資源:
           Items Resource代表所有可用Item的集合。
           Item Resource代表一個單獨的item。
          現在,讓我們定義用來標志item的Resource URIs。假設我們的應用運行在本機“localhost”并且監聽8182端口:
          http://localhost:8182/firstResource/items
          :“items”Resource URI。
          http://localhost:8182/firstResource/items/{itemName}
          :“item”Resource URI,每個{itemName}代表一個Item的名字。
          下一步,定義每個Resource允許訪問的方法列表。
           “items”Resource響應GET請求并以一個XML文檔展示當前注冊的所有Item列表。另外,Resource支持通過POST請求創建新的Item。提交的實體包含新的Item的名字和描述,這些是以格式化的Web表單方式提交的。如果Resource成功創建新Item,它返回一個“Success - resource created”狀態(HTTP 201狀態代碼)并且告訴客戶端新Resource在哪里可以找到(HTTP "Location" header)。否則,它返回一個“Client error”狀態(HTTP 404狀態代碼)和一個簡單的錯誤信息。
           “item”Resource響應GET請求并以一個XML文檔來展示該Resource的名字和描述。也可以通過PUT和DELETE請求更新和刪除Resource。
          在描述兩個Resource對象前,首先編寫應用的代碼。為簡化起見,注冊的Item列表做為應用的一個屬性簡單地保存到內存里,并不保存到一個真實的數據庫。不管怎樣,我們假設你想邀請你的朋友們同時測試這個應用。因為我們只有一個“FirstResourceApplication”實例在運行,所以不得不考慮線程安全。這也就是為什么你會發現Map對象Items是不不可更改的,它是一個ConcurrentHashMap對象的實例。

          代碼:

          01packagefirstResource;
          02
          03importjava.util.Map;
          04importjava.util.concurrent.ConcurrentHashMap;
          05
          06importorg.restlet.Application;
          07importorg.restlet.Context;
          08importorg.restlet.Restlet;
          09importorg.restlet.Router;
          10
          11publicclassFirstResourceApplicationextendsApplication {
          12
          13   /** The list of items is persisted in memory. */
          14   privatefinalMap<String, Item> items;
          15
          16   publicFirstResourceApplication(Context parentContext) {
          17      super(parentContext);
          18      // We make sure that this attribute will support concurrent access.
          19       items =newConcurrentHashMap<String, Item>();
          20    }
          21
          22   /**
          23    * Creates a root Restlet that will receive all incoming calls.
          24    */
          25    @Override
          26   publicsynchronizedRestlet createRoot() {
          27      // Create a router Restlet that defines routes.
          28       Router router =newRouter(getContext());
          29
          30      // Defines a route for the resource "list of items"
          31       router.attach("/items", ItemsResource.class);
          32      // Defines a route for the resource "item"
          33       router.attach("/items/{itemName}", ItemResource.class);
          34
          35      returnrouter;
          36    }
          37
          38   /**
          39    * Returns the list of registered items.
          40    *
          41    * @return the list of registered items.
          42    */
          43   publicMap<String, Item> getItems() {
          44      returnitems;
          45    }
          46 }

          2.      實現Items Resource
            讓我們開始編寫Items Resource。如上文所述,它允許GET和POST請求。POST請求支持實現“post(Representation)”方法賦予處理消息實體的權限。此外,資源通過“allowPost”方法來確定是否開啟POST支持。缺省情況下,資源是不可更改的,拒絕POST、PUT和DELETE方法并返回“Method not allowed”狀態(HTTP 405狀態代碼)。

          同樣,通過實現“represent(Variant)”方法確定你可以接受GET請求并根據指定的Variant生成實體。在這個例子中,我們只生成“text/xml”這種形式。

          代碼:

          001packagefirstResource;
          002
          003importjava.io.IOException;
          004importjava.util.Collection;
          005
          006importorg.restlet.Context;
          007importorg.restlet.data.Form;
          008importorg.restlet.data.MediaType;
          009importorg.restlet.data.Request;
          010importorg.restlet.data.Response;
          011importorg.restlet.data.Status;
          012importorg.restlet.resource.DomRepresentation;
          013importorg.restlet.resource.Representation;
          014importorg.restlet.resource.StringRepresentation;
          015importorg.restlet.resource.Variant;
          016importorg.w3c.dom.Document;
          017importorg.w3c.dom.Element;
          018
          019/**
          020* Resource that manages a list of items.
          021*
          022*/
          023publicclassItemsResourceextendsBaseResource {
          024
          025   /** List of items. */
          026    Collection<Item> items;
          027
          028   publicItemsResource(Context context, Request request, Response response) {
          029      super(context, request, response);
          030
          031      // Get the items directly from the "persistence layer".
          032       items = getItems().values();
          033
          034      // Declare the kind of representations supported by this resource.
          035       getVariants().add(newVariant(MediaType.TEXT_XML));
          036    }
          037
          038    @Override
          039   publicbooleanallowPost() {
          040      returntrue;
          041    }
          042
          043   /**
          044    * Returns a listing of all registered items.
          045    */
          046    @Override
          047   publicRepresentation getRepresentation(Variant variant) {
          048      // Generate the right representation according to its media type.
          049      if(MediaType.TEXT_XML.equals(variant.getMediaType())) {
          050         try{
          051             DomRepresentation representation =newDomRepresentation(
          052                   MediaType.TEXT_XML);
          053            // Generate a DOM document representing the list of
          054            // items.
          055             Document d = representation.getDocument();
          056             Element r = d.createElement("items");
          057             d.appendChild(r);
          058            for(Item item : items) {
          059                Element eltItem = d.createElement("item");
          060
          061                Element eltName = d.createElement("name");
          062                eltName.appendChild(d.createTextNode(item.getName()));
          063                eltItem.appendChild(eltName);
          064
          065                Element eltDescription = d.createElement("description");
          066                eltDescription.appendChild(d.createTextNode(item
          067                      .getDescription()));
          068                eltItem.appendChild(eltDescription);
          069
          070                r.appendChild(eltItem);
          071             }
          072             d.normalizeDocument();
          073
          074            // Returns the XML representation of this document.
          075            returnrepresentation;
          076          }catch(IOException e) {
          077             e.printStackTrace();
          078          }
          079       }
          080
          081      returnnull;
          082    }
          083
          084   /**
          085    * Handle POST requests: create a new item.
          086    */
          087    @Override
          088   publicvoidpost(Representation entity) {
          089      // Parse the given representation and retrieve pairs of
          090      // "name=value" tokens.
          091       Form. form. =newForm(entity);
          092       String itemName = form.getFirstValue("name");
          093       String itemDescription = form.getFirstValue("description");
          094
          095      // Check that the item is not already registered.
          096      if(getItems().containsKey(itemName)) {
          097          generateErrorRepresentation(
          098                "Item " + itemName + " already exists.", "1", getResponse());
          099       }else{
          100         // Register the new item
          101          getItems().put(itemName,newItem(itemName, itemDescription));
          102
          103         // Set the response's status and entity
          104          getResponse().setStatus(Status.SUCCESS_CREATED);
          105          Representation rep =newStringRepresentation("Item created",
          106                MediaType.TEXT_PLAIN);
          107         // Indicates where is located the new resource.
          108          rep.setIdentifier(getRequest().getResourceRef().getIdentifier()
          109                + "/" + itemName);
          110          getResponse().setEntity(rep);
          111       }
          112    }
          113
          114   /**
          115    * Generate an XML representation of an error response.
          116    *
          117    * @param errorMessage
          118    *            the error message.
          119    * @param errorCode
          120    *            the error code.
          121    */
          122   privatevoidgenerateErrorRepresentation(String errorMessage,
          123          String errorCode, Response response) {
          124      // This is an error



          轉載地址:http://blog.ixpub.net/html/07/12399407-251280.html
          posted on 2008-11-28 14:46 蘆葦 閱讀(1271) 評論(0)  編輯  收藏 所屬分類: JAVA其他
          主站蜘蛛池模板: 安顺市| 务川| 棋牌| 奇台县| 武安市| 从化市| 辽宁省| 孟津县| 临潭县| 临沧市| 唐山市| 山阳县| 修文县| 汝南县| 张家港市| 卢湾区| 通州区| 昌吉市| 三穗县| 大竹县| 邵武市| 柯坪县| 鄢陵县| 赤峰市| 腾冲县| 松溪县| 沙田区| 乳山市| 静乐县| 巨野县| 镇沅| 无为县| 富源县| 柏乡县| 台州市| 云和县| 江都市| 吕梁市| 开原市| 昆山市| 佛教|