跳轉至內容

Compojure/核心庫

來自華夏公益教科書

關於最新資訊的重要說明

[編輯 | 編輯原始碼]

有關最新資訊,請參閱官方 Compojure wiki。此頁面嚴重過時,不應作為最近版本的指南。

compojure.http.*

[編輯 | 編輯原始碼]

HTTP 庫為 Compojure 提供了一種 RESTful 和函式式的方式來定義 Java servlet。其語法靈感來自 Ruby Web 框架 Sinatra。

要建立 servlet,您需要將一系列 HTTP 資源定義傳遞給 servlet 函式

(def #^{:doc "A simple greeter"} greet
  (servlet
    (GET "/greet" "Hello visitor!")
    (ANY "/*"     (page-not-found))))

Compojure 還提供了一個 defservlet 宏

(defservlet greet
  "A simple greeter"
  (GET "/greet" "Hello visitor!")
  (ANY "/*"     (page-not-found)))

傳遞給 defservlet 的資源定義是 Compojure 將 URL 路由與生成有用 HTTP 響應的程式碼關聯起來的方式,例如網頁或影像。

資源定義

[編輯 | 編輯原始碼]

資源定義採用以下形式

(method route & body)

方法可以是任何標準 HTTP 方法之一

GET  POST  PUT  DELETE  HEAD

或者,如果您希望匹配任何 HTTP 方法,您可以使用

ANY

偽造 HTML 表單的 PUT 和 DELETE

[編輯 | 編輯原始碼]

按照當前標準,HTML 表單只能呼叫 GET 和 POST 方法,但在 RESTful Web 服務中,您可能希望為資源實現 PUT 和 DELETE 方法。Compojure 提供了一種變通方法,使您能夠為瀏覽器和限制較少的客戶端實現 REST 的統一介面,而無需顯式伺服器端處理。客戶端應傳送一個名為“_method”的引數,其值為您真正想要呼叫的方法。您可以為此目的將隱藏欄位新增到 HTML 表單中,其他客戶端可以簡單地呼叫 PUT 或 DELETE 而不帶引數。Compojure 的處理程式基礎結構將在呼叫處理程式之前將實際方法替換為“_method”引數的值。

有關使用此技術的示例,請參閱部分#Servlet 繫結

路由引數

[編輯 | 編輯原始碼]

路由可以是固定字串,例如“/greet”,但通常您希望將路由的某些部分分配給影響輸出的引數

(GET "/greet/:name" {params :params} 
  (str "Hello " (params :name)))

在此,資源定義將“/greet”之後的路徑分配給引數 :name。可以透過 route 函式訪問來自路由的引數。

Servlet 繫結

[編輯 | 編輯原始碼]

除了路由之外,在所有資源宣告中預設情況下還提供了一些其他繫結

  • method - HTTP 方法
  • params - HTTP 引數的雜湊對映
  • headers - HTTP 標頭的雜湊對映
  • cookies - HTTP cookie 的雜湊對映
  • session - 對特定於會話的對映的 ref
  • request - HttpServletRequest 物件

以下是一個使用 session 和 params 繫結的示例

(GET "/name"
  (str "<p>Your current name is: " (@session :name) "</p>"
       "<form>Change name: <input name='name' type='text'>"
       "<input type='submit' value='Save'></form>"))
(POST "/name"
  (dosync
    (alter session assoc :name (params :name))
    (str "Your name was changed to " (@session :name))))

以下是一個使用“_method”變通方法將更新實現為 PUT 的相同示例

(GET "/name"
  (str "<p>Your current name is: " (@session :name) "</p>"
       "<form>Change name: <input name='name' type='text'>"
       "<input type='submit' value='Save'>"
       "<input type='hidden' name='_method' value='PUT'></form>"))
(PUT "/name"
  (dosync
    (alter session assoc :name (params :name))
    (str "Your name was changed to " (@session :name))))

生成響應

[編輯 | 編輯原始碼]

可以透過響應物件修改響應,但這幾乎沒有必要。相反,Compojure 採用函式式方法,從資源的返回值構建 HTTP 響應。

在前面的示例中,您可以看到如何返回字串會新增到響應主體中。其他標準 Clojure 型別會以不同的方式修改響應

  • java.lang.String - 新增到響應主體
  • java.lang.Number - 更改狀態碼
  • Clojure 對映 - 更新(合併)響應對映
  • Clojure 序列 - 懶載入新增到響應主體
  • java.io.File - 將檔案流式傳輸到響應主體
  • java.io.InputStream - 從流中讀取並新增到響應主體
  • java.net.URL - 將 URL 的資源流式傳輸到響應主體
  • java.servlet.http.Cookie - 將 cookie 新增到 HTTP 標頭

可以使用標準 Clojure 向量將這些修改連結在一起

(GET "/text"
  [{:headers {"Content-Type" "text/plain"}}
   "This is plain text."
   "And some more text."])
(GET "/bad"
  [404 "<h1>This page does not exist!</h1>"])
(GET "/download"
  (file "public/compojure.tar.gz"))   ; 'file' is an alias to 'new java.io.File'

compojure.html

[編輯 | 編輯原始碼]

HTML 庫提供了一種透過向量樹定義 HTML 或 XML 的方式。

(html [:p [:em "Hello World"]])
<p><em>Hello World</em></p>

標籤名稱取自向量的第一個專案,可以是字串、符號或關鍵字。您還可以選擇透過提供一個雜湊對映作為向量的第二個專案來指定標籤的屬性

(html [:div {:class "footer"} "Page 1"])
<div class="footer">Page 1</div>

html 函式還為定義 id 和 class 屬性提供了語法糖

(html [:h1.first  "Foo"]
      [:h2#second "Bar"])
<h1 class="first">Foo</h1><h2 id="second">Bar</h2>

任何序列都將擴充套件到包含向量中

(html [:em '("foo" "bar")])
<em>foobar</em>
(html [:ul
  (map (fn [x] [:li x])
       [1 2 3])])
<ul><li>1</li><li>2</li><li>3</li></ul>

compojure.server.jetty

[編輯 | 編輯原始碼]

Jetty 庫為 Jetty Web 伺服器提供了一個 Clojure 友好的介面,因此您可以輕鬆地使用 servlet 對映建立 Web 伺服器。

(def my-server
  (http-server {:port 8080}
    "/*"       my-main-servlet
    "/other/*" another-servlet
    ...))

您也可以使用 defserver 宏

(defserver my-server
  {:port 8080}
  "/*"       my-main-servlet
  "/other/*" another-servlet
  ...))

建立 Jetty 伺服器後,使用 (start my-server) 和 (stop my-server) 啟動和停止 Web 伺服器。

華夏公益教科書