1. Что такое «сервлет»?

Сервлет является интерфейсом, реализация которого расширяет функциональные возможности сервера. Сервлет взаимодействует с клиентами посредством принципа запрос-ответ. Хотя сервлеты могут обслуживать любые запросы, они обычно используются для расширения веб-серверов.

Большинство необходимых для создания сервлетов классов и интерфейсов содержатся в пакетах javax.servlet и javax.servlet.http.

Основные методы сервлета:

  • public void init(ServletConfig config) throws ServletException запускается сразу после загрузки сервлета в память;

  • public ServletConfig getServletConfig() возвращает ссылку на объект, который предоставляет доступ к информации о конфигурации сервлета;

  • public String getServletInfo() возвращает строку, содержащую информацию о сервлете, например: автор и версия сервлета;

  • public void service(ServletRequest request, ServletResponse response) throws ServletException, java.io.IOException вызывается для обработки каждого запроса;

  • public void destroy() выполняется перед выгрузкой сервлета из памяти.

Текущая спецификация - Servlet 3.1 описана в JSR-340 и принята в 2013 году.

2. В чем заключаются преимущества технологии сервлетов над CGI (Common Gateway Interface)?

  • Сервлеты предоставляют лучшую производительность обработки запросов и более эффективное использование памяти за счет использования преимущество многопоточности (на каждый запрос создается новая нить, что быстрее выделения памяти под новый объект для каждого запроса, как это происходит в CGI).

  • Сервлеты, как платформа и система являются независимыми. Таким образом веб-приложение, написанное с использованием сервлетов может быть запущена в любом контейнере сервлетов, реализующим этот стандарт и в любой операционной системе.

  • Использование сервлетов повышает надежность программы, т.к. контейнер сервлетов самостоятельно заботится о жизненном цикле сервлетов (а значит и за утечками памяти), безопасности и сборщике мусора.

  • Сервлеты относительно легки в изучении и поддержке, таким образом разработчику необходимо заботиться только о бизнес-логике приложения, а не внутренней реализации веб-технологий.

3. Какова структура веб-проекта?

src/main/java Исходники приложения/библиотеки

src/main/resources Ресурсные файлы приложения/библиотеки

src/main/filters Файлы сервлетных фильтров

src/main/webapp Исходники веб-приложения

src/test/java Исходники тестов

src/test/resources Ресурсные файлы тестов

src/test/filters Тесты сервлетных фильтров

src/it Интеграционные тесты

src/assembly Описание сборки

src/site Сайт

LICENSE.txt Лицензия проекта

NOTICE.txt Замечания и определения библиотек зависимостей.

README.txt Описание проекта

4. Что такое «контейнер сервлетов»?

Контейнер сервлетов — программа, представляющая собой сервер, который занимается системной поддержкой сервлетов и обеспечивает их жизненный цикл в соответствии с правилами, определёнными в спецификациях. Может работать как полноценный самостоятельный веб-сервер, быть поставщиком страниц для другого веб-сервера, или интегрироваться в Java EE сервер приложений.

Контейнер сервлетов обеспечивает обмен данными между сервлетом и клиентами, берёт на себя выполнение таких функций, как создание программной среды для функционирующего сервлета, идентификацию и авторизацию клиентов, организацию сессии для каждого из них.

Наиболее известные реализации контейнеров сервлетов:

  • Apache Tomcat

  • Jetty

  • JBoss

  • WildFly

  • GlassFish

  • IBM WebSphere

  • Oracle Weblogic

5. Зачем нужны сервера приложений, если есть контейнеры сервлетов?

  • Пулы соединений с БД

    • Возможность периодического тестирования доступности СУБД и обновления соединения в случае восстановления после сбоев

    • Замена прав доступа при подключении

    • Балансировка нагрузки между несколькими СУБД, определение доступность или недоступность того или иного узла

    • Защита пула соединений от некорректного кода в приложении, которое по недосмотру не возвращает соединения, просто отбирая его после какого-то таймаута.

  • JMS

    • Доступность сервера очередей сообщений "из-коробки".

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

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

    • В некоторых серверах приложений поддерживается Unit-of-Order - гарантированный порядок обработки сообщений, удовлетворяющих некоторым критериям.

  • JTA Встроенная поддержка распределенных транзакций для обеспечения согласованности данных в разные СУБД или очереди.

  • Безопасность

    • Наличие множества провайдеров безопасности и аутентификации:

      • во встроенном или внешнем LDAP-сервере

      • в базе данных

      • в различных Internet-directory (специализированных приложениях для управления правами доступа)

    • Доступность Single-Sign-On (возможности разделения пользовательской сессии между приложениями) посредством Security Assertion Markup Language (SAML) 1/2 или Simple and Protected Negotiate (SPNEGO) и Kerberos: один из серверов выступает в роли базы для хранения пользователей, все другие сервера при аутентификации пользователя обращаются к этой базе.

    • Возможность авторизации посредством протокола eXtensible Access Control Markup Language (XACML), позволяющего описывать довольно сложные политики (например, приложение доступно пользователю только в рабочее время).

    • Кластеризация всего вышеперечисленного

  • Масштабируемость и высокая доступность Для контейнера сервлетов обычно так же возможно настроить кластеризацию, но она будет довольно примитивной, так как в случае его использования имеются следующие ограничения:

    • Сложность передачи пользовательской сессии из одного центра обработки данных (ЦоД) в другой через Интернет

    • Отсутствие возможности эффективно настроить репликации сессий на большом (состоящем из 40-50 экземпляров серверов) кластере

    • Невозможность обеспечения миграции экземпляров приложения на другой сервер

    • Недоступность механизмов автоматического мониторинга и реакции на ошибки

  • Управляемость

    • Присутствие единого центра управления, т.н. AdminServer и аналога NodeManager’а, обеспечивающего

      • Возможность одновременного запуска нескольких экземпляров сервера

      • Просмотр состояния запущенных экземпляров сервера, обработчиков той или иной очереди, на том или ином сервере, количества соединений с той или иной БД

  • Административный канал и развертывание в промышленном режиме Некоторые сервера приложений позволяют включить так называемый "административный канал" - отдельный порт, запросы по которому имеют приоритет.

    • Просмотр состояния (выполняющихся транзакций, потоков, очередей) в случае недоступности ("зависания") сервера

    • Обновление приложений "на-лету", без простоя:

      • добавление на сервер новой версии приложения в "закрытом" режиме, пока пользователи продолжают работать со предыдущей

      • тестирование корректности развертывания новой версии

      • "скрытый" перевод на использование новой версии всех пользователей

6. Как контейнер сервлетов управляет жизненным циклом сервлета, когда и какие методы вызываются?

Контейнер сервлетов управляет четырьмя фазами жизненного цикла сервлета:

  • Загрузка класса сервлета — когда контейнер получает запрос для сервлета, то происходит загрузка класса сервлета в память и вызов его конструктора без параметров.

  • Инициализация класса сервлета — после того как класс загружен контейнер инициализирует объект ServletConfig для этого сервлета и внедряет его через init() метод. Это и есть место где сервлет класс преобразуется из обычного класса в сервлет.

  • Обработка запросов — после инициализации сервлет готов к обработке запросов. Для каждого запроса клиента сервлет контейнер порождает новый поток и вызывает метод service() путем передачи ссылки на объекты ответа и запроса.

  • Удаление - когда контейнер останавливается или останавливается приложение, то контейнер сервлетов уничтожает классы сервлетов путем вызова destroy() метода.

Таким образом, сервлет создаётся при первом обращении к нему и живёт на протяжении всего времени работы приложения (в отличии от объектов классов, которые уничтожаются сборщиком мусора после того, как они уже не используются) и весь жизненный цикл сервлета можно описать как последовательность вызова методов:

  • public void init(ServletConfig config) — используется контейнером для инициализации сервлета. Вызывается один раз за время жизни сервлета.

  • public void service(ServletRequest request, ServletResponse response) — вызывается для каждого запроса. Метод не может быть вызван раньше выполнения init() метода.

  • public void destroy() — вызывается для уничтожения сервлета (один раз за время жизни сервлета).

7. Что такое «дескриптор развертывания»?

Дескриптор развертывания — это конфигурационный файл артефакта, который будет развернут в контейнере сервлетов. В спецификации Java Platform, Enterprise Edition дескриптор развертывания описывает то, как компонент, модуль или приложение (такое, как веб-приложение или приложение предприятия) должно быть развернуто.

