2014-02-12 44 views
3

我正在使用「Web Development with Clojure」一書來製作教程留言簿應用程序並遇到了麻煩。看起來,自本書發佈以來,一些圖書館及其功能已經更新,導致我對網絡開發的介紹略有顛簸。我可以通過更新依賴關係來解決大部分問題,或者在不能時使用舊版本的庫,但是這種策略已經達到了極限,並且遇到了一個棘手的問題。我得到這個堆棧跟蹤,當我嘗試到本地主機服務器上運行我的應用程序:「使用Clojure進行Web開發」:沒有這樣的變量:db/get-user

Exception in thread "main" java.lang.RuntimeException: No such var: db/get-user, compiling:(guestbook/routes/auth.clj:38:14) 
    at clojure.lang.Compiler.analyze(Compiler.java:6380) 
    at clojure.lang.Compiler.analyze(Compiler.java:6322) 
    at clojure.lang.Compiler$InvokeExpr.parse(Compiler.java:3573) 
    at clojure.lang.Compiler.analyzeSeq(Compiler.java:6562) 
    at clojure.lang.Compiler.analyze(Compiler.java:6361) 
    at clojure.lang.Compiler.access$100(Compiler.java:37) 
    at clojure.lang.Compiler$LetExpr$Parser.parse(Compiler.java:5973) 
    at clojure.lang.Compiler.analyzeSeq(Compiler.java:6560) 
    at clojure.lang.Compiler.analyze(Compiler.java:6361) 
    at clojure.lang.Compiler.analyzeSeq(Compiler.java:6548) 
    at clojure.lang.Compiler.analyze(Compiler.java:6361) 
    at clojure.lang.Compiler.analyze(Compiler.java:6322) 
    at clojure.lang.Compiler$BodyExpr$Parser.parse(Compiler.java:5708) 
    at clojure.lang.Compiler$FnMethod.parse(Compiler.java:5139) 
    at clojure.lang.Compiler$FnExpr.parse(Compiler.java:3751) 
    at clojure.lang.Compiler.analyzeSeq(Compiler.java:6558) 
    at clojure.lang.Compiler.analyze(Compiler.java:6361) 
    at clojure.lang.Compiler.analyzeSeq(Compiler.java:6548) 
    at clojure.lang.Compiler.analyze(Compiler.java:6361) 
    at clojure.lang.Compiler.access$100(Compiler.java:37) 
    at clojure.lang.Compiler$DefExpr$Parser.parse(Compiler.java:529) 
    at clojure.lang.Compiler.analyzeSeq(Compiler.java:6560) 
    at clojure.lang.Compiler.analyze(Compiler.java:6361) 
    at clojure.lang.Compiler.analyze(Compiler.java:6322) 
    at clojure.lang.Compiler.compile1(Compiler.java:7148) 
    at clojure.lang.Compiler.compile(Compiler.java:7219) 
    at clojure.lang.RT.compile(RT.java:398) 
    at clojure.lang.RT.load(RT.java:438) 
    at clojure.lang.RT.load(RT.java:411) 
    at clojure.core$load$fn__5018.invoke(core.clj:5530) 
    at clojure.core$load.doInvoke(core.clj:5529) 
    at clojure.lang.RestFn.invoke(RestFn.java:408) 
    at clojure.core$load_one.invoke(core.clj:5336) 
    at clojure.core$load_lib$fn__4967.invoke(core.clj:5375) 
    at clojure.core$load_lib.doInvoke(core.clj:5374) 
    at clojure.lang.RestFn.applyTo(RestFn.java:142) 
    at clojure.core$apply.invoke(core.clj:619) 
    at clojure.core$load_libs.doInvoke(core.clj:5413) 
    at clojure.lang.RestFn.applyTo(RestFn.java:137) 
    at clojure.core$apply.invoke(core.clj:619) 
    at clojure.core$require.doInvoke(core.clj:5496) 
    at clojure.lang.RestFn.invoke(RestFn.java:457) 
    at guestbook.handler$loading__4910__auto__.invoke(handler.clj:1) 
    at clojure.lang.AFn.applyToHelper(AFn.java:159) 
    at clojure.lang.AFn.applyTo(AFn.java:151) 
    at clojure.lang.Compiler$InvokeExpr.eval(Compiler.java:3458) 
    at clojure.lang.Compiler.compile1(Compiler.java:7153) 
    at clojure.lang.Compiler.compile1(Compiler.java:7143) 
    at clojure.lang.Compiler.compile(Compiler.java:7219) 
    at clojure.lang.RT.compile(RT.java:398) 
    at clojure.lang.RT.load(RT.java:438) 
    at clojure.lang.RT.load(RT.java:411) 
    at clojure.core$load$fn__5018.invoke(core.clj:5530) 
    at clojure.core$load.doInvoke(core.clj:5529) 
    at clojure.lang.RestFn.invoke(RestFn.java:408) 
    at clojure.core$load_one.invoke(core.clj:5336) 
    at clojure.core$compile$fn__5023.invoke(core.clj:5541) 
    at clojure.core$compile.invoke(core.clj:5540) 
    at user$eval19.invoke(form-init6949279956252999274.clj:1) 
    at clojure.lang.Compiler.eval(Compiler.java:6619) 
    at clojure.lang.Compiler.eval(Compiler.java:6609) 
    at clojure.lang.Compiler.load(Compiler.java:7064) 
    at clojure.lang.Compiler.loadFile(Compiler.java:7020) 
    at clojure.main$load_script.invoke(main.clj:294) 
    at clojure.main$init_opt.invoke(main.clj:299) 
    at clojure.main$initialize.invoke(main.clj:327) 
    at clojure.main$null_opt.invoke(main.clj:362) 
    at clojure.main$main.doInvoke(main.clj:440) 
    at clojure.lang.RestFn.invoke(RestFn.java:421) 
    at clojure.lang.Var.invoke(Var.java:419) 
    at clojure.lang.AFn.applyToHelper(AFn.java:163) 
    at clojure.lang.Var.applyTo(Var.java:532) 
    at clojure.main.main(main.java:37) 
