Сервлет - це Java-nporpaMMa, яка як свій суперклас використовує клас HttpServiet. Сервлет використовується для того, щоб розширити можливості існуючого сервера, зокрема Web-сервера. Як правило, сервлет працює на спеціальному сервері. Такі сервери звуться серверів Java-додатків (Java Application Server). До складу сервера Java-додатків як складовий блок входить Web-сервер (іноді не один, а кілька), а також сервери, що працюють із серверними компонентами, сервери допоміжних служб тощо. Сервлет працює в оточенні, яке надає йому сервер. Частина сервера, призначена для роботи із сервлетами, називається контейнером сервлетів. Специфікація сервлетів передбачає наявність у класі сервлету стандартних методів, виконання яких відбувається на тому чи іншому етапі життєвого циклу сервлету. Виклик цих методів здійснюється контейнером сервлетів. Імплементація специфікації сервлетів входить до набору стандартних пакетів Java.
У цій книзі розглядається сервер Java-додатків під назвою Blazix. Сервер Blazix надає повний набір можливостей для роботи із сервлетами. Крім створення класу (або класів) сервлета, а також для конфігурування створеної програми-сервлета, встановлення її на сервер необхідно змінити файл конфігурації Web-сервера. Основні значення вказуються у файлі конфігурації у такому вигляді: servlet.name: myservlet
servlet.myservlet.className: mypackage.MyServletClass servlet.myservlet.url: /mysrvlet
У кожного сервлета має бути поставлене ім'я(servlet.name), яким він ідентифікується на сервері. Це ім'я використовується для завдання властивостей сервлета, зокрема, для вказівки імені класу, в якому зберігається програма сервлета (наступний рядок), а також адреси, за якою відбувається звернення до цього сервлета (третій рядок).
Клієнт запитує у Web-сервера адресу, за якою розташований сервлет (адреса має бути вказана як значення servlet.myservlet.url у файлі конфігурації Web-сервера). Сервер передає запит та дані (якщо вони є) сервлету, отримує відповідь від сервлета та надсилає його клієнту.
На цьому пояснення про те, що таке сервлет можна було б закінчити. Однак існує безліч цікавих та корисних деталей, на яких слід затримати увагу та вивчити їх докладніше.
Особливо важливо мати на увазі, що шлях до класу сервлету має бути вказаний у змінній ciasspath або його можна помістити в каталог C:\Blazix\classes або в каталог, який вказаний у файлі конфігурації Web-сервера як значення server.ciassDir. Після того, як файл конфігурації був змінений і в нього вставлена інформація про новий сервлет, сервер повинен бути зупинений і запущений знову. Сервлет може бути розміщений і на сервері, що працює, за допомогою утиліти адміністрування, але для цього сервлет повинен бути упакований у файл Web-архіву WAR. Якщо файл класу сервлета змінено, то зупиняти сервер і запускати його знову необов'язково. За замовчуванням сервер налаштований так, що виклик сервлета за адресою http://localhost:81/_reload призводить до того, що всі класи будуть перезавантажені і змінений клас сервлета буде доступним для клієнтських запитів (рис. 4.1). Відвідайте цю сторінку після того, як буде змінено файл сервлетового класу. Зупинка сервера просто не потрібна.
Якщо читач вже мав деякий досвід роботи з сервлетами, він оцінить ту простоту, яка властива серверу Blazix проти іншими Java- серверами, наприклад, із сервером Tomcat.
Щоб одразу приступити до справи, розглянемо простий приклад, сервлет some- Servlet (Листинг 4.1).
Лістинг 4.1. Сервлет SomeServlet.java I
import java.io.*; import javax.servlet.*; import javax.servlet.http.*;
public class SomeServlet extends HttpServlet ( public void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException ( Printwriter out = response.getWriter(); out.println("Hello World");
У файлі конфігурації Web-сервера запишемо наступне:
servlet.name: перша
servlet.first.className: SomeServlet
servlet.first.url: /dofirst
Тоді звернення до сервлета з браузера набуде вигляду http://localhost:81 / Dofirst (рис. 4.2).
Сервлети Java надають платформонезалежний метод створення Web-додатків (це не безперечно, проте ми не будемо розглядати це питання глибше, оскільки тоді нам потрібно визначитися з тим, що розуміти під Web-додатком, що не входить до переліку тем, що розглядаються), причому багато додатків відрізняються швидкістю в роботі та позбавлені тих обмежень, які є у CGI-додатків. Сервлет працює під керуванням Web-сервера і, на відміну аплета, не вимагає графічного інтерфейсу користувача. Сервлет взаємодіє із сервером, обмінюючись із запитами і відповідями. Клієнтська програма звертається до сервера із запитами. Запит обробляється сервером, передається сервлет, сервлет посилає відповідь через сервер клієнту. На сьогоднішній день сервлет дуже популярні при створенні інтерактивних Web-додатків. Існує безліч Web-серверів, здатних працювати із сервлетами, серед них такі сервери, як Tomcat, iPlanet Web Server (раніше Netscape
Enterprise Server), Blazix. J Builder Enterprise використовує сервер Borland Enterprise Server (BES), що входить до складу пакету, а також підтримує роботу з серверами Web Logic, WebSphere та iPlanet. J Builder Enterprise Server включає сервер Tomcat, який використовується "за замовчуванням".
Мал. 4.2. Звернення до сервлета
Однією важливою перевагою сервлетів є швидкість їхньої роботи. На відміну від програм CGI, сервлети завантажуються в пам'ять лише один раз і потім виконуються безпосередньо з пам'яті. Сервлети, по суті, є багатопотоковими додатками. До того ж вони платформонезалежні, оскільки написані мовою Java.
Технологія JSP, якій присвяченоглава 3, є розширенням технології сервлетів, в JSP особливу увагуприділяється роботі з HTML- та XML-документами. У складі HTML-і XML-коду JSP-фрагменти знаходять своє найчастіше застосування. Як зробити вибір та вирішити, що використовувати: сервлети чи серверні сторінки? Сервлети більше підходять для розв'язання задач низькорівневого програмування та менш пристосовані для розв'язання задач створення логіки подання програми. Серверні сторінки JSP, навпаки, в основному сконцентровані на тому, як уявити результат користувачеві в найбільш зручному вигляді. Серверні сторінки створюються вбудованими в HTML-код, використовуючи стиль створення HTML-документів. Технологія JSP надає набагато багатші можливості, ніж простий HTML. Сторінки JSP можуть надавати можливості реалізації логіки програм з використанням простих компонентів Java, а також серверних компонентів EJB, шляхом створення користувацьких бібліотек ярликів. Самі собою серверні сторінки Java можуть бути модульними, багаторазово використовуваними компонентами, які працюють із логікою уявлення, які можна використовувати разом із різними шаблонами і фільтрами. JSP-сторінки перетворюються на сервлети, тому теоретично можна користуватися виключно сервлетами. Однак технологія JSP створена для того, щоб спростити процес створення Web-документів, відокремивши логіку подання програми від змісту документа. У більшості випадків відповідь, що відправляється клієнтові, складається як з шаблонів подання документа, так і з даних, які генеруються автоматично, заповнюючи шаблон. У таких ситуаціях виявляється набагато легше працювати з JSP, ніж із сервлетами.
Однією із найприємніших особливостей Java є її багатогранна природа. Звичайно, створення традиційних десктопних і навіть мобільних додатків- це здорово. Але що, якщо ви хочете піти з проторених доріжок і зайти на територію розробки веб-додатків на Java? Для вас є хороша новина: у комплекті з мовою йде повноцінний Servlet API, який дозволяє вам створювати надійні веб-програми без особливих турбот.
Створення програм на Java за допомогою Servlets
Отже, ми вже створили конфігураційні файли програми. Однак у поточному стані він буквально нічого не робить. Ми хочемо, щоб клієнти могли реєструватися за допомогою HTML-форми, тому наступне, що нам потрібно зробити - це створити JSP-файли, які відображатимуть вищезгадану форму та дані клієнта після успішного завершення реєстрації. Цим ми зараз і займемося.
Працюємо над зовнішнім виглядом
Зовнішній вигляд програми визначатиметься двома JSP-файлами – у контексті MVC вони називаються уявленнями. Перший відповідатиме за відображення форми реєстрації та можливих помилоквикликаних після перевірки введених даних. Другою буде звичайною сторінкою привітання, де будуть показані дані, введені клієнтом, після успішного завершення процесу реєстрації.
Ось перший JSP-файл:
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
Реєстрація
$ (Violation).
Файл містить простий HTML з кількома додатками. Ось вона, принадність JSP у поєднанні з JSTL і JEL. Зверніть увагу, як легко перевірити наявність помилок валідації, використовуючи такі стандартні теги, як<с:if>і
Атрибут форми реєстрації action вказує на наступну URL: $(pageContext.request.contextPath)/processcustomer . Це означає, що кожного разу, коли клієнт намагається зареєструватися, дані будуть відправлятися в processcustomer незалежно від URL, за яким доступна форма. Це досягається за рахунок функціональності об'єктів, доступних з JSP-файлу, таких як request.
Незабаром ми побачимо, як сервлет зв'язується з URL processcustomer і як він взаємодіє з введеними даними. А поки давайте подивимося на JSP-файл, який відповідає за сторінку привітання:
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
Дякую за реєстрацію!
Ваші введені дані:
Ім'я:$(Firstname)
Прізвище:$(lastname)
Email:$(email)
Тепер, коли ми розібралися з відображенням сторінок, наступним кроком буде створення сервлета, відповідального за збір даних клієнта з запитів POST і підтвердження даних простим способом.
Пишемо контролер
Написати сервлет, здатний отримати дані з форми реєстрації, простіше. Все, що нам потрібно зробити - це написати підклас для класу HttpServlet і реалізувати його методи doGet() або doPost() (або обидва, якщо треба). У цьому випадку сервлет буде взаємодіяти з даними, що надходять із POST-запитів.
Ось як він виглядає:
@WebServlet(name = "CustomerController", urlPatterns = "/processcustomer") Public class CustomerController extends HttpServlet ( @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, request); .setAsRequestAttributes(request); List violations = customer.validate(); ).forward(request, response); ) private String determineUrl(List violations) ( if (!violations.isEmpty()) ( return "/"; ) else ( return "/WEB-INF/views/customerinfo.jsp"; ) ) private static class RequestCustomer (private final String firstName; private final String lastName; private final String email; private RequestCustomer(String firstName, String lastName, String email) ( this.firstName = firstName; this.lastName = lastName; this.email = email; ) public static RequestCustomer fromRequestParameters(HttpServletRequest request) ( return new RequestCustomer(request.getParameter("firstname"), request.getParameter("lastname"), request.getParameter("email")); ) public void setAsRequest ( request.setAttribute("firstname", firstName); request.setAttribute("lastname", lastName); request.setAttribute("email", email); ) public List validate() ( List violations = new ArrayList<>(); if (!StringValidator.validate(firstName)) ( violations.add("Ім'я є обов'язковим полем"); ) if (!StringValidator.validate(lastName)) ( violations.add("Прізвище є обов'язковим полем"); ) if ( !EmailValidator.validate(email)) ( violations.add("Email повинен бути правильно сформований"); ) return violations; ) ) )
Перше, на що тут варто звернути увагу - використання анотації @WebServlet(name = "CustomerController", urlPatterns = "/processcustomer") . Вона каже контейнер сервлет використовувати клас CustomerController для обробки HTTP-запитів за адресою /processcustomer . Того ж ефекту можна досягти шляхом додавання директив зіставлення сервлетів в web.xml , як , але оскільки ми використовуємо Servlet Specification 3.1, нам немає необхідності вдаватися до такого способу.
Тут ми назвали сервлет CustomerController, оскільки вважається гарною практикою використовувати ім'я класу сервлета як значення атрибута name анотації @WebServlet. В іншому випадку, деякі контейнери не зможуть виконати зіставлення, що призведе до помилки 404.
Сам клас CustomerController виконує кілька найпростіших завдань. По-перше, він збирає введені у форму дані, використовуючи реалізацію інтерфейсу HttpServletRequest, який містить значення, що відповідають полям firstname, lastname та email форми. Потім він встановлює ці значення як атрибути запиту, тому їх можна повторно відобразити або у формі, або на сторінці з результатами. Зрештою, валідатори перевіряють правильність введених даних.
Валідатори - це прості класи, які перевіряють певні властивості, наприклад, чи є порожній рядок і чи виглядає email як email. На GitLab автора можна подивитися на їхню реалізацію.
Результат валідації впливає на подальший перебіг подій: якщо дані не валідні, клієнт перенаправляється через об'єкт RequestDispatcher на сторінку реєстрації, де відображаються відповідні помилки. Якщо все гаразд, відображається сторінка привітання.
Отже, ми створили цілий веб-додаток на Java, який дозволяє зареєструвати клієнтів за допомогою HTML-форми, базового сервлета та кількох JSP-файлів. Час його запустити.
Запускаємо програму
Для запуску програми потрібно зробити наступні кроки:
IntelliJ IDEA). Коли ви розгорнете проект і запустите його, повинен запуститися стандартний бразуер з вікном реєстрації.
Висновок
Отже, ви набули всіх навичок, необхідних для створення власної веб-програми на Java без необхідності вдаватися до складних фреймворків. Все, що вам потрібно, - Servlet API, технологія на зразок JSP для відображення та вбудовані засоби Java. Здорово, правда?
Варто зазначити, що реалізація класу CustomerController підкреслює переваги та недоліки сервлетів: з одного боку, він коротко показує, наскільки легко обробляти параметри запиту та надсилати відповіді клієнту різних форматах. Але ця функціональність має свою ціну: обидві реалізації інтерфейсів HttpServletResponse та HttpServletResponse є звичайними локаторами служб. Не можна сказати, що це погано, оскільки локатори просто містять дані. Однак треба пам'ятати, що ці реалізації завжди будуть прив'язані до сервлета.
Servlet- це java-програма, яка виконується на серверній стороні Web-програми. Так само, як аплети динамічно розширюють функціональні можливості Web-браузера, сервлет динамічно розширюють функціональні можливості Web-сервера.
Роботу servlet"а можна описати наступним чином: при надходженні запиту від клієнта Web-сервер за допомогою спеціального конфігураційного файлу може визначити, який сервлет необхідно виконати. Після цього Web-сервер запускає JVM, яка в свою чергу виконує сервлет. Servlet обробляє запит і передає вміст Web -серверу (можливо у вигляді HTML-сторінки) Web-сервер відправляє клієнту відповідь (сформовану сервлетом HTML-сторінку).
WEB-сервер по суті є певним контейнером, який завантажує servlet"І, виконує їх, і, отримавши від них результат, відправляє його клієнту.
Servlet в архітектурі Web-програми
Через свою потужність і гнучкість, servletВи можете відігравати значну роль в архітектурі системи. Вони можуть виконувати прикладні завдання, призначені для проміжного рівня, працювати як проксі-сервер для клієнта і навіть покращувати функціональність проміжного рівня, додаючи підтримку нових протоколів та інших функцій. Проміжний рівень виконує функції сервера додатків так званої трирівневої системи клієнт-сервер і розташований між "легковажним" клієнтом, таким як Web-браузер, та джерелом даних.
Servlet як проксі-сервер
Для підтримки аплетів сервлети можуть виконувати функції проксі-серверів. Це може бути важливо, оскільки система безпеки Java дозволяє аплетам з'єднуватися тільки з сервером, з якого вони були завантажені. Якщо аплет потребує з'єднання з сервером баз даних, розташованому на іншій машині, servletможе створити це з'єднання аплету.
Тимчасові та постійні servlet"и
Сервлети можуть запускатись та зупинятися для кожного клієнтського запиту. Також вони можуть запускатись при старті Web-сервера та існувати до його зупинки. Тимчасові servlet"и завантажуються на вимогу і пропонують хороший спосіб збереження ресурсів сервера для рідко використовуваних функцій. Постійні сервлети завантажуються при старті Web-сервера і існують до його зупинки. наприклад, встановлення з'єднання з базою даних), якщо вони пропонують постійну функціональність на стороні сервера (наприклад, служба RMI), або у випадках, коли вони повинні відповідати на запити клієнта якнайшвидше. servletа постійним або тимчасовим; це функція налаштування Web-сервера.
Життєвий цикл сервлету, javax.servlet.Servlet
Сервлети виконуються на платформі Web-сервера як частину цього процесу, як і сам Web-сервер. Web-сервер відповідає за ініціалізацію, виклик та знищення кожного екземпляра сервлета. Web-сервер взаємодіє із сервлетом через простий інтерфейс: javax.servlet.Servlet.
Інтерфейс javax.servlet.Servlet включає три основні способи:
- init()
- service()
- destroy()
і два допоміжні методи:
- getServletConfig()
- getServletInfo()
Подібність між інтерфейсами servlet"а і аплету Java очевидні. Саме так і було спроектовано! Java сервлети є для Web-серверів тим самим, чим є аплети для Web-браузерів. Аплет виконується в Web-браузері, виконуючи дії на його запит через спеціальний інтерфейс. Сервлет робить те саме, працюючи на Web-сервері.
Ініціалізація сервлету, метод init()
При першому завантаженні сервлета викликається метод init(). Це дає можливість сервлету виконати будь-яку роботу з установки, наприклад, відкриття файлів або встановлення з'єднань з серверами. Якщо сервлет встановлений на сервері постійно, він завантажується під час запуску сервера. Інакше сервер активізує сервлет при отриманні першого запиту від клієнта виконання послуги, що забезпечується цим сервлетом.
Гарантується, що метод init()закінчиться перед будь-яким іншим зверненням до сервлета – таким як, наприклад, виклик методу service(). Зверніть увагу, що init()буде викликано лише один раз; він не буде викликатися, поки сервлет не буде вивантажений і потім завантажений сервером знову.
Метод init()приймає один аргумент – посилання на об'єкт ServletConfigщо містить аргументи для ініціалізації сервлету. Цей об'єкт має метод getServletContext(), що повертає об'єкт ServletContext, Що містить інформацію про оточення сервлета.
Ядро сервлету, метод service()
Метод service()є серцем сервлету. Кожен запит від клієнта призводить до одного виклику методу service(). Цей метод читає запит і формує повідомлення у відповідь за допомогою своїх двох аргументів ServletRequest і ServletResponse:
Таким чином, існують два способи передачі від клієнта до сервлета. Перший – через надсилання значень у параметрах запиту. Значення параметрів можна вставити в URL. Другий спосіб передачі від клієнта до сервлета здійснюється через InputStream (чи Reader).
Робота методу service()сутнісно проста – він створює у відповідь кожен клієнтський запит, переданий йому з сервера. Однак необхідно пам'ятати, що можуть існувати кілька паралельних запитів, що обробляються в один і той самий час. Якщо метод service()вимагає будь-яких зовнішніх ресурсів, таких як файли, бази даних, то необхідно гарантувати, щоб доступ до ресурсів був захищеним.
Вивантаження сервлету, метод destroy()
Метод destroy()викликається звільнення всіх ресурсів (наприклад, відкриті файлита з'єднання з базою даних) перед вивантаженням сервлета. Цей метод може бути порожнім, якщо немає необхідності виконувати будь-які завершальні операції. Перед викликом методу destroy()сервер чекає або завершення всіх обслуговуючих операцій, або закінчення певного часу. Це означає, що метод destroy()може бути викликаний під час виконання будь-якого тривалого методу service().
Важливо оформити метод destroy()таким чином, щоб уникнути закриття необхідних ресурсів до тих пір, поки всі дзвінки service()не завершаться.
Конфігурація сервлета, метод getServletConfig()
Метод getServletConfig()повертає посилання на об'єкт, що реалізує інтерфейс ServletConfig. Цей об'єкт надає доступом до інформації про конфігурації сервлета, тобто. доступ до параметрів ініціалізації сервлету та об'єкту контексту сервлету ServletContext, який дає доступ до сервлета та його оточення.
Інформація про сервлет, метод getServletInfo()
Метод getServletInfo()визначається програмістом, що створює сервлет, для повернення рядка, що містить інформацію про сервлет, наприклад: автор і версія сервлета.
Інтерфейс ServletRequest
ServletRequest надає клієнтську інформацію параметри HTTP запиту сервлету, тобто. забезпечує дані включаючи назву параметра та значення, атрибути, та вхідний потік. Ця інформація передається у метод service().
Наступний servlet прикладпоказує, як отримати інформацію з параметра requestметоду service():
BufferedReader reader; String param1; String param2; public void service(ServletRequest request, ServletResponse response) ( reader = request.getReader(); param1 = request.getParameter("First"); param2 = request.getParameter("Second"); )
Додаткова інформація про запит доступна сервлет через методи, основні з яких наведені в наступній таблиці:
getAttribute() | Повертає значення вказаного атрибута цього запиту. |
getContentLength() | Розмір запиту, якщо відомий. |
getContentType() | Повертає тип MIME тіла запиту. |
getInputStream() | Повертає InputStream для читання двійкових даних із тіла запиту. |
GetParameterNames() | Повертає масив рядків із іменами всіх параметрів. |
getParameterValues() | Повертає масив значень зазначеного параметра. |
getProtocol() | Повертає протокол та версію для запиту як рядок виду |
getReader() | Повертає BufferedReader для отримання тексту з запиту тіла. |
getRealPath() | Повертає реальний шлях для зазначеного віртуального шляху. |
getRemoteAddr() | IP-адреса клієнта, який надіслав цей запит. |
getRemoteHost() | Ім'я хоста клієнтської машини, що надіслав цей запит. |
getScheme() | Повертає схему, що використовується в URL цього запиту (наприклад, https, http, ftp тощо). |
getServerName() | Ім'я хоста сервера, який прийняв цей запит. |
getServerPort() | Повертає номер порту, який використовується для отримання цього запиту. |
Інтерфейс ServletResponse
Інтерфейс ServletResponse- Це інструмент для надсилання даних клієнту. Усі методи даного інструменту служать саме для вирішення цього завдання:
Public java.lang.String getCharacterEncoding() public void setLocale(java.util.Locale loc) public java.util.Locale getLocale()
Перший спосіб повертає MIME тип кодування (наприклад - UTF8), у якій видаватиметься інформація. Другі два методи теж працюють із charset. Вони вказують на мову, що використовується в документі (наприклад - російська).
Public ServletOutputStream getOutputStream() throws java.io.IOException
Метод getOutputStream повертає потік виведення даних для сервлета. Цей потік використовується, наприклад, виведення бінарних файлів. Текстові дані можна виводити за допомогою java.io.Writer:
Public java.io.PrintWriter getWriter() throws java.io.IOException
Метод getWriter() автоматично конвертує рядки в той charset, що вказаний у методі getCharacterEncoding() та getLocale().
Public void setContentLength(int len)
Методом setContentLength встановлюється значення поля HTTP заголовка "Content-Length"
Public void setContentType(String type)
Метод setContentType використовується для надсилання MIME типу вмісту документа. Поле HTTP заголовка "Content-Type".
Потік виведення даних буферизований. Це означає, що порцію даних буде видано клієнту лише після заповнення буфера.
Public void setBufferSize(int size) public int getBufferSize() public void flushBuffer() throws java.io.IOException public void resetBuffer()
Наведені вище 4 методи дозволяють, відповідно, встановити розмір буфера відправки, отримати його розмір, ініціалізувати відправлення вміст буфера клієнту, не чекаючи його заповнення, а також очистити буфер від даних.
Public boolean isCommitted()
Методом isCommitted можна отримати прапор, вже розпочато відправлення даних клієнту. Прапор буде позитивним, якщо HTTP заголовок відповіді було вже надіслано.
Public void reset()
Якщо HTTP заголовок ще не надіслано, то метод reset "скидає" HTTP заголовок до значень "за замовчуванням".
Діаграми JFreeChart у сервлетах
Графічна бібліотека JFreeChart може бути використана в сервлетах для створення діаграм та їх відображення на сторінках сайтів у вигляді зображень. Подробиці опису та приклади використання JFreeChart у сервлетах представлені .
Сервлет із графічною бібліотекою Chart.js
JNI у сервлеті
У ряді випадків може знадобитися використання JNI у WEB-додатку. Приклад використання JNI у сервлетах представлений.
JMS повідомлення у сервлеті
Сервлет може бути використаний для обміну JMSповідомленнями між програмами. Приклад використання сервлета для надсилання та читання JMS повідомлень у контейнері JBoss представлений.
Java Servlet - це програма на стороні сервера, написана однойменною мовою програмування, яка отримує сигнали клієнта і відправляє йому відповіді назад. Це ключовий елемент, що формує типовий Java EE, окрім JSP, EJB, XML та інших пов'язаних технологій. Програма може бути упакована в файл WAR(Web AR chive) для розгортання веб-сервері. Сервер, який може запускати Java-сервлет, називається контейнером. Програма, яка запускається на такому сервері, може створювати динамічні веб-сторінки.
Java Servlet: основи
Найбільш популярними та широко використовуваними контейнерами є Tomcat та JBoss. Технічно сервлет – це нормальний Java-клас, який має розширення для загального клієнт-серверного протоколу або HTTP. На практиці він застосовується для обробки запитів через перевизначення HttpServlet GET і POST відповідно. Контейнер Java Servlet надає Http.ServletRequest та Http.ServletResponse - об'єкти, що працюють за схемою запит-відповідь. І зазвичай використовується в поєднанні з JSP для створення динамічного контенту.
Типовий сценарій моделі:
Java Servlet Filters - це компоненти Java, що підключаються, які використовуються для перехоплення та обробки запитів до їх відправки сервлетам і відповіді після завершення його коду, і до того, як контейнер відправить відповідь клієнту.
Загальні завдання, які виконують із фільтрами:
Фільтри підключаються та настроюються у файлі дескриптора розгортання (web.xml). Сервлети та фільтри не знають один про одного, тому можна додати або видалити фільтр просто відредагувавши web.xml. Допускається мати кілька фільтрів для одного ресурсу або створити ланцюжок фільтрів для web.xml або запустити Java Servlet filters, реалізуючи інтерфейс javax.servlet.Filter.
Паралельні запити на сервер обробляються потоками, що забезпечує важливі якості веб - багатопоточність та паралелізм.
Основні функції:
Необхідність застосування динамічних веб-сторінок
Існує чимало причин, через які бізнес хотів би створювати динамічні веб-сторінки на льоту, наприклад, коли дані на веб-сайті часто змінюються. Сайти новин та погоди зазвичай покладаються на CGI, щоб підтримувати свіжий контент, що не вимагає постійної уваги розробників. Веб-сторінки електронної комерції, в яких перераховані поточні ціни та рівні запасів, використовують CGI для отримання цього контенту на вимогу, отримуючи його із внутрішньої інфраструктури компанії.
Багато користувачів мають досвід використання технології Джава для створення веб-сервісів на базі CGI, але Java Servlets більш ефективні, потужніші, простіше у використанні і дешевше традиційних альтернатив CGI.
Переваги Java Servlets:
З моменту появи мови програмування Java пройшло майже двадцять років. За цей час Java пророкували смерть і забуття, програмісти на сях сміялися з її гальмування і жадібності до ресурсів. Але були й ті, хто повірив у Java, вони розробляли всілякі бібліотеки, розвивали співтовариство, наполегливо доводили, що Java немає меж: realtime, embedded, ІІ - можливо все. Ми вирішили не залишатися осторонь і зробити в цій рубриці невеликий цикл статей з Java. Поїхали!
Ваш чайник вибирає Java
Як запевняє сама Oracle, на сьогоднішній день віртуальна машина Javaвстановлена на більш ніж трьох мільярдах пристроїв. І це не лише комп'ютери та смартфони, а й фотоапарати, телевізори, Blue-ray-програвачі, принтери, сім-карти, банківські автомати та навіть автомобілі. Цей список буде неухильно зростати, а разом із ним і пропозиції від роботодавців для Java-програмістів. Навіть зараз кількість вакансій для програмістів Java перевищує решту. І компанії готові платити все більше і більше, переманюючи співробітників та організуючи вигідніші умови праці.
А чим вона хороша?
Програмістів Java приваблює мінімалізм синтаксису. Жодних зайвих модифікаторів та службових слів. Навіть відсутність множинного успадкування, яке спочатку трохи бентежило програмістів на С++, у результаті виявляється розумним і виправданим. Проста логіка, автоматична робота з пам'яттю, докладна документація, форуми з відповідями на всі питання, відкритий код – все це дозволяє швидко вникнути у процес розробки та значно зменшує кількість потенційних помилок. Навіть індійські селяни освоюють Java за пару місяців, принаймні так йдеться у їхніх дипломах:). Крім того, Java - мова, що інтерпретується. Вихідний код компілятор переводить на так званий байт-код, який нескладно перетворити назад, що робить Java особливо привабливим для реверс-інжинірингу.
Ну-с, приступимо
Java - об'єктно-орієнтована мова, це означає, що всі змінні, методи, константи оголошуються в рамках будь-якого класу. Крім класів, є ще інтерфейси – особлива абстрактна конструкція, яка дозволяє описати поведінку об'єкта, не вказуючи на конкретну реалізацію. І якщо множинного успадкування класів в Java немає, то інтерфейсів клас може реалізовувати будь-яку кількість, що дозволяє одному об'єкту мати безліч функцій, але надавати тільки частину з них.
Типи даних можна розділити на дві групи: прості (int, long, char тощо) і об'єктні: класи, інтерфейси, масиви. Прості типи завжди та скрізь фіксованої розмірності. Наприклад, на будь-якій архітектурі та будь-якому пристрої int займає чотири байти пам'яті. Це досить зручно під час обчислень. Масив даних містить спеціальний атрибут length, який зберігає розмір масиву, за що окреме спасибі розробникам. Дані різних типів по-різному передаються методами. Прості типи завжди передаються за значенням. Об'єктні – завжди за посиланням для економії пам'яті. Це означає, що й ми передаємо int a = 10 і змінюємо його значення на 5 у викликаному методі, то вихідному методі a як і дорівнюватиме 10. Але якщо змінимо властивість об'єкта, воно зміниться й у вихідному методі.
Пам'ятай про пам'ять
Хоча програміст Java і звільнений від необхідності виділяти та звільняти пам'ять, незнання деяких особливостей роботи віртуальної машиниі збирача сміття може запросто перетворити твою програму на ненаситного монстра, що пожирає процесорний час і всю доступну пам'ять.
Створюючи новий масив, завжди пам'ятай, що набагато простіше створити багато маленьких шматочків пам'яті, ніж один величезний. Інакше ризикуєш нарватися на помилку Out of memory, що означає, що пам'ять у тебе була, та вся вийшла.
Багато програмістів, коли переходять на Java і дізнаються про автоматичне очищення пам'яті, починають створювати об'єкти у величезних кількостях, сподіваючись, що все це забереться саме. Тим часом збирач сміття подібний до машини, яка може прибрати сміття, тільки викинуте в урну біля будинку. Якщо якісь дані тобі більше не потрібні, не варто зберігати їх про всяк випадок, як купа старих листівок, - присвій покажчику на дані null, допоможи прибиральнику прибратися:). Також хорошим тоном буде зробити clear для списку, якщо він вже не знадобиться. Пам'ятай, об'єкт зберігатиметься у пам'яті, поки коді на нього є посилання. Навіть якщо твоя програма працює на 16 гігах пам'яті і вилетіти з Out of memory їй не загрожує, від надлишку пам'яті, що використовується, вона буде ставати все більш неповороткою і гальмованою. 99% скарг користувачів на повільну роботу Java-програм пов'язано з написаним неефективно вихідним кодом. Якщо тобі потрібно постійно створювати об'єкти, які використовуються швидко і більше не потрібні, наприклад, багато дрібних повідомлень, задумайся про створення пулу, в якому зберігатиметься деяка кількість екземплярів для багаторазового використання. Пам'ятай, створення та видалення об'єкта - операція дорога.
За справу, панове
Один приклад кращий за тисячу слів. Погортати мануал і подивитися на стандартні хеллоуворди ти можеш і без нас, тому вважатимемо, що ти це вже зробив і готовий до реалізації цікавішого прикладу.
Ми з тобою займемося серверним застосуванням Java та напишемо невелику програму для «стеження» за користувачами соціальних мереж. Для цього навіть не доведеться працевлаштовуватися в АНБ – користувачі самі про себе все викладають, а нам залишиться тільки цю інформацію отримати, систематизувати та гарно відобразити. Візьмемо один із популярних соціальних сервісів, наприклад foursquare, і намалюємо на карті переміщення наших друзів.
Спершу подивимося, що ми можемо витягнути з чотирьохплощ. Пробігшись по сторінках для розробників, ми звертаємо свою увагу на два методи:
- https://developer.foursquare.com/docs/users/checkins – місця, які відвідав користувач. На жаль, поки що підтримується тільки для зареєстрованого в програмі користувача, і ходять чутки, що через обмеження в реалізації так воно й залишиться;
- https://developer.foursquare.com/docs/checkins/recent – місця, які відвідали друзі зареєстрованого користувача. Якщо трохи пограти з цією функцією, то з'ясовується сумний факт: для кожного друга повертається одно місце - останнє, де він відзначився.
Щоб користуватися foursquare API, необхідно зареєструвати наш майбутній додаток, йдемо за цією адресою: https://ua.foursquare.com/developers/register і заповнюємо поля (так, у самому foursquare теж доведеться зареєструватися, але з цим ти чудово впораєшся і без мене).
З важливих полів тут можна відзначити лише «Назва програми», «Download / welcome page url» (впиши сюди довільну веб-адресу) та «Redirect URI(s)» - це адреса, на яку нас відправить сервер після реєстрації. Сюди ми пізніше впишемо потрібне значення, а поки що можеш просто вписати будь-яку веб-адресу. Тиснемо «Зберегти», і наша програма tracker успішно зареєстрована.
Піднімаємось у хмари
Капітан Очевидність повідомляє, що будь-якому серверному додатку для роботи потрібний сервер. Піднімати сервер самостійно геморойно, тому скористаємося популярними зараз хмарними рішеннями. Спонсором хмари виступить корпорація Google, тому що їхній Google App Engine безкоштовний, досить легкий у налаштуванні та використанні. Для початку йдемо сюди та завантажуємо Google App Engine SDK for Java.
Тепер можна розпочинати створення проекту. Для розробки Java я користуюся IntelliJ IDEA, але ти можеш скористатися безкоштовним і не менш відомим середовищем Eclipse.
Виберемо новий проект Java. Назвемо його nsa_tracker.
На наступній вкладці відзначимо ліворуч Web Application і Google App Engine і вкажемо шлях до завантаженої раніше та розпакованої App Engine SDK.
А тепер відкинься у кріслі і дозволь IDE зробити свою справу. Якщо ти вибрав IDEA і все зробив правильно, то побачиш готовий проект, який при запуску відкриває вікно браузера з порожнім вмістом. Можна приступати до кодингу.
Починаємо шукати
Отже, у нас є папка з проектом, де лежить папка src. Туди ми складатимемо вихідники. Вихідники Java групуються за пакетами. Пакет – це папка на диску. Пакети потрібні, щоб не звалювати всі вихідники на купу, а розділяти їх, керуючись принципами логіки. Наприклад, код, пов'язаний з інтерфейсом користувача, логічно помістити в пакет ui, мережеві взаємодії - в пакет network. Це значно полегшує розвиток та підтримку проекту згодом. Історично склалася практика починати структуру пакетів з назви компанії, за яким слідує назва програми. Це допоможе легко ідентифікувати наші вихідники серед купи таких же надалі. Для програми ми створимо пакет org.nsa.tracker. У ньому ми й створюватимемо класи.
Для обробки запитів користувачів на сервері використовуються сервлети. Сервлет – це клас, який успадковує, як правило, HttpServlet і працює за принципом запит – відповідь. Все, що потрібно - це перевизначити метод doGet. За запитом від користувача нам потрібно авторизуватись у foursquare, завантажити список чекінів друзів та перенаправити запит на сторінку з карткою.
Для роботи з foursquare API скористаємося безкоштовною бібліотекою foursquare-api-java, яку можна взяти звідси. Бібліотека Java є ZIP-архівом з розширенням jar, що містить відкомпільовані Java-класи, які реалізують певну функціональність. Для авторизації нам знадобляться ClientId та ClientSecret, отримані на етапі реєстрації додатка у чотирикваріі. Так як ці параметри не змінюються у процесі виконання програми, оголосимо їх як константи.
Private static final String CLIENT_ID = "FAKE_CLIENT_ID"; private static final String CLIENT_SECRET = "FAKE_CLIENT_SECRET";
Final означає, що цій змінній надано остаточне значення, яке не дано змінити. Static робить змінну доступною для всіх екземплярів цього класу. Скориставшись прикладом авторизації з бібліотеки foursquare-api-java, отримаємо приблизно наступний код:
Protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException ( FoursquareApi foursquareApi = новий FoursquareApi(CLIENT_ID, CLIENT_SECRET ="; ) ( // Вирушаємо на сторінку реєстрації resp.sendRedirect(foursquareApi.getAuthenticationUrl()); ) else ( try ( foursquareApi.authenticateCode(code); // Реєстрація успішна, завантажимо даних Result
Зверніть увагу на "throws ServletException, IOException" в оголошенні методу. Цей рядок означає, що метод потенційно може залишити один з цих винятків. Виняток Java - це об'єкт, який сигналізує про виникнення виняткової ситуації. Вони бувають перевірені та неперевірювані. Перевірені винятки потрібно обробляти, оточивши частину коду блоком try-catch, або передавати вище. Неперевірені винятки зазвичай не обробляються, тому що виникають у випадках, коли програма не в змозі відновити свій стан. У цьому методі ми обробляємо лише виняток FoursquareApiException.
Коли веб-сервер отримує запит для програми, він використовує дескриптор розгортання, щоб зіставити URL-адресу запиту з кодом, який повинен обробити запит. Дескриптор розгортання є XML-файл з назвою web.xml. Додамо опис сервлета стеження.
Тепер запити на адресу /track буде обробляти наш сервлет з ім'ям TrackerServlet. Можна надати параметру Callback Url правильне значення http://localhost:8080/track.
Для виведення результатів можна скористатися Static Maps API, люб'язно наданим тим самим корпорацією Google (https://developers.google.com/maps/documentation/staticmaps/). Наш сервлет генеруватиме просту HTML-сторінку і повертатиме її у відповідь на запит користувача.
StringBuilder sb = New StringBuilder("
- "); index = 1; for (Checkin checkin: result.getResult()) ( sb.append("
Для генерації сторінки використовується клас StringBuilder, це зумовлено тим, що рядки Java є незмінними об'єктами. При конкатенації рядків за допомогою оператора +. створюється новий рядокв пам'яті. StringBuilder дозволяє заощаджувати пам'ять, тому що використовує масив char для зберігання рядків, що з'єднуються. Передаємо відповідь користувачу:
Byte resultBytes = sb.toString().getBytes("utf-8"); resp.setContentLength(resultBytes.length); resp.getOutputStream().write(resultBytes);
…І все готове. Запускаємо і бачимо щось схоже на картинку з підписом «Результат роботи програми».
Що далі?
Програму можна покращити, наприклад розділити збір даних та відображення. Винести збір даних в окремий сервіс, який працюватиме постійно та запам'ятовуватиме всі переміщення користувачів у базі даних. Тоді можна буде відображати вже не окремі точки, а зв'язковий маршрут. Покопавшись трохи у чотирьохквадрах API, можна отримати навіть більше інформації про активність користувача.
Але сподіваюся, мені вдалося головне: переконати тебе в тому, що Java це просто і круто. До зустрічі за місяць!
Книги для Java-програмера
Почати вивчати мову ми радимо з книги Java. Посібник для початківців» (Java: A Beginner's Guide) Герберта Шілдта. Наступний рівень – «Java. Повне керівництвовід нього ж, а більше про сервлети ти можеш дізнатися з книги «Java сервлети та JSP: збірка рецептів» (Java Servlet and JSP Cookbook) Брюса У. Перрі.