Этот конфигурационный файл указывает параметры развертывания для модуля или приложения с определенными настройками, параметры безопасности и описывает конкретные требования к конфигурации. Для синтаксиса файлов дескриптора развертывания используется язык XML.

<?xml version="1.0" encoding="UTF-8" ?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
    version="2.4">

    <display-name>Display name.</display-name>
    <description>Description text.</description>

    <servlet>
        <servlet-name>ExampleServlet</servlet-name>
        <servlet-class>xyz.company.ExampleServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
        <init-param>
            <param-name>configuration</param-name>
            <param-value>default</param-value>
        </init-param>
    </servlet>

    <servlet-mapping>
        <servlet-name>ExampleServlet</servlet-name>
        <url-pattern>/example</url-pattern>
    </servlet-mapping>

    <servlet>
        <servlet-name>ExampleJSP</servlet-name>
        <jsp-file>/sample/Example.jsp</jsp-file>
    </servlet>

    <context-param>
        <param-name>myParam</param-name>
        <param-value>the value</param-value>
    </context-param>
</web-app>

Для веб-приложений дескриптор развертывания должен называться web.xml и находиться в директории WEB-INF, в корне веб-приложения. Этот файл является стандартным дескриптором развертывания, определенным в спецификации. Также есть и другие типы дескрипторов, такие, как файл дескриптора развертывания sun-web.xml, содержащий специфичные для Sun GlassFish Enterprise Server данные для развертывания именно для этого сервера приложений или файл application.xml в директории META-INF для приложений J2EE.

8. Какие действия необходимо проделать при создании сервлетов?

Чтобы создать сервлет ExampleServlet, необходимо описать его в дескрипторе развёртывания:

<servlet-mapping>
    <servlet-name>ExampleServlet</servlet-name>
    <url-pattern>/example</url-pattern>
</servlet-mapping>
<servlet>
    <servlet-name>ExampleServlet</servlet-name>
    <servlet-class>xyz.company.ExampleServlet</servlet-class>
    <init-param>
        <param-name>config</param-name>
        <param-value>default</param-value>
    </init-param>
</servlet>

Затем создать класс xyz.company.ExampleServlet путём наследования от HttpServlet и реализовать логику его работы в методе service() или методах doGet()/doPost().

9. В каком случае требуется переопределять метод service()?

Метод service() переопределяется, когда необходимо, чтобы сервлет обрабатывал все запросы (и GET, и POST) в одном методе.

Когда контейнер сервлетов получает запрос клиента, то происходит вызов метода service(), который в зависимости от поступившего запроса вызывает или метод doGet() или метод doPost().

10. Есть ли смысл определять для сервлета конструктор? Каким образом лучше инициализировать данные?

Большого смысла определять для сервлета конструктор нет, т.к. инициализировать данные лучше не в конструкторе, а переопределив метод init(), в котором имеется возможность доступа к параметрам инициализации сервлета через использование объекта ServletConfig.

11. Почему необходимо переопределить только init() метод без аргументов?

Метод init() переопределяется, если необходимо инициализировать какие-то данные до того как сервлет начнет обрабатывать запросы.

При переопределении метода init(ServletConfig config), первым должен быть вызван метод super(config), который обеспечит вызов метода init(ServletConfig config) суперкласса. GenericServlet предоставляет другой метод init() без параметров, который будет вызываться в конце метода init(ServletConfig config).

Необходимо использовать переопределенный метод init() без параметров для инициализации данных во избежание каких-либо проблем, например ошибку, когда вызов super() не указан в переопределенном init(ServletConfig config).

12. Какие наиболее распространенные задачи выполняются в контейнере сервлетов?

  • Поддержка обмена данными. Контейнер сервлетов предоставляет легкий способ обмена данными между веб клиентом (браузером) и сервлетом. Благодаря контейнеру нет необходимости создавать слушателя сокета на сервере для отслеживания запросов от клиента, а также разбирать запрос и генерировать ответ. Все эти важные и комплексные задачи решаются с помощью контейнера и разработчик может сосредоточиться на бизнес логике приложения.

  • Управление жизненным циклом сервлетов и ресурсов. Начиная от загрузки сервлета в память, инициализации, внедрения методов и заканчивая уничтожением сервлета. Контейнер так же предоставляет дополнительные утилиты, например JNDI, для управления пулом ресурсов.

  • Поддержка многопоточности. Контейнер самостоятельно создает новую нить для каждого запроса и предоставляет ей запрос и ответ для обработки. Таким образом сервлет не инициализируется заново для каждого запроса и тем самым сохраняет память и уменьшает время до обработки запроса.

  • Поддержка JSP. JSP классы не похожи на стандартные классы джавы, но контейнер сервлетов преобразует каждую JSP в сервлет и далее управляется контейнером как обычным сервлетом.

  • Различные задачи. Контейнер сервлетов управляет пулом ресурсов, памятью приложения, сборщиком мусора. Предоставляются возможности настройки безопасности и многое другое.

13. Что вы знаете о сервлетных фильтрах?

Сервлетный фильтр - это Java-код, пригодный для повторного использования и позволяющий преобразовать содержание HTTP-запросов, HTTP-ответов и информацию, содержащуюся в заголовках HTML. Сервлетный фильтр занимается предварительной обработкой запроса, прежде чем тот попадает в сервлет, и/или последующей обработкой ответа, исходящего из сервлета.

Сервлетные фильтры могут:

  • перехватывать инициацию сервлета прежде, чем сервлет будет инициирован;

  • определить содержание запроса прежде, чем сервлет будет инициирован;

  • модифицировать заголовки и данные запроса, в которые упаковывается поступающий запрос;

  • модифицировать заголовки и данные ответа, в которые упаковывается получаемый ответ;

  • перехватывать инициацию сервлета после обращения к сервлету.

Сервлетный фильтр может быть конфигурирован так, что он будет работать с одним сервлетом или группой сервлетов. Основой для формирования фильтров служит интерфейс 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().

Интерфейс FilterConfig содержит метод для получения имени фильтра, его параметров инициации и контекста активного в данный момент сервлета. С помощью своего метода doFilter() каждый фильтр получает текущий запрос request и ответ response, а также FilterChain, содержащий список фильтров, предназначенных для обработки. В doFilter() фильтр может делать с запросом и ответом всё, что ему захочется - собирать данные или упаковывать объекты для придания им нового поведения. Затем фильтр вызывает chain.doFilter(), чтобы передать управление следующему фильтру. После возвращения этого вызова фильтр может по окончании работы своего метода doFilter() выполнить дополнительную работу над полученным ответом. К примеру, сохранить регистрационную информацию об этом ответе.

После того, как класс-фильтр откомпилирован, его необходимо установить в контейнер и «приписать» (map) к одному или нескольким сервлетам. Объявление и подключение фильтра отмечается в дескрипторе развёртывания web.xml внутри элементов <filter> и <filter-mapping>. Для подключение фильтра к сервлету необходимо использовать вложенные элементы <filter-name> и <servlet-name>.

Объявление класс-фильтра FilterConnect с именем FilterName:

  <filter>
        <filter-name>FilterName</filter-name>
        <filter-class>FilterConnect</filter-class>
        <init-param>
                <!--- фильтр имеет параметр инициализации `active`, которому присваивается значение `true`. -->
                <param-name>active</param-name>
                <param-value>true</param-true>
        </init-param>
  </filter>

Подключение фильтра FilterName к сервлету ServletName:

  <filter-mapping>
        <filter-name>FilterName</filter-name>
        <servlet-name>ServletName</servlet-name>
  </filter-mapping>

Для связи фильтра со страницами HTML или группой сервлетов необходимо использовать тег <url-pattern>:

Подключение фильтра FilterName ко всем вызовам .html страниц

  <filter-mapping>
          <filter-name>FilterName</filter-name>
          <url-pattern>*.html</url-pattern>
  </filter-mapping>

Порядок, в котором контейнер строит цепочку фильтров для запроса определяется следующими правилами:

  • цепочка, определяемая <url-pattern>, выстраивается в том порядке, в котором встречаются соответствующие описания фильтров в web.xml;

  • последовательность сервлетов, определенных с помощью <servlet-name>, также выполняется в той последовательности, в какой эти элементы встречаются в дескрипторе развёртывания web.xml.

14. Зачем в сервлетах используются различные listener?

