Содержание


Построение веб-приложения Clojure с помощью DevOps Services и Bluemix

Comments

Создайте небольшое веб-приложение на языке Clojure, которое позволяет анонимно делать предложения и выставлять их на всеобщее обозрение для оценки. Облачное приложение suggestions работает в Bluemix и Cloudant и использует базу данных на сервере. Исходный код приложения находится в IBM® DevOps Services.

Функциональное и полезное веб-приложение без хлопот менее чем в 200 строк кода? Звучит слишком хорошо, чтобы быть правдой? Но это правда. Гибкость Bluemix и лаконичность Clojure делают это возможным! Я продемонстрирую это.

Что требуется для создания приложения

  • Учетная запись Bluemix
  • Учетная запись DevOps Services (прежнее название: JazzHub)
  • Знакомство с Clojure и Leiningen
  • Clojure и Leiningen, установленные локально (для выполнения шага Hello World)
  • Библиотеки Clojure: compojure, clutch и clostache (не беспокойтесь, Leiningen обеспечит все зависимости.)

Запустить приложениеПолучить код

Начало: приложение Hello World

С помощью следующих простых шагов создайте приложение Hello World на языке Clojure.

Шаг 1. Создайте новый проект в Leiningen

  1. Перейдите в каталог своего нового проекта и подайте команду lein new <appname>. Будет создан новый каталог со скелетом приложения.
  2. В новом каталоге откройте файл 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 для построения веб-приложений). Код также указывает, где искать функцию обработчика, которая служит точкой входа в приложение. В предыдущем листинге Clojure ищет функцию app в файле handler.clj в папке suggestions. На следующем шаге показано, как создать этот файл.

Шаг 2. Обработка входящих запросов

  1. В папке проекта перейдите в папку src/suggestions и удалите файл core.clj. Он вам не понадобится.
  2. Вместо этого создайте файл с именем 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 предоставляет такую возможность.

  1. Войдите в DevOps Services.
  2. Нажмите кнопку CREATE PROJECT. Окно Create Project
  3. В открывшемся окне свойств проекта введите значимое имя своего проекта. Выберите Jazz SCM или Git для управления версиями и укажите, будет ли ваш проект закрытым. Чтобы следовать этому руководству, выберите Git и отметьте пункт Deploy to Bluemix. Указание местоположения проекта
    Указание местоположения проекта
  4. Выполнив предыдущий шаг, нажмите кнопку CREATE, чтобы создать новый проект DevOps. Это может занять минуту. Когда процесс завершится, можно переходить к следующему шагу.

Шаг 2. Перемещение приложения в облако

Для переноса готового приложения Hello World с локального жесткого диска в DevOps Services можно использовать несколько методов, в том числе перетаскивание файлов в веб-среду IDE. Один простой подход заключается в том, чтобы создать ZIP-архив приложения и импортировать его прямо в свой проект, используя следующие шаги.

  1. На обзорной странице проекта нажмите кнопку EDIT CODE. Кнопка Edit Code
    Кнопка Edit Code
  2. Выберите из меню File > Import > File or zip archive. В следующем окне выберите ZIP-файл с исходным кодом своего приложения. File > Import > File or zip archive
    File > Import > File or zip archive
  3. В ответ на запрос Unzip archive? нажмите кнопку OK.

Поздравляем! Теперь исходный код вашего приложения живет в облаке.

Шаг 3. Подготовка к развертыванию

Чтобы развернуть приложение в Bluemix, необходимо создать и отредактировать файл manifest.yml, управляющий способом развертывания приложения, и создать еще один файл, указывающий Bluemix, как запускать ваше приложение.

  1. Создайте с помощью DevOps Services файл с именем manifest.yml. Поместите в него следующий код.
    applications: 
    - name: helloworld         # имя BlueMix-приложения 
      memory: 512M 
      instances: 1 
      buildpack: git://github.com/heroku/heroku-buildpack-clojure.git # buildpack-пакет Clojure 
      path: .

    Этот код указывает Bluemix имя приложения (helloworld), количество выделяемой ему памяти (будьте щедрым для Clojure-приложений), количество выполняемых экземпляров и способ сборки приложения.

  2. Добавьте еще один файл – Procfile. Этот файл сообщает Bluemix, как запускать приложение. Добавьте в него следующую строку:
    web: lein ring server

Создав и отредактировав два файла, вы готовы к развертыванию приложения.

Шаг 4. Фиксации и развертывание

