Журнал Хакер corporate blog
Website development
Java
23 April 2015

Веб на чистой Java. Изучаем Vaadin — крутой фреймворк для создания веб-приложений



В клиент-серверной архитектуре место Java-приложения — преимущественно на серверной стороне, при этом веб-интерфейс пишется отдельной группой фронт-енд разработчиков на JavaScript. Java не предлагает адекватных средств для создания современного веб-интерфейса (когда в последний раз ты видел Java-апплет..?) ни с точки зрения дизайна, ни с точки зрения реализации клиент-серверного взаимодействия.

А что, если бы все клиент-серверное приложение целиком писалось на Java, но его клиентская часть была бы «нативной» для браузера и соответствовала бы самым современным представлениям о юзабилити?

Введение



Рис. 1. Логотип Vaadin

Vaadin (кстати, в переводе с финского это слово означает «олениха») поддерживает все распространенные браузеры как обычных компьютеров, так и мобильных устройств и планшетов. Вся разработка ведется на Java, но Java-код выполняется только на сервере, на клиенте же выполняется чистый JavaScript.

Структурно Vaadin состоит из серверного API, клиентского API, набора компонентов пользовательского интерфейса с обеих сторон, механизма тем для оформления интерфейса и модели данных, позволяющей связывать серверные компоненты непосредственно с данными. Можно применять две основные модели разработки: на стороне сервера и на стороне клиента (браузера).


Рис. 2. Архитектура Vaadin

На рис. 2 показаны основные архитектурные компоненты веб-приложения, построенного с использованием Vaadin.

Серверная модель разработки


Оптимизировано для производительности


Серверная модель разработки для Vaadin является основной и позволяет создавать законченные приложения без разработки на стороне клиента. При этом используется AJAX-движок Vaadin Client-Side Engine, который формирует пользовательский интерфейс в браузере. Серверный подход позволяет фактически забыть про то, что разработка ведется под веб, и разрабатывать пользовательский интерфейс почти как традиционную Java-программу с непосредственным доступом к данным и сервисам на сервере. При этом серверная часть Vaadin позаботится и о формировании пользовательского интерфейса в браузере, и об AJAX-взаимодействии между браузером и сервером. Движок Vaadin осуществляет рендеринг пользовательского интерфейса приложения серверной стороны в браузере и реализует все детали обмена клиента и сервера.

Серверная часть приложения Vaadin исполняется как обычный сервлет сервера приложений Java. Она представляет собой чистую Java в JAR-файле, который может добавляться к любому стандартному веб-приложению и работает на любом контейнере сервлетов или портлетов от Tomcat до Oracle WebLogic. Сервлет принимает HTTP-запросы от клиента и интерпретирует их как события конкретной пользовательской сессии. События ассоциированы с компонентами пользовательского интерфейса и доставляются к обработчикам (event listeners), определенным в приложении. Если логика пользовательского интерфейса вносит изменения в компоненты пользовательского интерфейса со стороны сервера, сервлет рендерит их для отображения в веб-браузере и формирует ответ. Движок клиентской части, выполняемый в браузере, получает ответ и на его основе производит изменения в загруженной в браузере веб-странице.

Клиентская модель разработки


Оптимизировано для контроля


Клиентская модель позволяет разрабатывать виджеты и приложения на языке Java, которые затем компилируются в выполняемый в браузере JavaScript с помощью компилятора Vaadin Compiler, основанного на Google Web Toolkit (GWT). Можно использовать и непосредственно JavaScript. Это предоставляет полный доступ к структуре DOM и максимальный контроль над браузером.

Подготовка среды разработки


Ниже описывается использование Vaadin в среде NetBeans 8.0.2 (версия Vaadin Plug-in for NetBeans — 1.1.3); во врезке есть ссылки на обучающие видео для работы в IntelliJ IDEA и Eclipse (плагин для Eclipse включает в себя графический редактор пользовательского интерфейса).

