跳转至内容

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)))] " "
   )))
华夏公益教科书