将lein ring uberjar部署到Tomcat的路由不正确

时间:2014-04-28 12:42:41

标签: tomcat clojure compojure

我正在使用Clojure构建一个示例Web应用程序。我正在使用lein ring插件和compojure进行路由。

当我使用lein ring server运行应用时,一切正常。我可以浏览localhost:3000 / items,一切看起来都很好css& js已加载。

但是当我构建一个uberwar(lein ring uberwar webdev.war)并将其部署到Tomcat时,路由是错误的。

部署后,我浏览到localhost:8080 / webdev / items

css / js文件未加载,因为它们的路径不包含上下文"webdev"

同样,我在Hiccup中定义的表单会尝试回发到/items,而webdev也不会包含上下文(defproject webdev "0.1.0-SNAPSHOT" :description "FIXME: write description" :url "http://example.com/FIXME" :license {:name "Eclipse Public License" :url "http://www.eclipse.org/legal/epl-v10.html"} :dependencies [[org.clojure/clojure "1.5.1"] [ring "1.2.2"] [hiccup "1.0.5"] [compojure "1.1.6"] [org.clojure/java.jdbc "0.3.3"] [postgresql/postgresql "9.1-901.jdbc4"]] :plugins [[lein-ring "0.8.10"]] :ring {:init webdev.core/create-db-schema :handler webdev.core/app :servlet-path-info? true } )

这是我的project.clj,core.clj和views.clj

Project.clj:

(ns webdev.core
  (:require [webdev.item.model :as items])
  (:require [webdev.item.handler :refer [handle-index-items
                                         handle-create-item
                                         handle-delete-item
                                         handle-update-item]])
  (:require
            [hiccup.middleware :refer [wrap-base-url]]
            [ring.middleware.reload :refer [wrap-reload]]
            [ring.middleware.params :refer [wrap-params]]
            [ring.middleware.resource :refer [wrap-resource]]
            [ring.middleware.file-info :refer [wrap-file-info]]
            [compojure.core :refer [defroutes ANY GET POST PUT DELETE]]
            [compojure.route :as route]
            [compojure.handler :as handler]
            [ring.handler.dump :refer [handle-dump]]))

(defn greet [req]
  {:status 200
   :body "Hello, World!!!!!!!!!!!!!"
   :headers {}})

(defroutes routes
  (GET "/" [] greet)

  (ANY "/request" [] handle-dump)

  (GET "/items" [] handle-index-items)
  (POST "/items" [& params] (handle-create-item params))
  (DELETE "/items/:item-id" [item-id] (handle-delete-item item-id))
  (PUT "/items/:item-id" [& params] (handle-update-item params))

  (route/resources "/" {:root "static"})

  (route/not-found "Page not found."))


(defn create-db-schema []
  (items/create-table))


(defn wrap-server-response [hndlr]
  (fn [req]
    (let [response (hndlr req)]
      (assoc-in response [:headers "Server:"] "my-server"))))


(def sim-methods {"PUT"     :put
                  "DELETE"  :delete})

(defn wrap-simulated-methods [hndlr]
  (fn [req]
    (if-let [method (and (= :post (:request-method req))
                         (sim-methods (get-in req [:params "_method"])))]
      (hndlr (assoc req :request-method method))
      (hndlr req))))

(def app-routes
  (wrap-base-url
    (wrap-file-info
      (wrap-server-response
       (wrap-params
        (wrap-simulated-methods routes))))))

(def app
  (handler/site app-routes))

Core.clj

(ns webdev.item.view
  (:require [hiccup.page :refer [html5]]
            [hiccup.core :refer [html h]]))


(defn new-item []
  (html
   [:form.form-horizontal
    {:method "POST" :action "/items"}
     [:div.form-group
      [:label.control-label.col-sm-2 {:for :name-input}
       "Name"]
      [:div.col-sm-10
       [:input#name-input.form-control
        {:name :name :placeholder "Name"}]]]
   [:div.form-group
    [:label.control-label.col-sm-2 {:for :desc-input}
     "Description"]
    [:div.col-sm-10
     [:input#desc-input.form-control
      {:name :description :placeholder "Description"}]]]
   [:div.form-group
    [:div.col-sm-offset-2.col-sm-10
     [:input.btn.btn-primary
      {:type :submit
       :value "New item"}]]]]))


(defn delete-item-form [id]
  (html
   [:form.form-horizontal
    {:method "POST" :action (str "/items/" id)}
    [:div.form-group
     [:input {:type :hidden
              :name "_method"
              :value "DELETE"}]
     [:div.col-sm-offset-2.col-sm-10
      [:input.btn.btn-danger.btn-xs
       {:type :submit
        :value "Delete" }]]]]))


