我正在使用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
如何解决此问题?
答案 0 :(得分:2)
好的,经过多次谷歌搜索'和实验我似乎已经为我的问题提出了一些合理的解决方案。
我对Clojure很新,我跟着这个优秀video tutorial的例子。
然后我修改了示例,因为我想尝试将应用程序部署到Tomcat
。
麻烦开始的时候。正如我在我的问题中所述,如果我在开发期间通过lein ring server
运行应用程序,那么一切都很好。但是我想将我的应用部署到Tomcat
,为了做到这一点,我需要构建一个uberwar
。
lein ring uberwar webdev.war
命令正是我所需要的。
将应用部署到Tomcat
后,发生了以下问题
css
和js
个文件。 之前我没有注意到,当构建uberwar
时,:context
密钥会添加到request
地图中。 (我认为你还必须使用wrap-base-url
中间件才能将密钥添加到请求图中。
为了获得服务的css和js文件,我需要使用include-css
命名空间中的include-js
和hiccup.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
密钥,我的css
和js
文件可以正确使用。
下一个问题是我的表单没有回发到正确的网址。所以我再一次需要更改视图中的代码。我现在需要使用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函数image
和element
,而不是使用裸html。