先理思路
开启监听-> 接受请求-> 拿到request 和response ->分发请求到相应的servlet->执行
开始动手
从包来看
这个手写是完全模拟了servlet一整套的流程
MyRequest
request需要一个输入流 得到请求信息 封装好 这个mini版本是基于http协议 拿到method和path就可以了
public class MyRequest {
private String method;
private String path;
//这里的资源交给外层关闭
public MyRequest(InputStream inputStream) throws IOException {
String content = "";
byte[] buff = new byte[1024];
int len;
if((len =inputStream.read(buff))!=-1){
content = new String(buff,0,len);
}
//第一行是请求方式
String line1 = content.split("\\n")[0];
String[] s = line1.split(" ");
method = s[0];
path = s[1];
System.out.println(content);
}
public String getMethod() {
return method;
}
public String getPath() {
return path;
}
}
打印一下接受的字符串信息 可以自行对应
MyResponse
public class MyResponse {
private OutputStream outputStream;
public MyResponse(OutputStream outputStream) {
this.outputStream = outputStream;
}
public void write(String str) {
//http协议需要返回一些信息 否则看不到
StringBuilder sb = new StringBuilder();
sb.append("HTTP/1.1 200 OK\n")
.append("Content-Type: text/html\n")
.append("\r\n")
.append("<html><body>")
.append(str)
.append("</body></html>");
try {
outputStream.write(sb.toString().getBytes());
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
Servlet
简单的一个抽象类 当然接口也可以 不影响,
生命周期相关
public abstract class Servlet {
public abstract void init();
public abstract void destroy();
}
HttpServlet
同servlet 其实也可以是接口 只是我都写成了抽象类…
public abstract class HttpServlet {
public abstract void service(MyRequest request, MyResponse response);
public abstract void doPost(MyRequest request, MyResponse response);
public abstract void doGet(MyRequest request, MyResponse response);
}
MyServlet
自定义一个servlet 用于生命周期的内容
public class MyServlet extends Servlet {
@Override
public void init() {
System.out.println("初始化成功");
}
@Override
public void destroy() {
System.out.println("tomcat销毁了");
}
}
MyHttpServlet
自定义HttpServlet 用于处理请求
public class MyHttpServlet extends HttpServlet {
@Override
public void service(MyRequest request, MyResponse response) {
if ("get".equalsIgnoreCase(request.getMethod())) {
doGet(request,response);
}else{
doPost(request,response);
}
}
@Override
public void doPost(MyRequest request, MyResponse response) {
response.write("this is servlet do post");
}
@Override
public void doGet(MyRequest request, MyResponse response) {
response.write("this is servlet do get");
}
}
MyHttpServlet1
再自定义一个servlet 因为正式环境是可以配置多个的
public class MyHttpServlet1 extends HttpServlet {
@Override
public void service(MyRequest request, MyResponse response) {
if ("get".equalsIgnoreCase(request.getMethod())) {
doGet(request,response);
}else{
doPost(request,response);
}
}
@Override
public void doPost(MyRequest request, MyResponse response) {
response.write("this is servlet1 do post");
}
@Override
public void doGet(MyRequest request, MyResponse response) {
response.write("this is servlet1 do get");
}
}
web.properties
替代web.xml 反正就是配置请求和处理的servlet信息 形式不重要
url=/servletTest
className=tomcat.MyHttpServlet
url1=/servletTest1
className1=tomcat.MyHttpServlet1
servlet=tomcat.servlet.MyServlet
Tomcat
核心类 不多废话上代码
public class Tomcat {
private int port = 8080;
private ServerSocket server;
private Map<String, HttpServlet> servletMap = new HashMap<>();
private Properties xml = new Properties();
private Servlet servlet;
public void init() {
//初始化 读取配置 并把请求和处理器的映射情况对应起来
String webInfo = this.getClass().getResource("/").getPath();
try (FileInputStream fis = new FileInputStream(webInfo + "web.properties")) {
xml.load(fis);
server = new ServerSocket(port);
//这里映射就简单写死 毕竟是mini版本
String url = xml.get("url").toString();
String url1 = xml.get("url1").toString();
String className = xml.get("className").toString();
String className1 = xml.get("className1").toString();
String servletName = xml.get("servlet").toString();
HttpServlet servlet = (HttpServlet) Class.forName(className).newInstance();
HttpServlet servlet1 = (HttpServlet) Class.forName(className1).newInstance();
this.servlet = (Servlet) Class.forName(servletName).newInstance();
this.servlet.init();
//实例化之后放在map中
servletMap.put(url, servlet);
servletMap.put(url1, servlet1);
} catch (Exception e) {
e.printStackTrace();
}
}
public void start() {
InputStream inputStream = null;
try {
init();
while (true) {
Socket accept = server.accept();
inputStream = accept.getInputStream();
OutputStream outputStream = accept.getOutputStream();
MyRequest request = new MyRequest(inputStream);
MyResponse response = new MyResponse(outputStream);
//如果这个请求有映射 那就进入相应的位置 如果没有就不处理
//这个位置可以根据需求自由分配 也可以添加过滤器之类的东西
//我这里就写了一个简单版本的
if(servletMap.containsKey(request.getPath())){
HttpServlet servlet = servletMap.get(request.getPath());
servlet.service(request,response);
}
}
}catch (Exception e){
e.printStackTrace();
}finally {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
Tomcat tomcat = new Tomcat();
tomcat.start();
}
}
最后得到了相应的内容: