Сервлети в чистому вигляді: зміна парадигми (исходники)

Вважається, що для Web-сторінок з динамічним вмістом технологія JavaServer Pages (JSP) дозволяє відокремити завдання розробника від завдань дизайнера користувальницького інтерфейсу. До нещастя, технологія JSP занадто складна для багатьох дизайнерів, так що Java-програмістам доводиться особисто займатися обробкою JSP-сторінок, часто з незадовільними результатами. У цій статті демонструються переваги нестандартного підходу: використання простих об’єктів-помічників (helper) для побудови Web-інтерфейсу, заснованого тільки на сервлетах.

Від редактора: Цей прийом не рекомендується для команд, в яких беруть участь HTML-кодери. Він призначений для Java Web-розробників, які пишуть і підтримують свій власний HTML-код в нескладних Web-додатках.


Технологія JSP спроектована так, щоб відокремити завдання Web-розробника від персоналу, який займається проектуванням динамічних GUI сторінок. До нещастя, технологія JSP занадто складна для багатьох дизайнерів користувальницьких інтерфейсів, так як додає кілька шарів для вирішення різних проблем при генерації динамічного вмісту. Наприклад, для інтернаціоналізації додатків необхідно зберігати текст у певному місці, окремо від сторінок користувальницького інтерфейсу, і звертатися до нього за допомогою спеціальних ключів. Так що Java-розробникам доводиться працювати c JSP-сторінками в поодинці, часто переробляючи роботу дизайнерів користувальницького інтерфейсу, додаючи taglib “и і інші елементи, щоб уникнути ускладнення сторінки через додавання Java-коду.


Всупереч усталеній точці зору, можна побудувати простий і симпатичний Web-інтерфейс додатка, заснований на звичайних сервлетах, за допомогою простих об’єктів-помічників. Ця стаття закликає розглянути генерацію представлення для динамічних Web-сторінок за допомогою стандартних засобів Java. Я поясню переваги цього підходу і продемонструю його на прикладі програми для підрахунку очок, яке я розробив для чемпіонату NCAA March Madness.


Зауваження. Підхід, продемонстрований в цій статті, призначений для Java Web-розробників, які пишуть і підтримують власний HTML код, а не для команд, до складу яких входять HTML кодери.


Динамічний HTML


Підхід, заснований на чистих сервлетах, дозволяє спростити архітектуру. Він включає базовий клас-сервлет і спеціалізовані об’єкти-генератори, які підкласи сервлету використовують для виробництва вихідних даних. Коду в даному випадку виходить трохи, тому що більша частина HTML інкапсульовані в методах об’єктів-помічників, які можуть бути перевизначені при необхідності. Повторне використання коду завжди вітається, і більшість Web-сайтів спільно використовують так багато HTML між різними сторінками, що повторне використання є вкрай важливим. Методи генерації HTML призводять до прямолінійного і компактному коду сервлетов, а, отже, й зручному для підтримки, так як вартість підтримки коду більш-менш пропорційна розміру коду. Переписавши UI інтерфейс з JSP на “Чисті” сервлети, я зміг скоротити розмір коду на дві третини.


Наприклад, візьмемо цю складну конструкцію для виведення посилання в залежності від прав доступу користувача:






<c:if test=”${user.permission[ sessionScope.ConstantMap[ EDIT_WIDGET ] ] != 0}”>
<c:url var=”editUrl” value=”/EditWidget.jsp”/>
<div class=”navigation”><a href=”<c:out value=”${editUrl}”/>”>Edit
this widget</a></div>
</c:if>

Вона стає значно зрозумілішим при використанні синтаксису Java:






if (user.getPermission(Constants.EDIT_WIDGET) != 0)
out.printNavlinkDIV(“/EditWidget.jsp”, “Edit this widget”);

Врахуйте також кількість допоміжного коду, зекономленого за рахунок вилучення і виведення бізнес-об’єктів в одному і тому ж місці, замість передачі їх через запит. Стислість – сестра таланту.