Caused by: java.lang.RuntimeException: No such var: db/get-user 
    at clojure.lang.Util.runtimeException(Util.java:219) 
    at clojure.lang.Compiler.resolveIn(Compiler.java:6848) 
    at clojure.lang.Compiler.resolve(Compiler.java:6818) 
    at clojure.lang.Compiler.analyzeSymbol(Compiler.java:6779) 
    at clojure.lang.Compiler.analyze(Compiler.java:6343) 
    ... 72 more 
Compilation failed: Subprocess failed 

我想我可能有一對夫婦在這裏,我並不需要加載的東西,但我project.clj文件看起來像這樣:

(defproject guestbook "0.1.0-SNAPSHOT" 
    :description "FIXME: write description" 
    :url "http://example.com/FIXME" 
    :dependencies [[org.clojure/clojure "1.5.1"] 
       [compojure "1.1.6"] 
       [hiccup "1.0.5"] 
       [ring-server "0.3.1"] 
       [lein-light-nrepl "0.0.15"] 
       [org.clojure/clojurescript "0.0-2156"] 
       [org.clojure/java.jdbc "0.2.3"] 
       [org.xerial/sqlite-jdbc"3.7.2"] 
       [lib-noir "0.8.0"]] 
    :repl-options {:nrepl-middleware [lighttable.nrepl.handler/lighttable-ops]} 
    :plugins [[lein-ring "0.8.7"] 
      [lein-ancient "0.5.4"]] 
    :ring {:handler guestbook.handler/app 
     :init guestbook.handler/init 
     :destroy guestbook.handler/destroy} 
    :aot :all 
    :profiles 
    {:production 
    {:ring 
    {:open-browser? false, :stacktraces? false, :auto-reload? false}} 
    :dev 
    {:dependencies [[ring-mock "0.1.5"] [ring/ring-devel "1.2.1"]]}}) 

