Меню
Безкоштовно
Головна  /  ПЗ/ Пишемо сервлет для стеження за користувачами соцмереж. Java

Пишемо сервлет для стеження за користувачами соцмереж. Java

Сервлети (Servlets) – це java-програми, які виконуються на серверній стороні Web-програми. Так само, як аплети динамічно розширюють функціональні можливості Web-браузера, сервлети динамічно розширюють функціональні можливості Web-сервера. Хоча сервлети можуть обслуговувати будь-які запити, вони зазвичай використовуються для розширення веб-серверів. Для таких програм технологія Java Servlet визначає HTTP-специфічні сервлет класи. Пакети javax.servlet та javax.servlet.http забезпечують інтерфейси та класи для створення сервлетів.

  • Яка структура веб-проекту?

  • Що таке контейнер сервлетів? Життєвий цикл сервлету.

Контейнер сервлетів – програма, що управляє життєвим циклом сервлетів.
Життєвий цикл сервлета: ним управляє контейнер сервлетів, при першому зверненні до сервлета відбувається його завантаження на згадку і викликається метод init(). Протягом роботи програми відбуваються виклики методів service() для обробки запитів клієнта. Після завершення роботи програми викликається метод destroy() і сервлет вивантажується з пам'яті.

  • Які завдання, функціональність контейнера сервлетів?

Контейнер сервлетів може працювати як повноцінний самостійний веб-сервер, бути постачальником сторінок іншого веб-сервера, наприклад Apache, або інтегруватися в Java EE сервер додатків. Забезпечує обмін даними між сервлетом і клієнтами, бере на себе виконання таких функцій, як створення програмного середовища для сервлета, що функціонує, ідентифікацію та авторизацію клієнтів, організацію сесії для кожного з них.

  • Чим відрізняється sendRedirect() від forward()?

Для виклику JSP відносною дорогою застосовується метод forward(), для звернення до JSP абсолютною дорогою використовується метод sendRedirect(). Відмінність цих методів у тому, що з методом forward() передається вже існуючий об'єкт запиту request, а виклику методу sendRedirect() формується новий запит. Інформацію в останньому випадку слід передавати з іншими об'єктами. До того ж, метод forward() спрацьовує швидше.

  • Що ви знаєте про сервлет фільтри?

Реалізація інтерфейсу Filter дозволяє створити об'єкт, який перехоплює запит, може трансформувати заголовок та вміст запиту клієнта. Фільтри не створюють запиту або відповіді, а лише модифікують їх. Фільтр виконує попередню обробку запиту, перш ніж той потрапляє в сервлет, з подальшим (якщо необхідно) обробкою відповіді, що виходить із сервлета. Фільтр може взаємодіяти з різними типами ресурсів, зокрема і сервлетами, і з JSP-сторінками. Сервлетні фільтри можуть:

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

