Как стать автором
Обновить

Компактный Java сервлет для мобильного веб

Время на прочтение 7 мин
Количество просмотров 6.3K

Основная область программирования для меня, это разработка программного обеспечения для автоматизации учёта в торговли. С возможностью использовать для этого сервлеты Java я столкнулся в 2009 году, когда вместе с последней, вышедшей для десктопа, версией Openbravo POS шёл модуль ресторана для PDA. Основной идей тогда для разработчиков Openbravo POS было, чтобы не усложнять десктопную версию приложения, вынести узкую бизнес-логику в отдельное небольшое приложение, главной изюминкой которого был компактный веб-интерфейс для доступа с любого устройства, а не только того, где может быть запущена Java c Swing. При этом тогда предполагалось, что сервлет не только будет работать с одной и той-же базой, что и десктоп версия, но и контейнер для него будет интегрирован в приложение на десктопе, после запуска которого пользователь автоматический получал доступ к POS в радиусе действия Wi-Fi сети. В рамках комьюнити данная идея дальнейшего развития не получила, но я с 2012 для своих клиентов заложенными тогда принципы продолжаю пользоваться, и в данной статье расскажу читателям, как используя Stripes Framework в связке с jQuery Mobile и ORMLite, получить инструмент для быстрой разработки небольших сервлетов ориентированных на мобильный веб.

Инструментарий


Обычно, когда ищешь инструмент разработки, то стараешься найти что-то универсальное, что можно изучив однажды использовать повторно на протяжении достаточно долгого времени. В 2012 года именно с этим я столкнулся, когда попытался переделать исходный код ресторанного модуля Openbravo POS. В его основе лежал фреймворк Struts 1, изучать написание XML-схем для которого меня совсем не радовало, но на удачу, как раз в тот момент, мне на глаза попался обзор технологий экосистемы Java от RebelLabs. Один из разделов этого обзора был посвящён популярности веб-фреймворков у разработчиков, в эту 10-ку с почётными 2% входил Stripes. С его освоения я и начал изучение основ разработки Java сервлетов. Также мне помогло то, что к тому моменту на Хабре в «Песочнице» уже была обзорная статья про этот фреймворк.

В Stripes всё подчинено логике реакции на контролеры(ActionBean), которые отвечают за получение доступа к модели данных для дальнейшего отображения пользователю через шаблоны страниц JSP. Так как мне нужен был мобильный веб-интерфейс, то для визуальной части я выбрал jQuery Mobile, главный плюс которого, это возможность практически не касаясь JavaScript использовать только HTML5 разметку для построения динамической реакции на действия контролера.

Третьим элементом, отвечающим за работу с моделью данных, мной сначала был выбран совсем простой Persist ORM/DAO, но когда его функционала стало недостаточно, я сменил его на более мощный ORMLite. Главным при выборе стала лёгкость использования уже существующей модели представления и отсутствия необходимости написания SQL-запросов обходясь, как и в случае Stripes, только аннотациями.

Модель-Представление-Контролер


Ключевым в Stripes является 100% ориентированность на концепцию MVC(Model-View-Controller). А главной целью создания данного фреймворка в 2005 году было создание более легковесной реализация MVC концепции для Java EE, чем была реализована в популярном на тот момент фреймворке Struts. К версии 1.5 в 2008 году эта цель авторами Stripes была полностью достигнута и данный фреймворк начал набирать популярность среди разработчиков.

При проектировании структуры исходного кода сервлета следует стараться не выходить за рамки парадигмы Модель-Представление-Контролер, что не очень сложно сделать для большинства задач при создании CRUD-приложений. Для примера, в исходном коде для справочника товаров, это будет выглядеть так:

Источник данных, исходная SQL-таблица
CREATE TABLE PRODUCTS (
    ID VARCHAR(255) NOT NULL,
    NAME VARCHAR(255) NOT NULL,
    CODE VARCHAR(255) NOT NULL,
    PRICESELL DOUBLE NOT NULL,
    CATEGORY VARCHAR(255) NOT NULL,
    PRIMARY KEY (ID),
    CONSTRAINT PRODUCTS_FK_1 FOREIGN KEY (CATEGORY) REFERENCES CATEGORIES(ID)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE UNIQUE INDEX PRODUCTS_CODE_INX ON PRODUCTS(CODE);
CREATE UNIQUE INDEX PRODUCTS_NAME_INX ON PRODUCTS(NAME);


Модель данных с аннотациями для ORMLite
@DatabaseTable(tableName = "PRODUCTS")
public class Product {

    public static final String ID = "ID";
    public static final String NAME = "NAME";
    public static final String CODE = "CODE";
    public static final String PRICESELL = "PRICESELL";
    public static final String CATEGORY = "CATEGORY";

    @DatabaseField(generatedId = true, columnName = ID)
    private UUID id;

    @DatabaseField(columnName = NAME, unique = true, canBeNull = false)
    private String name;
    
    @DatabaseField(columnName = CODE, unique = true, canBeNull = false)
    private String code;

    @DatabaseField(columnName = PRICESELL, canBeNull = false)
    private BigDecimal pricesell;

    @DatabaseField(foreign = true,
            columnName = CATEGORY,
            foreignColumnName = ProductCategory.ID,
            foreignAutoRefresh = true,
            canBeNull = false)
    private ProductCategory productCategory;

    // ...
    // Перечисления методов get и set.
    // ...
}



В начале, с помощью ORMLite, задаётся структура модели данных и её связь с реляционной базой данных(значение полей tableName и columnName). Затем через геттеры и сеттеры модель предоставляет доступ для остальных классов и методов сервлета.

Контроллер Stripes для ввода/вывода данных
public class ProductCreateActionBean extends ProductBaseActionBean {

    private static final String PRODUCT_CREATE = "/WEB-INF/jsp/product_create.jsp";

    @DefaultHandler
    public Resolution form() {
        // Открытие формы для заполнения.
        return new ForwardResolution(PRODUCT_CREATE);
    }

    public Resolution add() {
        // ...
        // После проверки полученных значений, создание записи в таблице.
        // ...
    }

    @ValidateNestedProperties({        
        @Validate(on = {"add"},
                field = "name",
                required = true,
                trim = true,
                maxlength = 255),
        @Validate(on = {"add"},
                field = "code",
                required = true,
                trim = true,
                minlength = 8,
                maxlength = 13),
        @Validate(on = {"add"},
                field = "priceSell",
                required = true,
                converter = BigDecimalTypeConverter.class),
        @Validate(field = "productCategory.id",
                required = true,
                converter = UUIDTypeConverter.class)
    })
    @Override
    public void setProduct(Product product) {
        super.setProduct(product);
    }

}


Контроллер перехватывает данные передаваемые пользователем и обрабатывает их согласно заданных аннотаций. Например, выполняя Resolution form(), получив значение ключевого поля productCategory.id, он пропускает его через UUIDTypeConverter, проверяя соответствует-ли оно допустимым для UUID критериям.

Шаблон JSP с разметкой jQueryMobile и полями Stripes

    <!-- Заглавие страницы -->

    <stripes:layout-component name="content">
        <stripes:errors />
        <stripes:messages />
        <stripes:form action="/ProductCreate.action?add">
            <div>
                <stripes:hidden name="product.productCategory.id" value="${actionBean.product.productCategory.id}"/>
            </div>
            <ul data-role="listview" data-inset="true">                
                <li class="ui-field-contain">
                    <stripes:label name="label.Product.name" for="productName" />
                    <input name="product.name" id="productName" type="text"
                           data-clear-btn="true">
                </li>
                <li class="ui-field-contain">
                    <stripes:label name="label.Product.code" for="productCode" />
                    <input name="product.code" id="productCode" type="text"
                           data-clear-btn="true">
                </li>
                <li class="ui-field-contain">
                    <stripes:label name="label.Product.price" for="productPrice"/>
                    <input name="product.priceSell" id="productPrice" type="number"
                           step="0.01"                           
                           value="0.00"
                           data-clear-btn="true">
                </li>
                <li class="ui-body ui-body-b">
                    <fieldset class="ui-grid-a">
                        <div class="ui-block-a">
                            <sdynattr:submit name="add" data-theme="a"/>
                        </div>
                        <div class="ui-block-b">
                            <sdynattr:reset name="clear" data-theme="b"/>
                        </div>
                    </fieldset>
                </li>
            </ul>        
        </stripes:form>
    </stripes:layout-component>

    <!-- Окончание страницы -->




В шаблоне страницы разметка jQuery Mobile также может служить для предварительной проверки вводимых данных, например в визуальной форме предлагая пользователю на мобильном устройстве разные клавиатуры для текста и чисел(в input параметр type равен "text" или "number").

Для чего подходит


В конце прошлого 2013 года RebelLabs был опубликован новый обзор перспектив развития фреймворков в будущем 2014 году. Stripes в данный обзор не вошёл, так как в основном внимание было уделено более полярным чем он фреймворкам, таким как Spring, Grails или Vaadin. Но мне кажется, что если совместно с ним использовать jQuery Mobile и ORMLite, то и он сейчас найдёт свою нишу в инструментарии разработчика на Java. По крайней мере в 4 из 7 предложенных RebelLabs сфер применения с ним можно чувствовать себя вполне уверенно:
  1. Приложения CRUD — об этом было выше, если всё делать последовательно и по одной схеме, то очень сложно сделать плохо. Главное при проектировании стараться каждое действие контроллера делать максимально полным, но не переполненным.
  2. Мобильные приложения — тут основная нагрузка лежит на jQuery Mobile, для Java программиста несомненный плюс, что кроме HTML5 можно не трогать JavaScript и CSS.
  3. Прототипы приложений — это основное для чего я использую эту связку, набрав с 10-ок сервлетов в портфолио, можно отдельные компоненты каждого из них легко между собой тасовать под разные бизнес-процессы.
  4. Портирование десктоп приложений — а с этого у меня всё и началось, и именно для такого применения я могу порекомендовать в первую очередь сплав этих трёх фрейморков.



Это итог, новый интерфейса с jQuery Mobile версии 1.4 в 2014 году, в сравнении с тем интерфейсом, что был в 2009 году у PDA модуля Openbravo POS.

В качестве примера практической реализации изложенного в статье, небольшой проект CRUD-сервлета для каталог товара: github.com/nordpos-mobi/product-catalog
Теги:
Хабы:
0
Комментарии 0
Комментарии Комментировать

Публикации

Истории

Работа

Ближайшие события

Московский туристический хакатон
Дата 23 марта – 7 апреля
Место
Москва Онлайн
Геймтон «DatsEdenSpace» от DatsTeam
Дата 5 – 6 апреля
Время 17:00 – 20:00
Место
Онлайн