html текст
All interests
  • All interests
  • Design
  • Food
  • Gadgets
  • Humor
  • News
  • Photo
  • Travel
  • Video
Click to see the next recommended page
Like it
Don't like
Add to Favorites

Node.js vs Java + Rhino + Jetty + FreeMarker из песочницы


Хоть Node.js и обзавелся с момента своего появления множеством модулей, он все еще существенно уступает по возможностям мощному набору библиотек Java. Так отчего бы не воспользоваться потенциалом Java для разработки web-приложений на JavaScript? Давайте посмотрим, как можно построить удобный JavaScript MVC framework на Java.

Mozilla Rhino


Прежде всего, начнем с носорогов. Для компиляции/интерпретации JavaScript будем использовать движок Mozilla Rhino, обеспечивающий отличную интеграцию кода ECMAScript в Java-приложения. Начиная с J2SE 6 Rhino включается в JRE в составе Java Scripting API, однако версия в JRE значительно устаревшая и, кроме того, с некоторыми неприятными особенностями реализации от Sun, поэтому лучше воспользоваться свежим build-ом.

Прежде всего, helloworld.js:
print('Hey you!');

Предполагая, что библиотеки Rhino распакованы в ./lib, запускаем пример следующим образом:
java -Djava.ext.dirs=./lib org.mozilla.javascript.tools.shell.Main helloworld.js


Кстати, в комплекте идет и отладчик с неплохим UI, запускается он так:
java -Djava.ext.dirs=./lib org.mozilla.javascript.tools.debugger.Main helloworld.js



Rhino, помимо стандартных объектов ECMAScript, включает в глобальный контекст целый ряд функций, облегчающих связь JavaScript с Java. Да, если вы еще не поняли, из кода на JavaScript можно будет прозрачно работать с кодом на Java. Для работы с пакетами существует глобальный объект Packages. Например, так можно создать экземпляр java.io.File:
var file = new Packages.java.io.File('filename');

Впрочем, также существуют глобальные объекты java, com, org, edu и net, поэтому код можно сократить до следующего:
var file = new java.io.File('filename');

Для импорта можно пользоваться таким pattern-ом:
var File = java.io.File;
//...
var file = new File('filename');

Но все же удобнее так:
importClass(java.io.File);
//...
var file = new File('filename');

Или так:
importPackage(java.io);
//...
var file = new File('filename');

Rhino позволяет реализовывать интерфейсы Java удобным для JS-программиста способом:
var runnable = new java.lang.Runnable({run: function() { print("I'm running!"); }});
new java.lang.Thread(runnable).start();

Кстати, обратите внимание на то, что java.lang не импортируется в глобальный контекст во избежание конфликтов со встроенными типами ECMAScript.

А еще последние версии Rhino включают полноценную реализацию CommonJS, которую можно включить в Rhino Shell с помощью switch-а -require.

Если у нас есть модуль ./modules/math.js:
exports.sum = function(a, b) {
  return a + b;
}

То воспользоваться им можно так:
var math = require('math');
print(math.sum(2, 4));

Запускается этот код так:
java -Djava.ext.dirs=./lib org.mozilla.javascript.tools.shell.Main -require -modules ./modules test.js


Jetty


В качестве основы для HTTP-сервера возьмем Jetty. Jetty — контейнер servlet-ов, а заодно и гибкий в настройке web-server с поддержкой SPDY, WebSocket, OSGi, JMX, JNDI и JAAS. Скачать дистрибутив можно тут.

Простейший код, запускающий Jetty:
importPackage(org.eclipse.jetty.server);

var server = new Server(8888); // Порт 8888
server.start();
server.join(); // Передадим управление Jetty

JAR-ы из дистрибутива Jetty следует также поместить в ./lib, в дальнейшем все будем запускать так:
java -Djava.ext.dirs=./lib org.mozilla.javascript.tools.shell.Main -require -modules ./modules server.js

Да, это все.

Этот сервер выдает HTTP 404 при любом запросе. Превратим его в простой файловый сервер.
importPackage(org.eclipse.jetty.server);
importPackage(org.eclipse.jetty.server.handler);

var resourceHandler = new ResourceHandler();
resourceHandler.setDirectoriesListed(true); // Разрешим просмотр списка файлов в папках
resourceHandler.setResourceBase('web'); // Установим базовой директорию ./web
resourceHandler.setWelcomeFiles(['index.html']); // В качестве главной страницы будет использоваться index.html

var server = new Server(8888);
server.setHandler(resourceHandler);
server.start();
server.join();

Теперь попробуем создать servlet.
importPackage(org.eclipse.jetty.server);
importPackage(org.eclipse.jetty.server.handler);
importPackage(org.eclipse.jetty.servlet);
importPackage(javax.servlet.http);

var contextHandler = new ServletContextHandler(ServletContextHandler.SESSIONS);
contextHandler.setContextPath('/');
contextHandler.addServlet(
  new ServletHolder(new HttpServlet({ // Обратим еще раз внимание на то, как изящно реализуются интерфейсы
    doGet: function(request, response) {
      response.setContentType('text/plain');
      response.getWriter().println('Yes, it works!');
    }
  })),
  '/test'
);

var server = new Server(8888);
server.setHandler(contextHandler);
server.start();
server.join();

Наш servlet доступен на http://localhost:8888/test. В качестве еще одного примера оформим в виде модуля servlet, генерирующий на лету картинку с текстом.
importPackage(java.awt.image);
importClass(java.awt.Color);
importClass(javax.imageio.ImageIO); // Входит в состав J2SE 6

var width = 400, height = 400;

