上一篇,我们讲解了如果开发一个简单的Http服务器,这一篇,我们扩展一下,让我们的服务器具备servlet的解析功能。
简单介绍下Servlet接口
如果我们想要自定义一个Servlet,那么我们必须继承Servlet,并且实现下面几个重要的方法public void init(ServletConfig config) throws ServletExceptionpublic void service(ServletRequest request,ServletResponse response) throws ServletException,java.io.IOExceptionpublic void destroy()public ServletConfig getServletConfig()public String getServletInfo()
五个方法中,init,destroy,service都是和servlet的生命周期相关的方法。当实例化某个servlet类之后,servlet会调用init进行初始化,当servlet的请求到达之后,就会调用service方法,并将servletRequest和servletResponse对象作为参数传入,前者包含客户端的Http请求的信息,后者包含服务器的响应信息。
这个简单的Servlet容器的流程如下
- 等待http请求
- 对应的servletRequest对象和servletResponse对象,
- 判断请求的类型,如果是请求静态资源,则找到静态资源的文件,返回给客户端
- 如果是Servlet请求,载入servlet类,调用service()方法,传入servletRequest对象和servletResponse对象
涉及到的主要的类
- SimpleServletContainerServer
- Request
- Response
- Servlet
- PrimitiveServlet
- StaticProcessor
- ServletProcessor
关于Request和Response的定义在上一篇幅有定义,这里我们稍微扩展了一下,碍于篇幅,不在这里展示。
PrimitiveServlet类,继承自Servlet,Servlet请求的处理类
类定义:package servletContainer;import java.io.IOException;import base.Request;import base.Response;import base.ServletConfig;import interf.Servlet;public class PrimitiveServlet implements Servlet { @Override public void init(ServletConfig config) { System.out.println("PrimitiveServlet init"); } @Override public void service(Request request, Response response) throws IOException { response.getOutput().write("Primitive Servlet".getBytes()); } @Override public void destroy() { } @Override public ServletConfig getServletConfig() { return null; } @Override public String getServletInfo() { return null; }}
SimpleServletContainerServer 类
功能:程序入口,监听Http请求,并且负责创建Request和Response 类定义package servletContainer;import java.io.IOException;import java.io.InputStream;import java.io.OutputStream;import java.net.InetAddress;import java.net.ServerSocket;import java.net.Socket;import base.Request;import base.Response;import servletContainer.processor.ServletProcessor;import servletContainer.processor.StaticProcessor;public class SimpleServletContainerServer { private static final String SHUT_DOWN = "/SHUTDOWN"; private boolean shutdown = false; private ServletProcessor servletProcessor = new ServletProcessor(); private StaticProcessor staticProcessor = new StaticProcessor(); public static void main(String args[]){ SimpleServletContainerServer server = new SimpleServletContainerServer(); server.init(); server.await(); } public void init(){ servletProcessor.init(); staticProcessor.init(); } 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(!shutdown){ Socket socket = null; InputStream input = null; OutputStream output = null; try{ socket = serverSocket.accept(); input = socket.getInputStream(); output = socket.getOutputStream(); Request request = new Request(input); request.parse(); Response response = new Response(output); response.setRequest(request); if(request.getUri().startsWith("/servlet/")){ servletProcessor.process(request, response); } else{ staticProcessor.process(request, response); } socket.close(); shutdown = request.getUri().equals(SHUT_DOWN); } catch (Exception e){ e.printStackTrace(); System.exit(1); } } } }
我们引入了StaticProcessor和ServletProcessor进行逻辑的处理,我们看下这两个类的定义
首先这两个类都继承自IProcessor接口package servletContainer.processor;import base.Request;import base.Response;public interface IProcessor { public void init(); public void process(Request request, Response response);}
StaticProcessor类主要是处理静态资源请求
类定义package servletContainer.processor;import base.Request;import base.Response;public class StaticProcessor implements IProcessor { @Override public void process(Request request, Response response) { try{ response.sendStaticResource(); } catch (Exception e){ e.printStackTrace(); } } @Override public void init() { } }
ServeletProcessor主要负责处理Servlet请求,初始化的时候,初始化所有的Servlet子类,接收到servlet的http请求之后,根据请求名称,调用对应的service函数。
类定义package servletContainer.processor;import java.util.HashMap;import java.util.Map;import base.Request;import base.Response;import interf.Servlet;import servletContainer.PrimitiveServlet;public class ServletProcessor implements IProcessor { private Mapmap = new HashMap (); public ServletProcessor() { } public void init(){ PrimitiveServlet servlet = new PrimitiveServlet(); servlet.init(null); map.put("PrimitiveServlet", servlet); } @Override public void process(Request request, Response response) { String uri = request.getUri(); String servletName = uri.substring(uri.lastIndexOf("/") + 1); Servlet servlet = map.get(servletName); try{ if(servlet != null){ servlet.service(request, response); } else{ String errorMessage = "HTTP/1.1 404 File Not Found\r\n" + "Content-Type: text/html\r\n" + "Content-Length:23\r\n" + "\r\n" + " File Not Found
"; response.getWriter().print(errorMessage.getBytes()); } } catch (Exception e){ e.printStackTrace(); } catch (Throwable e){ e.printStackTrace(); } } }
结果
我们在eclipse里运行结果