手动实现一个简易版 tomcat(yet)
Posted 无
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了手动实现一个简易版 tomcat(yet)相关的知识,希望对你有一定的参考价值。
https://mp.weixin.qq.com/s?__biz=MzA5MzcxNjY4Ng==&mid=2648107477&idx=1&sn=237afdcd8dc67f3a36aac8a38fcaada9&chksm=887be074bf0c69627659d3f076420ba7d477bc08405437eafe4d99ed22e6d2f9a53c80a73d87&mpshare=1&scene=1&srcid=0606qoAMsGtii5eGzil3h35x&key=abc5240e014eede13ee3b36db10a8651176fd1ff480250a3b2660676db6e3a4f4c0857207a64f65dbafc7c5276b2d8e8375d9a65c25572ed6df33fa45995f85c0fc5588801f2def497593ae43d6347d5&ascene=0&uin=MTA2NzUxMDAyNQ%3D%3D&devicetype=iMac+MacBookAir6%2C2+OSX+OSX+10.10.5+build(14F2511)&version=11020012&lang=zh_CN&pass_ticket=mxEo2xKCtH9iR2PLbxrAcJSXJ7pfbLGSU5PqNtNoXLtIgAf3or95FesHIZkUX27e
tomcat简介
Tomcat是Apache 软件基金会(Apache Software Foundation)的Jakarta 项目中的一个核心项目,由Apache、Sun 和其他一些公司及个人共同开发而成。由于有了Sun 的参与和支持,最新的Servlet 和JSP 规范总是能在Tomcat 中得到体现,Tomcat 5支持最新的Servlet 2.4 和JSP 2.0 规范。因为Tomcat 技术先进、性能稳定,而且免费,因而深受Java 爱好者的喜爱并得到了部分软件开发商的认可,成为目前比较流行的Web 应用服务器。
2手动实现
项目结构如下图所示
接下来我们就开始一步步实现,有servlet开发经验的对于Request和Response一定不陌生,所以就先实现自己的Request和Response。首先实现Response如下所示。
package com.duomeng.tomcat;
import java.io.IOException;
import java.io.InputStream;
/**
*
*/
public class MyRequest {
private String url;
private String method;
public MyRequest(InputStream inputStream) throws IOException {
StringBuilder httpRequest = new StringBuilder();
byte[] httpRequestByte = new byte[1014];
int length = 0;
if ((length = inputStream.read(httpRequestByte)) > 0) {
httpRequest.append(new String(httpRequestByte,0,length));
}
System.out.println("httpRequest = [" + httpRequest + "]");
/**
GET /student HTTP/1.1
Host: localhost:8080
Connection: keep-alive
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (Khtml, like Gecko) Chrome/66.0.3359.181 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,
*/
String httpHead = httpRequest.toString().split("
")[0];
url = httpHead.split("\s")[1];
method = httpHead.split("\s")[0];
System.out.println("MyRequests = [" + 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;
}
}
接着来实现自己的Reponse,如下图所示。
package com.duomeng.tomcat;
import java.io.IOException;
import java.io.OutputStream;
public class MyResponse {
private OutputStream outputStream;
public MyResponse(OutputStream outputStream) {
this.outputStream = outputStream;
}
public void write(String content) throws IOException {
/**
* HTTP/1.1 200 OK
Content-type:text/html
*/
StringBuffer stringBuffer = new StringBuffer();
stringBuffer.append("HTTP/1.1 200 OK
")
.append("Content-type:text/html
")
.append("
")
.append("<html><head><title>Hello World</title></head><body>")
.append(content)
.append("</body><html>");
outputStream.write(stringBuffer .toString().getBytes());
outputStream.close();
}
}
有了自己的请求信息和响应信息,那接下来就要写servlet了。通常写自己的Servlet的时候要继承一个Servlet的父类HttpServlet,所以首先要写一个Servlet的父类,代码如下。
package com.duomeng.tomcat;
public abstract class MyServlet {
protected abstract void doGet(MyRequest request,MyResponse response);
protected abstract void doPost(MyRequest request,MyResponse response);
public void service(MyRequest request,MyResponse response) throws NoSuchMethodException {
if (request.getMethod().equalsIgnoreCase("POST")) {
doPost(request,response);
}else if(request.getMethod().equalsIgnoreCase("GET")){
doGet(request,response);
}else {
throw new NoSuchMethodException("not support");
}
}
}
那么接下来就要写自己业务相关的Servlet,这里写一个和学生相关的Servlet,叫StudentServlet,还有一个和老师相关的Servlet,叫TeacherServlet。具体的代码分别如下。
package com.duomeng.tomcat;
import java.io.IOException;
public class StudentServlet extends MyServlet{
@Override
protected void doGet(MyRequest request, MyResponse response) {
try {
response.write("I am a student.");
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
protected void doPost(MyRequest request, MyResponse response) {
try {
response.write("I am a student.");
} catch (IOException e) {
e.printStackTrace();
}
}
}
和老师相关的Servlet如下:
package com.duomeng.tomcat;
import java.io.IOException;
public class TeacherServlet extends MyServlet{
@Override
protected void doGet(MyRequest request, MyResponse response) {
try {
response.write("I am a treacher.");
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
protected void doPost(MyRequest request, MyResponse response) {
try {
response.write("I am a treacher.");
} catch (IOException e) {
e.printStackTrace();
}
}
}
因为浏览器在请求的时候还会请求浏览器上面显示的favicon.ico,所以要编写一个相关的servlet来处理请求,代码如下。
package com.duomeng.tomcat;
import java.io.IOException;
public class FaviconServlet extends MyServlet{
@Override
protected void doGet(MyRequest request, MyResponse response) {
try {
response.write("Favicon");
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
protected void doPost(MyRequest request, MyResponse response) {
try {
response.write("Favicon");
} catch (IOException e) {
e.printStackTrace();
}
}
}
以上就是写的跟具体实际当中业务相关的代码,还记得在Servlet的时候要在项目web.xml中配置请求地址和具体的servlet的映射关系,所以此处要手动来实现一个映射的关系。具体代码如下。
package com.duomeng.tomcat;
public class ServletMapping {
private String servletName;
private String url;
private String clazz;
public ServletMapping(String servletName, String url, String clazz) {
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;
}
}
以上是每个具体的Servlet的信息,接下来要写一个存储有映射关系的类,代码如下。
package com.duomeng.tomcat;
import java.util.ArrayList;
import java.util.List;
public class ServletMappingConfig {
public static List<ServletMapping> servletMappings = new ArrayList<ServletMapping>(16);
static {
servletMappings.add(new ServletMapping("student","/student","com.duomeng.tomcat.StudentServlet"));
servletMappings.add(new ServletMapping("teacher","/teacher","com.duomeng.tomcat.TeacherServlet"));
servletMappings.add(new ServletMapping("favicon","/favicon.ico","com.duomeng.tomcat.FaviconServlet"));
}
}
接下来就是真正的主角登场了,那就是对于请求做分发处理的相关逻辑了,具体代码如下所示。
package com.duomeng.tomcat;
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 int port = 8080;
private Map<String,String> urlServletMap = new HashMap<String, String>(16);
public MyTomcat(int port) {
this.port = port;
}
public void start(){
//初始化请求映射关系
initServletMapping();
ServerSocket serverSocket = null;
try {
serverSocket = new ServerSocket(port);
System.out.println("My tomcat begin start");
while (true){
Socket socket = serverSocket.accept();
InputStream inputStream = socket.getInputStream();
OutputStream outputStream = socket.getOutputStream();
MyRequest request = new MyRequest(inputStream);
MyResponse response = new MyResponse(outputStream);
//分发请求
dispatch(request,response);
socket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
private void initServletMapping(){
for (ServletMapping servletMapping:ServletMappingConfig.servletMappings) {
urlServletMap.put(servletMapping.getUrl(),servletMapping.getClazz());
}
}
private void dispatch(MyRequest request,MyResponse response){
String clazz = urlServletMap.get(request.getUrl());
try {
Class servletClass = Class.forName(clazz);
MyServlet myServlet = (MyServlet)servletClass.newInstance();
myServlet.service(request,response);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
new MyTomcat(8080).start();
}
}
如果没有问题的话,启动main函数之后,在浏览器发起具体的请求会看到如下显示内容。
以上是关于手动实现一个简易版 tomcat(yet)的主要内容,如果未能解决你的问题,请参考以下文章
Kotlin学习之旅解决错误:kotlin.NotImplementedError: An operation is not implemented: Not yet implemented(代码片段