跳轉至內容

Compojure/教程和技巧

來自華夏公益教科書

這是一個使用 Compojure Web 框架的示例集合。

服務靜態檔案

[編輯 | 編輯原始碼]

Compojure 預設情況下不提供靜態檔案,也不會在沒有匹配路由時自動處理 404 錯誤。Compojure 不會對你想做什麼做任何假設;你必須明確說明。

為了提供靜態檔案,你通常需要新增兩個處理程式。一個用於服務檔案,另一個用於在第一個處理程式失敗時引發 404 錯誤

  (compojure.route/files "public")
  (compojure.route/not-found "Not found.")

https://weavejester.github.io/compojure/compojure.route.html 文件所述

使用名稱空間和 :require 對映,例如

  (ns coolproject.handler
    (:require [compojure.core :refer :all]
              [compojure.route :as route]))
  

然後你對 compojure.route 的呼叫可以簡化為

  (route/files "public")

它將自動在你的 src/resources/public 目錄中查詢靜態檔案(.css、影像等)。

圍繞 Servlet 組織程式碼

[編輯 | 編輯原始碼]

兩個 Compojure Servlet 相比一個 Servlet 的唯一優勢是功能劃分清晰。例如,如果你的網站有一個與公共網站截然不同的管理員介面,你可能希望建立兩個 Servlet;一個用於公共訪問,另一個用於管理員控制面板。

另一種需要多個 Servlet 的情況是,你的一個 Servlet 是用 Java 編寫的。例如,Jetty 包含一個用於處理 Cometd 請求的 Servlet,ContinuationCometdServlet。在我使用 Compojure 構建的應用程式中,我將此 Servlet 繫結到 "/_cometd/*",並將我的主要 Compojure Servlet 繫結到 "/*".

但對於正常使用,我傾向於將所有內容都放在一個 Servlet 中。如果你看一下像 Ruby on Rails 這樣的框架,所有的路由資訊都儲存在一個檔案中。Compojure Servlet 具有類似的用途,它們充當通往構成你的網站的 Clojure 函式的閘道器。實際的 Servlet 本身應該包含很少的邏輯,它應該看起來幾乎像整個網站的高階概述。

在表單中讀取日期

[編輯 | 編輯原始碼]

以下程式碼定義了 input-date-field 函式,它可以像其他任何輸入輔助函式一樣使用。該表單將以 Unix 時間格式返回日期。引數是:表單欄位的名稱、當前值以及年份選擇器的起始年和結束年。

 ;;; Date form field
 
 (def *date-class* (.getClass (new java.util.Date (long 0))))
 (def *date-format* (new java.text.SimpleDateFormat "yyyy-MM-dd"))
 
 (defn parseLong [s]
   (try (Long/parseLong (str s)) (catch java.lang.Exception e 0)))
 
 (defn get-date-from-anything [value]
   "Returns a Date object. Accepts a Date, number or String."
   (cond 
     (nil? value)
       (new java.util.Date (long 0))
     (instance? *date-class* value)
       value
     (number? value)
       (new java.util.Date (* 1000 (long value)))
     true
       (new java.util.Date (* 1000 (long (parseLong (str value)))))))
 
 (import '(java.util Calendar))
 (def monthNames ["January" "February" "March" "April" "May" "June" "July" "August" "September" "October" "November" "December"])
 
 (defn input-date-field 
   "Creates a form element to input a date"
   [name value fromYear toYear]
   (let [calendar (Calendar/getInstance)
         name (.replaceAll (str name) ":" "")]
     (.setTime calendar (get-date-from-anything value))
     (html
       (str "<script>
         function changed_date_" name "()
         {
           function $(id) { return document.getElementById(id); }
           var date = new Date(parseInt($('year_" name "').value), parseInt($('month_" name "').value), parseInt($('day_" name "').value));
           $('" name "').value = date.getTime() / 1000;
           //alert('c=:' + $('" name "').value);
         }
       </script>")
       [:input {:type 'hidden :name name :id name :value value}]
       [:input {:type 'text :id (str "day_" name) :value (.get calendar Calendar/DAY_OF_MONTH) :size 1 :onchange (str "changed_date_" name "();")}] " "
       [:select {:id (str "month_" name) :onchange (str "changed_date_" name "();")}
         (reduce #(str % (html [:option {:value %2 :selected (if (= %2 (.get calendar Calendar/MONTH)) "true" nil)} (nth monthNames %2)])) "" (range 12))] " "
       [:select {:id (str "year_" name) :onchange (str "changed_date_" name "();")}
         (reduce #(str % (html [:option {:value (+ fromYear %2)} (+ fromYear %2)])) "" (range (- (inc toYear) fromYear)))] " "
   )))
華夏公益教科書