Сервлетний фільтр може бути налаштований так, що він буде працювати з одним сервлетом або групою сервлетів. Основою для формування фільтрів є інтерфейс javax.servlet.Filter, який реалізує три методи:

  • void init (FilterConfig config) throws ServletException;
  • void destroy();
  • void doFilter (ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException;

Метод init() викликається, перш ніж фільтр починає працювати, і налаштовує конфігураційний об'єкт фільтра. Метод doFilter виконує безпосередньо роботу фільтра. Таким чином, сервер викликає init() один раз, щоб запустити фільтр у роботу, а потім викликає doFilter() стільки разів, скільки запитів буде зроблено безпосередньо до цього фільтра. Після того, як фільтр закінчує свою роботу, викликається метод destroy().

  • Навіщо потрібні слухачі у сервлетах?

Слухачі контексту та сесій – це класи, які можуть стежити за тим, коли контекст або сесія були ініціалізовані, або відстежувати час, коли вони мають бути знищені, і коли атрибути були додані чи видалені з контексту чи сесії. Servlet 2.4 розширює модель слухачів запиту, дозволяючи відстежувати, як запит створюється та знищується, і, як атрибути додаються та видаляються із сервлета. У Servlet 2.4 додано такі класи:

  • ServletRequestListener
  • ServletRequestEvent
  • ServletRequestAttributeListener
  • ServletRequestAttributeEvent

  • Як обробити винятки, викинуті іншим сервлетом у додатку?

Так як браузер розуміє лише HTML, то коли програма викине виняток контейнер сервлетів обробить виняток і створить HTML response. Це аналогічно тому, що відбувається при кодах помилок на кшталт 404, 403 і т.д. Servlet API надає підтримку власних сервлетів для обробки винятків та помилок, які ми можемо задати у дескрипторі розгортання. Головне завдання таких сервлетів - обробити помилку або виняток та відправити зрозумілу HTML відповідь користувачеві. Наприклад, можна надати посилання на головну сторінку, а також опис деяких деталей про помилку.

  • Що таке дескриптор розгортання?

Дескриптор розгортання – це конфігураційний файл артефакту, який буде розгорнутий у контейнері сервлетів. У специфікації Java Platform, Enterprise Edition дескриптор розгортання описує те, як компонент, модуль або програма (така, як веб-додаток або програма підприємства) має бути розгорнуто.

Цей файл конфігурації вказує параметри розгортання для модуля або програми з певними налаштуваннями, параметри безпеки і описує конкретні вимоги до конфігурації. Для синтаксису файлів дескриптора розгортання використовується мова XML.

  • Як реалізувати запуск сервлета із запуском програми?

Контейнер сервлетів зазвичай завантажує сервлет при першому запиті клієнта, але іноді необхідно завантажити сервлет прямо на старті програми (наприклад якщо об'ємний сервлет і буде довго вантажитися). Для цього необхідно використовувати елемент load-on-startup у дескрипторі (або анотацію loadOnStartup), який вкаже необхідність завантаження сервлет при запуску.

Значення має бути int. Якщо значення негативне, то сервлет буде завантажений при запиті клієнта, і якщо 0 і далі, то завантажиться на старті програми. Чим менше число, тим раніше в черзі на завантаження буде сервлет.

  • Що таке об'єкт ServletConfig?

Інтерфейс javax.servlet.ServletConfig використовується для передачі конфігураційної інформації сервлету. Кожен сервлет має власний об'єкт ServletConfig, за створення екземпляра якого відповідальний контейнер сервлетів. Для встановлення параметрів конфігурації використовуються параметри init в web.xml (або анотації WebInitParam). Для отримання об'єкта ServletConfig цього сервлета використовується метод getServletConfig().

  • Що таке об'єкт ServletContext?

Інтерфейс javax.servlet.ServletContext визначає низку методів, які сервлет використовує, щоб зв'язатися з його контейнером сервлета, наприклад, отримати тип MIME файлу, диспетчеризувати запити, або записати у файл журналу. Об'єкт ServletContext є унікальним і доступний всім сервлетам веб-додатку. Ми можемо використовувати об'єкт ServletContext, коли нам необхідно надати доступ одному або кільком сервлетам до ініціалізованих параметрів веб-додатку. Для цього використовується елемент у web.xml. Об'єкт ServletContext можна отримати за допомогою методу getServletContext() в інтерфейсі ServletConfig.

Контейнери сервлетів також можуть надавати context об'єкти, унікальні для групи сервлетів. Кожна з груп буде пов'язана зі своїм набором URL-адрес шляхів хоста.

ServletContext був розширений у специфікації Servlet 3 і надає програмне додавання слухачів та фільтрів до програми. Також у цього інтерфейсу є безліч корисних методів на зразок getMimeType(), getResourceAsStream() і т.д.

  • У чому відмінності ServletContext та ServletConfig?

Нижче наведено деякі відмінності:

  • ServletConfig є унікальним об'єктом для кожного сервлета, в той час як ServletContext є унікальним для всієї програми.
  • ServletConfig використовується для надання параметрів ініціалізації сервлету, а ServletContext для надання параметрів ініціалізації програми для всіх сервлетів.
  • У нас немає можливості встановлювати атрибути в об'єкті ServletConfig, а можна встановити атрибути в об'єкті ServletContext, які будуть доступні іншим сервлетам.

  • Інтерфейс ServletResponse.

Інтерфейс ServletResponse – це інструмент для надсилання даних клієнту. Усі методи даного інструменту є саме цієї мети.

  • Інтерфейс ServletRequest.

Інтерфейс ServletRequest - інструмент для отримання параметрів HTTP запиту. Цей інтерфейс має деякі методи, ідентичні за назвою та призначенням з ServletContext.

  • Що таке Request Dispatcher?

Інтерфейс RequestDispatcher використовується для передачі запиту іншому ресурсу (це може бути HTML, JSP або інший сервлет у тому ж додатку). Ми можемо використовувати це для додавання контенту до відповіді іншого ресурсу. Цей інтерфейс використовується для внутрішньої комунікації між сервлетами в одному контексті. В інтерфейсі реалізовано два методи:

  • void forward(ServletRequest var1, ServletResponse var2) - передає запит із сервлета до іншого ресурсу (сервлета, JSP або HTML файлу) на сервері.
  • void include(ServletRequest var1, ServletResponse var2) - включає контент ресурсу (сервлет, JSP або HTML сторінка) у відповідь.

Доступ до інтерфейсу можна отримати за допомогою ServletContext getRequestDispatcher(String s). Шлях повинен починатися з / , який інтерпретуватиметься щодо поточного кореневого шляху контексту.

  • Як можна створити блокування (deadlock) у сервлеті?

Дідлок (deadlock) можна отримати реалізувавши зациклений виклик методу, наприклад, викликавши метод doPost() у методі doGet() і викликати doGet() у методі doPost().

  • Як отримати адресу сервлета на сервері?

Для отримання актуального шляху сервера на сервері можна використовувати цю конструкцію: getServletContext().getRealPath(request.getServletPath()).

  • Як отримати інформацію про сервер із сервлета?

Інформацію про сервер можна отримати за допомогою об'єкта ServletContext за допомогою методу getServerInfo(). Тобто. getServletContext().getServerInfo().

  • Як отримати ip-адресу клієнта на сервері?

Використовувати request.getRemoteAddr() для отримання клієнта ip в сервлеті.

  • Що ви знаєте про класи обгортки (wrapper) для сервлетів?

У Servlet HTTP API надаються два класи обгортки - HttpServletRequestWrapper та HttpServletResponseWrapper. Вони допомагають розробникам реалізовувати власні реалізації типів request і response сервлета. Ми можемо розширити ці класи та перевизначити лише необхідні методи для реалізації власних типів об'єктів відповідей та запитів. Ці класи не використовуються у стандартному програмуванні сервлетів.

З моменту появи мови програмування 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 result = foursquareApi.checkinsRecent("0.0,0.0", 100, 0l); ) catch (FoursquareApiException e) ( e.printStackTrace(); ) ) )