Робота з JSP і іншими технологіями відображення-можливо, один із самих ненадійних аспектів Web-розробки. JSP сторінки – це не HTML, не XML, не Java-код і не код JavaServer Pages Standard Tag Library (JSTL), не мова виразів (EL), а безладна суміш цих та інших технологій. Однак не тільки це безглузда суміш, але й кожен рівень абстракції створює нові перешкоди для розробки. Налагодження JSP сторінок, наприклад, вкрай нагадує пошук джерела за допомогою лози. Ви знаєте, що десь там під поверхнею є помилка, але не можете її виявити на підставі загадкового повідомлення про помилку, в якому вказаний номер рядка, не відповідний вашому коду.


Також JSP-технологія не дозволяє успадковувати базового класу, так що повторне використання зводиться до bean-компонентам, include-Файлам і специфічним taglib “ам. Taglib” и також занадто складні, щоб бути ефективним засобом повторного використання. Підтримка XML-файлу для кожного зробленого зміни в API вкрай втомлює, незважаючи на те що “проектування тегів це проектування мови”. Результат усього цього – ще один рівень в і без того багаторівневому інтерфейсі.







 



Відповідність стандартам HTML і XHTML
Инкапсулирование HTML в Java-методах приносить однаковість за рахунок повторного використання і допомагає мінімізувати число помилок. У свою чергу, це сприяє досягненню гідної мети – створення HTML-або XHTML-коду, відповідного стандартам. Я реалізував сайт March Madness відповідно до XHTML 1.0 Strict. Після завершення функціональності знадобилося всього близько півдюжини змін, щоб він пройшов перевірку в службі валідації W3C.
 

Зараз ми зустрічаємо новий World Wide Web. Незалежно від того, чи зможе AJAX перевернути Web-розробку, Web-сайти будуть ставати все більш і більш інтелектуальними. І хоча HTML сам по собі завжди декларативний, код, який він генерує, безумовно не декларативний. Технологія JSP і інші системи шаблонів неминуче виявляються занадто складними, так як вони намагаються виразити декларативно те, що насправді є динамічним висновком. Саме з цієї причини розробники змушені додавати scriplet “и в вихідний код JSP, так як те, що вони намагаються виразити це в такій же мірі логіка, як і форма.


Інкапсуліруя HTML як Java-код, можна виразити логіку виведення більш стисло. Конструкції if і цикли for приймають свою добре відому природну форму. А елементи сторінок можуть бути розкладені за легко підтримуваним і розуміється методам. Підтримка JSP-сторінок, які рідко добре документуються, в кращому випадку достатньо важка і схильна до помилок. Використовуючи “чисті” сервлети, можна максимізувати повторне використання коду, так як не потрібно писати новий клас для кожної конструюється сторінки.


Божевільний дизайн







 



March Madness (Березневе безумство)

Затяті американські баскетбольні фанати досягають повного божевілля кожен березень, коли 64 кращі чоловічі команди з Національної Атлетичної Асоціації Університетів (National Collegiate Athletic Association – NCAA) сходяться в чемпіонаті з іграми на вибування і єдиним переможцем, триваючому кілька тижнів. Безліч уболівальників насолоджуються, записуючи свої предсоревновательной прогнози і результати ігор в загальну схему, по мірі того як ситуація в чемпіонаті міняється і число учасників зменшується. Також багато обожнюють змагатися один з одним в неофіційних або спеціальних змаганнях, де нагороджують тих, чиї прогнози виявилися більш точними.


Щоб проілюструвати концепцію “чистих” сервлетов, я побудую інтерфейс для перегляду очок для чемпіонату NCAA March Madness (див. врізку March Madness і матеріали для скачування). Користувач може увійти в систему, вибрати з 64-х команд чемпіонату ті 20 команд, які, на його думку, є фаворитами, і присвоїти кожній команді ваговий коефіцієнт. Після початку ігор дані, введені користувачами, можна тільки переглядати, і адміністратор повідомляє переможців ігор, як тільки вони стають відомі. В залежності від команд, обраних користувачем, його окуляри акумулюються, співвідносяться з окулярами інших користувачів та виводяться по порядку.


