2011年6月9日木曜日

CL clack & cl-markup GET/POST/SESSION


このエントリーをはてなブックマークに追加


Clackをもう少し。Webで必須なデータの受け渡し部分について試してみた。

cl-markupはcl-whoと挙動が違うので使うときは注意が必要。


(eval-when (:compile-toplevel :load-toplevel :execute)
  (require :clack)
  (require :cl-markup)
  (require :cl-ppcre)
  (require :drakma)
  )

(defpackage :sample-app
  (:use :cl
  :clack
  :clack.request
  :clack.app.route
  :clack.builder
  :clack.session.state.cookie
  :clack.middleware.session
  :cl-markup
  :cl-ppcre
  :drakma
  ))

(in-package :sample-app)

(defroutes sample-session-app (env)
     (GET  "/"          #'index)    ; トップページ。
     (GET  "/getdata"   #'getdata)  ; GETによるデータ受け渡し
     (POST "/postdata"  #'postdata) ; POSTによるデータ受け渡し
     (GET  "/session"   #'session)) ; sessionによるデータの受け渡し

(defun index (env)
  "トップページを生成
   最初にセッションに変数を代入している。"
  (setf (gethash :data1 (getf env :clack.session)) "データ1")
  (setf (gethash :data2 (getf env :clack.session)) "データ2")
  (setf (gethash :data3 (getf env :clack.session)) '("データ3-1" "データ3-2" "データ3-3"))
  `(200
 (:content-type "text/html")
 (,(markup
    (html
  (:head
   (:meta :content "text/html" :charset "UTF-8")
   (:title "index"))
  (:body
   ;; GETデータを送信するフォーム
   (:form :method "get" :action "/getdata"
    "GET"
    (:input :type "text" :name "getname")
    (:input :type "submit"))
   ;; POSTデータを送信するフォーム
   (:form :method "post" :action "/postdata"
    "POST"
    (:input :type "text" :name "postname")
    (:input :type "submit"))
   (:br)
   ;; セッションデータを確認する画面へのリンク
   (:a :href "/session" "セッションテスト")
   ))))))

(defun get-parameter (uri)
  "URIからGETデータを分離する適当な関数"
  (when (cl-ppcre:scan "\\?" uri)
 (let ((get-data (second (cl-ppcre:split "\\?" uri))))
    (when get-data
   (mapcar #'(lambda (x) (cl-ppcre:split "\\=" x))
     (cl-ppcre:split "\\&" get-data))))))

(defun getdata (env)
  "GETされたデータを表示する"
  `(200
 (:content-type "text/html")
 (,(markup
    (html
  (:head
   (:meta :content "text/html" :charset "UTF-8")
   (:title "get"))
  (:body
   (loop for i in (get-parameter (getf env :request-uri))
   collect (format nil "~a" (hunchentoot:url-decode (second i))))
   ))))))

(defun postdata (env)
  "POSTされたデータを表示する"
  (let ((req (make-request env)))
 `(200  
   (:content-type "text/html")
   (,(markup
   (html
    (:head
     (:meta :content "text/html" :charset "UTF-8")
     (:title "post"))
    (:body
     "post data: " (body-parameter req "postname"))))))))

(defun session (env)
  "セッションデータを表示する"
  `(200
 (:content-type "text/html")
 (,(markup
    (html
  (:head
   (:meta :content "text/html" :charset "UTF-8")
   (:title "session"))
  (:body
   (gethash :data1 (getf env :clack.session)) (:br)
   (gethash :data2 (getf env :clack.session)) (:br)
   (loop for i in (gethash :data3 (getf env :clack.session))
   collect (markup (:span i (:br))))
   ))))))

;; セッションを有効にしてClackを起動
(clackup
 (builder (<clack-middleware-session> :state (make-instance '<clack-session-state-cookie>))
 #'sample-session-app))

SESSIONを有効にしてトップページにアクセスするとCookieが挿入されるようになる。
CL-USER> (drakma:http-request "http://localhost:5000")
"<html><head><meta content=\"text/html\" charset=\"UTF-8\" /><title>test</title></head><body><form method=\"get\" action=\"/getdata\">GET<input type=\"text\" name=\"getname\" /><input type=\"submit\" /></form><form method=\"post\" action=\"/postdata\">POST<input type=\"text\" name=\"postname\" /><input type=\"submit\" /></form><br /><a href=\"/session\">セッションテスト</a></body></html>"
200
((:CONTENT-LENGTH . "371") (:DATE . "Wed, 08 Jun 2011 22:08:11 GMT") (:SERVER . "Hunchentoot 1.1.1") (:CONNECTION . "Close") (:SET-COOKIE . "CLACK.SESSION=dd878a54b3570f7bb06236358ebe56194ff6b848; path=/; expires=Sat, 14 Nov 2122 18:59:08 GMT") (:CONTENT-TYPE . "text/html"))
#<URI http://localhost:5000/>
#<FLEXI-STREAMS:FLEXI-IO-STREAM #x2103B8F79D>
T
"OK"
この状態でブラウザからlocalhost:5000へアクセスし、フォームに入力してSUBMITボタンを押せばデータの受け渡しが確認できる。



cl-markupはcl-whoとは使い勝手が違うのでちょっと注意が必要。loopで回して直接文字列を出力(タグを使わない)場合は以下みたいにする(のが正しいのかな?)
CL-USER> (markup
    (html
     (:body
      (loop for i in '(1 2 3 4 5)
      collect (format nil "~a<br />~%" i)))))
"<html><body>1<br />
2<br />
3<br />
4<br />
5<br />
</body></html>"

1 件のコメント:

深町英太郎 さんのコメント...

get-parameterは、Clack.Requestのquery-parameterで取れます

http://clacklisp.org/doc/clack.request.html

> cl-markupはcl-whoとは使い勝手が違うのでちょっと注意が必要。loopで回して直接文字列を出力(タグを使わない)場合は以下みたいにする(のが正しいのかな?)

正しいです。もし<br />をmarkupで書きたければ、

(loop for i in '(1 2 3 4 5)
collect (princ-to-string i)
collect (markup (:br)))

コメントを投稿