今日は、Clojure言語でWebアプリケーションを作成するための基本を説明します。 複雑なロジックやトレンディなフレームワークはありません。 多数のプリミティブライブラリが使用されます。 前述のとおり、それらが提供する機能について簡単に説明します。
プリミティブのWebアプリケーションのアーキテクチャは、パス、パラメーター、メソッドに応じてハンドラーにリクエストを送信するWebサーバーで構成されます。 ハンドラーは特定のコードを実行し、データベースへのクエリを作成し、ファイルシステムで動作します。 要求を処理した後、応答が生成され、クライアントに送信されます。
アプリケーションはフォームを介して1つの値を取得し、データベースから2番目の値を取得して追加し、結果をクライアントに提供します。 この場合、入力された値はデータベース内の古い値を置き換えます。 愚かで、役に立たず、おもしろいロジックではありません。
Clojureでアプリケーションを開発するには、もちろんClojureといくつかの補助ライブラリが必要です。 まず、
Cloj 、SUDDENLY、
Leiningenをダウンロードします。 実際、Clojureで作成するには、Clojureをすぐにインストールすることはできませんが、Leiningenをダウンロードできます。 これは、Clojureでプロジェクトをビルドするためのユーティリティであり、依存関係や拡張可能なプラグインなどの通常の一連のタスクをサポートしています。 詳細については、
プロジェクトページまたは
Alex Ottに送信し
てください 。
それでは始めましょう:
D:\dev\clojure>lein new web-clojure-demo Created new project in: D:\dev\clojure\web-clojure-demo
どうしたの? Leiningenは、次の階層を持つプロジェクトフォルダーを作成しました。
src/ web_clojure_demo/ core.clj test/ web_clojure_demo/ test/ core.clj .gitignore README project.clj
まず、project.cljファイルに興味があります。 構造的には、通常のClojureソースコードが含まれています。
(defproject web-clojure-demo "1.0.0-SNAPSHOT" :description "FIXME: write description" :dependencies [[org.clojure/clojure "1.2.1"]])
ライニンゲンはこのファイルの内容を使用してプロジェクトを操作します。 ドキュメントにあるさまざまなディレクティブを指定することができます。 私たちは主に依存関係セクションに興味があります。 その中で、アプリケーションで使用されるライブラリを指定できます。
lein depsコマンドが
実行されると 、Leiningenはすべての依存関係をlib /フォルダーに個別に配置し、必要に応じてそれらをリポジトリからダウンロードします。
セクションで指定する必要がある多くのライブラリを使用します
:依存関係 :
- clojure-contrib-標準言語ライブラリには含まれていないさまざまな便利な機能が含まれています。文字列と入出力ストリームを操作するための関数、コレクションを操作するための追加関数、モナドなど。
- リングは、HTTP経由で多くの抽象化を提供するライブラリです。
- compojure -Webアプリケーションを作成するためのマクロと関数のセットが含まれています。 リングのラッパーです。
- clj-redisはRedisのクライアントライブラリです。 この例では、このNoSQLリポジトリを使用します。 リレーショナルソリューションについては、ClojureQLに注目することをお勧めします。
- enlive-クライアントへのHTML応答を作成するためのライブラリ。 テンプレートからロジックを完全に削除するという点で注目に値します。
アプリケーションをデバッグするには、Leiningenプラグインが必要です。 project.cljに別のセクション
dev-dependenciesを追加するだけです。
これは次のようになります。
(defproject web-clojure-demo "1.0.0-SNAPSHOT" :description "FIXME: write description" :dependencies [[org.clojure/clojure "1.2.1"] [org.clojure/clojure-contrib "1.2.0"] [ring/ring-jetty-adapter "0.2.5"] [compojure "0.6.2"] [clj-redis "0.0.9"] [enlive "1.0.0-SNAPSHOT"]] :dev-dependencies [[lein-ring "0.4.0"]] :ring {:handler web-clojure-demo.core/engine})
次に、
src / web_clojure_demo / core.cljファイルを開きます 。 これまでのところ、名前空間宣言のみが含まれています。 必要な依存関係と次のコードを追加します。
(ns web-clojure-demo.core (:use compojure.core) (:use [ring.adapter.jetty :only [run-jetty]]) (:use [ring.util.response]) (:require [compojure.route :as route] [compojure.handler :as handler] [clj-redis.client :as redis] [net.cgrand.enlive-html :as html])) (def db (redis/init {:url "redis://127.0.0.1:6379"})) (defn parse-input [a] (Integer/parseInt a)) (html/deftemplate page-index "web_clojure_demo/index.html" [ctxt] [:title] (html/content "Awesome application") [:#old] (html/content (:old ctxt)) [:#msg2] (html/set-attr "style" "display: none")) (html/deftemplate page-summary "web_clojure_demo/index.html" [ctxt] [:title] (html/content "Awesome application") [:#old] (html/content (:old ctxt)) [:#msg2] (html/content (str "Summary is " (:sum ctxt)))) (defn summary [value] (let [old (redis/get db "value")] (redis/set db "value" value) (page-summary { :sum (+ (parse-input value) (parse-input old)) :old old}))) (defn index [] (let [old (redis/get db "value")] (page-index {:old old}))) (defroutes main-routes (GET "/" [] (index)) (POST "/some_action" [value] (summary value)) (route/not-found "Page not found")) (def engine (handler/site main-routes))
次に、
index.htmlテンプレートを配置します。
<html> <head> <title></title> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> </head> <body> <div> <div id="msg1">Old value: <span id="old" /></div> <div id="msg2" /> <form method="post" action="/some_action" > <input type="text" name="value" ></input><input type="submit" name="ok" ></input> </form> </div>
お気づきのように、特別なタグは含まれていません。
次に、コンソールを使用して、依存関係を更新し、デバッグWebサーバーを起動する必要があります。
D:\dev\clojure\web-clojure-demo>lein deps Copying 19 files to D:\dev\clojure\web-clojure-demo\lib Copying 17 files to D:\dev\clojure\web-clojure-demo\lib\dev D:\dev\clojure\web-clojure-demo>lein ring server 2011-03-31 22:23:25.125::INFO: Logging to STDERR via org.mortbay.log.StdErrLog 2011-03-31 22:23:25.125::INFO: jetty-6.1.14 2011-03-31 22:23:25.203::INFO: Started SocketConnector@0.0.0.0:3000 Started server on port 3000
project.cljに戻ると、
リング{:handler web-clojure-demo.core / engine}という属性が追加されていることに気付くでしょう。 内部Leiningen Webサーバーは、アプリケーションのテスト中にすべてのリクエストをハンドラーに転送できます。 このLeiningenプラグインはいくつかのスタブを使用するため、これは非常に便利です。たとえば、Webサーバーを再起動せずにソースコードを更新できます。
内部で何が起こるか見てみましょう。
(def db (redis/init {:url "redis://127.0.0.1:6379"}))
このコードは、Redisリポジトリに接続されます。 作業には引き続きdb変数を使用します。
(defroutes main-routes (GET "/" [] (index)) (POST "/some_action" [value] (summary value)) (route/not-found "Page not found")) (def engine (handler/site main-routes))
このコードは、さまざまな要求のハンドラーを定義します。 この場合、compojureライブラリが使用されます。
サイトマクロは、一般的なサイトの操作に必要な機能(セッション、Cookie、パラメーターなど)をサポートするハンドラー関数を作成します。
メインルートは、radic要求とハンドラー関数のリストをリストします。 適切なハンドラーがない場合、
not-foundがトリガーされます。
(defn index [] (let [old (redis/get db "value")] (page-index {:old old}))) (defn summary [value] (let [old (redis/get db "value")] (redis/set db "value" value) (page-summary { :sum (+ (parse-input value) (parse-input old)) :old old})))
これらはリクエストを処理する関数です。 1つ目はデータベースの値を受け取り、テンプレートから応答生成関数を呼び出し、2つ目はデータベースに既存の値を追加して送信し、応答を生成させます。
(html/deftemplate page-index "web_clojure_demo/index.html" [ctxt] [:title] (html/content "Awesome application") [:#old] (html/content (:old ctxt)) [:#msg2] (html/set-attr "style" "display: none")) (html/deftemplate page-summary "web_clojure_demo/index.html" [ctxt] [:title] (html/content "Awesome application") [:#old] (html/content (:old ctxt)) [:#msg2] (html/content (str "Summary is " (:sum ctxt))))
deftemplateマクロは、
ctxtパラメーターを受け入れる関数を作成し、htmlテンプレートをロードして、指定されたルールに従って変換します。この場合、これはコンテンツまたはスタイルを変更するジョブです。 Enliveライブラリを使用すると、htmlを使用したより興味深い操作が可能になります。
アプリケーションは次のようになります。






おっと!
この誤解を修正してください。 コードを編集します。
(html/deftemplate page-summary "web_clojure_demo/index.html" [ctxt] [:title] (html/content "Awesome application") [:#old] (html/content (:old ctxt)) [:#msg2] (html/content (if (:error ctxt) (:error ctxt) (str "Summary is " (:sum ctxt))))) (defn summary [value] (let [old (redis/get db "value")] (try (let [ a (parse-input value) b (parse-input old)] (redis/set db "value" value) (page-summary { :sum (+ ab) :old old})) (catch NumberFormatException e (page-summary {:old old :error "Number Format Exception"})))))
これで、アプリケーションは不適切なデータを正しく処理します。 エラーの場合、メッセージがクライアントに表示されます。

おわりに
十分に説明していなかった場合は、このことをお知らせください。記事を補足します。 質問がある場合は、恥ずかしがらないでください。 健康的であまり批判されていない人も大歓迎です。
この例のソースコードは
リポジトリにあり
ます 。