exports.doGet = function(request, response) {
  var image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
  var graphics = image.createGraphics();
  var color = new Color(Math.random(), Math.random(), Math.random());
  graphics.setColor(color);
  graphics.fillRect(0, 0, width, height);
  graphics.setColor(color.brighter());
  graphics.drawString('On the fly!', 10, 20);

  response.setContentType('image/png');
  var outputStream = response.getOutputStream();
  ImageIO.write(image, 'png', outputStream);
  outputStream.close();
};

Поместим его в папку ./modules как imageServlet.js и включим в код сервера:
contextHandler.addServlet(
  new ServletHolder(new HttpServlet(require('imageServlet'))),
  '/image.png'
);

Что там с СУБД? Посмотрим, как получить список баз данных из MySQL.
importPackage(java.sql);

exports.doGet = function(request, response) {
  try {
    var connection = DriverManager.getConnection('jdbc:mysql://localhost/?', 'root', '');
    try {    
      var resultSet = connection
        .createStatement()
        .executeQuery('show databases;');

      response.setContentType('text/html;charset=UTF-8');
      var writer = response.getWriter();
      writer.println('<h1>Databases</h1>');
      while (resultSet.next()) {
        writer.println(resultSet.getString('Database') + '<br />');
      }
    } catch(e) {} finally {
      resultSet.close();
    }
  } catch(e) {} finally {
    if(connection)
      connection.close();
  }  
};

Для этого кода понадобится MySQL Connector/J для JDBC.

Теперь остался последний компонент, шаблонизатор.

FreeMarker


FreeMarker — определенно лучший шаблонизатор для Java, причем не только для HTML и HTTP. Про его богатые возможности можно написать отдельную статью, так что сразу перейдем к конкретике.

Положим в ./templates/template.ftl такой вот шаблон:
<html>
<head>
<title>${title}</title>
</head>
<body>
<h1>${title}</h1>
<#if message??>
  <pre>${message?html}</pre>
<#else>
  <form method="post">
    <textarea name="message"></textarea>
    <p><input type="submit" value="Post!"/></p>
  </form>
</#if>
</body>
</html>

Суффикс ?html заменяет в подставляемой переменной те самые спецсимволы на escape-последовательности. Этот шаблон будет использовать следующий servlet:
importPackage(Packages.freemarker.template);
importPackage(Packages.freemarker.ext.rhino);

var configuration = new Configuration();
configuration.setObjectWrapper(new RhinoWrapper()); // Поистине приятный сюрприз.
var template = configuration.getTemplate('templates/template.ftl');

exports.doGet = function(request, response) {
  response.setContentType('text/html;charset=UTF-8');
  template.process(
    {'title': 'Compose a message'},
    response.getWriter()
  );
};

exports.doPost = function(request, response) {
  response.setContentType('text/html;charset=UTF-8');
  template.process(
    {
      'title': 'Message',
      'message': request.getParameter('message')
    },
    response.getWriter()
  );
};

Сравнение с Node.js я благородно сваливаю на читателя. Полный код примера доступен на GitHub.
Читать дальше
Twitter
Одноклассники
Мой Мир

материал с habrahabr.ru

2

      Add

      You can create thematic collections and keep, for instance, all recipes in one place so you will never lose them.

      No images found
      Previous Next 0 / 0
      500
      • Advertisement
      • Animals
      • Architecture
      • Art
      • Auto
      • Aviation
      • Books
      • Cartoons
      • Celebrities
      • Children
      • Culture
      • Design
      • Economics
      • Education
      • Entertainment
      • Fashion
      • Fitness
      • Food
      • Gadgets
      • Games
      • Health
      • History
      • Hobby
      • Humor
      • Interior
      • Moto
      • Movies
      • Music
      • Nature
      • News
      • Photo
      • Pictures
      • Politics
      • Psychology
      • Science
      • Society
      • Sport
      • Technology
      • Travel
      • Video
      • Weapons
      • Web
      • Work
        Submit
        Valid formats are JPG, PNG, GIF.
        Not more than 5 Мb, please.
        30
        surfingbird.ru/site/
        RSS format guidelines
        500
        • Advertisement
        • Animals
        • Architecture
        • Art
        • Auto
        • Aviation
        • Books
        • Cartoons
        • Celebrities
        • Children
        • Culture
        • Design
        • Economics
        • Education
        • Entertainment
        • Fashion
        • Fitness
        • Food
        • Gadgets
        • Games
        • Health
        • History
        • Hobby
        • Humor
        • Interior
        • Moto
        • Movies
        • Music
        • Nature
        • News
        • Photo
        • Pictures
        • Politics
        • Psychology
        • Science
        • Society
        • Sport
        • Technology
        • Travel
        • Video
        • Weapons
        • Web
        • Work

          Submit

          Thank you! Wait for moderation.

          Тебе это не нравится?

          You can block the domain, tag, user or channel, and we'll stop recommend it to you. You can always unblock them in your settings.

          • habrahabr.ru
          • домен habrahabr.ru

          Get a link

          Спасибо, твоя жалоба принята.

          Log on to Surfingbird

          Recover
          Sign up

          or

          Welcome to Surfingbird.com!

          You'll find thousands of interesting pages, photos, and videos inside.
          Join!

          • Personal
            recommendations

          • Stash
            interesting and useful stuff

          • Anywhere,
            anytime

          Do we already know you? Login or restore the password.

          Close

          Add to collection

             

            Facebook

            Ваш профиль на рассмотрении, обновите страницу через несколько секунд

            Facebook

            К сожалению, вы не попадаете под условия акции