Listener (слушатель) работает как триггер, выполняя определённые действия при наступлении какого-либо события в жизненном цикле сервлета.

Слушатели, разделённые по области видимости (scope):

  • Request:

    • ServletRequestListener используется для того, чтобы поймать момент создания и уничтожения запроса;

    • ServletRequestAttributeListener используется для прослушивания событий, происходящих с атрибутами запроса.

  • Context:

    • ServletContextListener позволяет поймать момент, когда контекст инициализируется либо уничтожается;

    • ServletContextAttributeListener используется для прослушивании событий, происходящих с атрибутами в контексте.

  • Session:

    • HttpSessionListener позволяет поймать момент создания и уничтожения сессии;

    • HttpSessionAttributeListener используется при прослушивании событий происходящих с атрибутами в сессии;

    • HttpSessionActivationListener используется в случае, если происходит миграция сессии между различными JVM в распределённых приложениях;

    • HttpSessionBindingListener так же используется для прослушивания событий, происходящих с атрибутами в сессии. Разница между HttpSessionAttributeListener и HttpSessionBindingListener слушателями: первый декларируется в web.xml; экземпляр класса создается контейнером автоматически в единственном числе и применяется ко всем сессиям; второй: экземпляр класса должен быть создан и закреплён за определённой сессией «вручную», количество экземпляров также регулируется самостоятельно.

Подключение слушателей:

<web-app>
    ...
    <listener>
        <listener-class>xyz.company.ExampleListener</listener-class>
    </listener>
    ...
</web-app>

HttpSessionBindingListener подключается в качестве атрибута непосредственно в сессию, т.е., чтобы его подключить необходимо:

  • создать экземпляр класса, реализующего этот интерфейс;

  • положить созданный экземпляр в сессию при помощи setAttribute(String, Object).

15. Когда стоит использовать фильтры сервлетов, а когда слушателей?

Следует использовать фильтры, если необходимо обрабатывать входящие или исходящие данные (например: для аутентификации, преобразования формата, компрессии, шифрования и т.д.), в случае, когда необходимо реагировать на события - лучше применять слушателей.

16. Как реализовать запуск сервлета одновременно с запуском приложения?

Контейнер сервлетов обычно загружает сервлет по первому запросу клиента.

Если необходимо загрузить сервлет прямо на старте приложения (например если загрузка сервлета происходит длительное время) следует использовать элемент <load-on-startup> в дескрипторе или аннотацию @loadOnStartup в коде сервлета, что будет указывать на необходимость загрузки сервлета при запуске.

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

<servlet>
    <servlet-name>ExampleServlet</servlet-name>
    <servlet-class>xyz.company.ExampleServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
</servlet>

17. Как обработать в приложении исключения, выброшенные другим сервлетом?

Когда приложение выбрасывет исключение контейнер сервлетов обрабатывает его и создаёт ответ в формате HTML. Это аналогично тому, что происходит при кодах ошибок вроде 404, 403 и т.д.

В дополнении к этому существует возможность написания собственных сервлетов для обработки исключений и ошибок с указанием их в дескрипторе развертывания:

<error-page>
    <error-code>404</error-code>
    <location>/AppExceptionHandler</location>
</error-page>

<error-page>
    <exception-type>javax.servlet.ServletException</exception-type>
    <location>/AppExceptionHandler</location>
</error-page>

Основная задача таких сервлетов - обработать ошибку/исключение и сформировать понятный ответ пользователю. Например, предоставить ссылку на главную страницу или же описание ошибки.

18. Что представляет собой ServletConfig?

Интерфейс javax.servlet.ServletConfig используется для передачи сервлету конфигурационной информации. Каждый сервлет имеет свой собственный экземпляр объекта ServletConfig, создаваемый контейнером сервлетов.

Для установки параметров конфигурации используются параметры init-param в web.xml:

<servlet>
    <servlet-name>ExampleServlet</servlet-name>
    <servlet-class>xyz.company.ExampleServlet</servlet-class>
    <init-param>
        <param-name>exampleParameter</param-name>
        <param-value>parameterValue</param-value>
    </init-param>
</servlet>

или аннотации @WebInitParam:

@WebServlet(
    urlPatterns = "/example",
    initParams = {
        @WebInitParam(name = "exampleParameter", value = "parameterValue")
    }
)
public class ExampleServlet extends HttpServlet {
    //...
}

Для получения ServletConfig сервлета используется метод getServletConfig().

19. Что представляет собой ServletContext?

Уникальный (в рамках веб-приложения) объект ServletContext реализует интерфейс javax.servlet.ServletContext и предоставляет сервлетам доступ к параметрам этого веб-приложения. Для предоставления доступа используется элемент <context-param> в web.xml:

<web-app>
    ...
    <context-param>
        <param-name>exampleParameter</param-name>
        <param-value>parameterValue</param-value>
    </context-param>
    ...
</web-app>

Объект ServletContext можно получить с помощью метода getServletContext() у интерфейса ServletConfig. Контейнеры сервлетов так же могут предоставлять контекстные объекты, уникальные для группы сервлетов. Каждая из групп будет связана со своим набором URL-путей хоста. В спецификации Servlet 3 ServletContext был расширен и теперь предоставляет возможности программного добавления слушателей и фильтров в приложение. Так же у этого интерфейса имеется множество полезных методов таких как getServerInfo(), getMimeType(), getResourceAsStream() и т.д.

20. В чем отличия ServletContext и ServletConfig?

  • ServletConfig уникален для сервлета, а ServletContext - для приложения;

  • ServletConfig используется для предоставления параметров инициализации конкретному сервлету, а ServletContext для предоставления параметров инициализации для всех сервлетов приложения;

  • для ServletConfig возможности модифицировать атрибуты отсутствуют, атрибуты в объекте ServletContext можно изменять.

21. Для чего нужен интерфейс ServletResponse?

Интерфейс ServletResponse используется для отправки данных клиенту. Все методы данного инструмента служат именно этой цели:

  • String getCharacterEncoding() - возвращает MIME тип кодировки (к примеру - UTF8), в которой будет выдаваться информация;

  • void setLocale(Locale locale)/Locale getLocale() - указывают на язык используемый в документе;

  • ServletOutputStream getOutputStream()/PrintWriter getWriter() - возвращают потоки вывода данных;

  • void setContentLength(int len) - устанавливает значение поля HTTP заголовка Content-Length;

  • void setContentType(String type) - устанавливает значение поля HTTP заголовка Content-Type.

  • void reset() - позволяет сбросить HTTP заголовок к значениям по-умолчанию, если он ещё не был отправлен

  • и др.

22. Для чего нужен интерфейс ServletRequest?

Интерфейс ServletRequest используется для получения параметров соединения, запроса, а также заголовков, входящего потока данных и т.д.

23. Что такое Request Dispatcher?

Интерфейс RequestDispatcher используется для передачи запроса другому ресурсу, при этом существует возможность добавления данных, полученных из этого ресурса к собственному ответу сервлета. Так же этот интерфейс используется для внутренней коммуникации между сервлетами в одном контексте.

В интерфейсе объявлено два метода:

  • void forward(ServletRequest var1, ServletResponse var2) — передает запрос из сервлета к другому ресурсу (сервлету, JSP или HTML файлу) на сервере.

  • void include(ServletRequest var1, ServletResponse var2) — включает контент ресурса (сервлет, JSP или HTML страница) в ответ.

Доступ к интерфейсу можно получить с помощью метода интерфейса ServletContext - RequestDispatcher getRequestDispatcher(String path), где путь начинающийся с /, интерпретируется относительно текущего корневого пути контекста.

24. Как из одного сервлета вызвать другой сервлет?

Для вызова сервлета из того же приложения необходимо использовать механизм внутренней коммуникации сервлетов (inter-servlet communication mechanisms) через вызовы методов RequestDispatcher:

  • forward() - передаёт выполнение запроса в другой сервлет;

  • include() - предоставляет возможность включить результат работы другого сервлета в возвращаемый ответ.

Если необходимо вызывать сервлет принадлежащий другому приложению, то использовать RequestDispatcher уже не получится, т.к. он определен только для текущего приложения. Для подобных целей необходимо использовать метод ServletResponse - sendRedirect() которому предоставляется полный URL другого сервлета. Для передачи данных между сервлетами можно использовать cookies.

25. Чем отличается sendRedirect() от forward()?

