У меня есть сайт, написанный на Node.js, и иногда там требуется сделать что-то, для чего Node.js не предназначен: например, произвести какие-нибудь математические вычисления.
В этом примере мы будем вычислять «хеш» пароля.
Доверим эту работу «бекенду», написанному на (подходящем для вычислений) функциональном языке программирования. Например, на Scala. Функционально это будет так: Node.js отправляет GET-запрос на хеширование на «бекенд», «бекенд» думает-думает и в ответ отсылает вычисленный хеш в формате Json. Обычный HTTP запрос-ответ, ничего сложного.
Есть множество подходов к решению поставленной задачи в плане выбора набора «фреймворков».
Я немного писал на Ruby (не на «Рельсах»), с удовольствием пользуясь фреймворком Sinatra. И на Node.js пользуюсь клоном Sinatra по имени Express. Выяснилось, что и для Scala тоже написан соответствующий клон — Scalatra. Её мы и будем использовать.
Существует также несколько признанных легковесных Rest «фреймворков» для Scala:
Эти «фреймворки» были предложены мне пользователем btd в комментариях. Однако ни один из них мне не понравился — слишком там всё замудрёно, как и в самом языке Scala. Мне по душе что-нибудь попроще… Отчасти поэтому многие могут негодовать, что здесь я пишу не на Scala, а на Яве в синтаксисе Scala. Не спорю, мне больше по душе Яваскрипт, и Scala как раз даёт мне тот подход «функция есть объект», которого так не хватало Яве в сравнении с Яваскриптом.
Если по дзен-буддистски, то достаточно двух файлов: build.sh вида
Однако лучше использовать «сборщика», чтобы не возиться с масками имён файлов, и с длинным classpath в одну строку: правильный сборщик (не Maven) даст вам гораздо больше свободы (и читаемости), чем shell. Он сам за вас скачает все используемые библиотеки, и сам добавит каждый Jar’ник поимённо в classpath (и вам не придётся делать это руками).
На должность сборщика мы возьмём молодой (вот-вот выйдет версия 1.0) и развивающийся проект Gradle, который мне больше напоминает старого доброго Ant’а, чем Maven’а, в том, что не запирает разработчика в жёсткие рамки, а, наоборот, даёт полную свободу творчества, да ещё и на адекватном языке Groovy (клон Ruby в мире Явы).
Ставим JDK. Проверяем:
* Возможно ещё понадобится натравить системную переменную
Качаем Scala, и прописываем
Качаем Gradle, и прописываем
Сам проект расположился на github'е. Здесь я приведу код трёх основных файлов.
Инструкции по сборке для Gradle — build.gradle
Теперь собственно наш REST web-сервис, дающий возможность захешировать пароль на Whirlpool или SHA-512 — Hasher.scala
И написанный мною пускатель веб-сервера (запускает все веб-сервисы из пакета «package», заданного в build.gradle) — Main.scala
Качаем архив, распаковываем, заходим в папку и выполняем команду
Приветствие
Хешируем наш пароль по алгоритму SHA-512
Хешируем наш пароль по алгоритму Whirlpool
Scalatra
Как писать сборку на Gradle
Простой REST-сервис на Jersey
О Gradle по-русски
Что такое Scala и чем она удобна
Unfiltered — лёгкий REST фреймворк для Scala
Spray — продвинутый REST фреймворк для Scala
Blue Eyes — тоже продвинутый REST фреймворк для Scala
В этом примере мы будем вычислять «хеш» пароля.
Доверим эту работу «бекенду», написанному на (подходящем для вычислений) функциональном языке программирования. Например, на Scala. Функционально это будет так: Node.js отправляет GET-запрос на хеширование на «бекенд», «бекенд» думает-думает и в ответ отсылает вычисленный хеш в формате Json. Обычный HTTP запрос-ответ, ничего сложного.
Инструментарий
Есть множество подходов к решению поставленной задачи в плане выбора набора «фреймворков».
Я немного писал на Ruby (не на «Рельсах»), с удовольствием пользуясь фреймворком Sinatra. И на Node.js пользуюсь клоном Sinatra по имени Express. Выяснилось, что и для Scala тоже написан соответствующий клон — Scalatra. Её мы и будем использовать.
Популярные Rest «фреймворки» для Scala
Существует также несколько признанных легковесных Rest «фреймворков» для Scala:
- Spray — суперсовременный, быстрый, масштабируемый «фреймворк», основанный на Akka (Эрланг для Scala), который умеет всё
- Blue Eyes — общепризнанный предшественник Spray
- Unfiltered — очень маленький и самобытный «фреймворк», похожий по функциональности на Sinatra
Эти «фреймворки» были предложены мне пользователем btd в комментариях. Однако ни один из них мне не понравился — слишком там всё замудрёно, как и в самом языке Scala. Мне по душе что-нибудь попроще… Отчасти поэтому многие могут негодовать, что здесь я пишу не на Scala, а на Яве в синтаксисе Scala. Не спорю, мне больше по душе Яваскрипт, и Scala как раз даёт мне тот подход «функция есть объект», которого так не хватало Яве в сравнении с Яваскриптом.
Как всё это дело запускать
Если по дзен-буддистски, то достаточно двух файлов: build.sh вида
“javac -d classes *.java; scalac -classpath […] -d classes *.scala”
и run.sh вида “scala -classpath […] -Dпорт=8090 Main”
. Однако лучше использовать «сборщика», чтобы не возиться с масками имён файлов, и с длинным classpath в одну строку: правильный сборщик (не Maven) даст вам гораздо больше свободы (и читаемости), чем shell. Он сам за вас скачает все используемые библиотеки, и сам добавит каждый Jar’ник поимённо в classpath (и вам не придётся делать это руками).
На должность сборщика мы возьмём молодой (вот-вот выйдет версия 1.0) и развивающийся проект Gradle, который мне больше напоминает старого доброго Ant’а, чем Maven’а, в том, что не запирает разработчика в жёсткие рамки, а, наоборот, даёт полную свободу творчества, да ещё и на адекватном языке Groovy (клон Ruby в мире Явы).
Установка
Ставим JDK. Проверяем:
java -version
* Возможно ещё понадобится натравить системную переменную
JAVA_HOME
на папку с JDK, и прописать bin
в PATH.Качаем Scala, и прописываем
bin
в PATH
. Проверяем: scala –version
Качаем Gradle, и прописываем
bin
в PATH
. Проверяем: gradle –v
Проект
Сам проект расположился на github'е. Здесь я приведу код трёх основных файлов.
Инструкции по сборке для Gradle — build.gradle
// используем язык Scala
apply plugin: 'scala'
ext.scala_version = '2.9.1'
ext.jersey_version = '1.12'
ext.description = 'Accessing various calculation tasks'
// основная задача — запускает наш веб-сервис
// сначала запускает «compileJava» и «compileScala», а потом уже выполняется сама
task go(dependsOn: ['compileJava', 'compileScala'], type: JavaExec) {
main = 'Main'
classpath = sourceSets.main.runtimeClasspath
standardInput = System.in
systemProperty 'package', 'web'
systemProperty 'port', '8090'
}
// наборы исходных кодов
sourceSets
{
// главный
main
{
java
{
// исходники Явы искать в папке «sources»
srcDir 'sources'
}
scala
{
// исходники 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
// прочие библиотеки, используемые в программе
compile group: 'org.scalatra', name: 'scalatra_2.9.1', version: '2.1.0.M1'
runtime group: 'org.scalatra', name: 'scalatra_2.9.1', version: '2.1.0.M1'
compile group: 'org.mortbay.jetty', name: 'jetty', version: '7.0.0.pre5'
runtime group: 'org.mortbay.jetty', name: 'jetty', version: '7.0.0.pre5'
compile group: 'javax.servlet', name: 'javax.servlet-api', version: '3.0.1'
// до кучи можно просто класть jar-ники в папку «libraries»,
// и они тоже подхватятся в качестве библиотек
compile fileTree(dir: 'libraries', include: '*.jar')
runtime fileTree(dir: 'libraries', include: '*.jar')
}
// откуда качать используемые библиотеки
repositories
{
mavenCentral()
}
Теперь собственно наш REST web-сервис, дающий возможность захешировать пароль на Whirlpool или SHA-512 — Hasher.scala
package web
import hash.Whirlpool
import hash.SHA
class Hasher extends tools.WebService
{
def path = "/захѣшировать"
get("/")
{
"Доступные алгоритмы: Whirlpool, SHA"
}
get("/Whirlpool/:what")
{
val что = params("what")
json("что" -> что, "хѣш" -> Whirlpool.hash(что))
}
get("/SHA/:what")
{
val что = params("what")
json("что" -> что, "хѣш" -> SHA.hash(что))
}
}
И написанный мною пускатель веб-сервера (запускает все веб-сервисы из пакета «package», заданного в build.gradle) — Main.scala
import org.mortbay.jetty.Server
import org.mortbay.jetty.servlet.{Context, ServletHolder}
import tools._
object Main extends App
{
// создаём Jetty
val server = new Server(System.getProperty("port").toInt)
val root = new Context(server, "/", Context.SESSIONS)
// в каком пакете искать наши Rest веб-сервисы
val package_name : String = System.getProperty("package")
// каждый класс ScalatraServlet из этого пакета (и подпакетов) "замапить" на свой путь.
// путь определяется методом "path" этого класса.
for (handler <- PackageScanner.getClasses(package_name) if classOf[org.scalatra.ScalatraServlet].isAssignableFrom(handler))
{
// создаём сервлет из этого класса
val servlet = handler.newInstance().asInstanceOf[javax.servlet.Servlet]
// на какой путь "замапим" сервлет
try
{
// получаем это из метода path()
val path = handler.getMethod("path").invoke(servlet).toString
// "мапим" сервлет на этот путь в Jetty
root.addServlet(new ServletHolder(servlet), path + "/*")
println(handler.getPackage().getName() + "." + handler.getName() + " is mapped to " + path)
}
catch
{
// не написан метод path() у сервлета
case error: NoSuchMethodException =>
throw new RuntimeException("Method path() not found in class " + handler.getPackage().getName() + "." + handler.getName())
}
}
// запускаем Jetty
server.start()
server.join()
}
Запускаем
Качаем архив, распаковываем, заходим в папку и выполняем команду
gradle go
. При успешном выполнении вы узреете в консоли запуск веб-сервера:gradle go :compileJava :compileScala :processResources UP-TO-DATE :classes :go SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder". SLF4J: Defaulting to no-operation (NOP) logger implementation SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further detail > Building > :go
Проверяем
Приветствие
Хешируем наш пароль по алгоритму SHA-512
Хешируем наш пароль по алгоритму Whirlpool
Если вам нечем заняться (или интересно), то можете почитать ещё
Scalatra
Как писать сборку на Gradle
Простой REST-сервис на Jersey
О Gradle по-русски
Что такое Scala и чем она удобна
Unfiltered — лёгкий REST фреймворк для Scala
Spray — продвинутый REST фреймворк для Scala
Blue Eyes — тоже продвинутый REST фреймворк для Scala