(defn update-checked-form [id checked]
  (html
   [:form.form-horizontal
    {:method "POST" :action (str "/items/" id)}
    [:div.form-group
     [:input {:type :hidden
              :name "_method"
              :value "PUT"}]
     [:input {:type :hidden
              :name "checked"
              :value (str (not checked))}]
     [:div.col-sm-offset-2.col-sm-10
      [:input.btn.btn-primary.btn-xs
       {:type :submit
        :value (if checked "Done" "To-do")}]]]]))


(defn items-page [items]
  (html5 {:lang :en}
         [:head
           [:title "CLOJURE Web Dev Tutorial"]
           [:meta {:name :viewport :content "width=device-width, initial-scale=1.0"}]
           [:link {:href "/bootstrap/css/bootstrap.min.css"
                   :rel :stylesheet}]]
         [:body
          [:div.container
            [:h1 "My Items"]
            [:div.row
             (if (seq items)
               [:table.table.table-striped
                [:thead
                 [:tr
                  [:th "Name"]
                  [:th "Description"]
                  [:th.col-sm-2]
                  [:th.col-sm-2]]]
                 [:tbody
                  (for [i items]
                    [:tr
                     [:td (h (:name i))]
                     [:td (h (:description i))]
                     [:td (update-checked-form (:id i) (:checked i))]
                     [:td (delete-item-form (:id i))]])]]
               [:div.col-sm-offset-1 "There are no items."])]
          [:div.col-sm-6
           [:h2 "Create a new item"]
           (new-item)]]
          [:script {:src "http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"}]
          [:script {:src "/bootstrap/js/bootstrap.min.js"}]]))

View.clj

{{1}}

I saw this related question but I didn't seem to help

如何解决此问题?

2 个答案:

答案 0 :(得分:2)

好的,经过多次谷歌搜索'和实验我似乎已经为我的问题提出了一些合理的解决方案。

我对Clojure很新,我跟着这个优秀video tutorial的例子。

然后我修改了示例,因为我想尝试将应用程序部署到Tomcat

麻烦开始的时候。正如我在我的问题中所述,如果我在开发期间通过lein ring server运行应用程序,那么一切都很好。但是我想将我的应用部署到Tomcat,为了做到这一点,我需要构建一个uberwar

lein ring uberwar webdev.war命令正是我所需要的。

将应用部署到Tomcat后,发生了以下问题

  1. 已停止投放cssjs个文件。
  2. 表单未回复到正确的网址
  3. 表单帖子也尝试重定向到错误的网址
  4. 后重定向

    之前我没有注意到,当构建uberwar时,:context密钥会添加到request地图中。 (我认为你还必须使用wrap-base-url中间件才能将密钥添加到请求图中。

    为了获得服务的css和js文件,我需要使用include-css命名空间中的include-jshiccup.page函数。

    所以不要使用

    [:script {:src "http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"}]
              [:script {:src "/bootstrap/js/bootstrap.min.js"}]
    

    在我的views.clj中。我用了

    (include-css "/bootstrap/css/bootstrap.min.css")
    (include-js "http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"
                           "/bootstrap/js/bootstrap.min.js")
    

    这些功能显然尊重:context密钥,我的cssjs文件可以正确使用。

    下一个问题是我的表单没有回发到正确的网址。所以我再一次需要更改视图中的代码。我现在需要使用form/form-to命名空间中的hiccup.form来定义表单。

    (form/form-to [:post (str "/items/" id)
    

    这些功能显然也:context知道。

    最后,我需要在表单发布后修复redirects。为了实现这一点,我需要更改handle-create-item, handle-delete-item and handle-update-item的处理程序签名和相应的路由定义,以便除了处理程序所需的其他参数之外,它们还会传递request映射。然后我刚刚创建了一个小帮手函数

    defn items-list [req]
      (str (:context req) "/items"))
    

    :context地图中删除request并将其添加到路线中。

    我进行了这些更改后,我的应用现在可以通过lein ring server在我开发时以及部署到Tomcat服务器时在本地正确运行。

    我希望这可以帮助其他人面对类似的问题。完整的源代码可以在my github account

    找到

答案 1 :(得分:0)

感谢您发布您的发现 - 非常有帮助,因为我和您一样处于同一阶段。除了我目前的StackExchange级别之外,我会发表评论,但只是添加了link-to名称空间中的Hiccup函数imageelement,而不是使用裸html。