forward():

  • Выполняется на стороне сервера;

  • Запрос перенаправляется на другой ресурс в пределах того же сервера;

  • Не зависит от протокола клиентского запроса, так как обеспечивается контейнером сервлетов;

  • Нельзя применять для внедрения сервлета в другой контекст;

  • Клиент не знает о фактически обрабатываемом ресурсе и URL в строке остается прежним;

  • Выполняется быстрее метода sendRedirect();

  • Определён в интерфейсе RequestDispatcher.

sendRedirect():

  • Выполняется на стороне клиента;

  • Клиенту возвращается ответ 302 (redirect) и запрос перенаправляется на другой сервер;

  • Может использоваться только с клиентами HTTP;

  • Разрешается применять для внедрения сервлета в другой контекст;

  • URL адрес изменяется на адрес нового ресурса;

  • Медленнее forward() т.к. требует создания нового запроса;

  • Определён в интерфейсе HttpServletResponse.

26. Для чего используются атрибуты сервлетов и как происходит работа с ними?

Атрибуты сервлетов используются для внутренней коммуникации сервлетов.

В веб-приложении существует возможность работы с атрибутами используя методы setAttribute(), getAttribute(), removeAttribute(), getAttributeNames(), которые предоставлены интерфейсами ServletRequest, HttpSession и ServletContext (для областей видимости request, session, context соответственно).

27. Каким образом можно допустить в сервлете deadlock?

Можно получить блокировку, например, допустив циклические вызовы метода doPost() в методе doGet() и метода doGet() в методе doPost().

28. Как получить реальное расположение сервлета на сервере?

Реальный путь к расположению сервлета на сервере можно получить из объекта ServletContext:

getServletContext().getRealPath(request.getServletPath()).

29. Как получить информацию о сервере из сервлета?

Информацию о сервере можно получить из объекта ServletContext:

getServletContext().getServerInfo().

30. Как получить IP адрес клиента на сервере?

IP адрес клиента можно получить вызвав request.getRemoteAddr().

31. Какие классы-обертки для сервлетов вы знаете?

Собственные обработчики ServletRequest и ServletResponse можно реализовать, добавив новые или переопределив существующие методы у классов-обёрток ServletRequestWrapper (HttpServletRequestWrapper) и ServletResponseWrapper (HttpServletRequestWrapper).

32. В чем отличия GenericServlet и HttpServlet?

Абстрактный класс GenericServlet — независимая от используемого протокола реализация интерфейса Servlet, а абстрактный класс HttpServlet в свою очередь расширяет GenericServlet для протокола HTTP..

33. Почему HttpServlet класс объявлен как абстрактный?

Класс HTTPServlet предоставляет лишь общую реализацию сервлета для HTTP протокола. Реализация ключевых методов doGet() и doPost(), содержащих основную бизнес-логику перекладывается на разработчика и по умолчанию возвращает HTTP 405 Method Not Implemented error.

34. Какие основные методы присутствуют в классе HttpServlet?

  • doGet() - для обработки HTTP запросов GET;

  • doPost() - для обработки HTTP запросов POST;

  • doPut() - для обработки HTTP запросов PUT;

  • doDelete() - для обработки HTTP запросов DELETE;

  • doHead() - для обработки HTTP запросов HEAD;

  • doOptions() - для обработки HTTP запросов OPTIONS;

  • doTrace() - для обработки HTTP запросов TRACE.

35. Стоит ли волноваться о многопоточной безопасности работая с сервлетами?

Методы init() и destroy() вызываются один раз за жизненный цикл сервлета — поэтому по поводу них беспокоиться не стоит.

Методы doGet(), doPost(), service() вызываются на каждый запрос клиента и т.к. сервлеты используют многопоточность, то здесь задумываться о потокобезопасной работе обязательно. При этом правила использования многопоточности остаются теми же: локальные переменные этих методов будут созданы отдельно для каждого потока, а при использовании глобальных разделяемых ресурсов необходимо использовать синхронизацию или другие приёмы многопоточного программирования.

36. Какой метод HTTP не является неизменяемым?

HTTP метод называется неизменяемым, если он на один и тот же запрос всегда возвращает одинаковый результат. HTTP методы GET, PUT, DELETE, HEAD и OPTIONS являются неизменяемыми, поэтому необходимо реализовывать приложение так, чтобы эти методы возвращали одинаковый результат постоянно. К изменяемым методам относится метод POST, который и используется для реализации чего-либо, что изменяется при каждом запросе.

К примеру, для доступа к статической HTML странице используется метод GET, т.к. он всегда возвращает одинаковый результат. При необходимости сохранять какую-либо информацию, например в базе данных, нужно использовать POST метод.

37. Какие есть методы отправки данных с клиента на сервер?

  • GET - используется для запроса содержимого указанного ресурса, изображения или гипертекстового документа. Вместе с запросом могут передаваться дополнительные параметры как часть URI, значения могут выбираться из полей формы или передаваться непосредственно через URL. При этом запросы кэшируются и имеют ограничения на размер. Этот метод является основным методом взаимодействия браузера клиента и веб-сервера.

  • POST - используется для передачи пользовательских данных в содержимом HTTP-запроса на сервер. Пользовательские данные упакованы в тело запроса согласно полю заголовка Content-Type и/или включены в URI запроса. При использовании метода POST под URI подразумевается ресурс, который будет обрабатывать запрос.

38. В чем разница между методами GET и POST?

  • GET передает данные серверу используя URL, тогда как POST передает данные, используя тело HTTP запроса. Длина URL ограничена 1024 символами, это и будет верхним ограничением для данных, которые можно отослать через GET. POST может отправлять гораздо большие объемы данных. Лимит устанавливается web-server и составляет обычно около 2 Mb.

  • Передача данных методом POST более безопасна, чем методом GET, так как секретные данные (например пароль) не отображаются напрямую в web-клиенте пользователя, в отличии от URL, который виден почти всегда. Иногда это преимущество превращается в недостаток - вы не сможете послать данные за кого-то другого.

  • GETметод является неизменяемым, тогда как POST — изменяемый.

39. В чем разница между PrintWriter и ServletOutputStream?

PrintWriter — класс для работы с символьным потоком, экземпляр которого можно получить через метод ServletResponse getWriter();

ServletOutputStream — класс для работы байтовым потоком. Для получения его экземпляра используется метод ServletResponse getOutputStream().

40. Можно ли одновременно использовать в сервлете PrintWriter и ServletOutputStream?

Так сделать не получится, т.к. при попытке одновременного вызова getWriter() и getOutputStream() будет выброшено исключение java.lang.IllegalStateException с сообщением, что уже был вызван другой метод.

41. Расскажите об интерфейсе SingleThreadModel.

Интерфейс SingleThreadModel является маркерным - в нем не объявлен ни один метод, однако, если сервлет реализует этот интерфейс, то метод service() этого сервлета гарантированно не будет одновременно выполняться в двух потоках. Контейнер сервлетов либо синхронизирует обращения к единственному экземпляру, либо обеспечивает поддержку пула экземпляров и перенаправление запроса свободному сервлету. Другими словами, контейнер гарантирует отсутствие конфликтов при одновременном обращении к переменным или методам экземпляра сервлета. Однако существуют также и другие разделяемые ресурсы, которые даже при использовании этого интерфейса, остаются всё так же доступны обработчикам запросов в других потоках. Т.о. пользы от использования этого интерфейса немного и в спецификации Servlet 2.4 он был объявлен deprecated.

42. Что означает URL encoding? Как это осуществить в Java?

URL Encoding — процесс преобразования данных в форму CGI (Common Gateway Interface), не содержащую пробелов и нестандартных символов, которые заменяются в процессе кодирования на специальные escape-символы. В Java для кодирования строки используется метод java.net.URLEncoder.encode(String str, String unicode). Обратная операция декодирования возможна через использование метода java.net.URLDecoder.decode(String str, String unicode).

Hello мир! преобразовывается в Hello%20%D0%BC%D0%B8%D1%80!.

43. Какие различные методы управления сессией в сервлетах вы знаете?

При посещении клиентом Web-ресурса и выполнении вариантов запросов, контекстная информация о клиенте не хранится. В протоколе HTTP нет возможностей для сохранения и изменения информации о предыдущих посещениях клиента. Сеанс (сессия) — соединение между клиентом и сервером, устанавливаемое на определенное время, за которое клиент может отправить на сервер сколько угодно запросов. Сеанс устанавливается непосредственно между клиентом и Web-сервером. Каждый клиент устанавливает с сервером свой собственный сеанс. Сеансы используются для обеспечения хранения данных во время нескольких запросов Web-страницы или на обработку информации, введенной в пользовательскую форму в результате нескольких HTTP-соединений (например, клиент совершает несколько покупок в интернет-магазине; студент отвечает на несколько тестов в системе дистанционного обучения).

