摘要:只需不到200行代码,就能轻松地创建一个能正常运行、适用的Web应用程序?借助
Bluemix的灵活性和Clojure的简洁性,我们就可以实现此目的!
在Clojure中创建一个小型Web 应用程序,使用户能够匿名创建建议,并让其他人对这些建议进行评分。这个基于云的建议应用程序可以在Bluemix和Cloudant
上运行,而且使用了一个数据库后端。您可以在IBM? DevOps Services 上找到该应用程序的源代码。
“只需不到 200行代码,就能轻松地创建一个能正常运行、适用的Web应用程序?听起来似乎美好得有点不真实?但这是真的。借助
Bluemix的灵活性和Clojure的简洁性,我们就可以实现此目的!我将展示如何做。”
完成您的应用程序的前提条件
一个 Bluemix 帐户
一个 DevOps Services(以前称为 JazzHub)帐户
Clojure 和 Leiningen 的基本知识
Clojure 和 Leiningen 已安装在本地(用于完成 Hello
World 步骤)
Clojure 库:compojure、clutch 和 clostache(不要担心;Leiningen
可为您解决任何依赖项。)
运行应用程序、获取代码
入门:Hello World 应用程序
利用以下简单步骤,就可以通过 Clojure 创建一个 Hello World
应用程序。
第 1 步. 使用 Leiningen 创建一个新项目
更改到您想要存储项目的目录并发出命令 lein new <appname>。这将创建一个具有您应用程序的框架的新目录。
在新目录中,打开 project.clj 文件并编辑它,使之与以下代码清单相匹配。
(defproject suggestions "0.1.0-SNAPSHOT" :description "A small app that handles suggestions" :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"] [compojure "1.1.5"] ] :plugins [[lein-ring "0.8.3"]] :min-lein-version "2.0.0" :ring {:handler suggestions.handler/app} ) |
此代码向 Clojure 指定您打算使用的依赖项。(在本例中,依赖项是
compojure,它构建了 Web 应用程序。)该代码还指示在何处查找一个处理函数,使用它作为您应用程序的入口点。在前一个清单中,Clojure
在文件夹 suggestions 中的 handler.clj 文件中寻找函数 app。下一步是显示如何创建此文件。
第 2 步. 处理传入请求
在您的项目文件夹中,转到 src/suggestions 文件夹并删除
core.clj 文件。您不需要它。
创建一个名为 handler.clj 的文件并确保它包含以下代码。
(ns suggestions.handler (:use compojure.core)
(:require [compojure.handler :as handler]
[compojure.route :as route]
))
(defroutes app-routes
(GET "/" [] "<p>Hello World</p>")
(route/not-found "Not Found"))
(def app
(handler/site app-routes)) |
defroutes 函数为指定的路由(目前仅为 ‘/’)创建处理函数,支持您定义一个发送到浏览器的答案。前面的代码清单使用了硬编码的字符串,但它也可以是一个函数。
就这么简单。这个建议应用程序现在可输出前两个单词:“Hello World”。使用
lein ring server 命令构建和启动您的应用程序。您最喜爱的浏览器将会立即启动并显示 Hello
World。
迁移到云:将代码放在 DevOps Services 上
现在您的应用程序已在本地运行,下一步是将它迁移到云中。使用以下步骤将应用程序上传到
DevOps Services,在这里编辑您的代码,并从这里将它部署到 Bluemix。
第 1 步. 准备一个 DevOps Services 项目
在本地运行应用程序尽管不错,但更好的选择是将应用程序的源代码存储在云中,并从这里直接部署它。DevOps
Services 使这成为了可能。
![](images/2015090131.jpg)
1.登录到 DevOps Services。
2.单击 CREATE PROJECT。
![](images/2015090132.jpg)
Create Project 窗口的屏幕截图
3.在随后出现的项目设置屏幕中,为项目输入一个有意义的名称。选择希望使用
Jazz SCM 还是 Git 来执行源代码控制,以及您的项目是否应为私有。要学习本教程,请选择 Git
并勾选 Deploy to Bluemix。
指定项目位置的屏幕截图
完成前一步后,单击 CREATE 创建这个新 DevOps 项目。这一步可能需要一分钟。完成后即可前进到下一步。
第 2 步. 将应用程序迁移到云中
要将您创建的 Hello World 应用程序从硬盘迁移到 DevOps
Services 中,可以使用多种方法,包括将文件拖放到 Web IDE 上。一种简单方法是创建应用程序的一个
ZIP 归档文件,并直接将它导入您的项目中,步骤如下。
1.在项目概述页面中,单击 EDIT CODE。
![](images/2015090133.jpg)
顶部的 Edit Code 按钮的屏幕截图
2.从菜单中单击 File > Import > File
or zip archive。在随后打开的窗口中,挑选包含您应用程序的源代码的 ZIP 文件。
![](images/2015090134.jpg)
File > Import
> File or zip archive
3.在系统提示 Unzip archive? 时,单击 OK。
恭喜您!您应用程序的源代码现在已位于云中。
第 3 步. 准备部署
要将应用程序部署到 Bluemix,需要创建并编辑 manifest.yml
文件(它控制您应用程序的部署方式),并创建第二个文件来告诉 Bluemix 如何启动您的应用程序。
使用 DevOps Services 创建一个名为 manifest.yml
的文件。将以下代码放入该文件中。
applications: - name: helloworld # name of the BlueMix app memory: 512M instances: 1 buildpack: git://github.com/heroku/heroku-buildpack-clojure.git # The Clojure buildpack path: . |
此代码将会告诉 Bluemix 您的应用程序的名称 (helloworld),向它分配多少内存(对
Clojure 应用程序的内存分配比较大),要运行多少个实例,以及如何构建您的应用程序。
添加另一个名为 Procfile 的文件。此文件告诉 Bluemix 如何启动您的应用程序。将以下行添加到
Procfile 中:
创建并编辑这两个文件后,就可以部署您的应用程序了。
第 4 步. 提交和部署
要将应用程序部署到 Bluemix,您需要提交最新的更改。
1.单击左侧的 Git 选项卡,从 Editor 视图切换到 Git。
2.选择您想要提交到 Bluemix 的所有更改。输入一条有意义的提交消息并单击
Commit。
片刻之后,您的更改将被列出为传出更改。现在单击 Push 将您的更改发送到存储库的主要分支,并启动对
Bluemix 的自动部署。
![](images/2015090135.jpg)
Commit 1 file 按钮的屏幕截图
3.单击左侧的 Auto-Deployment Status 选项卡,以便了解应用程序部署如何进行。它应类似于下图。
![](images/2015090136.jpg)
简单部署窗口的屏幕截图
片刻之后,您应该看到结果列从 Pending 更改为 OK。您的应用程序现在已经可以在
Bluemix 上使用。单击您应用程序名称旁边的 URL,查看更改的实际效果。
将各部分结合起来构建建议应用程序
您现在已有一个有效的 Hello World 应用程序,只要您执行更改并推送它们,它就会自动部署到
Bluemix。该建议应用程序可用于执行以下任务:
1.浏览建议
2.对建议评分
3.输入一条新建议
使用请求来提供功能
该建议应用程序执行的功能比 Hello World 应用程序要多得多。因此,它的处理函数也增加了。它看起来类似于以下代码。
(defroutes app-routes (GET "/" [:as request] (suggestions.show/handle-sugg-request "1" request))
(GET "/sugg/:id" [id :as request]
(suggestions.show/handle-sugg-request id request))
(POST "/sugg/:id" [id :as request]
(suggestions.vote/vote-sugg id request)
(suggestions.show/handle-sugg-request id request))
(POST "/sugg/" [ :as request]
(suggestions.add/add-sugg ((request :params) :content
)
))
(route/resources "/") |
这些路线反映了建议应用程序的基本特性:
建议的显示由 suggestions.show/handle-sugg-request
函数管理。每个建议拥有自己的 ID,可通过一个惟一 URL 进行标识。应用程序的根页面 (/) 显示数据库中的第一条建议。
对建议的投票由一个对建议 URL 的 HTTP POST 请求启动。suggestions.vote/vote-sugg
函数将投票存储在 Cloudant 中。请求完成后,更新的建议可以使用 suggestions.show/handle-sugg-request
函数进行显示。
向 URL /sugg/ 提交一条建议会创建一条新建议。suggestions.add/add-sug
函数在 Cloudant 数据库中创建一个新文档,然后显示该新建议。
此外,静态文件由 route/resources 处理。此函数在 resources/public
文件夹中寻找文件。
将建议应用程序连接到 Cloudant
建议应用程序使用 Cloudant 作为一个 NoSQL 数据库,以便将建议存储为
JSON 文档。Bluemix 使得将 Cloudant NoSQL 数据库添加到应用程序中变得非常容易。
1.登录到 Bluemix 并打开目录。
2.向下滚动到 Data Management 部分并单击 Cloudant
NoSQL DB。
![](images/2015090137.jpg)
Data Management 窗口中的
Cloudant NoSQL DB 的屏幕截图
3.在屏幕的右侧,选择将使用 Cloudant NoSQL DB 的应用程序。为它提供一个有意义的名称,选择一个计划,然后单击
Create。
![](images/2015090138.jpg)
供您添加服务的 Cloudant NoSQL
DB 窗口
尽管可以查找新数据库的凭据并将它们硬编码到应用程序中,但一种不错的做法是从环境中读取它们。Bluemix
为您的应用程序提供了环境变量,其中包含您使用可通过 Bluemix 添加的不同服务所需的所有信息。
在这个建议应用程序示例中,使用的惟一一个服务是 Cloudant NoSQL
DB。为了读取此服务的凭据,该建议应用程序使用了以下代码。
(defn cloudant [] (str ((( ((json/read-str (System/getenv "VCAP_SERVICES") ) "cloudantNoSQLDB" )0) "credentials") "url") "/suggestions/") ) |
因为此函数用在应用程序中的多个地方,所以它被存储在 util.clj 文件中,需要数据库凭据的文件都包含该文件。
从数据库获取建议
可使用 clutch(一个用于 NoSQL 数据库的库)从 Cloudant
数据库获取建议。检索文档的代码很短,存储在 show.clj 文件中。
(defn handle-sugg-request [id r] (let [sugg (clutch/get-document (suggestions.util/cloudant) id) max-id ((clutch/get-document (suggestions.util/cloudant) "_all_docs") :total_rows) sugg-id (read-string id)]
(if (= id max-id)
(clostache/render-resource "main.mustache"
(assoc sugg :id id :next 1 :prev (dec sugg-id)
))
(if (= sugg-id 1)
(clostache/render-resource "main.mustache"
(assoc sugg :id id :next (inc sugg-id) :prev max-id
))
(clostache/render-resource "main.mustache"
(assoc sugg :id id :next (inc sugg-id) :prev (dec
sugg-id) )))))) |
前面的代码清单中的第 2 行使用了来自数据库的 ID id 检索建议。清单中的剩余代码处理将数据库文档呈现到
HTML 模板的过程。
将新建议存储在数据库中
向数据库添加新建议很简单。来自 add.clj 的相关函数位于以下代码清单中。
(defn add-sugg [content]
(let [maxid ((clutch/get-document (suggestions.util/cloudant)
"_all_docs") :total_rows) ]
(clutch/put-document (suggestions.util/cloudant)
(hash-map :content content :pro 0 :con 0 :_id
(str (inc maxid)) ))
(suggestions.show/handle-sugg-request (str maxid)
content)
)) |
在 let 语句中,maxid 被设置为数据库中的文档的编号,所以建议应用程序知道接下来使用哪个
ID。第 5 行使用 clutch/put-document 函数将建议存储在数据库中。
在执行这些步骤后,新存储的文档被显示为一个结果(参见前面的代码清单中的第
7 行)。
对建议投票
对建议投票,意味着修改数据库中的一个文档,比如读取它,执行更改,然后再次存储它。下面这个代码清单可用来管理投票功能。
(defn add-pro [sugg] (hash-map :content (:content sugg) :con (:con sugg) :pro (+ (:pro sugg) 1))) (defn add-neg [sugg] (hash-map :content (:content sugg) :pro (:pro sugg) :con (+ (:con sugg) 1)))
(defn vote-sugg [id r]
(let [sugg (clutch/get-document (suggestions.util/cloudant)
id)
rev (sugg :_rev)]
(if (= ((r :params) :vote) "con")
(clutch/put-document (suggestions.util/cloudant)
(assoc (add-neg sugg) :_id id :_rev rev))
)
(if (= ((r :params) :vote) "pro")
(clutch/put-document (suggestions.util/cloudant)
(assoc (add-pro sugg) :_id id :_rev rev))
))) |
前两行定义两个帮助函数,它们获取建议文档并返回包含另一个投票(积极或消极投票)的同一个文档。使用
clutch/get-document 函数可很轻松地读取文档。但是,要修改文档,则需要使用它的修订版本(存储在
_rev 文档属性中)。
确定投票是积极的还是消极的后,修改的建议文档会使用 clutch/put-document
函数写回到数据库中。
备注:另一个属性 _rev 包含之前检索的修订版本。只要修改了一个文档,这个修订版本就会发生更改。因此,Cloudant
可确保一项更改仅被应用于一个文档的最新版本。
传送静态文件
不是所有文件都是直接从应用程序生成的。该建议应用程序还使用了一些静态文件,比如
CSS、HTML 和图表。该建议应用程序使用以下代码作为静态文件的处理函数。
(ns suggestions.static
(:require [clostache.parser :as clostache]
))
(defn show-static-file [filename]
(clostache/render-resource filename (hash-map
:empty 1) )) |
此代码定义了一个函数来从应用程序的 resources/public 目录传送静态文件。
结束语
使用函数式语言(比如 Clojure)编写应用程序很有趣,但也有可能让人感到有点沮丧,因为这些语言获得的支持通常很少。使用
Bluemix 作为一个灵活的部署平台,语言选择就成为了一个适用性和个人偏好的问题,而不是哪些语言可用。现在您已知道如何从一个简单的
Hello World 应用程序入手来构建一个使用更新的 NoSQL DB 后端的完整应用程序。Clojure、Web
应用程序和Bluemix 是一种自然的搭配。
|