上篇写了一个简单的Java web服务器实现,只能处理一些静态资源的请求,本篇文章实现的Servlet容器基于前面的服务器做了个小改造,增加了Servlet请求的处理。
- 创建一个ServerSocket对象;
- 调用ServerSocket对象的accept方法,等待连接,连接成功会返回一个Socket对象,否则一直阻塞等待;
- 从Socket对象中获取InputStream和OutputStream字节流,这两个流分别对应request请求和response响应;
- 处理请求:读取InputStream字节流信息,转成字符串形式,并解析,这里的解析比较简单,仅仅获取uri(统一资源标识符)信息;
- 处理响应(分两种类型,静态资源请求响应或servlet请求响应):如果是静态资源请求,则根据解析出来的uri信息,从WEB_ROOT目录中寻找请求的资源资源文件, 读取资源文件,并将其写入到OutputStream字节流中;如果是Servlet请求,则首先生成一个URLClassLoader类加载器,加载请求的servlet类,创建servlet对象,执行service方法(往OutputStream写入响应的数据);
- 关闭Socket对象;
- 转到步骤2,继续等待连接请求;
代码实现:
添加依赖:
<!-- https://mvnrepository.com/artifact/javax.servlet/servlet-api --> <dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <version>2.3</version> </dependency>
服务器代码:
package ex02.pyrmont.first; import java.net.Socket; import java.net.ServerSocket; import java.net.InetAddress; import java.io.InputStream; import java.io.OutputStream; import java.io.IOException; import ex02.pyrmont.Request; import ex02.pyrmont.Response; import ex02.pyrmont.StaticResourceProcessor; public class HttpServer1 { // 关闭服务命令 private static final String SHUTDOWN_COMMAND = "/SHUTDOWN"; public static void main(String[] args) { HttpServer1 server = new HttpServer1(); //等待连接请求 server.await(); } public void await() { ServerSocket serverSocket = null; int port = 8080; try { //服务器套接字对象 serverSocket = new ServerSocket(port, 1, InetAddress.getByName("127.0.0.1")); } catch (IOException e) { e.printStackTrace(); System.exit(1); } // 循环等待请求 while (true) { Socket socket = null; InputStream input = null; OutputStream output = null; try { //等待连接,连接成功后,返回一个Socket对象 socket = serverSocket.accept(); input = socket.getInputStream(); output = socket.getOutputStream(); // 创建Request对象并解析 Request request = new Request(input); request.parse(); // 检查是否是关闭服务命令 if (request.getUri().equals(SHUTDOWN_COMMAND)) { break; } // 创建 Response 对象 Response response = new Response(output); response.setRequest(request); if (request.getUri().startsWith("/servlet/")) { //请求uri以/servlet/开头,表示servlet请求 ServletProcessor1 processor = new ServletProcessor1(); processor.process(request, response); } else { //静态资源请求 StaticResourceProcessor processor = new StaticResourceProcessor(); processor.process(request, response); } // 关闭 socket socket.close(); } catch (Exception e) { e.printStackTrace(); System.exit(1); } } } }
常量类:
package 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"; }
Request:
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.RequestDispatcher; import javax.servlet.ServletInputStream; import javax.servlet.ServletRequest; public class Request implements ServletRequest { private InputStream input; private String uri; public Request(InputStream input) { this.input = input; } public String getUri() { return uri; } /** * * requestString形式如下: * GET /index.html HTTP/1.1 * Host: localhost:8080 * Connection: keep-alive * Cache-Control: max-age=0 * ... * 该函数目的就是为了获取/index.html字符串 */ 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; } //从InputStream中读取request信息,并从request中获取uri值 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()); } /* implementation of the 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 getCharacterEncoding() { return null; } public int getContentLength() { return 0; } public String getContentType() { return null; } public ServletInputStream getInputStream() throws 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() throws 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, Object value) { } public void setCharacterEncoding(String encoding) throws UnsupportedEncodingException { } }