類比帶Servlet技術的HTTP伺服器的Java實現,servletjava
上一篇文章說道, Web發展初期, 使用者只能查看靜態頁面. 隨著Web發展,只能顯示靜態頁面的web顯然已經不能滿足福士的需求,所以出現了CGI和用Java編寫的Servlet程式.
Servlet可以根據使用者的請求動態產生html頁面,然後發給瀏覽器.
下面類比一下這個過程:
- HttpServer2類:伺服器類,負責啟動Http服務.
- Servlet介面: 定義Servlet服務介面.
- HelloServlet類:實現Servlet介面.使用者提交請求時,HttpServer2將請求發給HelloServlet處理.處理完後動態產生頁面返回給使用者.
- ServletRequest類: 封裝使用者的請求.交給HelloServlet處理.
- ServletResponse類: 封裝返回的響應.由HelloServlet返回.
HttpServer2類
伺服器類,負責啟動Http服務.
import java.io.*;import java.net.*;public class HttpServer2 { private static final int port = 8088; private ServerSocket serverSocket = null; public HttpServer2() throws IOException { serverSocket = new ServerSocket(port); System.out.println("HTTPServer startup OK..."); } public void work() throws IOException { while (true) { try { Socket socket = serverSocket.accept(); ServletRequest request = new ServletRequest( socket.getInputStream()); ServletResponse response = new ServletResponse( socket.getOutputStream()); System.out.println("Receive request:\n" + request.getRequest()); String servletName = request.getServletName(); //動態產生servlet Servlet servlet = (Servlet) Class.forName(servletName) .newInstance(); //調用servlet介面 servlet.init(); servlet.service(request, response); servlet.destroy(); socket.close(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } } public static void main(String[] args) throws IOException, InterruptedException { HttpServer2 httpServer = new HttpServer2(); httpServer.work(); }}
Servlet介面
定義Servlet服務介面.
public interface Servlet { public void init(); public void service(ServletRequest req, ServletResponse res) throws Exception; public void destroy();}
HelloServlet類
實現Servlet介面.使用者提交請求時,HttpServer2將請求發給HelloServlet處理.處理完後動態產生頁面返回給使用者.
public class HelloServlet implements Servlet { @Override public void init() { // TODO Auto-generated method stub System.out.println("servlet init "); } @Override public void service(ServletRequest req, ServletResponse res) throws Exception { // TODO Auto-generated method stub String contentType = req.getContentType(); String param = req.getParam(); //組裝HTTP回應標頭 String header = res.assembleResponseHeader(contentType); //組裝HTTP響應本文 String body = res.assembleResponseBody(param); //返迴響應 res.write(header + body); } @Override public void destroy() { // TODO Auto-generated method stub System.out.println("servlet destroy "); }}
ServletRequest類
封裝使用者的請求.交給HelloServlet處理.
import java.io.IOException;import java.io.InputStream;public class ServletRequest { private String request; private InputStream socketIn; private String URI; private String contentType; private String param; public ServletRequest(InputStream socketIn) throws IOException { // TODO Auto-generated constructor stub this.socketIn = socketIn; this.request = _getRequest(); this.URI = _getURI(); this.contentType = _getContentType(); this.param = _getParam(); } public String getRequest() { return request; } public String getURI() { return URI; } public String getContentType() { return contentType; } public String getParam() { return param; } private String _getRequest() throws IOException { int size = socketIn.available(); byte[] requestBuff = new byte[size]; socketIn.read(requestBuff); return new String(requestBuff); } //獲得要調用servlet的類名 public String getServletName(){ return URI.substring(URI.indexOf("/") + 1, URI.indexOf("?")); } private String _getURI() { String firstLine = request.substring(0, request.indexOf("\r\n")); String[] parts = firstLine.split(" "); return parts[1]; } private String _getContentType() { /* 決定HTTP響應本文的類型 */ return "html"; }//獲得請求參數 private String _getParam() { String paramString = URI.substring(URI.indexOf("?") + 1); String[] paramPairs = paramString.split("="); return paramPairs[1]; }}
ServletResponse類
封裝返回的響應.由HelloServlet返回.
import java.io.IOException;import java.io.OutputStream;public class ServletResponse { private OutputStream outputStream; public ServletResponse(OutputStream outputStream) { // TODO Auto-generated constructor stub this.outputStream = outputStream; } public String assembleResponseHeader(String contentType) { /* 建立HTTP響應結果 */ // HTTP響應的第一行 String responseFirstLine = "HTTP/1.1 200 OK\r\n"; // HTTP回應標頭 String responseHeader = "Content-Type:" + contentType + "\r\n\r\n"; return responseFirstLine + responseHeader; } public String assembleResponseBody(String param) { String content = "<body><h1>Hello:" + param + "</h1></body>"; String title = "<head><title>HelloWorld</title></head>"; String body = "<html>" + title + content + "</html>"; return body; } public void write(String res) throws IOException { outputStream.write(res.getBytes()); }}
測試
在chrome瀏覽器輸入http://localhost:8088/HelloServlet?username=tom.
即使用者請求的參數是tom,要調用HelloServlet. (在實際的servlet實現中,是用一個web.xm設定檔實現URI到servlet的映射.)
servlet解析出來後組裝成html返回給瀏覽器.顯示為Hello:tom