Использование javascript в Vaadin 7 или как я сэкономил $490 на графиках (часть 1)

в 16:59, , рубрики: highcharts, java, javascript, vaadin, Блог компании Dom24x7, Веб-разработка

В этой статье я расскажу вам как внедрял красивые графики в наш сервис учета коммунальных услуг Dom24x7 и с какими проблемами и неудобствами пришлось столкнуться.

Для Vaadin 7 имеется прекрасное официальное дополнение для работы с графиками, но проблема в том, что оно не бесплатное и стоит почти $500! Таких денег мне тратить не хотелось, и я решил поискать альтернативу из бесплатного, но, к сожалению, все что я нашел меня совершенно не удовлетворяло по качеству и тогда я вернул свое внимание на официальное дополнение для работы с графиками и решил изучить его повнимательнее.

Оказалось, что это дополнение всего лишь оболочка для прекрасной javascript библиотеки Highcharts, которую, о чудо, можно было использовать бесплатно в некоммерческих проектах, хотя есть еще прекрасная альтернативная библиотека Amcharts, но все же решил остановиться на предыдущей.

Кстати, разработчики Vaadin объясняют, почему так дорого просят за дополнение по работе с графиками тем, что им приходится приобретать корпоративную лицензию.

Определившись с библиотекой осталось решить вопрос, как же все таки ее подключить к своему проекту?
Статья состоит из двух частей. Первая часть это перевод статьи о том как подключать javascript библиотеки к vaadin проектам, а вторая часть расскажет о там, как я, используя полученные знания, написал библиотеку для отображения графиков.
Итак…

Vaadin 7 любит JavaScript компоненты

Использовать JavaScript компоненты в Vaadin 7 легко. Конечно, у Vaadin уже давно имеется метод Window.executeJavaScript(), но у этого метода довольно много ограничений. Например, если у вас имеются зависимости с Javascript файлами, то сложно гарантировать их загрузку до вызова.

Как и другие Vaadin 7 GWT компоненты, JavaScript компонент состоит из 4 частей:

  • серверный компонент (server-side component),
  • состояние (state),
  • коннектор (connector)
  • и клиентский компонент – виджет (client-side widget).

В простых примерах (например, как в рассмотренном ниже), проще объединить коннектор и клиентский виджет. Однако, связывая готовый javacsript виджет с функциональностью Javascript компонента, вы пишите только сам коннектор, который будет управлять виджетом (являющейся библиотекой).

Почти все, что вы можете делать с GWT виджетом, вы так же можете сделать и с виджетом JavaScript. Ниже мы рассмотрим простой пример, чтобы показать, как работают различный его части.

В рассмотренном ниже примере мы просто выведем на экран сообщение.

Серверная сторона

@JavaScript({ "js_label.js" })
public class JsLabel extends AbstractJavaScriptComponent {

    public JsLabel(String xhtml) {
        getState().xhtml = xhtml;
    }

    @Override
    protected JsLabelState getState() {
        return (JsLabelState) super.getState();
    }
}

Как мы видим, наш компонент очень простой. В нем объявлен только конструктор с одним параметром – текстом, который необходимо вывести на экран. Этот параметр передается на клиентскую сторону при помощи общего состояния. Важная часть кода – это аннотация, которая расширяет класс JsLabel.

JavaScript сообщает Vaadin о любых JavaScript файлах, которые требуются вашему виджету. В нашем примере требуется только js_label.js, который является реализацией клиентской стороны JsLabel. Так как мы указали относительный путь к файлу, то он должен находиться в том же самом java-пакете, что и класс JsLabel. Таким образом, в моем IDE, js_label.js и JsLabel.java расположены рядом. Если необходимо, то можно перечислить несколько файлов в виде строкового массива в аннотации JavaScript, также путь можно указать в формате URL.