Зверніть увагу на "throws ServletException, IOException" в оголошенні методу. Цей рядок означає, що метод потенційно може залишити один з цих винятків. Виняток Java - це об'єкт, який сигналізує про виникнення виняткової ситуації. Вони бувають перевірені та неперевірювані. Перевірені винятки потрібно обробляти, оточивши частину коду блоком try-catch, або передавати вище. Неперевірені винятки, як правило, не обробляються, тому що виникають у випадках, коли програма не може відновити свій стан. У цьому методі ми обробляємо лише виняток FoursquareApiException.

Коли веб-сервер отримує запит для програми, він використовує дескриптор розгортання, щоб зіставити URL-адресу запиту з кодом, який повинен обробити запит. Дескриптор розгортання є XML-файл з назвою web.xml. Додамо опис сервлета стеження.

track org.nsa.tracker.TrackerServlet track /track

Тепер запити на адресу /track буде обробляти наш сервлет з ім'ям TrackerServlet. Можна надати параметру Callback Url правильне значення http://localhost:8080/track.

Для виведення результатів можна скористатися Static Maps API, люб'язно наданим тим самим корпорацією Google (https://developers.google.com/maps/documentation/staticmaps/). Наш сервлет генеруватиме просту HTML-сторінку і повертатиме її у відповідь на запит користувача.

