- PVSM.RU - https://www.pvsm.ru -
Мой сайт написан на Node.js, и иногда мне требуется сделать что-то, для чего Node.js не предназначен [1]: например, произвести какие-нибудь математические вычисления.
В этом примере мы будем вычислять «хеш» пароля.
Доверим эту работу «бекенду», написанному на (подходящем для вычислений) функциональном языке программирования. Например, на Scala [2]. Функционально это будет так: Node.js отправляет GET-запрос на хеширование на «бекенд», «бекенд» думает-думает и в ответ отсылает вычисленный хеш в формате Json. Обычный HTTP запрос-ответ, ничего сложного.
Есть множество подходов к решению поставленной задачи в плане выбора набора «фреймворков».
Я немного писал на Ruby (не на «Рельсах»), с удовольствием пользуясь фреймворком Sinatra [3]. И на Node.js пишу, пользуясь клоном Sinatra по имени Express [4]. Выяснилось, что и для Scala тоже написан соответствующий клон — Scalatra [5]. Однако для своей работы она требует некоей непонятной штуки под названием Sbt [6] (Scala Build Tool). Эта штука — типа клон Явовского Maven [7]’а, только гораздо страшнее… Я так и не смог понять, что она делает…
В этой статье мы заложим свой путь написания REST’ового web-сервиса на Scala, без лишних заморочек, как и обещано, за 15 минут.
В качестве REST’ового фреймворка мы воспользуемся Jersey [8]. Это воплощение API JAX-RS [9]. Этот API пришёл из мира Явы Enterprise Edition, но, несмотря на это, не является какой-нибудь монструозной Годзиллой, а представляет собой вполне себе адекватный небольшой фреймворк, в той своей части, которая нам потребуется.
Jersey — это API, и его нужно запустить на каком-нибудь Явовом веб-сервере. Jetty, Tomcat, Grizzly — можно выбирать любой. Я выбрал Grizzly, просто потому что он попался мне на глаза. А так, я не знаю, чем он лучше того же Jetty. Может быть, побыстрее будет.
Если по дзен-буддистски, то достаточно двух файлов: build.sh вида “javac -d classes *.java; scalac -classpath […] -d classes *.scala”
и run.sh вида “scala -classpath […] -Dпорт=8090 Main”
.
Однако лучше использовать «сборщика», чтобы не возиться с масками имён файлов, и с длинным classpath в одну строку: правильный сборщик (не Maven, не Sbt) даст вам гораздо больше свободы (и читаемости), чем shell. Он сам за вас скачает все используемые библиотеки, и сам добавит каждый Jar’ник поимённо в classpath (и вам не придётся делать это руками).
На должность адекватного сборщика мы возьмём молодой (вот-вот выйдет версия 1.0) и развивающийся проект Gradle [10], который мне больше напоминает старого доброго Ant [11]’а, чем Maven’а, в том, что не запирает разработчика в жёсткие рамки, а, наоборот, даёт полную свободу творчества, да ещё и на адекватном языке Groovy [12] (клон Ruby в мире Явы).
Ставим JDK [13]. Проверяем: java -version
Качаем Scala [14], и прописываем bin в PATH. Проверяем: scala –version
Качаем Gradle [15], и прописываем bin в PATH. Проверяем: gradle –v
Древо проекта
Сам проект расположился на github'е [16]. Здесь я приведу код двух основных файлов.
Инструкции по сборке для Gradle — build.gradle
// используем язык Scala
apply plugin: 'scala'
ext.scala_version = '2.9.1'
ext.jersey_version = '1.12'
ext.description = 'Accessing various calculation tasks'
ext.classes_directory = new File('classes')
// вспомогательная функция удаления папки — аналог «rm -rf»
def delete_folder(File folder)
{
if (folder.isDirectory())
{
String[] children = folder.list()
int i = 0
while (i < children.length)
{
boolean success = delete_folder(new File(folder, children[i]))
if (!success)
{
return false
}
i++
}
}
// The directory is now empty so delete it
return folder.delete()
}
// эта задача очищает папку «classes» — можете запустить вручную, если будет нужно
task clean_output_folders <<
{
delete_folder(classes_directory)
classes_directory.mkdirs()
}
// основная задача — запускает наш веб-сервис
// сначала запускает «compileJava» и «compileScala», а потом уже выполняется сама
task go(dependsOn: ['compileJava', 'compileScala'], type: JavaExec) {
main = 'Main'
classpath = sourceSets.main.runtimeClasspath
standardInput = System.in
//args 'arguments`'
systemProperty 'port', '8090'
}
// наборы исходных кодов
sourceSets
{
// главный - Ява
main
{
java
{
// исходники искать в папке «sources»
srcDir 'sources'
}
scala
{
// исходники искать в папке «sources»
srcDir 'sources'
}
}
}
// скомпилированные Ява-классы класть в папку «classes»
sourceSets.main.output.classesDir = 'classes'
// используемые библиотеки
dependencies
{
// служебные библиотеки для обработки Scala из Gradle
scalaTools group: 'org.scala-lang', name: 'scala-compiler', version: scala_version
scalaTools group: 'org.scala-lang', name: 'scala-library', version: scala_version
// сама Scala, нужна для компиляции кода на Scala
compile group: 'org.scala-lang', name: 'scala-library', version: scala_version
// прочие библиотеки, используемые в программе
compile group: 'asm', name: 'asm', version: '3.3.1'
compile group: 'javax.ws.rs', name: 'jsr311-api', version: '1.1.1'
compile group: 'com.sun.jersey', name: 'jersey-bundle', version: jersey_version
compile group: 'com.sun.jersey', name: 'jersey-client', version: jersey_version
compile group: 'com.sun.jersey', name: 'jersey-core', version: jersey_version
compile group: 'com.sun.jersey', name: 'jersey-server', version: jersey_version
compile group: 'com.sun.jersey', name: 'jersey-grizzly2', version: jersey_version
compile group: 'com.sun.jersey', name: 'jersey-bundle', version: jersey_version
runtime group: 'asm', name: 'asm', version: '3.3.1'
runtime group: 'javax.ws.rs', name: 'jsr311-api', version: '1.1.1'
runtime group: 'com.sun.jersey', name: 'jersey-bundle', version: jersey_version
runtime group: 'com.sun.jersey', name: 'jersey-client', version: jersey_version
runtime group: 'com.sun.jersey', name: 'jersey-core', version: jersey_version
runtime group: 'com.sun.jersey', name: 'jersey-server', version: jersey_version
runtime group: 'com.sun.jersey', name: 'jersey-bundle', version: jersey_version
runtime group: 'com.sun.jersey', name: 'jersey-grizzly2', version: jersey_version
// до кучи можно просто класть jar-ники в папку «libraries»,
// и они тоже подхватятся в качестве библиотек
compile fileTree(dir: 'libraries', include: '*.jar')
compile files('classes')
runtime fileTree(dir: 'libraries', include: '*.jar')
runtime files('classes')
}
// откуда качать используемые библиотеки
repositories
{
mavenCentral()
}
И наш REST web-сервис, дающий возможность захешировать пароль на Whirlpool [17] или SHA-512 [18] — Hasher.scala
package resources
import javax.ws.rs._
import javax.ws.rs.core._
import hash.Whirlpool
import hash.SHA
import com.twitter.json.Json
@Path("/захѣшировать")
class Hasher
{
@GET
@Produces(Array("text/plain"))
def приветствие() : String =
{
"Доступные алгоритмы: Whirlpool, SHA"
}
@GET
@Path("Whirlpool/{что}")
@Produces(Array(MediaType.APPLICATION_JSON))
def whirlpool(@DefaultValue("") @PathParam("что") что : String) : String =
{
if (что == "")
throw new IllegalArgumentException("Что захешировать?")
Json.build(Map("что" -> что, "хѣш" -> Whirlpool.hash(что))).toString
}
@GET
@Path("SHA/{что}")
@Produces(Array(MediaType.APPLICATION_JSON))
def sha(@DefaultValue("") @PathParam("что") что : String) : String =
{
if (что == "")
throw new IllegalArgumentException("Что захешировать?")
Json.build(Map("что" -> что, "хѣш" -> SHA.hash(что))).toString
}
}
Качаем архив [19], распаковываем, заходим в папку и выполняем команду gradle go
. При успешном выполнении вы узреете в консоли запуск веб-сервера:
Starting grizzly... May 11, 2012 9:13:59 PM com.sun.jersey.api.core.PackagesResourceConfig init INFO: Scanning for root resource and provider classes in the packages: resources May 11, 2012 9:13:59 PM com.sun.jersey.api.core.ScanningResourceConfig logClasses INFO: Root resource classes found: class resources.Hasher May 11, 2012 9:13:59 PM com.sun.jersey.api.core.ScanningResourceConfig init INFO: No provider classes found. May 11, 2012 9:13:59 PM com.sun.jersey.server.impl.application.WebApplicationImpl _initiate INFO: Initiating Jersey application, version 'Jersey: 1.12 02/15/2012 05:30 PM' May 11, 2012 9:14:00 PM org.glassfish.grizzly.http.server.NetworkListener start INFO: Started listener bound to [localhost:8090] May 11, 2012 9:14:00 PM org.glassfish.grizzly.http.server.HttpServer start INFO: [HttpServer] Started.
* Я заметил такой глюк своего браузера (Chrome): если зайти по этим адресам до запуска веб-сервера, и жать-жать-жать на «Обновить», то после того, как веб-сервер запуститися, Chrome будет по-прежнему выдавать текст «404», хотя если после этого зайти на тот же Url из другого браузера — всё работает.
Приветствие [20]
Хешируем наш пароль по алгоритму SHA-512 [21]
Хешируем наш пароль по алгоритму Whirlpool [22]
Как писать сборку на Gradle [23]
Простой REST-сервис на Jersey [24]
О Gradle по-русски [25]
Что такое Scala и чем она удобна [26]
Unfiltered — лёгкий REST фреймворк для Scala [27]
Spray — продвинутый REST фреймворк для Scala [28]
Автор: kuchumovn
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/maven/7288
Ссылки в тексте:
[1] не предназначен: http://habrahabr.ru/post/128772/
[2] Scala: http://ru.wikipedia.org/wiki/Scala_(%D1%8F%D0%B7%D1%8B%D0%BA_%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F)
[3] Sinatra: http://titusd.co.uk/2010/04/07/a-beginners-sinatra-tutorial/
[4] Express: http://expressjs.com/
[5] Scalatra: http://www.scalatra.org/
[6] Sbt: https://github.com/harrah/xsbt/wiki
[7] Maven: http://ru.wikipedia.org/wiki/Maven
[8] Jersey: http://www.vogella.com/articles/REST/article.html
[9] JAX-RS: http://en.wikipedia.org/wiki/JAX-RS
[10] Gradle: http://gradle.org/
[11] Ant: http://ru.wikipedia.org/wiki/Apache_Ant
[12] Groovy: http://ru.wikipedia.org/wiki/Groovy
[13] JDK: http://www.oracle.com/technetwork/java/javase/downloads/index.html
[14] Scala: http://www.scala-lang.org/downloads
[15] Gradle: http://gradle.org/downloads
[16] на github'е: https://github.com/kuchumovn/scala_rest_tutorial
[17] Whirlpool: http://ru.wikipedia.org/wiki/Whirlpool
[18] SHA-512: http://ru.wikipedia.org/wiki/SHA-512
[19] Качаем архив: https://github.com/kuchumovn/scala_rest_tutorial/zipball/master
[20] Приветствие: http://localhost:8090/захѣшировать
[21] Хешируем наш пароль по алгоритму SHA-512: http://localhost:8090/захѣшировать/SHA/Господи Исѹсе Христе Сыне Божиi помилѹй мѧ грѣшнаго
[22] Хешируем наш пароль по алгоритму Whirlpool: http://localhost:8090/захѣшировать/Whirlpool/Господи Исѹсе Христе Сыне Божиi помилѹй мѧ грѣшнаго
[23] Как писать сборку на Gradle: http://www.gradle.org/docs/current/userguide/userguide.html
[24] Простой REST-сервис на Jersey: http://habrahabr.ru/post/115718/
[25] О Gradle по-русски: http://habrahabr.ru/post/106717/
[26] Что такое Scala и чем она удобна: http://www.scala-lang.org/docu/files/ScalaByExample.pdf
[27] Unfiltered — лёгкий REST фреймворк для Scala: http://unfiltered.databinder.net
[28] Spray — продвинутый REST фреймворк для Scala: https://github.com/spray/spray/wiki
Нажмите здесь для печати.