home文件:

(ns guestbook.routes.home 
    (:require [compojure.core :refer :all] 
      [guestbook.views.layout :as layout] 
      [hiccup.form :refer :all] 
      [guestbook.models.db :as db] 
      [noir.session :as session])) 


(defn format-time [timestamp] 
    (-> "dd/MM/yyyy" 
     (java.text.SimpleDateFormat.) 
     (.format timestamp))) 


(defn home [] 
    (layout/common [:h1 "Guestbook"] 
       [:p "Welcome to my guestbook"] 
       [:hr] 
       [:form] 
       [:p "name"] 
       [:input] 
       [:p "Message"] 
       [:textarea {:rows 10 :cols 40}])) 


(defn show-guests [] 
[:ul.guests 
    (for [{:keys [message name timestamp]} (db/read-guests)] 
    [:li 
     [:blockquote message] 
     [:p "-" [:cite name]] 
     [:time (format-time timestamp)]])]) 

(defn home [& [name message error]] 
    (layout/common 
    [:h1 "Guestbook " (session/get :user)] 
    [:p "Welcome to my guestbook"] 
    [:p error] 

    (show-guests) 

    [:hr] 

    (form-to [:post "/"] 
      [:p "Name:" (text-field "name" name)] 
      [:p "Message:" (text-area {:rows 10 :cols 40} "message" message)] 
      (submit-button "comment")))) 


(defn save-message [name message] 
(cond 
    (empty? name) 
    (home name message "You forgot to leave a name, dumbass.") 
    (empty? message) 
    (home name message "Don't you have something to say?") 
    :else 
    (do 
    (db/save-message name message) 
    (home)))) 



(defroutes home-routes 
    (GET "/" [] (home)) 
    (POST "/" [name message] (save-message name message))) 

處理程序:

(ns guestbook.handler 
    (:use compojure.core 
     ring.middleware.resource 
     ring.middleware.file-info 
     hiccup.middleware 
     guestbook.routes.home) 
    (:require [compojure.handler :as handler] 
      [compojure.route :as route] 
      [guestbook.models.db :as db] 
      [guestbook.routes.auth :refer [auth-routes]])) 

(defn init [] 
    (println "guestbook is starting") 
    (if-not (.exists (java.io.File. "./db.sq3")) 
    (db/create-guestbook-table))) 

(defn destroy [] 
    (println "guestbook is shutting down")) 

(defroutes app-routes 
    (route/resources "/") 
    (route/not-found "Not Found")) 

(def app 
    (-> (routes auth-routes home-routes app-routes) 
     (handler/site) 
     (wrap-base-url))) 

數據庫:

(ns guestbook.models.db 
    (:require [clojure.java.jdbc :as sql]) 
    (:import java.sql.DriverManager)) 

(def db {:classname "org.sqlite.JDBC", 
     :subprotocol "sqlite", 
     :subname  "db.sq3"}) 

(defn create-guestbook-table [] 
    (sql/with-connection 
    db 
    (sql/create-table 
     :guestbook 
     [:id "INTEGER PRIMARY KEY AUTOINCREMENT"] 
     [:timestamp "TIMESTAMP DEFAULT CURRENT_TIMESTAMP"] 
     [:name "TEXT"] 
     [:message "TEXT"]) 
    (sql/do-commands "CREATE INDEX timestamp_index ON guestbook (timestamp)"))) 

(defn read-guests [] 
    (sql/with-connection 
    db 
    (sql/with-query-results res 
     ["SELECT * FROM guestbook ORDER BY timestamp DESC"] 
     (doall res)))) 

(defn save-message [name message] 
    (sql/with-connection 
    db 
    (sql/insert-values 
     :guestbook 
     [:name :message :timestamp] 
     [name message (new java.util.Date)]))) 

授權:

(ns guestbook.routes.auth 
    (:require [compojure.core :refer [defroutes GET POST]] 
      [guestbook.views.layout :as layout] 
      [hiccup.form :refer 
      [form-to label text-field password-field submit-button]] 
      [noir.response :refer [redirect]] 
      [noir.session :as session] 
      [noir.validation 
      :refer [rule errors? has-value? on-error]] 
      [noir.util.crypt :as crypt] 
      [guestbook.models.db :as db])) 

(defn format-error [[error]] 
    [:p.error error]) 

(defn control [field name text] 
    (list (on-error name format-error) 
     (label name text) 
     (field name) 
     [:br])) 

(defn registration-page [] 
    (layout/common 
    (form-to [:post "/register"] 
     (control text-field :id "screen name") 
     (control password-field :pass "Password") 
     (control password-field :pass1 "Retype Password") 
     (submit-button "Create Account")))) 

(defn login-page [] 
    (layout/common 
    (form-to [:post "/login"] 
     (control text-field :id "screen name") 
     (control password-field :pass "Password") 
     (submit-button "login")))) 

(defn handle-login [id pass] 
    (let [user (db/get-user id)] 
    (rule (has-value? id) 
      [:id "screen name is required"]) 
    (rule (has-value? pass) 
      [:pass "password is required"]) 
    (rule (and user (crypt/compare pass (:pass user))) 
      [:pass "invalid password"]) 
    (if (errors? :id :pass) 
    (login-page) 
    (do 
     (session/put! :user id) 
     (redirect "/"))))) 

(defn handle-registration [id pass pass1] 
    (rule (= pass pass1) 
     [:pass "password was not retyped correctly"]) 
    (if (errors? :pass) 
    (registration-page) 
    (do 
     (db/add-user-record {:id id :pass (crypt/encrypt pass)}) 
     (redirect "/login")))) 

(defroutes auth-routes 
    (GET "/register" [] (registration-page)) 
    (POST "/register" [id pass pass1] 
     (handle-registration id pass pass1)) 

    (GET "/login" [] (login-page)) 
    (POST "/login" [id pass] 
    (handle-login id pass)) 

    (GET "/logout" [] 
     (layout/common 
      (form-to [:post "/logout"] 
      (submit-button "logout")))) 
    (POST "/logout" [] 
     (session/clear!) 
     (redirect "/"))) 

可能有人請幫我解卡,​​所以我可以重新進入我的教程的擺動?此外,關於如何有效更新基於已棄用庫的代碼的任何提示都將有所幫助。我爲長時間的代碼表示歉意,但我仍然是一個noob,並不完全確定問題出在哪裏。我懷疑它必須對數據庫依賴關係做些什麼,因爲特定的sql/with-connection在我的谷歌搜索[org.clojure/java.jdbc「0.2.3」]依賴項中被棄用了,這是現在在版本0.3.3。

回答

4

注意在堆棧跟蹤的第一行: Exception in thread "main" java.lang.RuntimeException: No such var: db/get-user, compiling:(guestbook/routes/auth.clj:38:14)

它尋找和編譯auth.clj,並指出這個問題時找不到db/get-user是上線38列14.你別名dbguestbook.models.db。讓我們在guestbook/models/db.clj中尋找get-user函數。它不在那裏!將功能添加到db.clj或從auth.clj刪除該功能的所有用法。

+0

非常感謝!我調整了代碼以確保它與我在教程中的位置相匹配,並且似乎啓動了本地主機,但現在我正在瀏覽器中獲取該代碼! java.lang.ClassCastException clojure.lang.Var $沒有限制不能轉換到java.util.concurrent.Future ... (來源不明)\t ring.adapter.jetty.proxy $ org.eclipse.jetty .server.handler.AbstractHandler $ 0.handle ... – kurofune

+0

無法排除只有那麼多信息的問題。 – deadghost

+0

我在書籍網站上轉載了我的問題,並帶有一個展開的堆棧跟蹤: kurofune

相關問題