Цей проект зайняв близько трьох тижнів мого вільного часу, більшу частину якого я присвятив метушні зі стилями та графікою, так як я не художник. Крім одного HTML-файлу та інших статичних ресурсів, рівень GUI складається з 21 Java класу, загальним розміром в 1334 Java-вирази, за вимірюваннями JavaNCSS.


Відхід від Model – View – Controller (MVC)


Архітектура, заснована тільки на сервлетах, яку я тут продемонструю, включає тільки один рівень представлення між клієнтом і бізнес-логікою. Шаблон Модель – Вид – Контролер (MVC), відомий як Model 2, насправді не є панацеєю, оскільки страждає серйозними обмеженнями, і Web-середовища для розробки додатків, що підтримують його, мають тенденцію до надмірного ускладнення. Spring MVC і JavaServer Faces (MVC) занадто багатослівні, як і Struts, конфігураційні файли якого є вкрай складними і об’ємними і повинні коректуватися кожен раз, щоб слідувати логіці управління додатками.


Наприклад, розробники часто невірно розуміють призначення модулів Action в Struts. Бізнес-логіка має тенденцію накопичуватися і застрявати в них (а то і на всьому протязі шляху від них до JSP). Реалізація уявлення і контролера як сервлетов спонукає зберігати бізнес-логіку там, де вона має бути, так як сервлети явно сфокусовані на взаємодії з браузером.


Для даного проекту використовувалося кілька класів з моєї власної elseforif-servlet бібліотеки. Саме ця бібліотека є ключем до архітектури проекту, так як вона надає зручний інтерфейс для генерації HTML. Але ми не будемо фокусуватися на бібліотеці, просто перевіримо концепцію, щоб довести життєвість мого підходу.


На малюнку 1 наведена часткова діаграма класів, елементи бібліотеки elseforif-servlet виділені зеленим.


Малюнок 1. Фрагмент діаграми класів
Фрагмент діаграми класів

Вгорі дерева знаходиться інтерфейс, що містить рядкові HTML константи, що використовуються і об’єктами, генеруючими HTML, і сервлетов. Пізніше ви побачите, як вони працюють. Потім ідуть класи HTMLWriter і HTMLFlexiWriter, Що реалізують базові низькорівневі HTML методи, які можуть знадобитися будь Web-сайту. Різниця між ними в тому, що HTMLWriter друкує інформацію безпосередньо в потік виводу, тоді як HTMLFlexiWriter також може повертати виведену інформацію у вигляді рядків. Часто виявляється зручним передати результат роботи одного методу-генератора HTML параметром в інший метод-генератор HTML, як у цьому прикладі.






out.printA(URL_ELSEFORIF, out.IMG(“/img/elseforif.gif”, 88, 31));
 

Клас MadnessWriter потім додає високорівневу функціональність для виводу HTML, необхідну для даного Web-сайту – загальні елементи, такі як верхній і нижній колонтитули та меню, все, що специфічно для даного сайту і неодноразово зустрічається на ньому. Це легкий, не пристосований до багатопоточності використанню об’єкт, створюваний для кожного запиту абстрактним базовим класом-сервлетов MadnessServlet за допомогою методу-фабрики.


Цей базовий клас відповідає за обробку основний керуючої логіки сервлети, так що конкретні підкласи можуть сфокусуватися на своїх специфічних завданнях. Після установки стандартних заголовків HTTP і виконання певної перевірки безпеки на рівні сторінки, він передає об’єкт MadnessWriter в захищений метод doBoth():






protected void doBoth(HttpServletRequest request, HttpServletResponse response,
HttpSession session, MadnessWriter out) throws ServletException, IOException

Клас MadnessServlet також реалізує інтерфейс MadnessConstants, Надаючи підкласам зручний доступ до статичних значень, визначених в HTMLConstants. Таким чином, застосування об’єкта MadnessWriter разом з цими константами дозволяє створити для сервлетов компактний Java-подібний синтаксис.







 



