servlet接口
使用servlet编程需要实现或者继承实现了javax.servlet.Servlet接口的类,其中定义了5个签名方法:
1 public void init(ServletConfig config) throws ServletException 2 public void service(ServletRequest req,ServletResponse res) throws ServletException,java.io.IOException 3 public void destroy() 4 public ServletConfig getServletConfig() 5 public java.lang.String getServletInfo()
init(),service(),destroy对应着servlet的生命周期,init只在加载该servlet时执行且只此一次,容器根据用户请求调用对应servlet的service执行方法,当实例销毁移除前容器调用destroy处理后续操作。
模拟容器主要工作流程:
- 等待http请求
- 根据请求创建对应Request与Response对象
- 如果请求的是静态资源,则调用StaticResourceProcessor发送对应资源
- 如果请求是servlet,则加载该类并执行其service方法
简单servlet容器
主要类信息如下:
- HttpServer 与web服务器类似,不同的是加入了servlet请求判断,并调用ServletProcessor处理对应servlet
- Request 与上一篇web服务器类似,但是实现了ServletRequest接口
- Response 与上一篇web服务器类似,但是实现了ServletResponse接口
- StaticResourceProcessor 用于处理请求静态资源时调用
- ServletProcessor 用于当请求是servlet时调用
- Constant 定义一些常量
- MyLogger 自己定义在控制台打印日志信息,可以忽略
- PrimitiveServlet 实现servlet接口,自定义servlet程序用于请求调用
说明:部分接口只是实现了需要用到的方法,并没有完全实现所有方法,使用默认即可,代码里面没有贴出来
(一)HttpServer
1 public class HttpServer { 2 MyLogger logger = new MyLogger<>(HttpServer.class); 3 private static final String SHUTDOWN_COMMAND = "/SHUTDOWN"; 4 private boolean shutdown = false; 5 6 public void await() { 7 ServerSocket serverSocket = null; 8 int port = 8080; 9 try { 10 serverSocket = new ServerSocket(port, 1, InetAddress.getByName("127.0.0.1")); 11 logger.log("server started......." + "at " + serverSocket.toString()); 12 } catch (IOException e) { 13 // TODO Auto-generated catch block 14 e.printStackTrace(); 15 System.exit(1); 16 } 17 while (!shutdown){ 18 Socket socket = null; 19 InputStream inputStream = null; 20 OutputStream outputStream = null; 21 try { 22 socket = serverSocket.accept(); 23 logger.log("accepted new request..."); 24 inputStream = socket.getInputStream(); 25 outputStream = socket.getOutputStream(); 26 Request request = new Request(inputStream); 27 request.Parse(); 28 Response response = new Response(outputStream); 29 response.setRequest(request); 30 logger.log("inition done,begin process......."); 31 if(request.getUri() == null){ 32 logger.log("request uri is null...close socket"); 33 socket.close(); 34 continue; 35 } 36 else if(request.getUri().startsWith("/servlet/")){ 37 logger.log("execute servlet..."); 38 ServletProcessor servletProcessor = new ServletProcessor(); 39 servletProcessor.process(request, response); 40 } 41 else { 42 logger.log("send staticResource..."); 43 StaticResourceProcessor staticResourceProcessor = new StaticResourceProcessor(); 44 staticResourceProcessor.process(request, response); 45 } 46 socket.close(); 47 shutdown = request.getUri().equals(SHUTDOWN_COMMAND); 48 } catch (IOException e) { 49 // TODO Auto-generated catch block 50 e.printStackTrace(); 51 } 52 } 53 } 54 }
(二)Request
1 public class Request implements ServletRequest{ 2 3 MyLogger logger = new MyLogger(ServletRequest.class); 4 private String uri; 5 private InputStream in; 6 7 public Request(InputStream in){ 8 this.in = in; 9 } 10 11 public String parseUri(String request){ 12 int index1,index2; 13 index1 = request.indexOf(" "); 14 if (index1 != -1){ 15 index2 = request.indexOf(" ", index1+ 1); 16 if (index1 < index2) 17 return request.substring(index1 + 1, index2); 18 } 19 return null; 20 } 21 22 public void Parse(){ 23 StringBuffer request = new StringBuffer(2048); 24 byte[] bs = new byte[2048]; 25 int i; 26 try { 27 i = in.read(bs); 28 } catch (IOException e) { 29 e.printStackTrace(); 30 i = -1; 31 } 32 33 for(int j=0; j<i; j++){ 34 request.append((char)bs[j]); 35 } 36 37 logger.log(request.toString()); 38 uri = parseUri(request.toString()); 39 if(uri != null) 40 logger.log("uri is " + uri); 41 } 42 43 public String getUri() { 44 return uri; 45 } 46 }
(三)Response
1 public class Response implements ServletResponse{ 2 3 MyLogger logger = new MyLogger(Response.class); 4 private static final int BUFFER_SIZE = 1024; 5 private Request request; 6 private OutputStream out; 7 private PrintWriter writer; 8 9 public Response(OutputStream out) { 10 this.out = out; 11 } 12 13 public void setRequest(Request request) { 14 this.request = request; 15 } 16 //假设请求的是图片资源 17 public void sendStaticResource() throws IOException{ 18 byte[] buffer = new byte[BUFFER_SIZE]; 19 FileInputStream fis = null; 20 File file = new File(Constant.WEB_ROOT, request.getUri()); 21 try { 22 logger.log("Begin read file + " + file.toString()); 23 fis = new FileInputStream(file); 24 String headerMsg = "HTTP/1.1 200 OK " + 25 "Content-Type: image/jpg " + 26 "Content-Length: " + file.length() + " " + 27 " " ; 28 logger.log("headerMsg-> " + headerMsg); 29 out.write(headerMsg.getBytes()); 30 int ch = fis.read(buffer, 0, BUFFER_SIZE); 31 while (ch != -1){ 32 out.write(buffer, 0, BUFFER_SIZE); 33 ch = fis.read(buffer, 0, BUFFER_SIZE); 34 } 35 } catch (FileNotFoundException e) { 36 String html = "<h1>file not found</h1>"; 37 logger.log("FileNotFoundException"); 38 String errorMsg = "HTTP/1.1 404 file not found " + 39 "Content-Type: text/html " + 40 "Content-Length: " + html.getBytes().length + " " + 41 " " + 42 html; 43 out.write(errorMsg.getBytes()); 44 logger.log("errorMsg->" + errorMsg); 45 } 46 finally { 47 if(fis != null){ 48 fis.close(); 49 } 50 } 51 } 52 }
(四)StaticResourceProcessor
1 public class StaticResourceProcessor { 2 public void process(Request request,Response response) { 3 try { 4 response.sendStaticResource(); 5 } catch (IOException e) { 6 e.printStackTrace(); 7 } 8 } 9 }
(五)ServletProcessor
1 public class ServletProcessor { 2 public void process(Request request,Response response){ 3 String uri = request.getUri(); 4 String servletName = uri.substring(uri.lastIndexOf("/") + 1); 5 URLClassLoader loader = null; 6 7 URL[] urls = new URL[1]; 8 URLStreamHandler urlStreamHandler = null; 9 File classPath = new File(Constant.WEB_ROOT); 10 try { 11 String repository = (new URL("file",null,classPath.getCanonicalPath() + 12 File.separator)).toString(); 13 urls[0] = new URL(null,repository,urlStreamHandler); 14 loader = new URLClassLoader(urls); 15 } catch (IOException e) { 16 // TODO Auto-generated catch block 17 e.printStackTrace(); 18 } 19 Class myClass = null; 20 try { 21 myClass = loader.loadClass(servletName); 22 } catch (ClassNotFoundException e) { 23 e.printStackTrace(); 24 } 25 26 Servlet servlet = null; 27 try { 28 servlet = (Servlet) myClass.newInstance(); 29 servlet.service((ServletRequest)request, (ServletResponse) response); 30 31 } catch (InstantiationException | IllegalAccessException e) { 32 // TODO Auto-generated catch block 33 e.printStackTrace(); 34 } catch (ServletException e) { 35 // TODO Auto-generated catch block 36 e.printStackTrace(); 37 } catch (IOException e) { 38 // TODO Auto-generated catch block 39 e.printStackTrace(); 40 } 41 42 } 43 }
(六)MyLogger
1 public class MyLogger<T> { 2 private String classStr = ""; 3 4 public void log(T msg){ 5 System.out.println(classStr + "(" + 6 (new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")).format(new Date()) + ")" + ": " + msg); 7 } 8 public MyLogger(Class classz){ 9 classStr = classz.getName(); 10 } 11 }
(七)PrimitiveServlet
1 public class PrimitiveServlet implements Servlet{ 2 MyLogger Logger = new MyLogger<>(PrimitiveServlet.class); 3 @Override 4 public void destroy() { 5 // TODO Auto-generated method stub 6 7 } 8 9 @Override 10 public ServletConfig getServletConfig() { 11 // TODO Auto-generated method stub 12 return null; 13 } 14 15 @Override 16 public String getServletInfo() { 17 // TODO Auto-generated method stub 18 return null; 19 } 20 21 @Override 22 public void init(ServletConfig arg0) throws ServletException { 23 // TODO Auto-generated method stub 24 25 } 26 27 @Override 28 public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException { 29 Logger.log("service execute....."); 30 PrintWriter writer = response.getWriter(); 31 writer.println("Hey,welcome on board!"); 32 writer.println("lets rock!"); 33 } 34 35 }
(八)Constant
public class Constant { public static final String WEB_ROOT = System.getProperty("user.dir") + File.separator + "bin"; }