App1 (before reading this chapter, we recommend that you take a look at how Tomcat works Reading Notes (a) ---------- a simple web server http://blog.csdn.net/dlf123321/article/details/39378157)
In the previous chapter, we developed a simple web server that allows users to access static resources on the server. Of course, this is far from enough. In this section, we try to let the server continue to support servlet on the basis of the corresponding static resources.
Servlet Interface
The javax. servlet. servlet interface defines five methods:
The servlets we use are indirect implementation classes of servlet interfaces.
Each time we instantiate a servlet, the servlet container will first call the init () method for initialization and then call the service () method to process user needs, the container will call the destroy () method before destroying the servlet.
Let's take a look at the test servlet we use in this section.
import javax.servlet.*;import com.jspsmart.upload.Request;import java.io.IOException;import java.io.PrintWriter;public class PrimitiveServlet implements Servlet { public void init(ServletConfig config) throws ServletException { System.out.println("init"); } public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException { System.out.println("from service"); PrintWriter out = response.getWriter(); out.println("Hello. Roses are red."); out.print("Violets are blue."); // out.flush(); } public void destroy() { System.out.println("destroy"); } public String getServletInfo() { return null; } public ServletConfig getServletConfig() { return null; }}
The five methods defined by the servlet are all implemented (however, the servlet to be implemented in this section does not have the ability to automatically call the init and destroy methods ).
Let's look at our main method. The program starts from here (it is not very different from the httpserver in the previous section)
Package ex02.pyrmont; import java.net. socket; import java.net. serversocket; import java.net. inetaddress; import Java. io. inputstream; import Java. io. outputstream; import Java. io. ioexception; public class httpserver1 {/** web_root is the directory where our HTML and other files reside. * For this package, web_root is the "webroot" directory under the working * directory. * The working directory is the loca Tion in the file system * from where the Java command was invoked. * // shutdown command Private Static final string shutdown_command = "/shutdown"; // The shutdown command has ed private Boolean shutdown = false; public static void main (string [] ARGs) {httpserver1 Server = new httpserver1 (); server. await ();} public void await () {serversocket = NULL; int Port = 8080; try {serve Rsocket = new serversocket (port, 1, inetaddress. getbyname ("127.0.0.1");} catch (ioexception e) {e. printstacktrace (); system. exit (1);} // loop waiting for a request while (! Shutdown) {Socket socket = NULL; inputstream input = NULL; outputstream output = NULL; try {socket = serversocket. accept (); input = socket. getinputstream (); Output = socket. getoutputstream (); // CREATE request object and parse request = new request (input); Request. parse (); // create response object response = new response (output); response. setrequest (request ); // no more static resources are processed here. // you can determine whether the requested static resources are servlet or check if this is a request for a servlet or a static resource. // a request for a servlet begins with "/servlet/" If (request. geturi (). startswith ("/servlet/") {servletprocessor1 processor = new servletprocessor1 (); processor. process (request, response);} else {staticresourceprocessor processor = new staticresourceprocessor (); processor. process (request, response);} // close the Socket socket. close (); // check if the previous URI is a shutdown command shutdown = request. geturi (). equals (shutdown_command);} catch (exception e) {e. printstacktrace (); system. exit (1 );}}}}
You can clearly see that the difference between this part and the previous section is mainly in the response part. More accurately, This is where
if (request.getUri().startsWith("/servlet/")) { ServletProcessor1 processor = new ServletProcessor1(); processor.process(request, response); } else { StaticResourceProcessor processor = new StaticResourceProcessor(); processor.process(request, response); }
Let's take a look at how to process a request starting with servlet.
Package ex02.pyrmont; import java.net. URL; import java.net. urlclassloader; import java.net. urlstreamhandler; import Java. io. file; import Java. io. ioexception; import javax. servlet. servlet; import javax. servlet. servletrequest; import javax. servlet. servletresponse; public class servletprocessor1 {public void process (request, response) {string uri = request. geturi (); string servletname = Uri. Substring (URI. lastindexof ("/") + 1); urlclassloader loader = NULL; try {// create a urlclassloader // The main function of try is to generate a urlclassloader URL [] URLs = new URL [1]; urlstreamhandler streamhandler = NULL; file classpath = new file (constants. web_root); // The URL constructor below is // java.net. URL. URL (string protocol, string host, string file) throws malformedurlexception string repository = (new URL ("file", null, classpat H. getCanonicalPath () + file. separator )). tostring (); system. out. println (servletname + "*****" + constants. web_root + "" + repository); // The URL constructor below is // java.net. URL. URL (URL context, string spec, urlstreamhandler handler) throws malformedurlexception // as to what urlstreamhandler is, temporarily ignore URLs [0] = new URL (null, repository, streamhandler ); loader = new urlclassloader (URLs);} catch (ioexception e) {system. out. Println (E. tostring () ;}class <?> Myclass = NULL; try {myclass = loader. loadclass (servletname); // load the requested servlet} catch (classnotfoundexception e) {system. out. println (E. tostring ();} servlet = NULL; try {servlet = (servlet) myclass. newinstance (); // generate an instance and call the service method servlet. service (servletrequest) request, (servletresponse) response);} catch (exception e) {system. out. println (E. tostring ();} catch (throwable e) {system. out. println (E. tostring ());}}}
Let's take a look at the other part. If the requested is not a servlet (This section is a static resource), what should we do?
package ex02.pyrmont;import java.io.IOException;public class StaticResourceProcessor { public void process(Request request, Response response) { try { response.sendStaticResource(); } catch (IOException e) { e.printStackTrace(); } }}
There is no difference with section 1.
Our request class must implement the servletrequest Interface
Package ex02.pyrmont; import Java. io. inputstream; import Java. io. ioexception; import Java. io. bufferedreader; import Java. io. unsupportedencodingexception; import Java. util. enumeration; import Java. util. locale; import Java. util. map; import javax. servlet. asynccontext; import javax. servlet. dispatchertype; import javax. servlet. requestdispatcher; import javax. servlet. servletcontext; import javax. servlet. servletinput Stream; import javax. servlet. servletrequest; import javax. servlet. servletresponse; public class request implements servletrequest {private inputstream input; private string URI; public request (inputstream input) {This. input = input;} Public String geturi () {return URI;} private string parseuri (string requeststring) {int index1, index2; index1 = requeststring. indexof (''); If (index1! =-1) {index2 = requeststring. indexof ('', index1 + 1); If (index2> index1) return requeststring. substring (index1 + 1, index2);} return NULL;} public void parse () {// read a set of characters from the socket stringbuffer request = new stringbuffer (2048 ); int I; byte [] buffer = new byte [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 ();} public void removeattribute (string attribute) {} public void setattribute (string key, object Value) {} public void setcharacterencoding (string encoding) throws unsupportedencodingexception {} // The missing method is automatically generated using eclipse and will not be repeated}
The same response must also implement the servletresponse interface.
Package ex02.pyrmont; import Java. io. outputstream; import Java. io. ioexception; import Java. io. fileinputstream; import Java. io. filenotfoundexception; import Java. io. file; import Java. io. printwriter; import Java. util. locale; import javax. servlet. servletresponse; import javax. servlet. servletoutputstream; import com.sun.org. apache. bcel. internal. generic. new; public class response implements servletresponse {priva Te static final int buffer_size = 1024; Request request; outputstream output; printwriter writer; public response (outputstream output) {This. output = output;} public void setrequest (request) {This. request = request;}/* This method is used to serve a static page */Public void sendstaticresource () throws ioexception {byte [] bytes = new byte [buffer_size]; fileinputstream FCM = NULL; tr Y {/* request. geturi has been replaced by request. getrequesturi */system. out. println (constants. web_root + "*****" + request. geturi (); file = new file (constants. web_root, request. geturi (); FCM = new fileinputstream (File);/* HTTP Response = status-line * (General-header | response-header | entity-header) CRLF) CRLF [Message-body] Status-line = http-version SP status-code SP reason-phras E crlf */int ch = FCM. Read (bytes, 0, buffer_size); system. Out. println ("response **"); While (Ch! =-1) {output. write (bytes, 0, CH); CH = FCM. read (bytes, 0, buffer_size) ;}} catch (filenotfoundexception e) {string errormessage = "HTTP/1.1 404 file not found \ r \ n" + "Content-Type: text/html \ r \ n "+" Content-Length: 23 \ r \ n "+" \ r \ n "+"
Test
Http: // localhost: 8080/servlet/primitiveservlet
Console display
GET/servlet/primitiveservlet HTTP/1.1
Accept: image/GIF, image/JPEG, image/pjpeg, image/pjpeg, application/X-Shockwave-flash,
Accept-language: ZH-CN
User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; sv1)
Accept-encoding: gzip, deflate
HOST: localhost: 8080
Connection: keep-alive
Primitiveservlet ***** D: \ Java code \ upload \ webroot file: D: \ Java code \ upload \ webroot \
From Service
Take a closer look
Violets are blue. This sentence is not printed.
Let's take a look at the printwriter line in the getwriter method of the response class.
I will not explain the above English
This bug will be modified in future versions
There is still a problem with the code above app2.
In the request section, parseuri is private. In this section, this is actually possible, but the problem is that this method may be used in external classes and should be public.
If it is changed to public, the problem occurs again.
public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException { System.out.println("from service"); Request r=(Request) request; System.out.println(r.parseUri("sdf")); PrintWriter out = response.getWriter(); out.println("Hello. Roses are red."); out.print("Violets are blue."); out.flush(); }
I changed the service in the servlet class to the above. Let's take a look. In fact, the request parseuri method should not be used in servlet!
What should we do?
First, change the public method of the parseuri Method to the default access modifier, And the classes outside the package cannot be accessed.
But there is another way
Facade mode !!
In the above example, the request we wrote implements servletrequest. We can write another requestfacade class so that it can also implement servletrequest (response similar)
Package ex02.pyrmont; import Java. io. ioexception; import Java. io. bufferedreader; import Java. io. unsupportedencodingexception; import Java. util. enumeration; import Java. util. locale; import Java. util. map; import javax. servlet. requestdispatcher; import javax. servlet. servletinputstream; import javax. servlet. servletrequest; public class requestfacade implements servletrequest {private servletrequest request = NULL; Public requestfacade (request) {This. request = request;} Public String getremotehost () {return request. getremotehost () ;}// omitting the implementation of the servletrequest interface // the method of the servletrequest interface calls the attribute request of the class to implement public void setcharacterencoding (string encoding) during the internal implementation of requestfacade) throws unsupportedencodingexception {request. setcharacterencoding (encoding) ;}} check servletprocessor and change it to the following servlet = NULL; requestfacade = new requestfacade (request); responsefacade = new responsefacade (response ); 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 ();} The httpserver is also changed to the following if (request. geturi (). startswith ("/servlet/") {servletprocessor2 processor = new servletprocessor2 (); processor. process (request, response );}
The parameters passed by app1 to the servlet are actually request type, which may cause the danger of calling the parseuri method.
The parameter passed by app2 to the servlet is actually requestfacade. It does not have the parseuri method at all, so it is naturally safe.
This article deletes the source code in the book. You can download the complete version.
In-depth analysis of Tomcat source code
Http://down.51cto.com/data/486495
How Tomcat works Reading Notes (2) ---------- a simple Servlet Container