Первым шагом в NetBeans IDE будет установка плагина (Tools -> Plugins -> Available Plugins, ввести vaadin в поле Search, установить галочку у 'Vaadin Plug-in for NetBeans' и нажать Install, согласившись со всеми вопросами).

Теперь при создании нового проекта (File -> New Project) стала доступна новая категория Vaadin. Выберем Vaadin Web Application Project, нажмем Next и укажем имя нового проекта, например myvaadin.


Рис. 3. Структура проекта

После нажатия Finish будет создана группа проектов приложения Vaadin по умолчанию. Основной файл с минимальным примером исходного кода приложения Vaadin расположен в проекте myvaadin-ui, файл /Source Packages/com.mycompany.myvaadin/MyUI.java; его ключевая часть выглядит так (опущены инструкции package и import):

@Theme("mytheme")
@Widgetset("com.mycompany.myvaadin.MyAppWidgetset")
public class MyUI extends UI {

    @Override
    protected void init(VaadinRequest vaadinRequest) {
        final VerticalLayout layout = new VerticalLayout();
        layout.setMargin(true);
        setContent(layout);

        Button button = new Button("Click Me");
        button.addClickListener(new Button.ClickListener() {
            @Override
            public void buttonClick(ClickEvent event) {
                layout.addComponent(new Label("Thank you for clicking"));
            }
        });
        layout.addComponent(button);

    }

    @WebServlet(urlPatterns = "/*", name = "MyUIServlet", asyncSupported = true)
    @VaadinServletConfiguration(ui = MyUI.class, productionMode = false)
    public static class MyUIServlet extends VaadinServlet {
    }
}

В этом простейшем проекте объявляется класс MyUI, являющийся наследником класса UI. В нем переопределяется метод init(). Внутри него создается вертикальная компоновка VerticalLayout, у нее включается отступ (margin), создается новая кнопка с обработчиком нажатия, который добавляет компонент типа Label с текстовой строкой. Затем кнопка добавляется к компоновке вызовом метода addComponent(). Директива Theme(«mytheme») задает используемую тему оформления (о них чуть ниже).

Перед первым запуском пересоберем все проекты (правый клик на 'myvaadin — myvaadin-parent' -> Build)

Для запуска в отладочном режиме можно использовать плагин Jetty или интегрированный в NetBeans сервер GlassFish Server
Щелкнем правой кнопкой на проекте -> Debug –> в окне Select Deployment Server из выпадающего списка выберем GlassFish Server.

После того как будут установлены все зависимости и перекомпилированы компоненты приложения, запустится сервлет и автоматически откроется окно браузера.


Рис. 4. Минимальное приложение Vaadin

Темы и стили


Взглянем непосредственно в инспекторе или в Firebug, что собой представляет кнопка на нашей форме (рис. 5).


Рис. 5. Кнопка пользовательского интерфейса

<div tabindex="0" role="button" class="v-button v-widget">
  <span class="v-button-wrap">
  <span class="v-button-caption">Click Me</span>
  </span>
</div>


Рис. 6. Просмотр HTML и стилей в Firebug

Все стили кнопки берутся из файла styles.css. Этот файл находится в разделе /Web Pages/VAADIN/themes/mytheme/ проекта myvaadin-ui и генерируется из SASS-файлов styles.scss, mytheme.scss и addons.scss, размещенных в том же каталоге. В них за основу берется базовый стиль, называющийся Valo (его предыдущая версия называлась Reindeer и местами по-прежнему упоминается в документации). Почитать про Valo можно здесь, а здесь можно посмотреть примеры всех компонентов.

Основные параметры темы вынесены в переменные, и для полной смены внешнего вида приложения достаточно изменения считаного числа параметров. Например, цвет шрифта определяется автоматически на основании цвета фона. Сам же цвет фона задается переменной $v-background-color. Чтобы изменить его, добавим в начало файла mytheme.scss следующую строку:

$v-background-color: #000;

