Пишем сайт на GWT: Часть 1 из песочницы

Добрый день дамы и господа,

На хабре есть не так много статей на тему GWT (Google Web Toolkit) и в большинстве своем написаны они в ключе «какая это бяка, ничего не умеет, ничего не понятно». Кроме того, как показывает мой опыт, большинство программистов о GWT вообще ничего не слышали, а те кто слышал, думают, что больше чем на „Hello World“он не способен. Я постараюсь показать вам, что с помощью этого замечательного Фреймворка можно делать такие вещи, которые большинству JavaScript программистам просто не по зубам.

Перед началом небольшое отступление, т.к. вопрос «а зачем?» обязательно прозвучит. Этот сайт я написал на GWT, т.к. у меня и выбора то не было. С HTML,CSS, PHP и JavaScriptом я знаком(был) весьма поверхностно( как собственно и большинство Java-программистов), а вот идея и желание были. А потому использовал я что имел и получилось вроде весьма не плохо.

Посмотрите на этот сайт. Да это не шедевр, но он показывает, что GWT может все, что может JavaScript и даже больше. Почему больше? Ответ на этот вопрос полностью совпадает с ответом на вопрос: «почему С++ может больше чем Assembler?». На эту тему я предлагаю подискутировать в комментариях. А мы возвращаемся к GWT. Нет ничего лучше( мое стойкое убеждение), чем объяснять что либо на примере, а посему я предлагаю вам препарировать этот сайт.



Итак, начали

Вешаем слушателей на элементы

Итак, любое GWT приложение состоит из как минимум одной HTML-страницы и кучи яваскриптов. Посмотрим на эту самую страничку. Как не сложно догадаться, все самое интересное будет происходить в диве „ content“. Весь хедер и футер сделаны хардкорно, т.е. статически, и по существу к GWT никакого отношения не имеют(выключите JavaScript и поймете о чем я ). Но вот клики на кнопки обрабатывает GWT. Как это сделано? На каждый див(кнопку) вешается слушатель:

final Element element = DOM.getElementById("homeSite");
        DOM.sinkEvents(element, Event.ONCLICK);
        DOM.setEventListener(element, new EventListener() {
            public void onBrowserEvent(Event event) {
                if (DOM.eventGetType(event) == Event.ONCLICK) {
                    // наша логика
                }
            }
        });


Вот и все, вот так просто. Я думаю в этом коде все понятно, может быть только за исключением строки:

DOM.sinkEvents(element, Event.ONCLICK);


Эта строка обязательна, т.к. говорит браузеру, что с этого момента этот элемент реагирует на клик. Если эту строку выкинуть, то слушатель сигнала о событии не получит и ваша логика, соответственно, обработана не будет. Эту мелочь надо просто знать, как собственно, везде и всегда.

Загрузка статического HTML-файла.

Но не весь контент генерируется на лету. Например центральная страница, это статический HTML. Как это так? Фаербаг вам это подтвердит. Он вам покажет, что на центральной странице грузится startRu.html (или startDE.html, если браузер сказал, что его родной язык- немецкий). Как это сделано?

RequestBuilder requestBuilder = new RequestBuilder(RequestBuilder.GET, GWT.getHostPageBaseURL() + "start/start" + language.getAbkurzung() + ".html");
        try {
            requestBuilder.sendRequest(null, new RequestCallback() {

                public void onResponseReceived(Request request, Response response) {

                    if (response.getStatusCode() != 200) {
                        Window.alert(language.getЕrror() + "!");
                    } else {
                        HTML startHTML = new HTML(response.getText());
                        RootPanel.get(„content“).getElement().setInnerHTML("");
                        RootPanel.get(„content“).add(startHTML);
                    }
                }

                public void onError(Request request, Throwable exception) {
                    Window.alert(language.getError() + "!");
                }
            });
        } catch (RequestException ex) {
            Window.alert(language.getError() + "!");
        }
    }


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

Переход между страницами

Обратите внимание как происходит переход между страницами. Старый контент медленно исчезает, а новый так же медленно появляется. Кому то этот эффект может не понравиться и поэтому я просто посмотрел, какое впечатление произведет сайт, если этот эффект отключить. На вкус и цвет, как известно фломастеры разные, но мне на сайт без этого эффекта смотреть было уже не приятно. Итак, как это сделано. В GWT есть класс Animation. Посмотрите примеры в интернете, т.к. код для статьи слишком громоздкий. Но идея в общем такова: я написал класс, который получает получает ссылку на виджет, который должен появится. Ссылка на актуальный виджет, который отображается в данный момент, хранится в статическом поле центрального класса, который выполняет роль склада(паттерн registry). У старого виджета медленно изменяется свойство Opacity с 1 до 0, потом старый виджет заменяется на новый и у него меняем свойство Opacity с 0 до 1. Замена виджетов происходит очень просто:

oldWidget.removeFromParent();
RootPanel.get(„content“).add(newWidget);


По этому же принципу появляются все Pop-Upы.

Я думаю для начала хватит.

На этой странице много чего интересного, например сайт запоминает установленный язык, работают кнопки вперед-назад, динамический перевод сайта с русского на немецкий и наоборот(перевод, кстати, при загрузке сайта происходит до того, как вы увидите страницу), один раз подгруженная страница кэшируется(посмотрите, подгружается ли повторно например startRu.html?). Когда вы наведете на маленькие иконки продукта в таблице «купленных» продуктов, вы увидите один маленький фокус. Мелочь, а приятно. Красивые тултипы, которые показывают ошибки при регистрации. Проверка полей на клиенте. Поля, которые принимают только цифры и много чего еще.Попробуйте «купить» один продукт, получите ссылку и посмотрите, что происходит. А вам интересно КАК это происходит?

И все это сделал человек, который не имеет(вернее не имел) практически ни малейшего понятия о HTML,CSS и JavaScript в свободное от работы/учебы/жены/детей время и успевал еще и пиво с друзьями попивать!

Задавайте вопросы, если вам интересно как та или иная фича реализована.

История о том, как я этот сервис пытался продвигать, тоже, кстати, весьма интересна.

А теперь я вам открою истинную цель этого топика. Я ищу людей/инвесторов/компаньонов для этого проекта. Любые идеи, пожелания, конструктивная критика приветствуются.
16 марта 2012, 16:56
110
schroeder 3,0

комментарии (42)

+3
vtysh #
GWT отличная технология, но на данный момент имеет определенные минусы, которые значительно уменьшают удовольствие от разработки: время компиляции, отсутствие инкрементальной компиляции (обещают, вроде, в версии 2.5), отладка в хроме тормозит ужасно (хотя, может, уже и поправили за последние пару месяцев).
+2
San13 #
компилить в JS надо только во время деплоймента. Отладка в хроме раза в 2-2.5 медленнее чем в FF, да, но раньше было по ощущениям в 5 раз 8). Поэтому девелопмент удобно делать в FF, а в хроме уже доводить совместимость.
–1
vajadhava #
Деплоймент всякий раз когда нужно посмотреть что получилось. А нужно постоянно.
Это ведь не js, который открыл в окне и мгновенно видишь как оно меняется по мере разработки. В консолько залез и поравил что нужно, внес изменений в код.
А тут: что-то поменял, запустил, ждешь две минуты пока скомпилится, увидел что получилось чуток не так, правишь, снова запускашь, снова две минуты ждешь, и так далее…
Пробовал простенький проект написать, как время компиляции дошло до 4 минут — плюнул и отказался.
+2
San13 #
Вы не понимаете? Hosted mode, не нужно ничего ждать. Простой проект, изменил какой-нибудь IF в java, нажимаешь F5 имеешь за 2-3 секунды результат, весьма сложный проект — 10 секунд предел.
–1
vajadhava #
Не так давно хостед мод тоже вполне себе тупил.
Браузер, который для хостед-мода используется — весьма себе поделие, кажущее периодически погоду. А чтобы в реальном браузере открыть — нужно компилить.

Вообще GWT создает впечатление продукта который постоянно находится в глубокой бете.
За 6 лет, которые его пилят, он так и не выстрелил. Что весьма себе показатель.
+1
voicer #
Уже давно (года три минимум) hosted mode работает в реальных браузерах.
Достаточно поставить специальный плагин.

0
vtysh #
чтобы в реальном браузере открыть — нужно компилить.

