1. Введение в сервлет
Servlet - это технология, предоставляемая Sun Company для разработки динамических веб -ресурсов.
Солнце обеспечивает интерфейс сервлета в своем API. Если пользователи хотят отправить динамический веб -ресурс (то есть разработать программу Java для вывода данных в браузер), им необходимо выполнить следующие два шага:
1. Напишите класс Java для реализации интерфейса сервлета.
2. Разверните разработанные классы Java на веб -сервер.
Согласно обычной привычке имени, мы обычно называем Java -программы, которые реализуют сервлет интерфейса сервлета.
2. Процесс эксплуатации сервлета
Программа сервлета вызывается веб -сервером. После того, как веб -сервер получает запрос на доступ к сервису клиента:
① Веб -сервер сначала проверяет, был ли он загружен и создал объект экземпляра сервлета. Если так, то выполните шаг 4 напрямую; В противном случае выполните шаг 2.
② Загрузите и создайте объект экземпляра сервлета.
③ Попросите метод init () объекта экземпляра сервлета.
④ Создайте объект httpservletRequest для инкапсуляции сообщений HTTP -запроса и объект Httpservletresponse, представляющий HTTP -ответные сообщения, а затем вызовите метод сервиса () и передайте объекты запроса и ответа в качестве параметров.
⑤ Перед тем, как веб -приложение будет остановлено или перезапущено, двигатель сервлета удалит сервлет и вызовет метод Destress () сервлета перед удалением.
3. Диаграмма вызова сервлета
4. Разработка сервлета в Eclipse
Создайте новый веб -проект в Eclipse, и Eclipse автоматически создаст структуру каталога, показанная на рисунке ниже:
4.1. Класс реализации интерфейса сервлета
Интерфейс Servlet Sun Company определяет два класса реализации по умолчанию, а именно: genericservlet и httpservlet.
Httpservlet относится к сервлету, который может обрабатывать HTTP -запросы. Он добавляет некоторые методы обработки протокола HTTP к исходному интерфейсу сервлета, который более мощный, чем интерфейс сервлета. Поэтому при написании сервлетов разработчики обычно должны наследовать этот класс и избегать непосредственного реализации интерфейса сервлета.
Когда httpservlet реализует интерфейс Сервлета, он перезаписывает метод обслуживания. Код в организме метода автоматически определит метод запроса пользователя. Если это запрос GET, называется метод Doget Httpservlet. Если это почтовый запрос, будет вызван метод Dopost. Следовательно, при написании сервлетов разработчикам обычно нужно только перезаписать метод догет или Dopost, а не перезаписать метод обслуживания.
4.2. Создать и писать сервлеты через Eclipse
Выберите пакет gacl.servlet.study, щелкните правой кнопкой мыши → Новый → Сервлет, как показано на рисунке ниже:
Таким образом, мы будем использовать Eclipse, чтобы помочь нам создать сервлет с именем ServletDemo1. Будет следующий код в созданном ServletDemo01:
Пакет gacl.servlet.study; import java.io.ioexception; import java.io.printwriter; import javax.servlet.servletexception; импорт javax.servlet.http.httpservlet; import javax.servlet.http.httpservlectrequest; javax.servlet.http.httpservletresponse; public class servletdemo1 расширяет httpservlet { /*** Метод Сервлета Конета. <br> * * Этот метод вызывается, когда форма имеет метод значения тега, чтобы получить. * * @param Запрос запроса Отправить клиентом на сервер * @param ответ Ответ отправил серверу на клиент * @throws servletexception, если произошла ошибка * @throws ioexception, если произошла ошибка */ public void doget (httpservlectrequest, httpservlectresponse response) throws revletexception, ioexception {response.setersponse) Printwriter Out = response.getWriter (); out.println ("<! Doctype html public/"-// w3c // dtd html 4.01 transitional // en/">"); out.println ("<head> <Title> a Servlet </title> </head>"); out.println ("<body>"); out.print («Это есть»); out.print (this.getClass ()); out.println (", с использованием метода Get"); out.println ("</body>"); out.println ("</html>"); out.flush (); out.close (); } /*** Метод Dopost Сервлета. <br> * * Этот метод вызывается, когда форма имеет метод значения тега, равный публикации. * * @param Запрос запроса отправить клиентом на сервер * @param response Ответ отправил серверу на клиенту * @throws servletexception, если произошла ошибка * @throws ioexception, если произошла ошибка */ public void dopost (httpservletrequest, httpserversponse response) throws uexception; response.setContentType ("text/html"); Printwriter Out = response.getWriter (); out.println ("<! Doctype html public/"-// w3c // dtd html 4.01 transitional // en/">"); out.println ("<html>"); out.println ("<head> <Title> a Servlet </title> </head>"); out.println ("<body>"); out.println ("<body>"); out.println («Это»); out.print (this.getClass ()); out.println (", с использованием метода Post"); out.println ("</body>"); out.println ("</html>"); out.flush (); out.close (); }}Эти коды автоматически генерируются Eclipse, и в файле web.xml есть две пары тегов, <servlet> </servlet> и <servlet-mapping> </servlet-mapping>. Эти две пары тегов настроены с помощью ServletDemo1, как показано на рисунке ниже:
Затем мы можем получить доступ к сервлету ServletDemo1 через браузер, как показано на рисунке ниже:
5. Обратите внимание на детали в разработке сервлета
5.1. Конфигурация сопоставления URL -адреса сервлета
Поскольку клиент обращается к ресурсам на веб -сервере с помощью URL -адреса, если программа Servlet хочет получить доступ к внешнему миру, он должен составить сопоставление программы сервлета по адресу URL -адреса. Эта работа выполняется в файле web.xml с использованием элемента <servlet> и элемента <servlet>.
Элемент <servlet> используется для регистрации сервлета. Он содержит два основных дочерних элемента: <Servlet-name> и <servlet-class>, которые используются для установки имени регистрации сервлета и полного имени класса сервлета соответственно.
Элемент <servlet> элемент используется для отображения пути внешнего доступа к зарегистрированному сервлету. Он содержит два дочерних элемента: <Servlet-name> и <Url-pattern>, которые используются для указания названия регистрации сервлета и пути внешнего доступа сервлета. Например:
<servlet> <vervlet-name> ServletDemo1 </servletdemo> <berlet-class> gacl.servlet.study.servletdemo1 </servlet-class> </servlet> <ervlet-mapping> <servlet-name> servletdemo1 </servlet-name> <urll-pattern>/servletdemo1 </servlet-patterning> <urlle-pattern>/servletdemo1 </servlet-patterpaping> <urll-pattern>/servletdemo1 </servlet-patterpaping> <urll-pattern>/servletdemo1 Тот же сервлет может быть сопоставлен с несколькими URL-адресами, то есть значение настройки элементов <servlet-name> множественных элементов <servlet-mapping> может быть именем регистрации того же сервлета. Например: <servlet> <vervlet-name> servletdemo1 </servlet-name> <servlet-class> gacl.servlet.study.servletdemo1 </servlet-class> </servlet> <servlet-mapping> <servlet-mapping> <servlet-name> servletdemo1 </servlet> <Url-pattern>/servlet/servletdemo1 </url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name> servletdemo1 </servlet-name> <url-pattern> /1.htm </url-pattern> </servlet> <servlet-mapping> <serlet-name> servletdemo1> </Servlet> <servlet> <servlet> name> name> </servlet> name> </servlet> name> </servlet> name> </servlet> имени <url-pattern>/2.jsp</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-mapping> <servlet-name>ServletDemo1</servlet-name> <url-pattern>/3.php</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-mapping> <servlet-name>ServletDemo1</servlet-name> <Url-pattern> /4.aspx </url-pattern> </servlet-mapping>
Через приведенную выше конфигурацию, когда мы хотим получить доступ к сервиру с именем ServletDemo1, мы можем использовать следующие адреса для доступа:
http: // localhost: 8080/javaweb_servlet_study_20140531/servlet/servletdemo1
http: // localhost: 8080/javaweb_servlet_study_20140531/1.htm
http: // localhost: 8080/javaweb_servlet_study_20140531/2.jsp
http: // localhost: 8080/javaweb_servlet_study_20140531/3.php
http: // localhost: 8080/javaweb_servlet_study_20140531/4.aspx
ServletDemo1 отображается с несколькими URL -адресами.
5.2. Используйте * картирование подстановочных знаков для URL -адресов доступа к сервлету
Символ*подстановочного знака также может использоваться в URL -адресах, на которые карты сервлета, но могут быть только два фиксированных формата: один - это «*. Например:
<servlet> <servlet-name> servletdemo1 </servlet-name> <bertlet-class> gacl.servlet.study.servletdemo1 </servlet> </servlet> <servlet-mapping> <servlet-name> servletdemo1 </servlet-name> <url-pattern>/*</url> servletdemo1 </servlet> <url-pattern>/*
*Он может соответствовать любому символу, поэтому вы можете использовать любой URL -адрес для доступа к сервлету ServletDemo1, как показано на рисунке ниже:
Для некоторых отношений с картированием ниже:
Карты сервиса1 в /abc /*
Servlet2 Карты в /*
Карты сервиса3 в /ABC
Servlet4 Карты на *.do
вопрос:
Когда URL -адрес запроса: «/bc/a.html», «/abc/*» и «/*», оба совпадают, что сервлет отвечает на двигатель сервлета, вызовет Servlet1.
Когда URL -адрес запроса составляет «/ABC», оба «/ABC/*» и «//ABC», который сервлет отвечает на двигатель сервлета, позволит Servlet3.
Когда URL -адрес запроса составляет «/bc/a.do», оба «/abc/*» и «*.do», который сервлет отвечает на двигатель сервлета, позволит Servlet1.
Когда URL -адрес запроса составляет «/а.do», оба «/*» и «*.do», который сервлет отвечает на двигатель сервлета, позвоните в Servlet2.
Когда URL -адрес запроса составляет «/xxx/yyy/a.do», оба «/*» и «*.do», который сервлет отвечает на двигатель сервлета, позвоните в Servlet2.
Принцип сопоставления - «Кто бы ни был похож на то, чтобы найти, кто бы ни выглядит больше»
5.3. Разница между сервлетом и обычными классами Java
Servlet - это класс Java для Call By других программ Java (двигатели сервлетов). Он не может работать самостоятельно, и его работа полностью контролируется и запланирована двигателем сервлета.
Для нескольких запросов сервлета от клиента обычно сервер создает только объект экземпляра сервлета. То есть, как только объект экземпляра сервлета будет создан, он будет находиться в памяти и обслуживать другие последующие запросы. Объект экземпляра сервлета не будет разрушен до тех пор, пока веб -контейнер не выходит.
В течение всей жизни сервлета метод инициирования сервлета называется только один раз. Каждый запрос на доступ к сервису заставляет двигатель Сервлета вызовать метод обслуживания сервлета один раз. Для каждого запроса доступа, двигатель Servlet создаст новый объект запроса HTTPServLERVLEQUEST и новый объект ответа httpservletresponse, а затем передаст эти два объекта в качестве параметров методу Service () сервлета, который он вызывает. Затем метод службы вызывает метод DOXXX в соответствии с методом запроса.
Если элемент <Load-on-startup> настроен в элементе <Servlet>, то когда веб-приложение запустится, он будет загружать и создавать объект экземпляра Servlet и вызовать метод init () объекта экземпляра Servlet.
Например:
<servlet> <servlet-name> Invoker </servlet-name> <vervlet-class> org.apache.catalina.servlets.invokerservlet </servlet> <Load-on-startup> 1 </load-on-startup> </servlet>
Цель: Напишите Initservlet для веб -приложения. Этот сервлет настроен на загрузку на запуск для создания необходимых таблиц базы данных и данных для всего веб -приложения.
5.4. Сервлет по умолчанию
Если путь отображения сервлета представляет собой только прямую черту (/), то этот сервлет становится сервлетом по умолчанию текущего веб -приложения.
Любой URL-адрес соответствующего <servlet-mapping> элемента, который не может быть найден в файле web.xml, их запросы доступа будут переданы сервлеу по умолчанию для обработки, то есть сервлет по умолчанию используется для обработки запросов доступа, которые не обрабатываются другими сервлетами. Например:
<servlet> <servlet-name> ServletDemo2 </servletdame> <berlet-class> gacl.servlet.study.servletdemo2 </servlet-class> <load-on-startup> 1 </load-on-startup> </servlet> <!-configure Servletdemo2 как Default Servlet-> <servlet-mapping> <! <servlet-name> servletdemo2 </servlet-name> <url-pattern>/</url-pattern> </servlet-mapping>
При доступе к несуществующему сервлету настроенный сервис по умолчанию используется для обработки, как показано на рисунке ниже:
В файле <Tomcat Installation> /conf/web.xml зарегистрировано сервис с именем org.apache.catalina.servlets.defauldervlet, и этот сервлет установлен в качестве сервлета по умолчанию.
<servlet> <servlet-name>default</servlet-name> <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class> <init-param> <param-name>debug</param-name> <param-value>0</param-value> </init-param> <init-param> <param-name>listings</param-name> <param-value> false </param-value> </init-param> <load-on-startup> 1 </load-on-startup> </servlet> <!-отображение для сервлета по умолчанию-> <servlet-pattern> </servlet-mapping> <url-pattern>/</url-pattern> </servlet-mapping> <url-pattern>/</url-pattern>
При доступе к статическому HTML -файлу и изображению на сервере Tomcat вы на самом деле получаете доступ к этому сервлету по умолчанию.
5.5. Проблемы безопасности ниток сервлета
Когда несколько клиентов получают доступ к одному сервису одновременно, веб -сервер создаст поток для запроса доступа каждого клиента и вызовет метод сервиса сервиса в этом потоке. Следовательно, если в методе обслуживания доступ к такому же ресурсу, он может вызвать проблемы безопасности потока. Например, следующий код:
Код, у которого нет проблем с безопасностью потока:
Package gacl.servlet.study; импорт java.io.ioexception; import javax.servlet.servletexception; import javax.servlet.http.httpservlet; import javax.servlet.http.httpservletrequest; import javax.servlet.http.httpservlectrequest; import javax.servlet.http.htptRequestRequest; javax.servlet.http.httpservletresponse; public class servletdemo3 расширяет httpservlet {public void doget (httpservletrequest, httpservletresponse response), бросает Servletexception, ioexception { /*** Когда несколько потоков доступают за код в этом методе, согласованно, будет тематической безопасности? Переменная I доступна одновременно с несколькими потоками, но нет проблемы безопасности потока, потому что я является локальной переменной в методе Дожета. * Когда несколько потоков получают доступ к методу Додета одновременно, в каждом потоке есть своя переменная I, * каждый поток управляет своей собственной переменной I, поэтому не существует проблемы безопасности потока *, когда многопотоковые обработки получают доступ к определенному методу одновременно, если некоторые ресурсы (переменные, коллекции и т. Д.) Определены внутри метода * Тогда у каждого потока есть эти вещи, так что не существует проблемы безопасности потока */ int i = 1; i ++; response.getWriter (). написать (i); } public void Dopost (httpservletRequest, httpservletresponse response) Throws ServletException, ioException {Doget (запрос, ответ); }} Код с проблемами безопасности потока:
пакет gacl.servlet.study; import java.io.ioexception; import javax.servlet.servletexception; import javax.servlet.http.httpservlet; import javax.servlet.http.httpservletrequest; import javax.servlet.httpsersesesesesesesesesesemesses. Httpservlet {int i = 1; public void Doget (httpservletrequest, httpservletresponse response) бросает Servletexception, ioException {i ++; try {thread.sleep (1000*4); } catch (прерванное искусство e) {e.printstacktrace (); } response.getWriter (). написать (i+""); } public void Dopost (httpservletRequest, httpservletresponse response) Throws ServletException, ioException {Doget (запрос, ответ); }}Определите I как глобальную переменную. Когда несколько потоков получают доступ к переменной, я одновременно будет, будут проблемы с безопасностью потоков, как показано на рисунке ниже: включите два браузера одновременно для моделирования параллельного доступа к одному сервлету. Обычно первый браузер должен увидеть 2, а второй браузер должен увидеть 3, но оба браузера видят 3, что не является нормальным.
Проблемы безопасности потока существуют только тогда, когда несколько потоков работают одновременно один и тот же ресурс. Следовательно, при написании сервлета, если доступ к определенному ресурсу (переменная, сбор и т. Д.). Так как решить эту проблему?
Давайте посмотрим на следующий код:
пакет gacl.servlet.study; import java.io.ioexception; import javax.servlet.servletexception; import javax.servlet.http.httpservlet; import javax.servlet.http.httpservletrequest; import javax.servlet.httpsersesesesesesesesesesemesses. Httpservlet {int i = 1; Public void Doget (httpservletRequest, httpservletresponse ответ) бросает Servletexception, ioException { /*** После добавления синхронизации, не существует проблемы безопасности потока при одновременном доступе к i. * Почему проблема с безопасностью потока после добавления синхронизации? * Если сейчас есть поток, доступа к объекту Сервлета, он сначала получит блокировку объекта Сервлета* После его выполнения, он вернет блокировку в объект сервлета. Поскольку он сначала получает блокировку объекта сервлета, * поэтому, когда другой поток обращается к объекту Сервлета, поскольку блокировка была забрана предыдущим потоком, последующий поток может ждать только в строке * *//синхронизированный (это) {// в Java, каждый объект имеет блокировку, и этот здесь ссылается на объект Сервлета i ++; try {thread.sleep (1000*4); } catch (прерванное искусство e) {e.printstacktrace (); } response.getWriter (). написать (i+""); }} public void dopost (httpservletrequest -запрос, httpservletresponse response) throws servletexception, ioexception {Doget (запрос, ответ); }}Теперь этот подход состоит в том, чтобы добавить блокировку в объект Сервлета, гарантируя, что только один поток в любое время получает доступ только к ресурсам в объекте сервлета, поэтому не будет проблем с безопасностью потока, как показано на рисунке ниже:
Хотя этот подход решает проблемы безопасности потока, написание сервлет не должно обрабатывать проблемы безопасности потока таким образом. Если 9999 человек получают доступ к сервлету одновременно, то эти 9999 человек должны стоять в очереди, чтобы получить доступ в последовательности.
В ответ на проблему безопасности в сервлетах Sun предоставляет решение: пусть сервлет реализует интерфейс SingleThreadModel. Если сервлет реализует интерфейс SingleThreadModel, двигатель сервлета вызовет свой метод обслуживания в режиме однополосной.
Глядя на Sevlet API, вы можете видеть, что интерфейс SingleThreadModel не определяет никаких методов или константов. В Java интерфейс, который не определяет никаких методов или константов, называется интерфейсом тега. Один из самых типичных интерфейсов TAG, который вы часто видите, «сериализуется». Этот интерфейс также не определяет никаких методов или константов. Что использует интерфейсы TAG в Java? Основная функция состоит в том, чтобы отметить объект и рассказать JVM, что может сделать этот объект. Например, объект класса, который реализует «сериализуемый» интерфейс, может быть сериализован, а также есть «клонируемый» интерфейс, который также является интерфейсом тега. По умолчанию объектам в Java не разрешается клонировать, как люди в реальной жизни, клонирование не допускается, но пока реализован «клонируемый» интерфейс, объект может быть клонирован.
Пусть сервис реализует интерфейс SingleThreadModel, просто добавьте объявление, чтобы реализовать интерфейс SingleThreadModel к определению класса сервлета.
Для сервлетов, которые реализуют интерфейс SingleThreadModel, двигатель сервиса по-прежнему поддерживает многопоточный паралрентный доступ к сервлету. Метод состоит в том, чтобы генерировать несколько объектов экземпляра сервлета, и каждый параллельный поток вызывает независимый объект экземпляра сервлета отдельно.
Реализация интерфейса SingleThreadModel не может действительно решить проблему безопасности потока сервлетов, потому что двигатель сервлета будет создавать несколько объектов экземпляра сервлета, и по-настоящему решать задачу безопасности с множественным трудом относится к проблеме, которую объект экземпляра сервлета вызывается несколькими потоками одновременно. Фактически, в сервлете API 2.4 SingleThreadModel был помечен как устаревший (устаревший).
Выше приведено в этой статье, я надеюсь, что это будет полезно для каждого обучения.