Существует несколько способов обеспечения уникального идентификатора сессии:

  • User Authentication — Предоставление учетных данных самим пользователем в момент аутентификации. Переданная таким образом информация в дальнейшем используется для поддержания сеанса. Это метод не будет работать, если пользователь вошёл в систему одновременно из нескольких мест.

  • HTML Hidden Field — Присвоение уникального значения скрытому полю HTML страницы, в момент когда пользователь начинает сеанс. Этот метод не может быть использован со ссылками, потому что нуждается в подтверждении формы со скрытым полем каждый раз во время формирования запроса. Кроме того, это не безопасно, т.к. существует возможность простой подмены такого идентификатора.

  • URL Rewriting — Добавление идентификатора сеанса как параметра URL. Достаточно утомительная операция, потому что требует постоянного отслеживания этого идентификатора при каждом запросе или ответе.

  • Cookies — Использование небольших фрагментов данных, отправленных web-сервером и хранимых на устройстве пользователя. Данный метод не будет работать, если клиент отключает использование cookies.

  • Session Management API — Использование специального API для отслеживания сеанса, построенный на основе и на методах, описанных выше и который решает частные проблемы перечисленных способов:

    • Чаще всего недостаточно просто отслеживать сессию, необходимо ещё и сохранять какие-либо дополнительные данные о ней, которые могут потребоваться при обработке последующих запросов. Осуществление такого поведения требует много дополнительных усилий.

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

44. Что такое cookies?

Сookies («куки») — небольшой фрагмент данных, отправленный web-сервером и хранимый на устройстве пользователя. Всякий раз при попытке открыть страницу сайта, web-клиент пересылает соответствующие этому сайту cookies web-серверу в составе HTTP-запроса. Применяется для сохранения данных на стороне пользователя и на практике обычно используется для:

  • аутентификации пользователя;

  • хранения персональных предпочтений и настроек пользователя;

  • отслеживания состояния сеанса доступа пользователя;

  • ведения разнообразной статистики.

45. Какие методы для работы с cookies предусмотрены в сервлетах?

Servlet API предоставляет поддержку cookies через класс javax.servlet.http.Cookie:

  • Для получения массива cookies из запроса необходимо воспользоваться методом HttpServletRequest.getCookies(). Методов для добавления cookies в HttpServletRequest не предусмотрено.

  • Для добавления cookie в ответ используется HttpServletResponse.addCookie(Cookie c). Метода получения cookies в HttpServletResponse отсутствует.

46. Что такое URL Rewriting?

URL Rewriting - специальная перезапись (перекодирование) оригинального URL. Данный механизм может использоваться для управления сессией в сервлетах, когда cookies отключены.

47. Зачем нужны и чем отличаются методы encodeURL() и encodeRedirectURL()?

HttpServletResponse.encodeURL() предоставляет способ преобразования URL в HTML гиперссылку с преобразованием спецсимволов и пробелов, а так же добавления session id к URL. Такое поведение аналогично java.net.URLEncoder.encode(), но с добавлением дополнительного параметра jsessionid в конец URL.

Метод HttpServletResponse.encodeRedirectURL() преобразует URL для последующего использования в методе sendRedirect().

Таким образом для HTML гиперссылок при URL rewriting необходимо использовать encodeURL(), а для URL при перенаправлении - encodeRedirectUrl().

48. Что такое «сессия»?

Сессия - это сеанс связи между клиентом и сервером, устанавливаемый на определенное время. Сеанс устанавливается непосредственно между клиентом и веб-сервером в момент получения первого запроса к веб-приложению. Каждый клиент устанавливает с сервером свой собственный сеанс, который сохраняется до окончания работы с приложением.

49. Как уведомить объект в сессии, что сессия недействительна или закончилась?

Чтобы быть уверенным в том, что объект будет оповещён о прекращении сессии, нужно реализовать интерфейс javax.servlet.http.HttpSessionBindingListener. Два метода этого интерфейса: valueBound() и valueUnbound() используются при добавлении объекта в качестве атрибута к сессии и при уничтожении сессии соответственно.

50. Какой существует эффективный способ удостоверится, что все сервлеты доступны только для пользователя с верной сессией?

Сервлет фильтры используются для перехвата всех запросов между контейнером сервлетов и сервлетом. Поэтому логично использовать соответствующий фильтр для проверки необходимой информации (например валидности сессии) в запросе.

51. Как мы можем обеспечить transport layer security для нашего веб приложения?

Для обеспечения transport layer security необходимо настроить поддержку SSL сервлет контейнера. Как это сделать зависит от конкретной реализации сервлет-контейнера.

52. Как организовать подключение к базе данных, обеспечить журналирование в сервлете?

При работе с большим количеством подключений к базе данных рекомендуется инициализировать их в servlet context listener, а также установить в качестве атрибута контекста для возможности использования другими сервлетами.

Журналирование подключается к сервлету стандартным для логгера способом (например для log4j это может быть property-файл или XML-конфигурация) , а далее эта информация используется при настройке соответствующего context listener.

53. Какие основные особенности появились в спецификации Servlet 3?

  • Servlet Annotations. До Servlet 3 вся конфигурация содержалась в web.xml, что приводило к ошибкам и неудобству при работе с большим количестве сервлетов. Примеры аннотаций: @WebServlet, @WebInitParam, @WebFilter, @WebListener.

  • Web Fragments. Одностраничное веб приложение может содержать множество модулей: все модули прописываются в fragment.xml в папке META-INF\. Это позволяет разделять веб приложение на отдельные модули, собранные как .jar-файлы в отдельной lib\ директории.

  • Динамическое добавление веб компонентов. Появилась возможность программно добавлять фильтры и слушатели, используя ServletContext объект. Для этого применяются методы addServlet(), addFilter(), addListener(). Используя это нововведение стало доступным построение динамической системы, в которой необходимый объект будет создан и вызван только по необходимости.

  • Асинхронное выполнение. Поддержка асинхронной обработки позволяет передать выполнение запроса в другой поток без удержания всего сервера занятым.

54. Какие способы аутентификации доступны сервлету?

Спецификация сервлетов определяет четыре типа проверки подлинности:

  • HTTP Basic Authentication - BASIC. При доступе к закрытым ресурсам появится окно, которое попросит ввести данные для аутентификации.

  • Form Based Login - FORM. Используется собственная html форма:

  • HTTP Digest Authentication - DIGEST. Цифровая аутентификация с шифрованием.

  • HTTPS Authentication - CLIENT-CERT. Аутентификация с помощью клиентского сертификата.

<login-config>
    <auth-method>FORM</auth-method>
    <form-login-config>
        <form-login-page>/login.html</form-login-page>
        <form-error-page>/error.html</form-error-page>
    </form-login-config>
</login-config>

55. Что такое Java Server Pages (JSP)?

JSP (JavaServer Pages) — платформонезависимая переносимая и легко расширяемая технология разработки веб-приложений, позволяющая веб-разработчикам создавать содержимое, которое имеет как статические, так и динамические компоненты. Страница JSP содержит текст двух типов: статические исходные данные, которые могут быть оформлены в одном из текстовых форматов HTML, SVG, WML, или XML, и JSP-элементы, которые конструируют динамическое содержимое. Кроме этого могут использоваться библиотеки JSP-тегов, а также EL (Expression Language), для внедрения Java-кода в статичное содержимое JSP-страниц.

Код JSP-страницы транслируется в Java-код сервлета с помощью компилятора JSP-страниц Jasper, и затем компилируется в байт-код JVM.

JSP-страницы загружаются на сервере и управляются Java EE Web Application. Обычно такие страницы упакованы в файловые архивы .war и .ear.

56. Зачем нужен JSP?

JSP расширяет технологию сервлетов обеспечивая возможность создания динамических страницы с HTML подобным синтаксисом.

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

Еще одним преимуществом JSP является горячее развертывание - возможность заменить одну страницу на другую непосредственно в контейнере без необходимости перекомпилировать весь проект или перезапускать сервер.

Однако рекомендуется избегать написания серьёзной бизнес-логики в JSP и использовать страницу только в качестве представления.