AbstractJavaScriptComponent – класс, который мы расширяем. Он позволяет создать двухстороннюю связь между JavaScript и Vaadin, с помощью объекта общего состояния.

Обратите внимание на то, что Vaadin знает, какой класс состояния используется, потому что мы переопределяем метод getState() для работы с нашим классом общего состояния. Такое поведение не является спецификой JavaScriptComponent, а характерно для всех компонентов Vaadin 7.

Определение состояния

public class JsLabelState extends JavaScriptComponentState {
    
    public String xhtml;
}

Единственная цель объекта состояния в том, чтобы передавать данные между серверной и клиентской стороной, причем в обе стороны. Для его создания необходимо расширить JavaScriptComponentState.

Чтобы сохранить наш код лаконичным и симметричным со стороны JavaScript (как вы ниже увидите), я решил определить поле xhtml как публичное (public). Нам ничего не мешает добавить туда getter и setter, но так как класс состояния предназначен только для передачи данных и в нем отсутствует какая-либо логика (и не должна там присутствовать), то getter и setter для полей в нашем случае не нужны.

Примечание: можно класс состояния сделать внутренним классом JsLabel для сокращения кода. Проблема с таким подходом в том, что встроенные классы состояния работают только с компонентами JavaScript. Общие классы состояния для GWT не работают как внутренние классы, за исключением некоторых особых случаев. Кроме того, если мы по каким-либо причинам не хотим вызывать метод getState(), то не забываем вручную вызывать метод markAsDirty() каждый раз, когда изменяем состояние. Поэтому, чтобы не было путаницы, настоятельно рекомендуется классы состояния держать отдельно от компонента.

Клиентская сторона

org_vaadin_blog_JsLabel = function() {
    var e = this.getElement();
	
    this.onStateChange = function() {
        e.innerHTML = this.getState().xhtml; 
    }
}

Именно этот js_label.js файл мы указали в аннотации JavaScript ранее. Здесь нужно обратить внимание на две вещи: имя функции и использование this.

Имеется соглашение в именовании, которому мы должны следовать. Это помогает Vaadin правильно найти JavaScript функцию для ее вызова, когда наш компонент используется. Мы берем полное имя класса серверного компонента и просто заменяем точки на подчеркивание. В нашем случае JavaScript функция должна называться org_vaadin_blog_JsLabel. Не беспокойтесь, если вы ошиблись в названии, то Vaadin подскажет как (по его мнению) должна называться функция.

Дополнительную информацию можно прочитать в JavaDoc класса AbstractJavaScriptComponent (ссылка на документацию alpha 3's JavaDoc. В примере мы используем только this.getElement() для получения элемента DOM, который был создан для нашего Vaadin виджета и this.getState() – для получения доступа к состоянию. В нашем случае мы читаем XHTML строку из состояния и вставляем его в DOM элемент innerHTML. К сожалению, компонент состояния не может быть обновлен на стороне клиента так, чтобы эти изменения были получены на стороне сервера.

Как упоминалось выше, этот файл — коннектор и виджет одновременно. Обязанность коннектора состоит в том, чтобы связать состояние и виджет. В нашем случае разделение только усложнило бы код, поэтому мы объединили виджет и коннектор в одном javascript файле.

Обратите внимание, что любые getters и setters в состоянии не могут использоваться на стороне JavaScript и мы работаем с полями как с обычными свойствами. Это верно даже в том случае, когда вы явно написали методы доступа в своем классе состояния.

Таким образом, мы имеем удобный механизм соединения JavaScript компонента с существующими виджетами (js библиотеками). Это удобно, когда вы владеете JavaScript и хотите запрограммировать небольшие и быстрые функции на стороне клиента. Но GWT, все же, лучшая альтернатива для создания более сложных и надежных компонентов для Vaadin.

В следующей статье я подробно опишу как, используя полученные знания, я создал оболочку javascript библиотеки для работы с графиками Highcharts.

Автор: evgajukov

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js