StringBuilder sb = New StringBuilder(" NSA Tracker"); sb.append(" "); sb.append("

    "); index = 1; for (Checkin checkin: result.getResult()) ( sb.append(" ").append(index++).append(" - ").append(checkin.getUser().getFirstName()) .append(" ").append(checkin.getUser().getLastName()).append(""); ) sb.append("
"); 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) Брюса У. Перрі.

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 представлений.

Що таке сервлети? Сервлети, фактично, це модулі обробки HTTP та FTP запитів, які використовуються для побудови порталів (web gates).

Основою цих порталів є власне WEB сервер – програма, яка тримає сокет сервера, приймає та передає дані. Найчастіше, для прискорення роботи, сервер буває написаний не на Java, а якоюсь іншою мовою програмування (наприклад на C++).

У зв'язку з сервером працює базовий сервлет. Саме йому відправляє сервер дані і від нього отримує відповідь, що відправляється клієнту. Фактично, базовий сервлет є "мозком" сервера. Основна функція цього сервлета - прочитати запит клієнта, розшифрувати його і, відповідно до розшифровки, передати роботу сервлету, що відповідає за цей тип інформації, що запитується. Найчастіше для досягнення швидкості роль базового сервлета грає сам сервер. Саме за такою схемою працює, скажімо, Jacarta Tomcat.

На малюнку зображено схему передачі викликів (request) і відповідей (response) між сервером і сервлетами. Дана схема зображує роботу HTTP сервера, який має кілька JSP сторінок і два ресурси "/sample1" та "/sample2", за обробку яких відповідає два сервлети - "Sample1 Servlet" та "Sample2 Servlet" відповідно.

Розберемо покроково те, що зображено малюнку:

  1. клієнт приєднується до сервера
  2. сервер передає запит (request) базовому сервлету (Basic Servlet)
  3. базовий сервлет виокремлює із запиту URI ресурсу
    • якщо URI вказує на "/sample1", запит повністю(без змін) передається сервлету "Sample1 Servlet", який надалі і обробляє цей запит
    • якщо URI вказує на "/sample2", сервер передає запит сервлету "Sample2 Servlet"
    • в інших випадках запит передається модулю "JSP Servlet"
  4. сервлет, якому було передано управління, обробляє дані, створює відповідь (response), після чого відповідь надсилається назад базовому сервлету.
  5. базовий сервлет, не обробляючи отримані дані, відразу пересилає їх назад серверу
  6. сервер видає дані клієнту

Таким чином досягається розбиття завдання обробки запиту на логічні частини, за кожну з яких відповідає свій модуль, свою "програмну цеглу". Насправді, ступенів обробки запиту може бути набагато більше. Наприклад, за методи "GET" і "POST" можуть відповідати різні модулі.

Інтерфейс Servlet

Об'єднує всі ці модулі те, що вони наскрізно пов'язані між собою за допомогою інтерфейсу javax.servlet.Servlet

Подивимося цей інтерфейс. У ньому зазначено всього 5 методів:

Public void init(ServletConfig config) throws ServletException Цей метод викликається, щоб проінформувати сервлет про те, що він включений як модуль обслуговування запитів клієнта. Параметр config поділяє інтерфейс javax.servlet.ServletConfig, що несе інформацію про оточення сервера, ім'я сервлета, початкові параметри та інші плюшки. Про інтерфейс javax.servlet.ServletConfig буде розказано трохи далі. Передбачається, що після виклику цієї функції, сервлет акуратно збереже цей config у себе в змінній і видаватиме його за допомогою іншого методу: public ServletConfig створення, іншу інформацію про сервлет, що і досягається викликом public String getServletInfo()

Щоб обробити запит та отримати результат його обробки, використовується функція

Public void service(ServletRequest request, ServletResponse response) throws ServletException, java.io.IOException У цій функції коду, який оброблятиме дані, передаються два інструменти: один - для отримання даних від сервера, інший - для відправки результату роботи сервлета. Відповідно це параметри request і response, що розділяють інтерфейси javax.servlet.ServletRequest і javax.servlet.ServletResponse Вся робота з даними ведеться саме через ці інтерфейси, тому далі поговоримо про них докладніше.

Після того, як сервер перестав потребувати цього модуля викликається метод

Public void destroy() який завершує всі операції з об'єктом сервлета.

Інтерфейс ServletConfig

4 методи, імена яких говорять самі за себе, складають суть інтерфейсу javax.servlet.ServletConfig:

Public String getServletName() public ServletContext getServletContext() public String getInitParameter(String name) java.util.Enumeration getInitParameterNames()

Думаю, призначення всіх функцій зрозуміло, крім

Public ServletContext getServletContext() Цей метод повертає посилання на дуже корисний інструмент для роботи з сервером:

Інтерфейс ServletContext

ServletContext - інтерфейс, що визначає доступ до наступних корисних функцій:

Public Object getAttribute(String name) public java.util.Enumeration getAttributeNames() public void setAttribute(String name, Object object) public void removeAttribute(String name) Чотири методи для роботи з аттрибутами. Роль атрибутів виконує будь-який об'єкт будь-якого класу. Мета даних функцій – пересилати між незв'язаними один з одним сервлетами різні об'єкти. public String getInitParameter(String name) java.util.Enumeration getInitParameterNames() Доступ до параметрів, з якими був запущений сервер. Тут можуть лежати ім'я хоста, порт та інші корисності. public int getMajorVersion() public int getMinorVersion() Повертає версії Servlet API. public String getMimeType(String file) Повертає MIME тип асоційований з файлом, шлях до якого вказаний у змінній файлі. Згадайте, як довелося визначати MIME у програмі SimpleWEBServer та оцініть зручність! public java.util.Set getResourcePaths() public java.net.URL getResource(String path) throws java.net.MalformedURLException public InputStream getResourceAsStream(String path) Повертає шляхи до доступних для сервера ресурсів і самі ресурси у вигляді URL і у вигляді потоків даних. public RequestDispatcher getRequestDispatcher(path) public RequestDispatcher getNamedDispatcher(name) RequestDispatcher - це інструмент для того, щоб надіслати запит іншому ресурсу. Ці функції потрібні, щоб отримати об'єкт цього інструменту для цих ресурсів. Тобто, скажімо, щоб перенаправити запит сервлету "sample1" з тіла сервлета, можна зробити так: getServletConfig().getServletContext().getNamedDispatcher("sample1").forward(request, response);

Власне клас RequestDispatcher включає лише два методи:

Public void forward(ServletRequest request, ServletResponse response) throws ServletException, java.io.IOException public void include(ServletRequest request, ServletResponse response) throws ServletException, java.io.IOException Причому перший - для перенаправлення викликаного сервлета результат роботи поточного. Наприклад, сервлет 1 друкує слово "test 1", потім викликає include для сервлета два, після чого друкує слово "test 2". Сервлет 2 просто друкує слово " and " . Результатом роботи сервлета 1 буде рядок "Test 1 and Test 2". public void log(String msg) Записати щось у лог сервера. public void log (String message, Throwable throwable) Визначити виняток і фразу, яка записуватиметься в лог після отримання цього виключення. public String getRealPath(String path) Переводить шлях типу "/index.html" до "http://host/contextPath/index.html" public String getServerInfo() Повертає ім'я сервера. public ServletContext getContext(String uripath) Цей метод дозволяє обмінюватися ServletContext між різними ресурсами одного і того ж сервера. public String getServletContextName() Повертає ім'я сервлета, якому належить даний об'єкт інтерфейсу ServletContect.

Інтерфейс ServletRequest

Інтерфейс ServletRequest - інструмент для отримання параметрів HTTP запиту. Цей інтерфейс має деякі методи, ідентичні за назвою та призначенням з ServletContext:

Public Object getAttribute(String name) public java.util.Enumeration getAttributeNames() public void setAttribute(String name, Object o) public void removeAttribute(java.lang.String name) public String getServerName()

Методи, що залишилися, дозволяють із зручністю працювати з HTTP заголовком запиту:

Public String getCharacterEncoding() public void setCharacterEncoding(String env) java.io.UnsupportedEncodingException Робота з кодуванням символів у полях HTTP заголовка. Функції задають метод розшифрування CGI запитів із форми %NN у звичайні символи. Наприклад, який стандарт - KOI8-R, windows-1251 або UTF-8 потрібно застосувати для розшифрування кириличних символів. public int getContentLength() public String getContentType() Читає поля "Content-Length", "Content-Type" з HTTP запиту. public jString getParameter(String name) public java.util.Enumeration getParameterNames() public String getParameterValues(String name) public java.util.Map getParameterMap() Функції для отримання поля з HTTP заголовка та його значення. public ServletInputStream getInputStream() throws java.io.IOException public java.io.BufferedReader getReader() throws java.io.IOException Отримати вхідний потік даних або його "читач". Reader застосовується для читання текстової інформації - він автоматично розшифрує рядки відповідно до заданого charset. Увага!У версії J2EE 1.3 є суттєвий баг: при розшифровці символу %25 (символ % у Post і Get запитах) Reader видає помилку (баг помічений на серверах Tomcat 4 та Resign). Можливо, що подібний баг є й іншими символами. public String getProtocol() Отримати версію HTTP протоколу запиту (наприклад - "HTTP/1.1"). public String getScheme() Повертає ім'я схеми запиту. Наприклад, "http", "https", або "ftp". public int getServerPort() public String getRemoteAddr() public String getRemoteHost() public boolean isSecure() Порт сервера, IP адреса клієнта, ім'я хоста клієнта і чи є з'єднання скретним (за протоколом HTTPS) public java.util.Locale get java.util.Enumeration getLocales() Мова документа, що віддається перевага клієнту (результат обробки поля "Accept-Language")

Інтерфейс 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 Повертає потік виведення даних для сервлета. Цей потік використовується, наприклад, виведення бінарних файлів. Текстові дані можна виводити за допомогою java.io.Writer: public java.io.PrintWriter getWriter() throws java.io.IOException Цей метод автоматично конвертує рядки в той charset, що вказаний у методі getCharacterEncoding() та getLocale(). public void setContentLength(int len) Цим методом встановлюється значення поля HTTP заголовка "Content-Length" public void setContentType(String type) Метод для надсилання MIME типу вмісту документа. Поле HTTP заголовка "Content-Type". public void setBufferSize(int size) public int getBufferSize() public void flushBuffer() throws java.io.IOException public void resetBuffer() Справа в тому, що потік виведення даних є буферизованим. Це означає, що наступну порцію даних буде видано клієнту тільки після заповнення буфера. Зазначені методи дозволяють, відповідно, встановити розмір буфера відправки, отримати його розмір, ініціалізувати відправлення вміст буфера клієнту, не чекаючи його заповнення, а також очистити буффер від даних. public boolean isCommitted() Цим методом можна отримати прапор, розпочато вже відправлення даних клієнту. Прапор буде позитивним, якщо HTTP заголовок відповіді було вже надіслано. public void reset() Якщо HTTP заголовок ще не відправлений, то цей метод "скидає" HTTP заголовок до значень "за замовчуванням".

Обумовлені типи сервлетів

Java Servlet API, крім власне інтерфейсів, також містить кілька класів сервлетів, які можуть бути основою для ваших програм.

Базовим для всіх цих класів є абстрактний клас javax.servlet.GenericServlet:

Public abstract class GenericServlet implements Servlet, ServletConfig, java.io.Serializable

Як видно з визначення цього класу, він має всі методи інтерфейсів Servlet та ServletConfig. Не реалізованим методом залишився тільки

Public abstract void service(ServletRequest req, ServletResponse res) throws ServletException, java.io.IOException який і був оголошений абстрактним.

На базі цього класу було створено інший абстрактний клас - javax.servlet.http.HttpServlet:

Public abstract class HttpServlet extends GenericServlet implements java.io.Serializable

Створений цей клас був відповідно до концепції "ще більше зручностей для програміста" і має багато корисних методів:

Protected void doDelete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, java.io.IOException protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, java.io. .io.IOException protected void doOptions(HttpServletRequest req, HttpServletResponse resp) throws ServletException, java.io.IOException protected void doPost(HttpServletRequest req, HttpServletResponse resp.) throws ServletException, ServletException throws ServletException, java.io.IOException protected void doTrace(HttpServletRequest req, HttpServletResponse resp) throws ServletException, java.io.IOException protected void service(HttpServletRequest req, HttpServletRequest , ServletR esponse res) throws ServletException, java.io.IOException Різні варіанти service(ServletRequest req, ServletResponse res) для різних HTTP методів від DELETE та GET до PUT та TRACE. А щоб з зручністю отримувати дані по CGI інтерфейсу не розшифровуючи заголовок були створені класи HttpServletRequest і HttpServletResponse, що входять разом з HttpServlet в пакет javax.servlet.http protected long getLastModified(HttpServletRequest req) Значення часу він бере із поля "Date" HTTP заголовка запиту. Якщо поле не виявлено, то повертає -1.

Відповідно розберемо й інтерфейси HttpServletRequest та HttpServletResponse. Вони є спадкоємцями відповідно ServletRequest та ServletResponse.

HttpServletRequest крім методів, успадкованих від ServletRequest, має такі корисні методи:

Cookie getCookies() Повертає набір куків, надісланих клієнтом серверу.

Клас Cookie, що входить у той же пакет javax.servlet.http, містить всю можливу інформацію про куку. Найважливішими методами цього класу є

Int getMaxAge() String getName() String getValue() видають, відповідно, скільки ще часу цьому куку залишилося жити, ім'я кука та його значення. Так само Cookie (String name, String value) setValue (String newValue) setMaxAge (int expiry) для створення кука, установки його значення і максимального віку. long getDateHeader(String name) Повертає дату з заголовка HTTP, якщо така є. int getIntHeader(java.lang.String name) Повертає чисельне значення поля з ім'ям name із заголовка HTTP запиту String getMethod() Повертає метод HTTP запиту. String getQueryString() String getRequestURI() StringBuffer getRequestURL() Повертає рядок, що міститься в URL документа після символу "?", URI документа та повний URL. HttpSession getSession() HttpSession getSession(boolean create) boolean isRequestedSessionIdFromCookie() boolean isRequestedSessionIdFromURL() boolean isRequestedSessionIdValid() Функції. що дозволяють працювати з таким найважливішим механізмом передачі даних, як сесії.

Сесії необхідні для того, щоб тягати за користувачем дані зі сторінки до сторінки. Наприклад, користувач заходить на сторінку (1), де відправляються деякі дані для сторінки (2), а та зберігає ще якісь речі для сторінки (3).

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

Можна так само зробити інакше - використовувати механізм сесій. Механізм цей працює так: дані, надіслані користувачем, сервер зберігає в окремому файлі - файлі сесії. З вмістом цього файлу і буде проводитися вся робота щодо зміни даних. Клієнту ж видається "ключ сесії" (він же Session key, він же Sesseion ID) - унікальний покажчик на файл, що містить дані саме для цього користувача. Тепер для того, щоб отримати всі дані щодо цього клієнта, серверу необхідно знати лише ключ сесії. Перевагою цього є зручність і швидкість його використання.

Ось і всі основні способи інтерфейсу HttpServletRequest. Повний список методів читайте у документації до Java Servlet API.

Тепер про інтерфейс HttpServletRequest. Основна відмінність класів, які розділяють цей інтерфес, у цьому, що дані виводяться відразу. Спочатку відбувається компанування всіх даних у HTTP відповідь. Відповідь надсилається лише після завершення роботи HttpServlet.service().

І так, про методи:

Void addHeader(String name, String value) void addIntHeader(String name, int value) void addDateHeader(String name, long date) Методи додають в заголовок HTTP параметри. Останній метод встановлює параметр "Date". void addCookie(Cookie cookie) Метод додає cookie у заголовок boolean containsHeader(String name) Дозволяє дізнатися, чи вже містить заголовок зазначений параметр. String encodeURL(String url) String encodeRedirectURL(String url) Перший метод кодує символи за допомогою заміни %NN. Другий метод робить те саме і викликає void sendRedirect(String location) void setStatus(int sc) void sendError(int sc) void sendError(int sc, String msg) Перший - встановлює код повернення, другі два - посилають повідомлення про помилку. В інтерфейсі задані наступні можливі помилки для параметра sc, що відповідають кодам повернення протоколу HTTP: SC_CONTINUE - Status code (100) SC_SWITCHING_PROTOCOLS - Status code (101) ) SC_NON_AUTHORITATIVE_INFORMATION - Status code (203) SC_NO_CONTENT - Status code (204) SC_RESET_CONTENT - Status code (205) SC_PARTIAL_CONTENT - Status code (206) SC_MULTIPLE_CHOICES - Status code (30 SC_SEE_OTHER - Status code (303) SC_NOT_MODIFIED - Status code (304) SC_USE_PROXY - Status code (305) SC_BAD_REQUEST - Status code (400) SC_UNAUTHORIZED - Status code (401) - Status code (404) SC_METHOD_NOT_ALLOWED - Status code (405) SC_NOT_ACCEPTABLE - Status code (406) SC_PROXY_AUTHENTICATION_REQUIRED - Status code (407) SC_REQUEST_TIMEOUT - Statu s code (408) SC_CONFLICT - Status code (409) SC_GONE - Status code (410) SC_LENGTH_REQUIRED - Status code (411) SC_PRECONDITION_FAILED - Status code (412) SC_REQUEST_ENTITY_TOO_LARGE - Status code (413) SC_REQUEST_URI_TOO_LONG - Status code (414) SC_UNSUPPORTED_MEDIA_TYPE - Status code (415) SC_REQUESTED_RANGE_NOT_SATISFIABLE - Status code (416) SC_EXPECTATION_FAILED - Status code (417) SC_INTERNAL_SERVER_ERROR - Status code (500) SC_NOT_IMPLEMENTED - Status code (501) SC_BAD_GATEWAY - Status code (502) SC_SERVICE_UNAVAILABLE - Status code (503) SC_GATEWAY_TIMEOUT - Status code (504) SC_HTTP_VERSION_NOT_SUPPORTED - Status code (505)

Ось і все, що можна розповісти про HttpServletResponse

Використання сервлетів у WEB додатках

Поговоримо тепер про використання сервлетів у WEB додатках. Для цього я наведу два корисні приклади, які можуть на практиці стати в нагоді.

Перший приклад показує методи роботи з HttpServlet та виведення вмісту HTML сторінки у стислому вигляді. За ідеєю HTML сторінка у відповіді браузера виводиться прямим текстом, але, щоб скоротити обсяг даних, що пересилаються, можна використовувати стиснення GZIP. Сучасні браузери (принаймні браузери 4 покоління та вище) підтримують такий метод пересилання текстової інформації та виведуть сторінку так, начебто її й не стискали.

import java. io.*; import javax. servlet.*; import javax. Servlet. http.*; import java. util. zip.*; // сервлет є спадкоємцем HttpServlet public class ZipServlet extends HttpServlet ( // Функція обробки методу GET public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException ( // встановлюємо, що сторінка є HTML документом response. setContentType("text/html"); // беремо параметр "Accept-Encoding" із HTTP заголовка String encodings = request. getHeader("Accept-Encoding"); // беремо параметр "encoding" - раніше задане кодування документа String encodeFlag = request. getParameter("encoding"); // Куди виводитимемо PrintWriter out; // якщо поле "Accept-Encoding" у запиті є if (encodings != null) ( // і якщо це поле містить значення "gzip", а кодування ще не було встановлено, if ((encodings. indexOf("gzip" ) != - 1 ) &&! encodeFlag. equals("none" )) ( // те, куди виводитимемо, буде за одним і стискатиме текст за допомогою GZIP out = new PrintWriter(new GZIPOutputStream(response. getOutputStream()) , false); // та встановлюємо прапор для браузера, що документ буде стиснутий response. setHeader("Content-Encoding", "gzip"); ) else out = response. getWriter(); ) else // Інакше виводити будемо без стиску out = response. getWriter(); out. println("This a test!!!"); // пишемо тіло документа out. close(); // і закриваємо висновок. //Все, після завершення роботи цієї ф-ії, документ буде відправлено } }

Другий приклад показує, як засобами сервлета можна здійснити безперервне виведення сторінки. Такий тип виведення сторінок може використовуватися, наприклад, у чатах: щоб прочитати нові повідомлення, не потрібно буде щоразу оновлювати сторінку, нові повідомлення просто згодом докачуватимуться. Потрібно врахувати, деякі проксі-сервери не підтримують такий вид пересилання даних, але з цим - на жаль - нічого зробити не можна.

import java. io.*; import javax. servlet.*; // Програма реалізує інтерфейс Servlet class DoloadServlet implements Servlet ( ServletConfig config; // об'єкт ServletConfig public DoloadServlet() () // нічого не робить // при ініціалізації зберігаємо config public void init(ServletConfig config) throws ServletException ( this. config = config;) // Видає збережений config public ServletConfig getServletConfig() ( return config;) // інформація про сервлет public String getServletInfo() ( return "DoloadServlet" ;) public void destroy() () // нічого не робить // опрацювання запиту public void service(ServletRequest request, ServletResponse response) throws ServletException, java. io. IOException ( // Розбирати запит ми не будемо, просто зразу // створюємо HTTP заголовок: String head = "HTTP/1.0 200 OK\n" + + "Server: DoloadServlet\n" + "Content-Type: text/html; charset=UTF-8\n"+ "Connection: Keep-Alive\n" + "Content-Encoding: multipart/mixed\n"+ "Transfer-Encoding: chunked" + "Pragma: no-cache\n\n" ; // тепер додаємо початкові дані // для цього прикладу - 20 тегів "
з перенесенням рядка
for (int i = 0; i< 20 ; i++ ) head = head + "
\n" ; // беремо потік виведення ServletOutputStream os=response. getOutputStream(); // пишемо туди заголовок та початкові дані os. print(head); // надсилаємо все записане в буфер до клієнта response. flushBuffer(); // починаємо додавати нові рядки: // ці рядки будуть виглядати так: номер рядка, потім "
\n"
// кожен новий рядок з'являтиметься раз на 3 секунди int i = 0; while (true) ( // інкримент лічильника i++; // пишемо рядок os. print("" + i+ "
\n" ); // скидання буффера response. flushBuffer(); // Приморожуємо потік на 3 секунди try ( sleep(3000 );) catch (Exception e)() ) ) )

Залишилося сказати, що механізм сервлет дуже пластичний і дозволяє творити такі речі, які могли б вимагати написання окремого WEB сервера (як, наприклад, у разі сервлета докачки). Мінусом роботи сервлет є низька швидкість першого запуску (сервлет просто компілюється JIT машиною), високе пореблення пам'яті і нестача всіх програм на Java - низька швидкість роботи з рядками. Остання обставина стає помітною при роботі сервлетів, які приймають текстові дані в запитах POST. POST запит HttpServlet розміром в 50 кб при парсингу за допомогою HttpServletRequest.getReader() може на пару хвилин паралізувати роботу сервера. Те саме стосується й інших програм на java.

Наведу два невеликі приклади:

// даний рядок String text // Приклад 1 // йде робота з рядком за допомогою операції "+" для String String test1 = ""; for (int i = 0; i< text. length(); i++ ) test1 += text. charAt(i); // Приклад 2 // йде робота з рядком за допомогою буфера char buf = new char [text. length()]; for (int i = 0; i< text. length(); i++ ) buf[ i] = text. charAt(i); String sample2 = new String(buf);

Якщо взяти невеликі рядки - до 2-3 кб, то відмінності в роботі прикладів несуттєві, якщо взяти рядок text розміром хоча б у 10 кб, то в першому випадку програма буде працювати з рядком значно повільніше. Це особливість java і проблема реалізації функцій класу String. Отже, якщо ви хочете написати швидкий сервлет, уникайте роботи з довгими рядками за допомогою класу String, використовуйте, наприклад, клас StringBuffer. Це попередження відноситься насамперед до отримання великих текстів з мережі та до обробки локальних файлів (наприклад, у разі текстової бази даних для гостьової книги при великій кількості повідомлень).

Ще одна проблема стосується мультизадачності WEB системи. Не забувайте, що ваші сервлети можуть одночасно запросити відразу кілька користувачів. Часто виникають проблеми синхронізації даних, обміну відомостями між різними обчислювальними потоками одного і того ж сервлета, а проблема, що найчастіше зустрічається - це проблема синхронного доступу до файлів та інших іменованих ресурсів системи. Наприклад, одна програма відкрила файл для читання, а інша тим часом намагається туди щось писати. В результаті друга програма або отримує виняток, або чекає, поки файл звільниться для запису. У зв'язку з цим хочу звернути вашу увагу: не залишайте за собою незакритих потоків і закривайте потоки, як тільки в них відпала потреба. Потік, звичайно, закриється пізніше автоматично, але це відбудеться тільки тоді, коли "сміттяр" до нього добереться, а тим часом друга програма так само не матиме доступу до файлу на запис.

Додатково до мультизадачності хочу відзначити, що за допомогою методів "Object getAttribute(String name)" та "void setAttribute(String name, Object object)" інтерфейсу ServletContext ви можете обмінюватися між сервлетами даними, у тому числі синхронізуючими.

Однією із найприємніших особливостей Java є її багатогранна природа. Звичайно, створення традиційних десктопних і навіть мобільних додатків – це чудово. Але що, якщо ви хочете піти з проторених доріжок і зайти на територію розробки веб-додатків на Java? Для вас є хороша новина: в комплекті з мовою йде повноцінний Servlet API, який дозволяє вам створювати надійні веб-програми без особливих турбот.

Створення програм на Java за допомогою Servlets

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

Працюємо над зовнішнім виглядом

Зовнішній вигляд програми визначатиметься двома JSP-файлами – у контексті MVC вони називаються уявленнями. Перший відповідатиме за відображення форми реєстрації та можливих помилок, спричинених після перевірки введених даних. Другою буде звичайною сторінкою привітання, де будуть показані дані, введені клієнтом, після успішного завершення процесу реєстрації.

Ось перший JSP-файл:

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> Реєстрація

Реєстрація

$ (Violation).