Сейчас не надо. Отладка работает без компиляции в любом браузере, где можно установить GWT Development Plugin. Правда тормозит на тяжелых проектах. Компилировать же не так часто надо. Но одна мысль, что надо бы скомпилировать наконец, вызывает у меня ужас.
0
shrike2004 #
Firebug — наше все.
0
vtysh #
Меня это всегда удивляло, почему технологии продвигаемые одной и той же компанией так плохо совмещаются во время разработки. Почему в IE и FF отладка работает на порядок шустрее остается для меня загадкой.
+3
Lendon #
Да, статей по GWT и вправду мало на хабре.
0
vitiko #
не индексируется поисковиками, как продвигать?
0
schroeder #
да, вы правы, это минус GWT. надеюсь гугл когда нибудь ситуацию исправит. А вообще, конкретно этот сайт не нуждается (почти) в индексировании.
0
Lendon #
Гугл уже исправил это.
+1
1nd1go #
Я делал перевод, что человек имеет против данного подхода.
0
vimvim #
Ограничения с индексированием сайта полностью сделанного на GWT это на самом деле огромная проблема. Вот Ваш сайт например похож на магазин. Любой опытный сеошник взглянув на его структуру ( фактически одну страницу ) скажем Вам что проблемы с продвижением будут гигантские ( если вообще разрешимые ). Нужны отдельные страницы для каждого товара, их перелинковка, уникальный контент на каждой странице и пр…
Вообще я допускаю что есть сайты не нуждающиеся в продвижение через поисковики, но это скорее исключение чем правило.
С другой стороне на GWT можно сделать все что делается на JS и при этом намного быстрее и эффективнее, тк мы имеем полную поддержку и контроль со стороны Java и IDE на этапе разработки. Например рефакторинг в GWT ( что-то типа сделать доп packages и пергруппировать функционал из классов ), делается элементарно. В JS это просто катастрофа, даже не смотря на все потуги IDE помочь в этом.
+4
Lendon #
Хорошый пример сайта на GWT.
+2
1nd1go #
GWT неплохая технология для таких сайтов. В принципе она хорошо вписывается стандартный сайт из какого-нибудь туториала любой интернет технологии (ну и конечно же «блог»). Веселости начинаются, когда твой сайт не просто переходы по страничкам, а уже Rich Interface Application, с рабочим столом, окошками, да и просто нетривиальная форма, с табличкой, фильтрацией, автокомплитом и т.п. Тут уже можно запросто выстрелить себе в ногу.

Я уже неоднократно убеждался и высказывал это мнение, что 80% функциональности на таких технологиях делается отлично, 10 процетов делается с большим трудом, а еще 10 с запредельными затратами, а то и вообще не возможно. Поэтому с аджайл-проектом, я бы не комитался на GWT.

А что касается продолжения, вы можете попробовать написать как unit-тестить GWT приложение, про паттерн MVP, про улучшайзеры типа либы GWT-Ext. Желательно в порядке усложнения и навешивания.
0
San13 #
вы не писали или не поняли GWT (?), поэтому ваше разделение на 80-10-10 неверно. Это не та технология связки java/javascript, где применимо подобное разделение. Не могли бы вы описать ваши сложности?
–4
Suvo #
Скажем подцепить к GWT бэкенд отличный от GAE
+6
San13 #
А при чем тут ГАЕ? 8-OO
0
eugenius_nsk #
_Всегда_, когда надо изменить поведение стандартных GWT-виджетов, начинаются сложности — потому что там все внутренности прибиты гвоздями и не позволяют вносить модификации*. В итоге чаще всего оказывается, что самый простой способ — это создать в _своём_ проекте пакет наподобие «com.google.gwt.user.client.ui» (потому что в GWT практически везде используется дефолтная область видимости, т.е. в пределах пакета), создать там свой класс, скопировать в него код нужного виджета, и уже там его изменять. При этом очень часто отнаследоваться от нужного виджета не получится, поэтому, скажем, какой-нибудь MyTextCell не будет являться TextCell-ом** — что часто очень неудобно.

Так что я вполне согласен с оценкой 80-10-10.

