Tomcat对于请求实际上会进行下面的处理:
第一:提供Socket服务
Tomcat的启动,必然是Socket服务,只不过它支持HTTP协议而已!
第二:进行请求的分发
要知道一个Tomcat可以为多个Web应用提供服务,那么很显然,Tomcat可以把URL下发到不同的Web应用。
第三:需要把请求和响应封装成request/response
通过输入流,对HTTP协议进行解析,拿到了HTTP请求头的方法以及URL。
package com.mytomcat; import java.io.IOException; import java.io.InputStream; public class MyRequest { private String url; private String method; public MyRequest() { // TODO Auto-generated constructor stub } // public MyRequest(String url, String method) { // super(); // this.url = url; // this.method = method; // } /** * 通过输入流,对HTTP协议进行解析,拿到HTTP请求头的方法以及URL。 * @param inputStream * @throws IOException */ public MyRequest(InputStream inputStream) throws IOException{ String httpRequest = ""; byte[] httpRequestBytes = new byte[1024]; int length = 0; if((length = inputStream.read(httpRequestBytes)) > 0){ httpRequest = new String(httpRequestBytes, 0, length); } String httpHead = httpRequest.split("\n")[0]; url = httpHead.split("\\s")[1]; method = httpHead.split("\\s")[0]; System.out.println(this); } public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } public String getMethod() { return method; } public void setMethod(String method) { this.method = method; } }基于HTTP协议的格式进行输出写入。
package com.mytomcat; import java.io.IOException; import java.io.OutputStream; public class MyResponse { private OutputStream outputStream; public MyResponse() { // TODO Auto-generated constructor stub } public MyResponse(OutputStream outputStream){ this.outputStream = outputStream; } /** * 基于HTTP协议的格式进行输出写入。 * @param content * @throws IOException */ public void write(String content) throws IOException{ StringBuffer buffer = new StringBuffer(); buffer.append("HTTP/1.1 200 OK\n") .append("Content-type: text/html\n") .append("\r\n") .append("<html><body>") .append(content) .append("</body></html>"); outputStream.write(buffer.toString().getBytes()); outputStream.close(); } }Servlet常见的doGet/doPost/service方法。
package com.mytomcat; public abstract class MyServlet { public abstract void doGet(MyRequest myRequest, MyResponse myResponse); public abstract void doPost(MyRequest myRequest, MyResponse myResponse); public void service(MyRequest myRequest, MyResponse myResponse){ if("POST".equalsIgnoreCase(myRequest.getMethod())){ doPost(myRequest, myResponse); }else if("GET".equalsIgnoreCase(myRequest.getMethod())){ doGet(myRequest, myResponse); } } }以下两个java类做测试用:
package com.mytomcat; import java.io.IOException; public class FindGirlServlet extends MyServlet { @Override public void doGet(MyRequest myRequest, MyResponse myResponse) { // TODO Auto-generated method stub try { myResponse.write("get--------FindGirlServlet"); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } @Override public void doPost(MyRequest myRequest, MyResponse myResponse) { // TODO Auto-generated method stub try { myResponse.write("post-----------FindGirlServlet"); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } package com.mytomcat; import java.io.IOException; public class HelloWorldServlet extends MyServlet { @Override public void doGet(MyRequest myRequest, MyResponse myResponse) { // TODO Auto-generated method stub try { myResponse.write("get--------HelloWorldServlet"); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } @Override public void doPost(MyRequest myRequest, MyResponse myResponse) { // TODO Auto-generated method stub try { myResponse.write("post-----------HelloWorldServlet"); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }web.xml中通过<servlet></servlet>和<servlet-mapping></servlet-mapping>来进行指定哪个URL交给哪个servlet进行处理。
package com.mytomcat; public class ServletMapping { private String servletName; private String url; private String clazz; public ServletMapping() { // TODO Auto-generated constructor stub } public ServletMapping(String servletName, String url, String clazz) { super(); this.servletName = servletName; this.url = url; this.clazz = clazz; } public String getServletName() { return servletName; } public void setServletName(String servletName) { this.servletName = servletName; } public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } public String getClazz() { return clazz; } public void setClazz(String clazz) { this.clazz = clazz; } } package com.mytomcat; import java.util.ArrayList; import java.util.List; /** * web.xml中通过<servlet></servlet>和<servlet-mapping></servlet-mapping> * 来进行指定哪个URL交给哪个servlet进行处理。 * @author kiss * */ public class ServletMappingConfig { public static List<ServletMapping> servletMappings = new ArrayList<ServletMapping>(); static{ servletMappings.add(new ServletMapping("findgirl", "/girl", "com.mytomcat.FindGirlServlet")); servletMappings.add(new ServletMapping("helloworld", "/hellworld", "com.mytomcat.HelloWorldServlet")); } }利用反射实例化具体的Servlet进行处理即可。
package com.mytomcat; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.ServerSocket; import java.net.Socket; import java.util.HashMap; import java.util.Map; public class MyTomcat { private Integer port = 8080; private Map<String, String> urlServletMap = new HashMap<String, String>(); public MyTomcat() { // TODO Auto-generated constructor stub } public MyTomcat(Integer port) { super(); this.port = port; } // public MyTomcat(Integer port, Map<String, String> map) { // super(); // this.port = port; // this.urlServletMap = map; // } /** * 启动mytomcat */ public void start(){ initServletMapping(); ServerSocket serverSocket = null; try { //相当于服务器启动了,并且监听了port serverSocket = new ServerSocket(port); System.out.println("MyTomcat is start-------"); while(true){ //等待客户端 连接port端口 Socket socket = serverSocket.accept(); //获取连接的输入输出流 InputStream inputStream = socket.getInputStream(); OutputStream outputStream = socket.getOutputStream(); MyRequest myRequest = new MyRequest(inputStream); MyResponse myResponse = new MyResponse(outputStream); dispatch(myRequest, myResponse); socket.close(); } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } finally { if(serverSocket != null){ try { serverSocket.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } /** * 初始化url与对应处理的servlet的关系 */ private void initServletMapping(){ for (ServletMapping servletMapping : ServletMappingConfig.servletMappings) { urlServletMap.put(servletMapping.getUrl(), servletMapping.getClazz()); } } /** * 请求分发 * @param myRequest * @param myResponse */ private void dispatch(MyRequest myRequest, MyResponse myResponse){ String clazz = urlServletMap.get(myRequest.getUrl()); try { //反射 @SuppressWarnings("unchecked") Class<MyServlet> myServletClass = (Class<MyServlet>) Class.forName(clazz); MyServlet myServlet = myServletClass.newInstance(); myServlet.service(myRequest, myResponse); } catch (ClassNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InstantiationException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public Integer getPort() { return port; } public void setPort(Integer port) { this.port = port; } }启动mytomcat
目前在浏览器上测试,会有两次连接,后一次连接丢失参数,导致会报空指针异常,还没找到原因。用postman测试工具测试一切正常。