Статьи

Простой вывод HTML из Java с использованием renderSnake

renderSnake — еще один интересный проект, который я заметил в разделе объявлений JavaLobby. Идея проста, но эффективна — производить вывод HTML при создании компонентов Java. Я поговорил с владельцем проекта Эрнестом Миклеем, чтобы узнать больше 

Эрнест Миклей — старший разработчик / архитектор программного обеспечения с 19-летним опытом в разработке программного обеспечения. Он имеет ученую степень в области компьютерных наук и обладает обширными знаниями в области языков программирования, инструментов, методологий, архитектур и практик. В основном работает в проектах, связанных с Java, Ruby, Flex и Smalltalk, для страхования, банковского дела и электронной коммерции. Он является владельцем нескольких проектов с открытым исходным кодом и участвует в других. Его основными интересами являются SOA, параллельное ориентированное программирование, доменно-управляемый дизайн, облачные вычисления и высокопроизводительные веб-сайты. В настоящее время он работает архитектором программного обеспечения в Bol.com.

DZone: Что такое renderSnake и как оно работает?

Эрнест Миклей:renderSnake — это библиотека классов и интерфейса, которые поддерживают создание компонентов Java (в виде классов), которые могут генерировать HTML, визуализируя себя с использованием объекта HtmlCanvas. Этот класс предоставляет методы для открытия и закрытия тегов HTML.

canvas.html().body()._body()._html();
<html><body></body></html>

Имя метода с префиксом подчеркивания проверит и закроет элемент. Большинство таких методов также принимают экземпляр HtmlAttributes. Этот класс предоставляет методы для добавления атрибутов, пар ключ-значение.

canvas.div(id("header"));
<div id="header">

В дополнение к тегам HtmlCanvas может также отображать компоненты. Компонент — это POJO, который реализует интерфейс Renderable и обычно инкапсулирует фрагмент HTML со страницы.

public class MyComponent implements Renderable {
public void renderOn(HtmlCanvas html) throws IOException {
html.h1().write("I am a component")._h1();
}
}

и вы можете использовать этот компонент, как это:

canvas.render(new MyComponent());

Вы можете прочитать больше о том, как работает renderSnake здесь

DZone: Откуда пришло название?

Эрнест Миклей: Название — это просто сочетание «рендера» и «змеи». Создание HTML осуществляется путем программной визуализации элементов (тегов, атрибутов) на холсте (пустой странице). Эта метафора взята из платформы Seaside, популярной платформы, основанной на веб-компонентах Smalltalk.
Мой хороший друг предложил мне связать проект с каким-нибудь животным существом. Если вы посмотрите на исходный код полученных определений метода renderOn, то с некоторым воображением вы сможете увидеть форму вертикальной волны, которая выглядит как движение змеи. «S» в имени написано в верхнем регистре, чтобы подчеркнуть это.

DZone: Как долго вы работаете над проектом?