Затем нужно щелкнуть правой кнопкой мышки на проекте myvaadin-ui и выбрать Vaadin -> Compile Widgetset and Theme или Compile Theme, после чего обновить в браузере страницу.
При этом фоновый цвет большинства элементов проекта изменится на черный, цвет шрифта изменится автоматически.

Благодаря такому подходу для того, чтобы полностью переоформить приложение, скажем, под плоский стиль Metro, достаточно двух десятков строк, переопределяющих значения переменных, без изменения собственно стилей. Результат можно посмотреть здесь (выбрав тему Metro в правом верхнем углу), а исходный текст — здесь:

Можно переопределять стиль и напрямую. К примеру, изменить цвет надписи на кнопке можно, добавив в файл mytheme.scss следующие строки (ниже строки «// Insert your own theme rules here»):

$textcolor: red;

.v-button-caption {
  color: $textcolor;
}

Затем перекомпилировать темы и обновить страницу браузера.

Вместо того чтобы создавать свою тему, можно воспользоваться и одной из готовых, изменив название темы с mytheme на одно из следующих: valo, runo, reindeer, chameleon, liferay.

Подробнее о темах можно прочитать здесь.

Создание браузерного файл-менеджера


Чтобы почувствовать всю элегантность подхода, предлагаемого Vaadin, реализуем прототип файл-менеджера.

Отображение файловой системы — знакомство с TreeTable и контейнерами


Container — интерфейс Vaadin, представляющий собой источник табличных или иерархических данных. Подробнее о контейнерах можно почитать здесь. Для доступа к базе данных SQL предназначен контейнер SQLContainer. Для файловой системы также существует готовый контейнер FilesystemContainer, который мы и используем в этом проекте.

Контейнер можно задавать в качестве источника данных для элементов типа Table (табличные данные), Tree и TreeTable (для отображения иерархических данных) и других.

Начнем с того, что создадим новый проект с названием fileman. Добавим классу MyUI метод создания и инициализации элемента TreeTable, который будет отображать структуру каталога (если строка в исходном тексте подсвечивается красным, это значит, что для данного класса нет соответствующей строки import; чтобы ее добавить, можно нажать <Alt + Enter> и выбрать «Add import for...». Нужно уточнить, что ниже для класса File потребуется выбрать из предложенных именно java.io.File):

public class MyUI extends UI
{
. . .
    private TreeTable treetable;

    private void initFileTree(ComponentContainer parentLayout) {
        // Создадим объект TreeTable для отображения иерархических данных в табличном виде
        treetable = new TreeTable("File System");
        treetable.setSelectable(true);
        treetable.setColumnCollapsingAllowed(true);
        treetable.setColumnReorderingAllowed(true);
        treetable.setSizeFull();
        parentLayout.addComponent(treetable);
    }
. . .
}    

Добавим метод установки новых данных TreeTable из FilesystemContainer

private void updateFileTree(File sourcePath) {
    // Создаем контейнер файловой системы
    FilesystemContainer currentFileSystem = new FilesystemContainer(sourcePath);
    currentFileSystem.setRecursive(false); // Отключаем рекурсивное считывание подкаталогов

    // Связываем его с объектом TreeTable, отображающим файловую систему
    treetable.setContainerDataSource(currentFileSystem);
    treetable.setItemIconPropertyId("Icon");
    treetable.setVisibleColumns(new Object[]{"Name", "Size", "Last Modified"}); // Для того чтобы скрыть колонку с идентификатором иконки, укажем нужные колонки
}

Также добавим метод определения каталога проекта по умолчанию.

private File currentPath;

// Вспомогательная функция для получения каталога приложения по умолчанию
// ~/NetBeansProjects/fileman/target/fileman-1.0-SNAPSHOT/
private void getDefaultDirectory() {
    UI ui = MyVaadinUI.getCurrent();
    VaadinSession session = ui.getSession();
    VaadinService service = session.getService();
    currentPath = service.getBaseDirectory();
}

Создадим новый метод initAll, добавив в него вызовы объявленных выше методов:

// Инициализация всех элементов
private void initAll(VerticalLayout layout) {
    initFileTree(layout);
    getDefaultDirectory();
    updateFileTree(currentPath);
}

В методе init() удалим все, что связано с кнопкой button, и добавим в конце вызов нового метода initAll() так, чтобы init() выглядел следующим образом:

@Override
protected void init(VaadinRequest request) {
    final VerticalLayout layout = new VerticalLayout();
    layout.setMargin(true);
    setContent(layout);
    initAll(layout);
}

Добавим заготовки под функции для

// Обновление всех элементов
private void updateAll() {
    updateFileTree(currentPath);
    updateInfo();
}

// Обновление информации о файле/каталоге (при изменении файла/каталога)
private void updateInfo() {
}

Сохраним файл и запустим приложение в отладочном режиме. Если приложение уже было запущено раньше, то после сохранения и завершения развертывания (deploy) достаточно просто обновить страницу в браузере.

Обработка событий компонента TreeTable


В конце метода initFileTree добавим обработчик одинарного и двойного нажатия кнопок мыши:

// Добавляем обработчик нажатия
treetable.addItemClickListener(new ItemClickEvent.ItemClickListener() {
    @Override
    public void itemClick(ItemClickEvent itemClickEvent) {
        String clickedFilename = itemClickEvent.getItemId().toString(); // Элемент, на котором была нажата кнопка мыши
        System.out.println("ItemClick: pathname:" + clickedFilename);

        // Если двойной клик
        if (itemClickEvent.isDoubleClick()) {
            doChangeDir(clickedFilename);
        } else {
            doSelectFile(clickedFilename);
        }
    }
});

Добавим методы классу MyUI для обработки действий пользователя

private String selectedFilename;

// Пользовательское действие — обновление каталога
private void doRefresh() {
    updateAll();
}

// Пользовательское действие — переход в другой каталог
private void doChangeDir(String path) {
    currentPath = new File(path);
    if (currentPath.isDirectory()) {
        selectedFilename = null;
        updateAll();
    }
}

// Пользовательское действие — переход в каталог на уровень выше
private void doUpLevel() {
    currentPath = currentPath.getParentFile();
    selectedFilename = null;
    updateAll();
}

// Пользовательское действие — выбор файла
private void doSelectFile(String filename) {
    selectedFilename = filename;
    updateInfo();
}

С этого момента по двойному клику уже можно переходить в каталог, находящийся уровнем ниже.

Главное меню — компонент MenuBar


Добавим главное меню с пунктами Refresh и Up Level в подменю File, подобное горизонтальным меню традиционных приложений:

private void initMenuBar(Layout parentLayout) {
    // Описание объекта MenuBar
    // https://vaadin.com/book/-/page/components.menubar.html

    // Создаем главное меню
    MenuBar menuBar = new MenuBar();    // Создаем объект
    menuBar.setWidth("100%");           // Растягиваем на 100% доступной ширины
    parentLayout.addComponent(menuBar); // Добавляем в layout    

    // Добавляем в главное меню подменю File
    final MenuItem fileMenuItem = menuBar.addItem("File", null, null);

    // Добавляем в меню File элемент Refresh и обработчик при его выборе
    fileMenuItem.addItem("Refresh", FontAwesome.REFRESH, new MenuBar.Command() {
        @Override
        public void menuSelected(MenuItem selectedItem) {
            doRefresh();
        }
    });

    // Добавляем в меню File элемент Up Level и обработчик при его выборе
    fileMenuItem.addItem("Up Level", FontAwesome.ARROW_UP, new MenuBar.Command() {
        @Override
        public void menuSelected(MenuItem selectedItem) {
            doUpLevel();
        }
    });
}

private void updateMenuBar() {
    // Пока ничего не делать
}

И вызов этих методов в метод InitAll() первой строкой (иначе меню окажется ниже всех других элементов):

initMenuBar(layout);

и в updateInfo():

updateMenuBar();

Верхняя и нижняя панели


Следующим шагом добавим панель сверху, на которой расположим кнопки и информацию о текущем пути / имени выбранного файла и панель снизу для отображения информации о файле. Внутри класса MyUI добавим:

private Label labelFileName;

// Инициализация верхней панели, содержащей кнопки и текущий путь / выбранный файл
private void initTopPanel(Layout parentLayout) {
    // Создаем новую горизонтальную компоновку, которая будет служить панелью инструментов
    HorizontalLayout topPanelLayout = new HorizontalLayout();
    // Растягиваем на 100% доступной ширины
    topPanelLayout.setWidth("100%");
    // Между элементами будет пустое пространство
    topPanelLayout.setSpacing(true);
    // Добавляем к основной компоновке
    parentLayout.addComponent(topPanelLayout); 

    // Создаем кнопку Refresh
    // Создаем сам объект
    Button button = new Button("Refresh");
    // Задаем иконку из FontAwesome
    button.setIcon(FontAwesome.REFRESH);
    // Есть стили разных размеров
    // button.addStyleName(ValoTheme.BUTTON_SMALL);
    // Добавляем в компоновку
    topPanelLayout.addComponent(button);                 
    // Добавляем обработчик нажатия
    button.addClickListener(new Button.ClickListener() { 
        @Override
        public void buttonClick(Button.ClickEvent event) {
            doRefresh();
        }
    });

    // Создаем кнопку Up Level
    // Создаем сам объект
    button = new Button("Up Level");
    // Задаем иконку из FontAwesome
    button.setIcon(FontAwesome.ARROW_UP);
    // Есть стили разных размеров
    // button.addStyleName(ValoTheme.BUTTON_SMALL);
    // Добавляем в компоновку
    topPanelLayout.addComponent(button);
    // Добавляем обработчик нажатия
    button.addClickListener(new Button.ClickListener() {
        @Override
        public void buttonClick(Button.ClickEvent event) {
            doUpLevel();
        }
    });

    // Добавляем текст с именем выбранного файла
    // Создаем сам объект
    labelFileName = new Label();
    // Добавляем в компоновку
    topPanelLayout.addComponent(labelFileName);
    topPanelLayout.setComponentAlignment(labelFileName, Alignment.MIDDLE_CENTER);
    // Данный компонент будет занимать все доступное место
    topPanelLayout.setExpandRatio(labelFileName, 1);
}

// Обновление верхней панели
private void updateTopPanel(File currentPath, String selectedFilename) {
    if (selectedFilename != null) {
        labelFileName.setValue(selectedFilename);
    } else {
        labelFileName.setValue(currentPath.toString());
    }
}

Инициализация нижней панели, содержащей информацию о выбранном файле

  Label[] bottomLabels;
  private void initBottomPanel(Layout parentLayout) {
    final String[] captions = new String[]{
        "File Size (Bytes)", "File Date", "Usable Space (Bytes)", "Total Space (Bytes)", "Free Space (Bytes)"
    };

    HorizontalLayout bottomPanelLayout = new HorizontalLayout();
    // Растягиваем на 100% доступной ширины
    bottomPanelLayout.setWidth("100%"); 
    parentLayout.addComponent(bottomPanelLayout);

    // Создаем объекты Label для отображения информации о файле
    bottomLabels = new Label[captions.length];
    for (int i = 0; i < captions.length; i++) {
        bottomLabels[i] = new Label();
        bottomLabels[i].setCaption(captions[i]);
        bottomLabels[i].setValue("NA");
        bottomPanelLayout.addComponent(bottomLabels[i]);
    }
}

// Обновление нижней панели
private void updateBottomPanel(String pathname) {
    try {
        File file = new File(pathname);
        // Присваиваем значения объектам Label — информация о файле
        bottomLabels[0].setValue(Long.toString(file.length()));
        bottomLabels[1].setValue((new Date(file.lastModified())).toString());
        // Информация о диске
        bottomLabels[2].setValue(Long.toString(file.getUsableSpace()));
        bottomLabels[3].setValue(Long.toString(file.getTotalSpace()));
        bottomLabels[4].setValue(Long.toString(file.getFreeSpace()));
    } catch (Exception e) { 
        // Скроем исключительную ситуацию
        for (Label bottomLabel : bottomLabels) {
            bottomLabel.setValue("NA");
        }
    }
}

Добавляем вызов этих методов в метод InitAll(), приведя его к следующему виду:

private void initAll(VerticalLayout layout) {
    initMenuBar(layout);
    initTopPanel(layout);

    initFileTree(layout);
    getDefaultDirectory();
    updateFileTree(currentPath);
            
    initBottomPanel(layout);
}


и в updateInfo(), приведя его к следующему виду:

private void updateInfo() {
    updateMenuBar();
    updateTopPanel(currentPath, selectedFilename);
    updateBottomPanel(selectedFilename);
}

После сохранения и обновления страницы в браузере, файл-менеджер получит меню, панель инструментов и панель статуса.

Предварительный просмотр и сплиттер — компоненты HorizontalSplitPanel, Embedded


Добавим нашему файл-менеджеру панель предварительного просмотра графических файлов. По аналогии несложно сделать предварительный просмотр для текстовых файлов с помощью компонента TextArea.

private HorizontalLayout previewLayout;
private Embedded previewEmbedded;

// Инициализация основной панели, содержащей просмотр файловой структуры и предварительный просмотр файла
private void initMainPanels(VerticalLayout parentLayout) {
    HorizontalSplitPanel mainPanels = new HorizontalSplitPanel();
    mainPanels.setSizeFull();
    parentLayout.addComponent(mainPanels);
    parentLayout.setExpandRatio(mainPanels, 1);

    initFileTree(mainPanels);
    initPreview(mainPanels);
}

// Инициализация панели предварительного просмотра файла
private void initPreview(ComponentContainer parentLayout) {
    previewLayout = new HorizontalLayout();
    previewLayout.setSizeFull();
    parentLayout.addComponent(previewLayout);
    
    // Создаем элемент для предпросмотра изображений
    // Создаем объект Embedded
    previewEmbedded = new Embedded("Preview area", null); 
    // Задаем видимость
    previewEmbedded.setVisible(true);    
    // Добавляем в компоновку
    previewLayout.addComponent(previewEmbedded); 
    // Располагаем по центру
    previewLayout.setComponentAlignment(previewEmbedded, Alignment.MIDDLE_CENTER); 
}

// Скрыть предварительный просмотр файла
private void clearPreview() {
    previewEmbedded.setSource(null);
    previewEmbedded.setVisible(true);
}

// Обновить предварительный просмотр файла
private void updatePreview(String pathname) {
    if (pathname == null || pathname.length() == 0) {
        clearPreview();
        return;
    }
    // Выделим расширение файла
    File file = new File(pathname);
    int lastIndexOf = pathname.lastIndexOf(".");
    String extension = (lastIndexOf == -1) ? "" : pathname.substring(lastIndexOf);
    // Ограничение на размер файла для предпросмотра — до 128 Кб
    final int PREVIEW_FILE_LIMIT = 128 * 1024;
    // Расширения файлов для предпросмотра с помощью объекта Embedded (изображения, Flash и так далее)
    final String[] imageExtensions = new String[]{
        ".gif", ".jpeg", ".jpg", ".png", ".bmp", ".ico", ".cur", "swf", "svg"
    };
    // Скроем объект, используемый для предпросмотра
    previewEmbedded.setVisible(false);
    // Проверим, не превышает ли размер файла пороговый
    if (file.length() > PREVIEW_FILE_LIMIT) {
        clearPreview();
        return;
    }
    // Если расширение файла — в списке изображений
    if (Arrays.asList(imageExtensions).contains(extension)) {
        Resource resource = new FileResource(file); // Создаем файловый ресурс
        previewEmbedded.setSource(resource);        // Задаем источник для объекта Embedded
        previewEmbedded.setVisible(true);           // Показываем объект
        previewLayout.setExpandRatio(previewEmbedded, 1.0f); // Будет занимать все доступное место 
    }
}

И добавляем метод initMainPanels() в метод InitAll(), вместо вызов метода инициализации дерева файлов initFileTree(), так как теперь он вызывается из initMainPanels:

private void initAll(VerticalLayout layout) {
    initMenuBar(layout);
    initTopPanel(layout);
    // initFileTree(layout);
    initMainPanels(layout);
    getDefaultDirectory();
    updateFileTree(currentPath);                
    initBottomPanel(layout);
}

и добавляем в updateInfo() строку

updatePreview(selectedFilename);      

Не забудь скопировать изображение в папку по умолчанию (<каталог проектов NetBeans (NetBeansProjects)>/fileman/fileman-ui/target/fileman-ui-1.0-SNAPSHOT
).

Ну вот и все, с помощью нашего файл-менеджера можно перемещаться по файловой системе, просматривать файлы и их свойства.

Мы получили клиент-серверное приложение для браузера, не написав ни строчки на JavaScript, не затратив времени на реализацию AJAX-взаимодействия и вообще не задумавшись о всех нюансах веб-разработки.


Рис. 6. Интерфейс приложения

Заключение


В целом фреймворк оставляет очень приятное впечатление своей продуманностью и документированностью, большим количеством примеров с исходными кодами на GitHub. Журнал «Хакер» (на данный момент под этим утверждением подписался автор, редактор и главред) рекомендует тебе его использование, в том числе внутрь и в неограниченных количествах!

Google Web Toolkit (GWT)


Google Web Toolkit (GWT) — библиотека с открытым кодом, предоставляющая набор Java API и визуальных компонентов, позволяющих разрабатывать AJAX-приложения на Java и затем компилировать их исходные тексты в высоко оптимизированный JavaScript, работающий на всех основных браузерах, включая мобильные браузеры для Android и iPhone. Подробнее — здесь.

VIDEO



WWW


  • Подробно начало работы описано в разделе Getting Started with Vaadin электронной книги Book of Vaadin.
  • Отличным дополнением книге служит Book of Vaadin Examples, с фрагментами исходного кода для подавляющего большинства разделов книги и элементов Vaadin.
  • Небольшой учебный пример приложения можно посмотреть здесь.
  • Более сложные демоприложения.
  • Документация по API доступна здесь.

Vaadin TouchKit


Vaadin TouchKit предназначен для разработки приложений для мобильных устройств. В него входят компоненты, оптимизированные для мобильного интерфейса, а также функции, специфичные для мобильных устройств. Кроме обычного интерфейса, формируемого на сервере, TouchKit поддерживает специальный офлайн-режим, в котором клиентский интерфейс сохраняется в кеше браузера и включается автоматически при недоступности сети.

Vaadin TestBench


Базируется на библиотеке Selenium, что позволяет управлять браузером непосредственно из кода Java.
С помощью Vaadin TestBench реализуется автоматизированное тестирование на всех уровнях и фазах разработки вплоть до сравнения скриншотов. Более подробно можно прочитать здесь.

Дополнения Vaadin


В Vaadin Directory на данный момент почти 500 различных дополнений, среди которых можно, например, отметить компонент Vaadin Charts, предназначенный для отрисовки графиков и диаграмм.

Для доступа к каталогу дополнений в контекстном меню проекта есть пункт Open Add-Ons Browser.

image

Впервые опубликовано в журнале «Хакер» от 02/2015.
Автор: Александр Лыкошин, alykoshin@gmail.com


Подпишись на «Хакер»

+13
84.2k 261
Comments 38
Top of the day