* — В последних версиях наметились некоторые подвижки в сторону улучшения, но пока очень небольшие. Ситуация в целом пока что остаётся прежней.
** — Пример навскидку, конкретно от TextCell-а отнаследоваться, может быть, и получится — надо смотреть.
+1
batment #
Статья понравилась, спасибо, все никак руки не доходят самому разобраться.
Кстати, есть ремейк GWT на Python — Pyjamas, если кого Java не устраивает. Разработчики говорят, что у них получилось тот же функционал вместить в 8 000 строк кода против 80 000 у GWT.
+1
nvbn #
Когда последний раз его пробовал, работало криво на приложениях сложнее хелловорда и часть пимеров с сайта вообще не работало.
0
San13 #
в GWT есть еще режим отладки и плагин для этих целей в бровзере. Вы пишете и отлаживаете код в бровзере без долгой компиляции в JS, а результат получается тот же (в том смысле, это это не эмуляция). Это и есть основная killer feature, которой в Pyjamas нету.
0
lukdiman #
На самом деле не все так гладко получается. Некоторые вещи, которые пишите на gwt отлично работают на jetty в дебаге, но не работают на, например, websphere. И я говорю не о хитрых конструкциях а о простых операциях в java. типо сравнение енумов и кое что еще
+1
lukdiman #
поэтому всегда советую тестировать gwt приложения на том что будет в проме. по крайней мере перед коммитами
+2
San13 #
вы о клиент сайде? он не зависит от бакенда
вы о сервер сайде? он не зависит от gwt
RPC тоже стандартное (сервлет на сервере, и стандартный XMLHTTPRequest с клиента).
Что я упустил такое?
Может для вебсферы нужен ibm jre? И оттуда нюансы?
+1
lukdiman #
gwt в дебаге иgwt скомпилянное это разные вещи. Конечно маленький процент различий но они есть. Проверено на собственном опыте. от бэкенда не зависит. просто у нас была сфера в проме
0
lukdiman #
когда только начинал проект меня самого этого удивило когда начали валиться баги в багтрекер и я не мог их воспроизвести на jetty. а потом с помощью кучи алертов выявились баги, которые проявлялись только если по честному скомпилять gwt код полностью. Еще это вызывало проблемы из-за того что проект компиляется целиком полтора часа :)
0
schroeder #
два часа это жесть. этот сайт компилируется полностью за 90 секунд в худшем случае на слабенькой машине
0
lukdiman #
проект реально огромен. напрягает очень сильно время компиляции. и при этом выжирает кучу оперативки, но правда когда даешь больше оперативки все упирается в диски. поэтому особо не помогает увеличение оперативки в какой-то момент
+1
San13 #
да, нужны хорошие тачки: больше ЦПУ и больше мозгов чтобы в параллел запускать билдиться модули при деплойменте. НО это в том случае если у вас не изолированы такие проблемы. Если вы видите расхождения между hosted mode и js mode (а я ни разу не видел, при плотном девелопменте большого проекта 3 года группой товарищей), вам следовало бы их изолировать отладить и пользовать уже этот код.

различие между hosted mode и js mode было только в том, что они давали разное прохождение таймеров. Если код был не продуман, то вполне возможная, но непредвиденная последовательность выполнений таймеров вылезала в js, которой не было в hosted mode, ну тут уже программист корявый значит, нареканий к gwt не было.

от этого всего я шизею, в хорошем смысле слова.

так что же за баги были у вас? про енумы что-то но я не понял что.
0
vtysh #
Проблемы вылазят иногда из-за неправильного перевода нативных JRE классов в Javascript. Некогда подпортила мне нервов реализация метода Char.isDigit в GWT. В дебаге все работало, после компиляции не работало. Оказалось, что isDigit в GWT работает только для стандартных латинских цифр (отладчик показал, что заменяется на простой регексп), для других же цифр метод работает некорректно.
0
eugenius_nsk #
> но правда когда даешь больше оперативки все упирается в диски
RAM-drive? ;-)
0
schroeder #
хм, вопросы не задаются. значит ли это, что ничего не интересует?
0
symbix #
Да просто такие элементарные вещи делаются на любом js mvc фреймворке в полторы строчки. Не видно в этих примерах ничего, кроме необходимости писать в 10 раз больше кода. Быть может, для крупных rich-client приложений и есть профит, но на приведенном примере не понять.
0
schroeder #
с удовольствием увижу полторы строчки кода для плавного изменения контента при переходе на другую страницу. А вообще имелись ввиду вопросы по другим моментам, здесь не описанных.
0
sidney3172 #
Зачем делать StartRu.html и StartDe.html? У вас верстка меняется в зависимости от языка? оО
Встроенные средства для перевода конечно не фонтан, но это лучше чем то как это реализовано…
На самом деле пример приведенные мне не очень нравится.
GWT создан чтобы быть понятным Java разработчику, чтобы он не думал (за редким исключением) что такое JS и как это все будет связано.
0
schroeder #
это сделано для того, что бы при первоночальной загрузке посетитель вообще не заметил изменение языка. В противном случае он сначала увидит чужой язык(если не повезло), а потом свой. По крайменей мере так работало у меня. не очень приятный момент.
+1
mais #
Я бы хотел обратить внимание автора на тот момент, что для переходов, хистори, букмарков — а так же разработки кода в хорошем стиле, в последних версиях GWT есть Activities & Places
0
schroeder #
вы правы, есть такая штука. в свое оправдание могу сказать, что мой велосипед прост, понятен, легко расширяем и самое главное я точно знаю как он работает и что надо сделать, что бы он работал по другому. Естейственно подход имеет право на жизнь до тех пор, пока код использую только я, а в этом случае так и есть.
0
Scala #
Мы всё ждём 2.5, в котором будут обещанные SourceMaps. Dev Mode пока самая тормозная сторона GWT. Firefox работает быстрее всех, но релизы плагина всегда запаздывают на пару версий, Chrome & IE очень медленные, Safari с версии 5 вообще перестал работать.

В остальном — наверное самый переспективный RIA Web фреймворк для Java.

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.