57. Опишите, как обрабатываются JSP страницы, начиная от запроса к серверу, заканчивая ответом пользователю.

Когда пользователь переходит по ссылке на страницу page.jsp, он отправляет http-запрос на сервер GET /page.jsp. Затем, на основе этого запроса и текста самой страницы, сервер генерирует java-класс, компилирует его и выполняет полученный сервлет, формирующий ответ пользователю в виде представления этой страницы, который сервер и перенаправляет обратно пользователю.

58. Расскажите об этапах (фазах) жизненного цикла JSP.

Если посмотреть код внутри созданной JSP страницы, то он будет выглядеть как HTML и не будет похож на java класс. Конвертацией JSP страниц в HTML код занимается контейнер, который так же создает и сервлет для использования в веб приложении.

Жизненный цикл JSP состоит из нескольких фаз, которыми руководит JSP контейнер:

  • Translation — проверка и парсинг кода JSP страницы для создания кода сервлета.

  • Compilation — компиляция исходного кода сервлета.

  • Class Loading — загрузка скомпилированного класса в память.

  • Instantiation — внедрение конструктора без параметра загруженного класса для инициализации в памяти.

  • Initialization — вызов init() метода объекта JSP класса и инициализация конфигурации сервлета с первоначальными параметрами, которые указаны в дескрипторе развертывания (web.xml). После этой фазы JSP способен обрабатывать запросы клиентов. Обычно эти фазы происходят после первого запроса клиента (т.е. ленивая загрузка), но можно настроить загрузку и инициализацию JSP на старте приложения по аналогии с сервлетами.

  • Request Processing — длительный жизненный цикл обработки запросов клиента JSP страницей. Обработка является многопоточной и аналогична сервлетам — для каждого запроса создается новый поток, объекты ServletRequest и ServletResponse, происходит выполнение сервис методов.

  • Destroy — последняя фаза жизненного цикла JSP, на которой её класс удаляется из памяти. Обычно это происходит при выключении сервера или выгрузке приложения.

59. Расскажите о методах жизненного цикла JSP.

Контейнер сервлетов (например, Tomcat, GlassFish) создает из JSP-страницы класс сервлета, наследующего свойства интерфейса javax.servlet.jsp.HttpJspBase и включающего следующие методы:

  • jspInit() — метод объявлен в JSP странице и реализуется с помощью контейнера. Этот метод вызывается один раз в жизненном цикле JSP для того, чтобы инициализировать конфигурационные параметры указанные в дескрипторе развертывания. Этот метод можно переопределить с помощью определения элемента JSP scripting и указания необходимых параметров для инициализации;

  • _jspService() — метод переопределяется контейнером автоматически и соответствует непосредственно коду JSP, описанному на странице. Этот метод определен в интерфейсе HttpJspPage, его имя начинается с нижнего подчеркивания и он отличается от других методов жизненного цикла тем, что его невозможно переопределить;

  • jspDestroy() — метод вызывается контейнером для удаления объекта из памяти (на последней фазе жизненного цикла JSP - Destroy). Метод вызывается только один раз и доступен для переопределения, предоставляя возможность освободить ресурсы, которые были созданы в jspInit().

60. Какие методы жизненного цикла JSP могут быть переопределены?

Возможно переопределить лишь jspInit() и jspDestroy() методы.

61. Как можно предотвратить прямой доступ к JSP странице из браузера?

Прямой доступ к директории /WEB-INF/ из веб-приложения отсутствует. Поэтому JSP-страницы можно расположить внутри этой папки и тем самым запретить доступ к странице из браузера. Однако, по аналогии с описанием сервлетов, будет необходимо настроить дескриптор развертывания:

<servlet>
    <servlet-name>Example</servlet-name>
    <jsp-file>/WEB-INF/example.jsp</jsp-file>
    <init-param>
        <param-name>exampleParameter</param-name>
        <param-value>parameterValue</param-value>
    </init-param>
</servlet>

<servlet-mapping>
    <servlet-name>Example</servlet-name>
    <url-pattern>/example.jsp</url-pattern>
</servlet-mapping>

62. Какая разница между динамическим и статическим содержимым JSP?

Статическое содержимое JSP (HTML, код JavaScript, изображения и т.д.) не изменяется в процессе работы веб приложения.

Динамические ресурсы созданы для того, чтобы отображать свое содержимое в зависимости от пользовательских действий. Обычно они представлены в виде выражений EL (Expression Language), библиотек JSP-тегов и пр.

63. Как закомментировать код в JSP?

  • <!—- HTML комментарий; отображается на странице JSP —-> такие комментарии будут видны клиенту при просмотре кода страницы.

  • <%—- JSP комментарий; не отображается на странице JSP —-%> такие комментарии описываются в созданном сервлете и не посылаются клиенту. Для любых комментариев по коду или отладочной информации необходимо использовать именно такой тип комментариев.

64. Какие существуют основные типы тегов JSP?

  • Выражение JSP: <%= expression %> - выражение, которое будет обработано с перенаправлением результата на вывод;

  • Скриплет JSP: <% code %> - код, добавляемый в метод service().

  • Объявление JSP: <%! code %> - код, добавляемый в тело класса сервлета вне метода service().

  • Директива JSP page: <%@ page att="value" %> - директивы для контейнера сервлетов с информацией о параметрах.

  • Директива JSP include: <%@ include file="url" %> - файл в локальной системе, подключаемый при трансляции JSP в сервлет.

  • Комментарий JSP: <%-- comment --%> - комментарий; игнорируется при трансляции JSP страницы в сервлет.

65. Что вы знаете о действиях JSP (Action tag и JSP Action Elements).

Action tag и JSP Action Elements предоставляют методы работы с Java Beans, подключения ресурсов, проброса запросов и создания динамических XML элементов. Такие элементы всегда начинаются с записи jsp: и используются непосредственно внутри страницы JSP без необходимости подключения сторонних библиотек или дополнительных настроек.

Наиболее часто используемыми JSP Action Elements являются:

  • jsp:include: <jsp:include page="относительный URL" flush="true"/> - подключить файл при запросе страницы. Если необходимо, чтобы файл подключался в процессе трансляции страницы, то используется директива page совместно с атрибутом include;

  • jsp:useBean: <jsp:useBean att=значение*/> или <jsp:useBean att=значение*>...</jsp:useBean> - найти или создать Java bean;

  • jsp:setProperty: <jsp:setProperty att=значение*/> - установить свойства Java bean, или явно, или указанием на соответствующее значение, передаваемое при запросе;

  • jsp:forward: <jsp:forward page="относительный URL"/> - передать запрос другой странице;

  • jsp:plugin: <jsp:plugin attribute="значение"*>...</jsp:plugin> - сгенерировать (в зависимости от типа браузера) тэги OBJECT или EMBED для апплета, использующего технологию Java Plugin.

66. Взаимодействие JSP - сервлет - JSP.

«JSP - сервлет - JSP» архитектура построения приложений носит название MVC (Model/View/Controller):

  • Model - классы данных и бизнес-логики;

  • View - страницы JSP;

  • Controller - сервлеты.

67. Какие области видимости переменных существуют в JSP?

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

В JSP предусмотрены следующие области действия переменных (объектов):

  • request область действия запроса - объект будет доступен на текущей JSP странице, странице пересылки (при использовании jsp:forward) или на включаемой странице (при использовании jsp:include);

  • session область действия сессии - объект будет помещен в сеанс пользователя, будет доступен на всех JSP страницах и будет существовать пока существует сессия пользователя, или он не будет из нее принудительно удален.

  • application область действия приложения - объект будет доступен для всех пользователей на всех JSP страницах и будет существовать на протяжении всей работы приложения или пока не будет удален принудительно и контекста приложения.

  • page область действия страницы - объект будет доступен только на той странице, где он определен. На включаемых (jsp:include) и переадресуемых (jsp:forward) страницах данный объект уже не будет доступен.

Таким образом, чтобы объект был доступен всем JSP страницам, необходимо указать область видимости application или session, в зависимости от того требуется ли доступ к объекту всем пользователям или только текущему.

Для указания требуемой области действия при определении объекта на JSP странице используется атрибут scope тега jsp:useBean:

<jsp:useBean id="myBean" class="ru.javacore.MyBean" scope="session"/>

Если не указывать атрибут scope, то по умолчанию задается область видимости страницы page

68. Какие неявные, внутренние объекты и методы есть на JSP странице?

