二.一个简单的Servlet容器
一.运行机制
1.Servlet容器:Servlet规范定义了一个API标准,基于这个标准,程序员只需要实现业务逻辑,而无须关心核心逻辑,从而达到任务分工,简化工作量,服务至上的目的
2. 所有的Servlet都实现了一个统一的接口,Servlet接口申明了5个签名方法:
Init(ServletConfig config)
Service(ServletRequest request,ServletResponse response)
Destory( )
getServeltConfig()
getServletInfo()
3. 流程:
- 等待http请求
- 对应的servletRequest对象和servletResponse对象,
- 判断请求的类型,如果是请求静态资源,则找到静态资源的文件,返回给客户端
- 如果是Servlet请求,载入servlet类,调用service()方法,传入servletRequest对象和servletResponse对象
4. 流程图:
5. 这样设计便存在了一个严重的安全问题,容器中Sevice方法中的Sevletrequest参数ServletResponse参数,可以取到里面所有方法,这样一来,所有的参数暴露出来了,很明显,这样是不合适的,所以这里提供了一个解决方案-使用门面模式对Servletrequest和ServletResponse进行传递,这样一来,程序员只能访问固定的方法了,保障程序的健壮性。
6. 流程图:
二.实战代码
1. Constans
package JayKing.ASimpleServlet; import java.io.File; public class Constans { public static final String SHUTDOWN_COMMAND = "/SHUTDOWN"; public static final String WEB_ROOT = System.getProperty("user.dir") + File.separator + "webroot"; public static final String errorMessage = "HTTP/1.1 404 File Not Found\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 23\r\n" + "\r\n" + "<h1>File Not Found</h1>"; }
2. HttpServer
package JayKing.ASimpleServlet; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.InetAddress; import java.net.ServerSocket; import java.net.Socket; public class HttpServer { public static Boolean shutdown = false; public static void main(String[] args) { HttpServer server = new HttpServer(); server.await(); } private void await() { int port = 8080; ServerSocket serversocket = null; try { serversocket = new ServerSocket(port, 100, InetAddress.getByName("localhost")); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } while (!shutdown) { Socket socket = null; InputStream in = null; OutputStream out = null; try { socket = serversocket.accept(); in = socket.getInputStream(); out = socket.getOutputStream(); Request request = new Request(in); request.parse(); Response response = new Response(out); response.setRequset(request); if (request.getUri().startsWith("/servlet/")) { ServletProcessor processor = new ServletProcessor(); processor.process(request, response); } else { System.out.println("Uri:"+request.getUri()); StaticResourceProcessor processor = new StaticResourceProcessor(); processor.process(request, response); } socket.close(); shutdown = request.getUri().equals(Constans.SHUTDOWN_COMMAND); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }
3. Requset
package JayKing.ASimpleServlet; import java.io.IOException; import java.io.InputStream; public class Request implements ServletRequest{ public InputStream in; public String uri; public Request(InputStream in) { this.in = in; } public String getUri() { return uri; } public 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() { StringBuffer request = new StringBuffer(2048); int i; byte[] buffer = new byte[2048]; try { i = in.read(buffer); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); i = -1; } for (int j = 0; j < i; j++) { request.append((char) buffer[j]); } uri = parseUri(request.toString()); } }
4. RequestFacade
package JayKing.ASimpleServlet; public class RequestFacade implements ServletRequest { private ServletRequest resquest; public RequestFacade(Request request) { this.resquest = resquest; } }
5. Rseponse
package JayKing.ASimpleServlet; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.OutputStream; public class Response implements ServletResponse{ public static final int BUFFER_SIZE = 1024; Request request; OutputStream out; public Response(OutputStream out) { this.out = out; } public void setRequset(Request request) { this.request = request; } public void sendStaticRescourse() throws IOException { byte[] bytes = new byte[BUFFER_SIZE]; FileInputStream fis = null; File file = new File(Constans.WEB_ROOT, request.getUri()); try { fis = new FileInputStream(file); int ch = fis.read(bytes, 0, BUFFER_SIZE); while(ch!=-1){ out.write(bytes,0,BUFFER_SIZE); ch=fis.read(bytes,0,BUFFER_SIZE); } } catch (FileNotFoundException e) { out.write(Constans.errorMessage.getBytes()); } catch (IOException e) { e.printStackTrace(); } finally { if (fis!= null) { fis.close(); } } } }
6. ResponseFacade
package JayKing.ASimpleServlet; public class ResponseFacade implements ServletResponse { private ServletResponse response; public ResponseFacade(Response response) { this.response = response; } }
7. Servlet
package JayKing.ASimpleServlet; public interface Servlet { public void init(); public void service(ServletRequest servletrequest,ServletResponse servletresposne); public void destory(); }
8. ServletProcessor
package JayKing.ASimpleServlet; import java.io.File; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; import java.net.URLStreamHandler; public class ServletProcessor { public void process(Request request, Response response) { String uri = request.getUri(); String ServletName = uri.substring(uri.lastIndexOf("/") + 1); ClassLoader classloader = null; Class myClass = null; String repository = null; URLClassLoader loader = null; URL[] urls = new URL[1]; URLStreamHandler streamhandler = null; File classPath = new File(Constans.WEB_ROOT); try { repository = (new URL("file", null, classPath.getCanonicalPath() + File.separator)).toString(); urls[0] = new URL(null, repository, streamhandler); loader = new URLClassLoader(urls); myClass = loader.loadClass(ServletName); } catch (MalformedURLException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } catch (IOException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } catch (ClassNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } Servlet servlet = null; RequestFacade requestFacade = new RequestFacade(request); ResponseFacade responseFacade = new ResponseFacade(response); try { servlet = (Servlet) myClass.newInstance(); servlet.service((ServletRequest) requestFacade, (ServletResponse) responseFacade); } catch (InstantiationException | IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
9. ServletRequest
package JayKing.ASimpleServlet; public interface ServletRequest { }
10. ServletResponse
package JayKing.ASimpleServlet; public interface ServletResponse { }
11. StaticResponseProcessor
package JayKing.ASimpleServlet; import java.io.IOException; public class StaticResourceProcessor { public void process(Request request,Response response){ try { response.sendStaticRescourse(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
三.运行程序
静态资源:打开浏览器在地址栏中输入URL:Http://localhost:8080/index.html
Servlet资源:打开浏览器在地址栏中输入URL:Http://localhost:8080/Servlet/MyServlet