Параметри та валідація
Можна ефективно обробляти параметри, не вдаючись до складних систем. Бібліотека elseforif-servlet включає декілька класів-помічників, які сервлети можуть використовувати безпосередньо, з допомогою шаблону декоратора, оголосивши їх параметри в методі init(). Це надає сервлетам зручну форму, перетворюючи init() в свого роду сигнатуру, так що можна відразу визначити, які параметри очікуються. Спеціальна реалізація Map інкапсулює аргументи і результати перевірки, які можуть передаватися в сесії і поширюватися між сервлетов при необхідності.
 

Говорячи мовою MVC, сервлети – в даному випадку базові компоненти користувальницького інтерфейсу – поєднують рівні уявлення і управління. Для протоколу, подібного HTTP, який не підтримує сеанс взаємодії з користувачем, це розумно. Запити на відображення і запити на оновлення даних приймають одну і тугіше просту форму, і між ними немає чіткого поділу. Я віддаю перевагу заради модульності реалізовувати сторінку з формою в одному сервлетов, а обробник цієї форми в іншому. Але як би ви їх не розділяли, логіка для генерації HTML, логіка для обробки параметрів сервлету і логіка навігації по сторінках тісно пов’язані між собою. Благий намір MVC відокремити їх один від одного породжує великі проблеми.


Реалізація бізнес-рівня повинна мати мало значення для рівня представлення. Головне – мати розумний бізнес-інтерфейс, щоб код користувальницького інтерфейсу займався тільки своєю справою. Для бізнес-рівня даного проекту я побудував досить простий CRUD (create-read-update-delete) інтерфейс для роботи з даними за допомогою Apache Derby.


Запуск програми


Це Web-додаток є практично самодостатнім, але може знадобитися змінити деякі змінні для налаштувань середовища у файлі web.xml, Перш ніж поміщати його в каталог webapps. Принаймні, вбудованому екземпляру СУБД Derby потрібно місце, щоб створити і зберігати файли з даними. За замовчуванням в UNIX використовується каталог /var/derby/, Так що якщо використовується Linux, то потрібно створити такий каталог і забезпечити сервлет-контейнер правом на запис туди. В додаток можна увійти, використовуючи ім’я користувача admin і пароль password. Додаткову інформацію можна знайти у файлі README завантаженого пакету.


Форма і її обробка


Тепер можна зануритися в код. Користувачі потрапляють на сторінку Picks (див. малюнок 2), щоб вибрати свої улюблені команди, перш ніж розпочнеться перший раунд чемпіонату. Після цього вони можуть тільки переглядати добірку команд, зазначених ними або іншими користувачами.


Малюнок 2. Сторінка Picks (відбір команд)
Сторінка Picks (відбір команд)

Першим ділом сервлет Picks для генерації сторінки витягує об’єкт з інформацією про користувача, Player в даній системі, з бізнес-рівня і виконує перевірку безпеки:






PlayerManager playerMan = PlayerManager.GetInstance();
Player player = playerMan.select(session.getAttribute(P_PLAYER_ID), true);
boolean readOnly = GetCutoffDateIsPassed() && !player.getAdmin();
String playerID = request.getParameter(P_PLAYER_ID);
if (playerID != null)
if (readOnly // player.getAdmin())
player = playerMan.select(playerID, true);
else
throw new ServletException(“You may not view other players” picks”
” until the cutoff date has passed: ” + CutoffDate + “.”);

Цим гарантується, що звичайні користувачі переглядають або редагують добірки команд згідно бізнес-правилами, і також готуються кілька локальних змінних, які визначатимуть поведінку сторінки, особливо змінна readOnly. Потім я отримую масив об’єктів Team, Який містить офіційний список учасників чемпіонату. Потім я викликаю метод, щоб отримати з цього масиву колекцію типу Map, Відсортовану за алфавітом, яка мені знадобиться для випадаючих списків:






TeamManager teamMan = TeamManager.GetInstance();
Team[] teams = teamMan.selectAll();
Map selectTeams = getDropDownMap(teams);

З цього моменту починається генерація HTML:






out.printPreContent(null, out.SCRIPTFile(“/js/picks.js”));

Цей метод друкує першу частину сторінки, включаючи тег HEAD повністю, відкриває тег BODY і логотип вгорі сторінки. Відзначимо URL до JavaScript-файлу, який додається в тег HEAD. Можна подумати, що ця операція провалиться після установки WAR файлу, так як в цьому випадку до всіх URL автоматично додасться префікс контексту / madness. Насправді префікс контексту передається динамічно в конструктор MadnessWriter, Який потім автоматично додає його до всіх URL, що починається зі слеша – вкрай корисна можливість, якщо ви не любите використовувати контекст.


На наступному рядку виконується виклик методу для виведення меню:






out.printMenu(URL_PICKS);
 

Передаючи URL для відображуваної сторінки, я змушую об’єкт MadnessWriter пропустити посилання на цю сторінку або зробити її неактивною. Потім я викликаю метод для початку елемента TABLE з графічною межею, який я називаю box (контейнер):






out.printBeginBox();
 

Цей код відкриває кілька тегів, специфічних для вмісту, який буде знаходитися в цьому контейнері, Далі я закрию ці теги за допомогою виклику схожого методу. Зауважте, що метод printMenu() вище також викликає ці методи. Такий вид інкапсуляції може прискорити налагодження. Наприклад, якщо є така помилка – деякі граничні елементи TD контейнера мають ширину в 1%, що може призвести до дуже товстою кордоні при розтягуванні вікна браузера, то я зможу виправити її в єдиному місці і для всього додатки відразу. Цього можна досягти за допомогою спеціальних taglib “ов, але не так просто.


На наступних рядках виводяться два DIV-Елемента, перший показує, чи успішно би відправлена ​​форма:






if (“true”.equals(request.getAttribute(P_SUCCESS)))
out.printDIV(“smallHeading”, “Team picks were saved successfully.”);
out.printDIV(“reminder”, “(Reminder: “Pick 20″ represents the team you”
+ ” think likeliest to win. “Pick 1″ is the least likely.)”);

Аргументи “smallHeading” і “reminder” вказують на класи каскадних таблиць стилів (Cascading Style Sheets – CSS), які будуть застосовані до відкривається елементам DIV, Після яких будуть надруковані Другий аргумент разом із закриваючими тегами DIV. Якщо зміст DIV елемента reminder виявиться занадто складним, можна викликати метод out.printBeginDIV(“reminder”), Який надрукує тільки відкриває тег DIV. Дане правило найменування методів присутня в класах HTMLWriter і HTMLFlexiWriter. Однак рядкові константи в інтерфейсі HTMLConstants трохи відрізняються – наприклад, для відкривають і закривають DIV тегов за замовчуванням використовуються DIV і END_DIV відповідно.


За DIV-Елементом reminder буде виведена форма з списком, що випадає для кожної з 20 команд, які обирають користувачем. Або, якщо користувач може лише переглядати відібрані команди, друкуються тільки назви команд. За допомогою синтаксису Java цю логіку можна виразити досить природно:






if (!readOnly)
out.printSELECT(P_PICK + i, selectTeams, teamID);
else
{
String teamName = (String)(selectTeams.get(teamID));
out.print((teamName != null) ? teamName : “(no pick)”);
}

Метод printSELECT() створює елемент OPTION для кожної пари ключ / значення в колекції типу Map, Відразу позначаючи один елемент, значення ключа якого збігається з teamID, Як обраний.


Після заповнення форми потрібно вивести список команд на правій частині сторінки. Масив команд сортується по регіону та рейтингом в NCAA. Для кожного регіону є невеликий заголовок, і список відображається в дві колонки. Для даної задачі потрібно виконати певні обчислення, так що вона винесена в окремий метод, представлений в лістингу 1.


Лістинг 1. Винос генерації HTML в окремий метод.





private void doRegionList(Team[] teams, MadnessWriter out) throws IOException
{
out.print(TABLE + TR);
out.printBeginTD(null, “regionList”);
for (int i = 0; i < teams.length; i++)
{
if ((i & 15) == 0)
{
if (i == 32)
{
out.print(END_TD + NL);
out.printBeginTD(null, “regionList”);
}
out.print(NL + DIV);
out.print(REGION_NAMES[i >> 4]);
out.print(“:” + END_DIV + OL);
}
out.print(NL + LI);
out.printHTMLEscape(teams[i].getFullName());
out.print(” (“);
out.print((teams[i].getRank() & 15) + 1);
out.print(“)”);
out.print(END_LI);
if ((i % 16) == 15)
out.print(END_OL);
}
out.print(END_TABLE_3);
}

Константа END_TABLE_3 є скороченням для комбінації закриваючих тегів TD, TR, TABLE. Це дуже зручно, після того як ви підключили цю константу, але стислість подібного синтаксису покладається на хороший дизайн HTML, що припускає використовувати HTML тільки для розмітки й зберігати якомога більше інформації про стилі відображення в таблиці стилів.


Тепер можна завершити генерацію сторінки:






out.printEndBox();
out.printPostContent();

Перший рядок закриває контейнер, який було розпочато раніше, і метод printPostContent() виводить частину, що залишилася сторінки, включаючи нижній колонтитул. Ось і все! Сторінка Picks з формою готова.


Сервлет-обробник (PicksAction) Відповідає на підтвердження сторінки Picks, збираючи ідентифікатори обраних команд з об’єкта запиту і передаючи їх в бізнес-рівень для поновлення відповідного користувачу об’єкта Player, І після цього возвращаяется на сторінку з формою Picks. Тут також виконується перевірка безпеки, не дозволяє користувачам змінювати список вибраних команд після початку ігор. Так як і форма, і її обробник – це просто сервлети, то немає ніякої явної причини, щоб вони були написані з різними інтерфейсами. Обидва відповідають на параметризрвані запити від браузера, використовуючи однакові бізнес-об’єкти, і разом формують цілісний компонент користувальницького інтерфейсу. Середа на основі MVC в даному випадку тільки заважала б лівій руці узгоджено працювати з правої.


Інші аспекти подібного підходу


Хоча середовища для розробки Web-додатків схильні ускладнювати загальний стан речей, вони вирішують безліч дрібних проблем. Архітектура, заснована на сервлетах, приносить із собою гнучкість для вирішення цих проблем, як і належить, не нав’язуючи конкретних рішень.


Безпека


У промисловому додатку безпеку на рівні сторінки, швидше за все, буде оброблятися декларативно на рівні конфігураційного файлу XML. Однак, на мій погляд, звичайно потрібно більше динамічний інтерфейс на рівні коду для управління нестандартними завданнями всередині сторінок, такими як функціональність, залежна від дати в сервлетов Picks. Це може робитися вбудованими методами безпеки Servlet API, такими як метод isUserInRole(), Доступний через об’єкт запиту або для цього може бути написаний окремий інтерфейс. Кодування c використанням Servlet API може використовуватися з будь-яким з цих підходів.







 



HotSwap і цикл розробки
Зміна і перекомпиляция звичайних класів може виявитися більш стомлюючим, ніж зміна JSP, які компілюються автоматично в запущеному додатку. Налагоджувальний інтерфейс Java HotSwap, Доданий у версії 1.4, вирішує цю проблему, дозволяючи перевантажувати змінені класи на льоту без перезапуску Web-додатки або втрати сеансу користувача. Хороша середу розробки вміє використовувати цю можливість. Мій сервлет-контейнер Caucho Resin 3.0 навіть може автоматично розпізнавати зміни в класах в каталозі WEB-INF/classes і моторно міняти їх на льоту.
 

Інтернаціоналізація


Хоча більшість середовищ підтримують інтернаціоналізацію текстових значень через файли властивостей (properties), цього ж результату можна домогтися з мінімальним кодуванням в генераторі HTML. Можна додати метод, наприклад, printText(), Який буде приймати ключ в якості вхідного параметра і виводити перекладене текстове значення, а метод text() буде просто повертати це значення. Згенерований у сервлетов код буде таким же лаконічним і швидким, як і його JSP-аналог, якщо не краще. Це також дає кращий контроль над обробкою неперекладених значень, наприклад, дозволяючи видати виняткову ситуацію чи використовувати значення з мови за замовчуванням.


Налаштування подання


Ця можливість з легкістю реалізується архітектурою проекту March Madness. Якщо зайти на домашню сторінку і увійти в систему, то буде показано вітальне повідомлення. Якщо натиснути на кому після “Welcome”, то уявлення сторінки зміниться. Ця альтернативна оболонка сайту – більше ніж просто додатковий CSS-файл. Я розширив клас MadnessWriter, І тепер, коли вибирається альтернативна оболонка, базовий клас-сервлет створює відповідний об’єкт-підклас і передає його в зачищений метод service(). Цей підклас MadnessWriter може не тільки перевизначити таблицю стилів за замовчуванням, але і структуру генерується HTML теж, наприклад, показавши інший логотип або більш складну кордон навколо контейнерів. Ніякого спеціального коду всередині самих сервлетов для цього не потрібно.


Використання відступів


Однією з проблем даного підходу може виявитися те, що згенерований HTML код не матиме відступів або буде погано читабельним. Хоча жахливі відступи часто створювані кодом на базі шаблонів, які використовують суміш HTML і scriptlet “ов, нічим не краще. Навіть якщо в коді немає scriptlet” ов, вирізка та вставка тексту через яке той час зазвичай призводять до кривому і несиметричному коду.


Мені вдалося зробити HTML, генерований проектом March Madness більш читабельним, додавши у генерований HTML кілька символів кінця рядка. Хоча акуратно відформатований HTML не є вкрай необхідним для даного підходу, так можна знайти більшість помилок у розмітці сторінки, переглядаючи Java код, а не згенерований HTML-код. Рознесення елементів і конструкцій по модулям сильно допомагає зберігати ясність і зручність підтримки.


Висновок


Ця стаття є запрошенням подумати про розробку за рамками середовищ для розробки Web-додатків, і представити Web-інтерфейс додатка, побудований безпосередньо на Java Servlet API. Вражаюча число середовищ і систем шаблонів, доступних Java Web-розробникам, змушує вважати себе незамінними, хоча вони часто дивно складні і важкі у використанні. Міркуючи про те, яка з них більше підходить до певного типу Web-додатки, можна заодно подумати, чого можна досягти за допомогою вбудованих можливостей мови, таких як розширення і інкапсуляція. Як говорить Брюс Тейт (Bruce Tate): “Зазвичай краще вирішувати проблеми за допомогою простоти і спритності, а не грубої сили “.


У Web-середовищ дійсно є певна сила, і JSP і шаблони відмінно працюють, коли в проекті є HTML-дизайнери, створюють і підтримують їх. Але для деяких проектів простота “чистих” сервлетов є правильною альтернативою зі своїми особливими перевагами, так як забезпечує контроль і гнучкість, не вимагаючи упаковки всього динамічного вмісту в об’єкти запиту. Unit-тестування “чистих” сервлетов можливо без будь-яких додаткових хитрувань. І повторно використовувати згенерований HTML так само просто, як додавати або перевизначати методи.


Так що дайте шанс цього підходу, і ви можете бути здивовані отриманим результатом.

Схожі статті:


Сподобалася стаття? Ви можете залишити відгук або підписатися на RSS , щоб автоматично отримувати інформацію про нові статтях.

Коментарів поки що немає.

Ваш отзыв

Поділ на параграфи відбувається автоматично, адреса електронної пошти ніколи не буде опублікований, допустимий HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

*