试了下CommonLisp的WEB开发
很多人喜歡Rails這種“All in One"的方式, 不過個人更喜歡搭積木的方式。每個小系統專心做好自己的事, 然后大家合作產生具有更強大功能的系統。 從網上收集了一些樣本代碼, 用SBCL試了下, 感覺不錯。
>(ql:quickload?"quickproject")
>(quickproject:make-project? "/media/E/RnD/clisp/web/"?:depends-on?'(hunchentoot cl-who cl-json parenacript css-lite elephant))
web項目的架子就搭好了:
%ls
README.txt? web.db? package.lisp? web.asd? web.lisp
%cat web.asd
(asdf:defsystem?:web
? :serial t
??:depends-on?(:hunchentoot
?????????????? :cl-who
?????????????? :cl-json
?????????????? :css-lite
?????????????? :parenscript
?????????????? :elephant)
??:components?((:file "package")
?????????????? (:file "web")))
其中各組件的功能,網上一查就知。簡單說一下:?
cl-who用于產生XHTML;? parenscript用于產生客戶端JavaScript;? elephant用于操作數據庫。
%cat package.lisp
(defpackage?:web
? (:use?:cl :cl-who :hunchentoot :parenscript :elephant)
? (:import-from?:css-lite :css)
? (:import-from?:json :encode-json-to-string))
%cat web.lisp
(in-package?#:web)
;;; "web" goes here. Hacks and glory await!
;; 啟動WEB服務器
(setf??*web-server*??(start??(make-instance?'hunchentoot:acceptor :port 8000)))
;; 輸出所有靜態內容
(push?(create-static-file-dispatcher-and-handler?"/GameVoter.png" "statics/imgs/GameVoter.png") ?*dispatch-table*)
(push?(create-static-file-dispatcher-and-handler?"/site.css" "statics/css/site.css")*dispatch-table*)
;; 啟動Elephant
(setf?*store*?(open-store?'(:clsql??(:sqlite3??"/media/E/RnD/clisp/web/web.db"))))
;; 將每一個游戲表示為Elephant持久類的一個實例
(defpclass?persistent-game?()
?? ((name :reader name :initarg :name :index t)
??? (votes :accessor votes :initarg :votes :initform 0 :index t)))
(defmethod?vote-for (user-selected-game)
??? (incf?(votes user-selected-game)))
(defun?game-from-name (name)
? (get-instance-by-value?'persistent-game?'name name))
(defun?game-stored? (game-name)
? (game-from-name game-name))
(defun?add-game (name)
? (with-transaction?()
??? (unless?(game-stored? name)
????? (make-instance?'persistent-game?:name name))))
;; 返回以流行程度排序的游戲列表
(defun?games ()
? (nreverse?(get-instances-by-range?'persistent-game?'votes nil nil)))
;; 對指定URL(加上.htm)自動生成 Hunchentoot 的處理器
(defmacro?define-url-fn ((name)??&body?body)
??`(progn
???? (defun ,name?()
???????,@body)
???? (push?(create-prefix-dispatcher?,(format?nil "/~(~a~)" name) ',name)?*dispatch-table*)))
;;標準頁面,使網站的風格一致
(defmacro?standard-page?((&key?title)?&body?body)
??`(with-html-output-to-string?(*standard-output* nil :prologue t :indent t)
???? (:html?:xmlns "http://www.w3.org/1999/xhtml"? :xml\:lang "en" :lang "en"
?????? (:head?
???????? (:meta?:http-equiv "Content-Type" :content "text/html;charset=utf-8")
?? ? (:title?,title)
?? ? (:link?:type "text/css" :rel "stylesheet" :href "/site.css"))
?? ??? (:body?
?? ????? (:div :id "header" ; Start all pages with our header.
?? ??????? (:img?:src "/GameVoter.png" :alt "Game Voter Logo" :class "logo")
?? ??????? (:span?:class "strapline" "Vote for your favourite Video Game"))
?? ??????,@body))))
;; 負責產生HTML的函數
(define-url-fn (index)
? (standard-page?(:title "Game Voter")
???? (:h1?"Vote on your all time favourite games!")
???? (:p?"Missing a game? Make it available for votes " (:a?:href "new-game" "here"))
???? (:h2?"Current stand")
???? (:div?:id "chart" ; Used for CSS styling of the links.
?????? (:ol
?? ?(dolist?(game (games))
?? ? (htm??
?? ?? (:li?(:a?:href (format?nil "vote?name=~a" (name game)) "Vote!")
?? ??????? (fmt?"~A with ~d votes" (name game) (votes game)))))))))
(define-url-fn (new-game)
? (standard-page?(:title "Add a new game")
???? (:h1?"Add a new game to the chart")
???? (:form?:action "/game-added" :method "post"
?? ???? :onsubmit (ps-inline?? ?? ; 客戶端驗證
?? ? ? ? ? (when?(=?name.value "")
?? ??? ??? ? (alert?"Please enter a name.")
?? ??? ??? ? (return?false)))
?????? (:p?"What is the name of the game?" (:br)
?? ??? (:input?:type "text" :name "name" :class "txt"))
?????? (:p?(:input :type "submit" :value "Add" :class "btn")))))
(define-url-fn (game-added)
? (let?((name (parameter "name")))
??? (unless?(or?(null?name) (zerop?(length?name))) ; 萬一 JavaScript 關閉了
????? (add-game name))
??? (redirect?"/index")))?
(define-url-fn (vote)
? (let?((game (game-from-name (parameter "name"))))
??? (if?game
?? ?(vote-for game))
??? (redirect?"/index")))
回到SBCL?
>(ql:quickload "web")
在瀏覽器中訪問 http://127.0.0.1:8000/index 試試!
總結
以上是生活随笔為你收集整理的试了下CommonLisp的WEB开发的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Common Lisp 初学者快速入门指
- 下一篇: Common Lisp语言快速入门