Эрнест Миклей:Проект начался в октябре 2010 года, и сначала он назывался NoJSP (да, я тоже следую за движением NoSQL), но это имя было отброшено из-за его негативного впечатления.
Я работал над большим проектом, в котором количество страниц и фрагментов JSP значительно увеличилось (более 400), большинство из которых следовали старой архитектуре Model 1. (http://www.java-samples.com/showtutorial.php?tutorialid=349). Его неконтролируемая сложность, частично связанная с технологией JSP, побудила меня экспериментировать с другим подходом, более близким к тому, что Java-разработчики знают и практикуют.

Имея опыт работы с инфраструктурой Seaside, которая также позволяет вам писать компоненты на том же языке программирования, что и логика вашей предметной области, я начал пробовать концепцию в Java для изучения API и конструкций классов. Затем я преобразовал часть существующего веб-приложения, чтобы увидеть, что потребуется для его реализации с помощью renderSnake. Как и ожидалось, с использованием компонентов было намного проще работать; Компоненты меньшего размера, легко комбинируемые, легко реорганизуются и лучше тестируются. Наконец, я сделал некоторые измерения производительности и посмотрел на распределение памяти / мусор, размер страницы и пропускную способность. Чтобы результаты были многообещающими, и тогда я решил продолжить этот проект и поделиться им с сообществом Java.
 
DZone: Почему вы выбрали Java в качестве языка проекта?

Эрнест Миклей:Ява была выбрана потому, что библиотека призвана стать альтернативой технологии JSP в веб-приложениях, использующей существующую «бизнес-логику» для управления фазой рендеринга. Другой мотивацией было быть как можно ближе к существующему популярному языку, для которого уже существуют многочисленные инструменты и библиотеки. Разработчики, которые хотят использовать renderSnake, не должны изучать еще один язык; все это Java и HTML.
 
DZone: Какие интеграции существуют?

Эрнест Миклей:Что касается хорошо известного шаблона MVC, я считаю renderSnake альтернативой реализации уровня представления для веб-приложений, которые принимают этот шаблон. Хотя библиотека включает в себя RenderSnakeServlet (часть контроллера), она разработана с минимальными зависимостями, так что она может интегрироваться с другими платформами. Если у такого фреймворка есть ловушка, где вы можете создать HtmlCanvas, тогда вы можете начать рендеринг ваших компонентов.

(1) Начать с простой интеграции — использование JSP. В этом подходе страница JSP используется в качестве контроллера, который извлекает объекты домена. Он создает объект HtmlCanvas и начинает рендеринг компонента Page. Ниже приведен пример скриптлета, который может быть частью файла accounts.jsp.

<%
// fetch the list of accounts
....
HtmlCanvas canvas = new HtmlCanvas(request,response,out);
canvas.getPageContext().set("accounts", listOfAccounts);
out.clearBuffer();
canvas.render(new AccountListPage());
%>

(2) Платформа Spring-MVC имеет гораздо лучшую поддержку для интеграции различных технологий представления. Библиотека renderSnake включает в себя и ViewResolver, и ArgumentResolver, чтобы обеспечить два решения для бесшовной интеграции. Используя последний подход, объявив аргумент HtmlCanvas в вашем методе диспетчеризации вашего контроллера, вы можете подготовить PageContext и начать рендеринг ваших компонентов.

@RequestMapping("/example.html")
@ResponseBody
public void renderExample(HtmlCanvas html) throws IOException {

html.getPageContext().set("today", new Date()); // stick domain objects in the context
html.render(new SiteLayoutWrapper(new ExampleUI())));
}

Библиотека renderSnake также обеспечивает интеграцию с исходными текстами на основе шаблонов. Классы StringResource и StringTemplate могут использоваться для инкапсуляции фрагментов многострочных текстов или встроенного Javascript, который должен быть включен на страницу. StringResource предназначен для переноса статического контента, StringTemplate предназначен для переноса контента, который имеет только несколько заполнителей контента.

DZone: Можете ли вы дать фрагмент кода, показывающий, как его использовать?

Эрнест Миклеи: Ниже приведен пример компонента Logo самого сайта renderSnake.
Он инкапсулирует фрагмент HTML, отвечающий за отображение заголовка и субтитров.
Объект html имеет методы для всех элементов HTML, таких как div, h1, a и style.
Эти методы необязательно принимают аргумент HtmlAttributes, который создается фабричными методами, такими как id, href и class_.
Поскольку каждый метод элемента HtmlCanvas возвращает сам себя, вы можете использовать свободный стиль программирования, «расставив точки».

public class Logo implements Renderable {
public void renderOn(HtmlCanvas html) throws IOException { //@formatter:off
html
.div(id("logo"))
.div(id("logo_text"))



.h1()
.a(href("index.html"))
.write("render")
.style().write(".snake { color:yellow; }")._style()



.span(class_("snake")).write("S")._span()
.write("nake")
._a()
._h1()
.h2().write("lean and mean HTML page writing machine")._h2()._div()



._div();
}
}

Используя правильный отступ источника, вы можете визуально убедиться, что элементы закрыты правильно (это проверяется во время выполнения).
Чтобы протестировать этот компонент изолированно, все, что вам нужно сделать, это создать HtmlCanvas и визуализировать экземпляр этого логотипа.  

 
DZone: Не могли бы вы предоставить нам обзор архитектуры?

Эрнест Микли: Вот две диаграммы, которые иллюстрируют использование и внутренний дизайн renderSnake.
Пример MVC показывает, как компоненты renderSnake могут использоваться для реализации слоя View в шаблоне MVC.

 

Диаграмма классов показывает основные классы для работы при сборке компонентов.

DZone: Почему вы говорите, что renderSnake эффективен?
Эрнест Миклеи: renderSnake разработан с минимальным созданием объектов, что приводит к низкой активности сборщика мусора. Вместо создания DOM-дерева объектов-элементов Html весь вывод записывается непосредственно в outputtream как (кодированные) строки. Тот же дизайн применяется к классу HtmlAttributes. Вместо того, чтобы поддерживать словарь атрибутов с информацией кодирования, пары ключ-значение атрибута записываются непосредственно в StringBuilder. Большинство компонентов рендеринга маленькие и недолговечные; они нужны только на этапе обработки запроса.