Чтобы развернуть приложение в Bluemix, необходимо зафиксировать последние изменения.

  1. Перейдите из представления редактора в Git, выбрав вкладку Git слева.
  2. Выберите все изменения, которые вы хотите сделать в Bluemix. Введите значимый комментарий к фиксации и нажмите кнопку Commit.

    Через мгновение ваши изменения будут перечислены в качестве исходящих. Теперь нажмите кнопку Push, чтобы отправить свои изменения в основную ветвь хранилища и запустить процесс автоматического развертывания в Bluemix.

    Кнопка Commit
    Кнопка Commit
  3. Выберите вкладку Auto-Deployment Status слева, чтобы увидеть ход процесса развертывания приложения. Он должен выглядеть как на следующем рисунке. Простое окно развертывания
    Простое окно развертывания

    Через несколько мгновений значение в столбце результатов изменится с Pending на ОК. Теперь приложение находится в Bluemix. Нажмите на ссылку рядом с именем приложения, чтобы увидеть изменения в действии.

Собираем все вместе: сборка приложения suggestions

Теперь у вас есть действующее приложение Hello World, которое автоматически развертывается в Bluemix всякий раз при внесении изменений и их публикации. Приложение suggestions позволяет решать следующие задачи:

  • просмотр предложений,
  • оценка предложений,
  • ввод нового предложения.

Использование запросов для выполнения функций

Приложение suggestions выполняет гораздо больше функций, чем приложение 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:

  • отображение предложения управляется функцией suggestions.show/handle-sugg-request. Каждое предложение имеет свой собственный идентификатор и может быть идентифицировано с помощью уникального URL-адреса. Корневая страница (/) приложения всегда указывает на первое предложение в базе данных;
  • голосование по предложению начинается с HTTP-запроса POST по URL-адресу предложения. Функция suggestions.vote/vote-sugg хранит результаты голосования в Cloudant. По завершении запроса обновленное предложение отображается с помощью функции suggestions.show/handle-sugg-request;
  • публикация предложения по URL-адресу /sugg/ приводит к созданию нового предложения. Функция suggestions.add/add-sug создает новый документ в базе данных Cloudant и отображает новое предложение;
  • кроме того, осуществляется управление маршрутами/ресурсами статических файлов. Эта функция разыскивает файлы в папке resources/public.

Подключение приложения suggestions к Cloudant

Приложение suggestions использует Cloudant в качестве базы данных NoSQL для хранения предложений в форме документов JSON. Bluemix позволяет очень легко добавить базу данных NoSQL Cloudant в приложение.

  1. Войдите в Bluemix и откройте каталог.
  2. Найдите раздел Data Management и нажмите кнопку Cloudant NoSQL DB. Cloudant NoSQL DB в окне управления данными
    Cloudant NoSQL DB в окне управления данными
  3. На правой стороне экрана выберите приложение, которое будет использовать Cloudant NoSQL DB. Введите значимое имя, выберите план и нажмите кнопку Create. Окно Cloudant NoSQL DB
    Окно Cloudant NoSQL DB

Можно просто взять реквизиты доступа новой базы данных и жестко запрограммировать их в свое приложение, но лучше считать их из переменной среды. Bluemix снабжает приложение переменными среды, содержащими всю информацию, необходимую для использования различных служб, которые вы добавляете в Bluemix.

В этом примере приложения suggestions используется единственная служба Cloudant NoSQL DB. Чтобы получить реквизиты доступа к этой службе, приложение использует следующий код.

(defn cloudant [] 
  (str ((( ((json/read-str (System/getenv "VCAP_SERVICES") ) "cloudantNoSQLDB" )0) "credentials") "url") "/suggestions/") 
  )

Поскольку эта функция используется в нескольких местах приложения, она хранится в файле util.clj, который включается в файлы, нуждающиеся в реквизитах доступа к базе данных.

Получение предложения из базы данных

Получим предложение из базы данных Cloudant с помощью clutch, библиотеки для баз данных NoSQL. Код для извлечения документа довольно короток и хранится в файле 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. Остальная часть листинга выполняет отрисовку документа из базы данных в 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 соответствует количеству документов в базе данных, поэтому приложение suggestions «знает», какой 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 гарантирует, что изменение применяется только к последней версии документа.

Создание статических файлов

Не все файлы создаются непосредственно из приложения. В приложении suggestions также используется несколько статических файлов, таких как 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. Clojure, веб-приложения и Bluemix естественным образом взаимодействуют друг с другом.


Ресурсы для скачивания


Похожие темы


Комментарии

Войдите или зарегистрируйтесь для того чтобы оставлять комментарии или подписаться на них.

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=40
Zone=Облачные вычисления
ArticleID=1021961
ArticleTitle=Построение веб-приложения Clojure с помощью DevOps Services и Bluemix
publish-date=11232015