У меня есть сайт, написанный на 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
