В предыдущей статье я написал простую реализацию веб -сервера Java, которая может обрабатывать только некоторые статические запросы на ресурсы. Контейнер сервлета, реализованный в этой статье, был немного изменен на основе предыдущего сервера, добавив обработку запросов сервлета.
Шаги выполнения программы
1. Создать объект Serversocket;
2. Вызовите метод принятия объекта Serversocket и дождитесь соединения. Если соединение будет успешным, будет возвращен объект сокета, в противном случае он будет заблокирован и ждать;
3. Получите потоки Byte InputStream и OutputStream из объекта сокета, и эти два потока соответствуют запросу и ответу на запрос и ответе соответственно;
4. Обработайте запрос: прочитайте информацию о потоке Byte InputStream, преобразуйте его в строковую форму и проанализируйте его. Проанализирование здесь относительно прост, и он получает только информацию URI (единый идентификатор ресурсов);
5. Обработайте ответ (в двух типах, ответа на запрос на статический ресурс или ответ на запрос сервлета): Если он является статическим запросом ресурса, на основе проанализированной информации URI, найдите файл запрашиваемого ресурса ресурса из каталога Web_ROOT, прочитать файл ресурса и записать его в байт -поток OutputStream; Если это запрос Сервлета, сначала сгенерируйте загрузчик класса UrlClassLoader, загрузите запрошенной класс сервлета, создайте объект сервлета и выполните метод службы (запишите данные ответа в outputStream);
6. Закройте объект сокета;
7. Перейдите к шагу 2 и продолжайте ждать запроса на соединение;
Реализация кода:
Добавить зависимости:
<!-https://mvnrepository.com/artifact/javax.servlet/servlet-api-> <depervice> <groupid> javax.servlet </GroupId> <ratifactid> Servlet-Api </artifactid> <serse> 2.3 </version> </depertive>>
Код сервера:
пакет ex02.pyrmont.first; import java.net.socket; import java.net.serversocket; импорт java.net.inetadress; импорт java.io.inputstream; import java.io.outputstream; import java.io.ioexception; импорт ex02.pyrmont.requestem; ex02.pyrmont.staticresourceprocessor; public class httpserver1 {// Close Service Command Private Static Final String uptowd_command = "/shutdown"; public static void main (string [] args) {httpserver1 server = new httpserver1 (); // ожидание сервера запроса подключения. Await (); } public void wait () {serversocket serversocket = null; int port = 8080; try {// Server Socket Object Serversocket = new Serversocket (порт, 1, inetAddress.getByName ("127.0.0.1")); } catch (ioException e) {e.printstackTrace (); System.Exit (1); } // цикл, чтобы ждать запроса, пока (true) {ocket socket = null; InputStream input = null; OutputStream output = null; Попробуйте {// ждать соединения после успеха соединения, верните сокет объекта сокета = serversocket.accep (); input = socket.getInputStream (); output = socket.getOutputStream (); // Создать объект запроса и запрос PARSE = New Request (Input); request.parse (); // Проверьте, является ли это командой Shutdown Service if (request.geturi (). Equals (shutdown_command)) {break; } // Создать ответ объекта ответа ответа = новый ответ (output); response.setRequest (запрос); if (request.geturi (). startswith ("/servlet/")) {// ups uri начинается с/Servlet/, указывая на то, что процессор Servlet Processor1 = new ServletProcessor1 (); Processor.Process (запрос, ответ); } else {// static resourcerSourceProcessor processor = new StaticResourceProcessor (); Processor.Process (запрос, ответ); } // закрыть сокет сокет.close (); } catch (Exception e) {e.printstackTrace (); System.Exit (1); }}}}Постоянный класс:
пакет ex02.pyrmont; import java.io.file; Public Class Constants {public Static Final String web_Root = System.getProperty ("user.dir") + file.separator + "webRoot"; Public Static Final String Web_Servlet_Root = System.getProperty ("user.dir") + file.separator + "target" + file.separator + "classes"; }Запрос:
пакет ex02.pyrmont; импорт java.io.inputstream; import java.io.ioexception; импорт java.io.bufferedreader; импорт java.io.unsupportedencodingexception; импорт java.util.enumeration; import java.util.locale; import java.Util.mapTACHER. javax.servlet.servletinputstream; import javax.servlet.servletRequest; запрос открытого класса реализует ServletRequest {private InputStream вход; частная строка URI; public Request (InputStream Input) {this.input = input; } public String geturi () {return uri; } /** * * * Форма requestString заключается в следующем: * get /index.html http /1.1 * host: localhost: 8080 * Соединение: Keep-alive * Cache-Control: max-age = 0 * ... * Цель этой функции-получить /index.html String * /private String parseuri (строка QueersString) {indEx1; index1 = requestString.indexof (''); if (index1! = -1) {index2 = requestString.indexof ('', index1 + 1); if (index2> index1) return requestString.substring (index1 + 1, index2); } return null; } // Читать набор символов из Socket StringBuffer Request = new StringBuffer (2048); int i; Byte [] buffer = новый байт [2048]; try {i = input.read (buffer); } catch (ioException e) {e.printstackTrace (); i = -1; } for (int j = 0; j <i; j ++) {request.append ((char) buffer [j]); } System.out.print (request.tostring ()); uri = parseuri (request.tostring ()); } / * Реализация ServletRequest * / public Object getAttribute (string attribute) {return null; } public enumeration <?> getAttributeNames () {return null; } public String getRealPath (String Path) {return null; } public requestDispatcher getRequestDispatcher (String Path) {return null; } public boolean issecure () {return false; } public String getCaracterencoDing () {return null; } public int getContentLength () {return 0; } public String getContentType () {return null; } public ServletInputStream getInputStream () бросает ioException {return null; } public locale getLocale () {return null; } public enumeration <?> getLocales () {return null; } public String getParameter (string name) {return null; } public Map <?,?> getParameterMap () {return null; } public enumeration <?> getParameterNames () {return null; } public String [] getParametervalues (String Parameter) {return null; } public String getProtocol () {return null; } public BufferedReader getReader () бросает ioException {return null; } public String getRemoteAddr () {return null; } public String getRemoteHost () {return null; } public String getScheme () {return null; } public String getServerName () {return null; } public int getServerport () {return 0; } public void removeAttribute (string attribute) {} public void setAttribute (string key, value value) {} public void setcharacterencoding (string encoding) бросает UnsupportedEncodingException {}}Ответ:
пакет ex02.pyrmont; импорт java.io.outputstream; импорт java.io.ioexception; импорт java.io.fileinputstream; импорт java.io.filenotfoundexception; импорт java.io.file; import.io.printwriter; import.localessessesessessessesessesessessessessessesessessesses. javax.servlet.servletoutputstream; Отклик открытого класса реализует Servletresponse {private Static Final Buffer_size = 1024; Запрос на запрос; Выходные выходные данные; Писатель Printwriter; Public Response (OutputStream Output) {this.Output = output; } public void setRequest (запрос запроса) {this.Request = request; } // Записать веб -файл в outputStream Byte Stream public void sendStaticResource () бросает ioException {byte [] bytes = new Byte [buffer_size]; FileInputStream fis = null; try { / * request.geturi был заменен request.getRequesturi * / file file = new File (constants.web_root, request.geturi ()); fis = new FileInputStream (file); / * * Http response = status-line ((общий заголовок | заголовок ответа | * Entity-Header) Crlf) Crlf [crlf Message-body] Status-line = * http-version sp-code sp couns-phrase crlf */ int ch = fis.read (bytes, 0, buffer_size); while (ch! = -1) {output.write (bytes, 0, ch); ch = fis.read (байты, 0, buffer_size); }} catch (filenotfoundexception e) {string errormessage = "http/1.1 404 Файл не найден/r/n" + "content-type: text/html/r/n" + "Содержание-длина: 23/r/n" + "/r/n" + "<h1> файл не найден </h1>"; output.write (errormessage.getbytes ()); } наконец {if (fis! = null) fis.close (); }} / ** Реализация ServletResponse* / public void flushBuffer () бросает ioException {} public int getBuffersize () {return 0; } public String getCaracterencoDing () {return null; } public locale getLocale () {return null; } public ServletOutputStream getOutputStream () бросает ioException {return null; } public printwriter getWriter () бросает ioException {// autoflush is true, println () будет промывать, // но print () нет. writer = new PrintWriter (output, true); вернуть писатель; } public boolean iscommitted () {return false; } public void reset () {} public void resetBuffer () {} public void setBuffersize (int size) {} public void setContentLength (int length) {} public void setContentType (строка типа) {} public void setlocale (локал локал) {}}}}}}}}}}}Обработка запроса на статический ресурс:
пакет ex02.pyrmont; import java.io.ioexception; открытый класс staticresourceprocessor {public void Process (запрос запроса, ответ ответ) {try {response.sendStaticResource (); } catch (ioException e) {e.printstackTrace (); }}}Обработка запроса сервлета:
пакет ex02.pyrmont.first; import java.net.url; import java.net.urlclassloader; import java.net.urlstreamhandler; импорт java.io.ioexception; импорт javax.servlet.servlet; import javax.servlet.servlectrequest; import javax.servlet.serspesses. ex02.pyrmont.constants; import ex02.pyrmont.request; import ex02.pyrmont.response; public Class servletprocessor1 {public void Process (запрос запроса, ответ ответ) {String uri = request.geturi (); String servletname = uri.substring (uri.lastindexof ("/") + 1); // ClassLoader, используемый для загрузки класса UrlClassLoader из указанного файла JAR или Directory Loader = null; try {urlstreamhandler streamhandler = null; // Создание загрузчика класса loader = new UrlClassLoader (новый URL [] {новый URL (null, "file:" + constants.web_servlet_root, streamhandler)}); } catch (ioException e) {System.out.println (e.toString ()); } Class <?> MyClass = null; try {// загрузить соответствующий класс сервлета myclass = loader.loadclass (ServletName); } catch (classnotfoundexception e) {System.out.println (e.toString ()); } Сервлет Сервл = null; try {// производить сервенс экземпляра servlet = (servlet) myclass.newinstance (); // выполнить метод обслуживания запроса ervlet servlet.service ((servletrequest), ((Servletresponse) ответ); } catch (Exception e) {System.out.println (e.toString ()); } catch (throwable e) {System.out.println (e.toString ()); }}}Класс сервлета:
Импорт javax.servlet.*; import java.io.ioexception; import java.io.printwriter; открытый класс Primitiveservlet реализует Servlet {public void init (ServletConfig Config) Throws ServletException {System.out.println («init»); } public void Service (запрос ServletRequest, ответ servletresponse) Throws ServletException, ioException {System.out.println ("From Service"); Printwriter Out = response.getWriter (); out.println ("Привет. Розы красные."); out.print («Фиалки синие»); } public void destress () {System.out.println ("Drester"); } public String getServletInfo () {return null; } public servletConfig getServletConfig () {return null; }} Тест результатов:
Статический запрос на ресурс:
Запрос сервлета (потому что это всего лишь первая строка, которая обновляется в браузере, вы не можете увидеть, как вторая строка фиалки синяя. Мы уточним контейнер позже):
улучшать
Контейнер сервлета, реализованный ранее, имеет серьезную проблему. В сервисе пользователь может напрямую преобразовать ServletRequest и Servletresponse в типы запроса и ответов и напрямую вызывать его внутренние общественные методы. Это плохой дизайн. Метод улучшения состоит в том, чтобы добавить классы внешности для запроса и ответа, чтобы пользователи могли получить доступ только к публичным методам, определенным в классе внешнего вида.
Запросить класс внешнего вида
пакет ex02.pyrmont.second; импорт java.io.ioexception; import java.io.bufferedReader; импорт java.io.unsupportedencodingexception; импорт java.util.enumeration; import java.util.locale; импорт java.util.map; import javax.servlet.erqueptr javax.servlet.servletinputstream; import javax.servlet.servletRequest; import ex02.pyrmont.request; public class requestfacade реализует ServletRequest {private servletRequest request = null; public requestFacade (запрос запроса) {this.request = request; } / * Реализация ServletRequest * / public Object getAttribute (string attribute) {return request.getAttribute (attribute); } public enumeration <?> getAttributeNames () {return request.getAttributeNames (); } @Suppresswarnings ("omemercation") public String getRealPath (String Path) {return request.getRealpath (path); } public requestDispatcher getRequestDispatcher (String Path) {return request.getRequestDispatcher (path); } public boolean issecure () {return request.issecure (); } public String getCaracterencoDing () {return request.getCaracterencoDing (); } public int getContentLength () {return request.getContentLength (); } public String getContentType () {return request.getContentType (); } public ServletInputStream getInputStream () бросает ioException {return request.getInputStream (); } public locale getLocale () {return request.getLocale (); } public enumeration <?> getLocales () {return request.getlocales (); } public String getParameter (string name) {return request.getParameter (name); } public map <?,?> getParameterMap () {return request.getParameterMap (); } public enumeration <?> getParameterNames () {return request.getParameterNames (); } public String [] getParametRovalues (String Parameter) {return request.getParametervalues (parameter); } public String getProtocol () {return request.getProtocol (); } public BufferedReader getReader () бросает ioException {return request.getReader (); } public String getRemoteAddr () {return request.getRemoteAddr (); } public String getRemoteHost () {return request.getRemotehost (); } public String getScheme () {return request.getScheme (); } public String getServerName () {return request.getServerName (); } public int getServerport () {return request.getServerport (); } public void removeAtTribute (string attribute) {request.RemoveAttribute (attribute); } public void setAtTribute (String Key, значение объекта) {request.setattribute (key, value); } public void setCaracterCoding (String Encoding) бросает UnsupportedEncodingException {request.setcharacterencoding (кодирование); }} Класс ответов
пакет ex02.pyrmont.second; импорт java.io.ioexception; import java.io.printwriter; импорт java.util.locale; импорт javax.servlet.servletresponse; импорт javax.servlet.servletoutputstream; импорт ex02.pyrmont.response; public responsefacade (ответ ответ) {this.response = response; } public void flushBuffer () бросает ioException {response.flushbuffer (); } public int getBuffersize () {return response.getBuffersize (); } public String getCaracterencoDing () {return response.getCaracterencoDing (); } public locale getLocale () {return response.getLocale (); } public servletOutputStream getOutputStream () бросает ioException {return response.getOutputStream (); } public printWriter getWriter () бросает ioException {return response.getWriter (); } public boolean iscommitted () {return response.iscommitted (); } public void reset () {response.reset (); } public void resetBuffer () {response.resetBuffer (); } public void setBuffersize (int size) {response.setBuffersize (size); } public void ResetBuffersize (размер); } public void resetBuffersize (int size); } public void setBuffersize (size); } public void setContentLength (int length) {response.setContentLength (длина); } public void setContentType (String type) {response.setContentType (type); } public void setlocale (locale locale) {response.setlocale (locale); }}Обработка запроса сервлета:
пакет ex02.pyrmont.second; импорт java.net.url; import java.net.urlclassloader; импорт java.net.urlstreamhandler; импорт java.io.ioexception; импорт javax.servlet.servlet; import javax.servlet.servletrequest; import javax.servlet.servses. ex02.pyrmont.constants; import ex02.pyrmont.request; import ex02.pyrmont.response; public Class ServletProcessor2 {public void Process (запрос запроса, ответ ответ) {String uri = request.geturi (); String servletname = uri.substring (uri.lastindexof ("/") + 1); // Class Loader, используемый для загрузки класса UrlClassLoader из указанного файла JAR или Directory Loader = null; try {urlstreamhandler streamhandler = null; // Создание загрузчика класса loader = new UrlClassLoader (новый URL [] {новый URL (null, "file:" + constants.web_servlet_root, streamhandler)}); } catch (ioException e) {System.out.println (e.toString ()); } Class <?> MyClass = null; try {// загрузить соответствующий класс сервлета myclass = loader.loadclass (ServletName); } catch (classnotfoundexception e) {System.out.println (e.toString ()); } Сервлет Сервл = null; // Добавить классы внешнего вида для запроса и ответа, а также представлены соображения безопасности для предотвращения непосредственного преобразования пользователей ServletRequest и Servletresponse в типы запроса и ответов в сервлетах, // и непосредственно вызвать их внутренние общественные методы, поскольку не будет никакого анализа, SendStaticResource и других методов в запросах и reckensfacade; RequestFacade requestFacade = new RequestFacade (request); Responsefacade responsefacade = new RecsionFacade (ответ); try {servlet = (Servlet) myclass.newinstance (); Servlet.service (((ServletRequest) requestFacade, (servletresponse) responsefacade); } catch (Exception e) {System.out.println (e.toString ()); } catch (throwable e) {System.out.println (e.toString ()); }}} Другие коды в основном такие же, как контейнер сервлета, реализованный ранее.
Программа проверки запрашивает статические ресурсы и сервлеты соответственно, и обнаруживает, что результаты соответствуют контейнеру, реализованному ранее;
Ссылка: «Глубокий анализ Tomcat»
@author, похожий на ветру, кодировщик
Выше всего содержание этой статьи. Я надеюсь, что это будет полезно для каждого обучения, и я надеюсь, что все будут поддерживать Wulin.com больше.