JSP implicit objects (неявные объекты) создаются контейнером при конвертации JSP страницы в код сервлета для помощи разработчикам. Эти объекты можно использовать напрямую в скриптлетах для передачи информации в сервис методы, однако мы не можем использовать неявные объекты в JSP Declaration, т.к. такой код пойдет на уровень класса.

Существует 9 видов неявных объектов, которые можно использовать прямо на JSP странице. Семь из них объявлены как локальные переменные в начале _jspService() метода, а два оставшихся могут быть использованы как аргументы метода _jspService().

  • out Object :

<strong>Current Time is</strong>: <% out.print(new Date()); %><br>
  • request Object :

<strong>Request User-Agent</strong>: <%=request.getHeader("User-Agent") %><br>
  • response Object :

<strong>Response</strong>: <%response.addCookie(new Cookie("Test","Value")); %>
  • config Object :

<strong>User init param value</strong>: <%=config.getInitParameter("User") %><br>
  • application Object :

<strong>User context param value</strong>: <%=application.getInitParameter("User") %><br>
  • session Object :

<strong>User Session ID</strong>: <%=session.getId() %><br>
  • pageContext Object :

<% pageContext.setAttribute("Test", "Test Value"); %>
<strong>PageContext attribute</strong>: {Name="Test",Value="<%=pageContext.getAttribute("Test") %>"}<br>
  • page Object :

<strong>Generated Servlet Name</strong>: <%=page.getClass().getName() %>
  • exception Object :

<strong>Exception occured</strong>: <%=exception %><br>

69. Какие неявные объекты не доступны в обычной JSP странице?

Неявный объект исключений JSP недоступен в обычных JSP страницах и используется на страницах ошибок JSP (errorpage) только для того, чтобы перехватить исключение, выброшенное JSP страницей и далее предоставить какую-либо полезную информацию клиенту.

70. Что вы знаете о PageContext и какие преимущества его использования?

Неявный объект JSP - экземпляр класса javax.servlet.jsp.PageContext предоставляет доступ ко всем пространствам имён, ассоциированным с JSP-страницей, а также к различным её атрибутам. Остальные неявные объекты добавляются к pageContext автоматически.

Класс PageContext это абстрактный класс, а его экземпляр можно получить через вызов метода JspFactory.getPageContext(), и освободить через вызов метода JspFactory.releasePageContext().

PageContext обладает следующим набором особенностей и возможностей:

  • единый API для обслуживания пространств имён различных областей видимости;

  • несколько удобных API для доступа к различным public-объектам;

  • механизм получения JspWriter для вывода;

  • механизм обслуживания использования сессии страницей;

  • механизм экспонирования («показа») атрибутов директивы page среде скриптинга;

  • механизмы направления или включения текущего запроса в другие компоненты приложения;

  • механизм обработки процессов исключений на страницах ошибок errorpage;

71. Как сконфигурировать параметры инициализации для JSP?

Параметры инициализации для JSP задаются в web.xml файле аналогично сервлетам - элементами servlet и servlet-mapping. Единственным отличием будет указание местонахождения JSP страницы:

<servlet>
    <servlet-name>Example</servlet-name>
    <jsp-file>/WEB-INF/example.jsp</jsp-file>
    <init-param>
        <param-name>exampleParameter</param-name>
        <param-value>parameterValue</param-value>
    </init-param>
</servlet>

72. Почему не рекомендуется использовать скриплеты (скриптовые элементы) в JSP?

JSP страницы используются в основном для целей отображения представления (view), а вся бизнес-логика (controller) и модель (model) должны быть реализованы в сервлетах или классах-моделях. Обязанность JSP страницы - создание HTML ответа из переданных через атрибуты параметров. Большая часть JSP содержит HTML код, а для того, чтобы помочь верстальщикам понять JSP код страницы предоставляется функционал элементов action, JSP EL, JSP Standart Tag Library. Именно их и необходимо использовать вместо скриптлетов для создания моста между (JSP)HTML и (JSP)Java частями.

73. Можно ли определить класс внутри JSP страницы?

Определить класс внутри JSP страницы можно, но это считается плохой практикой:

<%!
private static class ExampleOne {
  //...
}
%>

<%
private class ExampleTwo {
  //...
}
%>

74. Что вы знаете о Языке выражений JSP (JSP Expression Language — EL)?

JSP Expression Language (EL) — скриптовый язык выражений, который позволяет получить доступ к Java компонентам (JavaBeans) из JSP. Начиная с JSP 2.0 используется внутри JSP тегов для отделения Java кода от JSP для обеспечения лёгкого доступа к Java компонентам, уменьшая при этом количество кода Java в JSP-страницах, или даже полностью исключая его.

Развитие EL происходило с целью сделать его более простым для дизайнеров, которые имеют минимальные познания в языке программирования Java. До появления языка выражений, JSP имел несколько специальных тегов таких как скриптлеты (англ.), выражения и т. п. которые позволяли записывать Java код непосредственно на странице. С использованием языка выражений веб-дизайнер должен знать только то, как организовать вызов соответствующих java-методов.

Язык выражений JSP 2.0 включает:

  • Создание и изменение переменных.

  • Управление потоком выполнения программы: ветвление, выполнение различных типов итераций и т.д.

  • Упрощенное обращение к встроенным JSP-объектам.

  • Возможность создавать собственные функции.

Язык выражений используется внутри конструкции ${ ... }. Подобная конструкция может размещаться либо отдельно, либо в правой части выражения установки атрибута тега.

75. Какие типы EL операторов вы знаете?

Операторы в EL поддерживают наиболее часто используемые манипуляции данными.

Типы операторов:

  • Стандартные операторы отношения: == (или eq), != (или neq), < (или lt), > (или gt), <= (или le), >= (или ge).

  • Арифметические операторы: +, , *, / (или div), % (или mod).

  • Логические операторы: && (или and), || (или or), ! (или not).

  • Оператор empty — используется для проверки переменной на null, или «пустое значение», который зависит от типа проверяемого объекта. Например, нулевая длина для строки или нулевой размер для коллекции.

76. Назовите неявные, внутренние объекты JSP EL и их отличия от объектов JSP.

Язык выражений JSP предоставляет множество неявных объектов, которые можно использовать для получения атрибутов в различных областях видимости (scopes) и для значений параметров. Важно отметить, что они отличаются от неявных объектов JSP и содержат атрибуты в заданной области видимости. Наиболее часто использующийся implicit object в JSP EL и JSP page — это объект pageContext. Ниже представлена таблица неявных объектов JSP EL.

77. Как отключить возможность использования EL в JSP?

Для игнорирования выполнения языка выражений на странице существует два способа:

  • использовать директиву <%@ page isELIgnored = «true» %>,

  • настроить web.xml (лучше подходит для отключения EL сразу на нескольких страницах):

<jsp-config>
    <jsp-property-group>
        <url-pattern>*.jsp</url-pattern>
        <el-ignored>true</el-ignored>
    </jsp-property-group>
</jsp-config>

78. Как узнать тип HTTP метода используя JSP EL?

${pageContext.request.method}.

79. Что такое JSTL (JSP Standard tag library)?

JavaServer Pages Standard Tag Library, JSTL, Стандартная библиотека тегов JSP — расширение спецификации JSP (конечный результат JSR 52), добавляющее библиотеку JSP тегов для общих нужд, таких как разбор XML данных, условная обработка, создание циклов и поддержка интернационализации.

JSTL является альтернативой такому виду встроенной в JSP логики, как скриплеты (прямые вставки Java кода). Использование стандартизованного множества тегов предпочтительнее, поскольку получаемый код легче поддерживать и проще отделять бизнес-логику от логики отображения.

Для использования JSTL тегов необходимо:

  • подключить зависимости, например в pom.xml:

<dependency>
    <groupId>jstl</groupId>
    <artifactId>jstl</artifactId>
    <version>1.2</version>
</dependency>
<dependency>
    <groupId>taglibs</groupId>
    <artifactId>standard</artifactId>
    <version>1.1.2</version>
</dependency>
  • указать пространство имен основных тегов JSTL через указание на JSP странице код:

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/sql" prefix="sql" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/xml" prefix="x" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %>

80. Из каких групп тегов состоит библиотека JSTL?

Группы тегов JSTL согласно их функциональности:

  • Core Tags предоставляют возможности итерации, обработки исключений, URL, forward, redirect response и т.д.

  • Formatting Tags и Localization Tags предоставляют возможности по форматированию чисел, дат и поддержки i18n локализации и resource bundles.

  • SQL Tags — поддержка работы с базами данных.

  • XML Tags используются для работы с XML документами: парсинга, преобразования данных, выполнения выражений XPath и т.д..

  • JSTL Functions Tags предоставляет набор функций, которые позволяют выполнять различные операции со строками и т.п. Например, по конкатенации или разбиению строк.

81. Какая разница между <c:set> и <jsp:useBean>?

Оба тега создают и помещают экземпляры в заданную область видимости, но <jsp:useBean> только создаёт экземпляр конкретного типа, а <c:set>, создав экземпляр, позволяет дополнительно извлекать значение, например, из параметров запроса, сессии и т. д.

82. Чем отличается <c:import> от <jsp:include> и директивы <%@include %>?

По сравнению с action-тегом <jsp:include> и директивой <%@include %> тег <c:import> обеспечивает более совершенное включение динамических ресурсов, т.к. получает доступ к источнику, чтение информации из которого происходит непосредственно без буферизации и контент включается в исходную JSP построчно.

83. Как можно расширить функциональность JSP?

84. Что вы знаете о написании пользовательских JSP тегов?

85. Приведите пример использования собственных тегов.

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

/WEB-INF/exampleTag.tld

<?xml version="1.0" encoding="UTF-8"?>
<taglib version="2.1" xmlns="http://java.sun.com/xml/ns/j2ee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee web-jsptaglibrary_2_1.xsd">
    <tlib-version>1.0</tlib-version>
    <short-name>example</short-name>
    <uri>/WEB-INF/exampleTag</uri>
    <tag>
        <name>exampleTag</name>
        <tag-class>xyz.company.ExampleTag</tag-class>
        <body-content>empty</body-content>
        <info>The example tag displays Hello World!</info>
    </tag>
</taglib>

xyz.company.ExampleServlet.java

package xyz.company;

import java.io.IOException;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.TagSupport;

public class ExampleTag extends TagSupport{
    private static final long serialVersionUID = 1L;

    @Override
    public int doStartTag() throws JspException {
        try {
            pageContext.getOut().print("Hello World!");
        } catch(IOException ioException) {
            throw new JspException("Error: " + ioException.getMessage());
        }
        return SKIP_BODY;
    }
}

exampleTag.jsp

<%@ taglib uri="/WEB-INF/exampleTag.tld" prefix="example"%>
<%@ page session="false" pageEncoding="UTF-8"%>
<html>
<head>
<title>Example Tag</title>
</head>
<body>
    <h1>Example Tag</h1>
    <p><example:exampleTage /><p>
</body>
</html>

Также в пользовательских тегах существует возможность задать входные параметры. Например, существует необходимость отформатировать каким-либо стилем очень длинное число. Для этого можно использовать собственный тег по типу:

<mytags:formatNumber number="123456.789" format=",# #.00"/>

Используя входные параметры, число должно быть преобразовано на JSP странице в таком виде 123,456.79 согласно шаблону. Т.к. JSTL не предоставляет такой функциональности, необходимо создать пользовательский тег для получения необходимого результата.

86. Как сделать перенос строки в HTML средствами JSP?

Для переноса строки можно использовать тег c:out и атрибут escapeXml, который отключает обработку HTML элементов. В этом случае браузер получит следующий код в виде строки и обработает элемент <br> как требуется:

<c:out value="<br> creates a new line in HTML" escapeXml="true"></c:out>

87. Почему не нужно конфигурировать стандартные JSP теги в web.xml?

Стандартные теги JSP не конфигурируются в web.xml, потому что tld файлы уже находятся внутри каталога /META-INF/ в jar файлах JSTL.

Когда контейнер загружает веб-приложение и находит tld файлы в в jar файле в директории /META-INF/, то он автоматически настраивает их для непосредственного использования на JSP страницах. Остается только задать пространство имен на JSP странице.

88. Как можно обработать ошибки JSP страниц?

Для обработки исключений выброшенных на JSP странице достаточно лишь задать страницу ошибки JSP и при её создании установить значение page directive attribute isErrorPage в значение true. Таким образом будет предоставлен доступ к неявным объектам исключений в JSP и появится возможность передавать собственные, более информативные сообщения об ошибках клиенту. При этом настройка дескриптора развертывания выглядит так:

<error-page>
     <error-code>404</error-code>
     <location>/error.jsp</location>
</error-page>

<error-page>
     <exception-type>java.lang.Throwable</exception-type>
     <location>/error.jsp</location>
</error-page>

89. Как происходит обработка ошибок с помощью JSTL?

Для перехвата и обработки исключений в служебных методах класса служат JSTL Core Tags c:catch и c:if.

Тег c:catch перехватывает исключение и обертывает его в переменную exception, доступную для обработки в теге c:if:

____+++<c:catch var="exception">+++<% int x = 42/0;%>+++</c:catch>++++++<c:if test="${exception ne null}">+++Exception is : $\{exception} +
Exception Message: ${exception.message}+++</c:if>+++

----

Обратите внимание что используется язык выражений JSP EL в теге `c:if`.

[к оглавлению](#servlets-jsp-jstl)

## Как конфигурируется JSP в дескрипторе развертывания.
Для настройки различных параметров JSP страниц используется элемент `jsp-config`, который отвечает за:

+ управление элементами скриптлетов на странице;
+ управления выполнением в языке выражений;
+ определение шаблона URL для encoding;
+ определение размера буфера, который используется для объектов на странице;
+ обозначение групп ресурсов, соответствующих шаблону URL, которые должны быть обработаны как XML документ.

```xml
<jsp-config>
    <taglib>
        <taglib-uri>http://company.xyz/jsp/tlds/customtags</taglib-uri>
        <taglib-location>/WEB-INF/exampleTag.tld</taglib-location>
    </taglib>
</jsp-config>
----

== Можно ли использовать Javascript на JSP странице?

Да, это возможно. Несмотря на то, что JSP это серверная технология, на выходе она всё равно создает `HTML` страницу, на которую можно добавлять Javascript и CSS.

== Всегда ли создается объект сессии на JSP странице, можно ли отключить его создание?

Jsp-страница, по умолчанию, всегда создает сессию. Используя директиву `page` с атрибутом `session` можно изменить это поведение:

`<%@ page session ="false" %>`

== Какая разница между `JSPWriter` и сервлетным `PrintWriter`?

`PrintWriter` является объектом отвечающим за запись содержания ответа на запрос. `JspWriter` использует объект `PrintWriter` для буферизации. Когда буфер заполняется или сбрасывается, `JspWriter` использует объект `PrintWriter` для записи содержания в ответ.

== Опишите общие практические принципы работы с JSP.

Хорошей практикой работы с технологией JSP является соблюдение следующих правил:

* Следует избегать использования элементов скриптлетов на странице. Если элементы _action_, _JSTL_, _JSP EL_ не удовлетворяют потребностям, то желательно написать собственный тег.
* Рекомендуется использовать разные виды комментариев: так JSP комментарии необходимы для уровня кода и отладки, т.к. они не будут показаны клиенту.
* Не стоит размещать какой-либо бизнес логики внутри JSP страницы. Страницы должны использоваться только для создания ответов клиенту.
* Для повышения производительности лучше отключать создание сессии на странице, когда это не требуется.
* Директивы `taglib`, `page` в начале JSP страницы улучшают читабельность кода.
* Следует правильно использовать директиву `include` и элемент `jsp:include action`. Первая используется для статических ресурсов, а второй для динамических ресурсов времени выполнения.
* Обработку исключений нужно производить с помощью страниц ошибок. Это помогает избегать запуска специальных служебных методов и может повысить производительность.
* Использующиеся CSS и JavaScript должны быть разнесены в разные файлы и подключаться в начале страницы.
* В большинстве случаев JSTL должно хватать для всех нужд. Если это не так, то в начале следует проанализировать логику своего приложения, и попробовать перенести выполнения кода в сервлет, а далее с помощью установки атрибутов использовать на JSP странице только результат.

== Источники

* http://javastudy.ru/interview/jee-servlet-api-questions/[javastudy.ru]
* http://www.java2ee.ru/servlets/[java2ee.ru]
* http://java-online.ru/jsp-questions.xhtml[Java-online]
* http://www.codenet.ru/webmast/java/jsp.php[Codenet]
* https://articles.javatalks.ru/articles/24[JavaTalks Articles]