1.为什么需要写一个tomcat
掌握Java Web应用程序的部署和管理技能。作为一名Java开发人员,我们需要将Java Web应用程序部署到Web服务器上进行运行和测试。掌握Tomcat的使用方法可以帮助我们更好地进行Java Web应用程序的部署和管理。
理解Web服务器的工作原理和技术架构。Tomcat作为一款Web服务器,它对于Java Web应用程序的运行有着重要的作用。学习Tomcat可以让我们更深入地理解Web服务器的工作原理和技术架构,这对于我们进行Web开发有着非常重要的意义。
学习Java Web应用程序的性能优化和调试技巧。在Java Web应用程序的开发过程中,我们经常需要对程序进行性能优化和调试。学习Tomcat可以帮助我们更好地掌握Java Web应用程序的性能优化和调试技巧,从而提高程序的运行效率和稳定性。
2.项目结构
3.效果演示
访问已存在的页面,这里举例说明用的是index.html
访问不存在的页面时,自动跳转到error.html页面
上述实现主要通过判断浏览器所请求的url中获取到请求信息,然后再进行判断请求信息在项目中是否存在,存在则进行响应,不存在则进行返回error.html
4.代码展示
4.1 Tomcat类
public class Tomcat {
public static void start() {
MyServer myServer = new MyServer();
myServer.receive();
}
public static void main(String[] args) {
System.out.println("Server startup successfully");
Tomcat.start();
}
}
该文件主要的作用就是调用MyServer 中的receive方法进行启动自定义tomcat。
4.2 MyServer类
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class MyServer {
// 端口
private int port = 8080;
//接受浏览器请求方法
public void receive() {
try {
// 绑定相对应的端口信息
ServerSocket serverSocket = new ServerSocket(port);
while (true) {
Socket socket = serverSocket.accept();
InputStream inputStream = socket.getInputStream();
OutputStream outputStream = socket.getOutputStream();
MyHttpRequest myHttpRequest = new MyHttpRequest(inputStream);
myHttpRequest.parse();
// 获取到请求路径
String url = myHttpRequest.getUrl();
System.out.println(url);
// 判断请求路径中的数据是否存在
MyHttpResponse response = new MyHttpResponse(outputStream);
// 自己写一个成功的响应头
String successHeader = "HTTP/1.1 200 OK\r\n" +
"Content-Type: text/html\r\n" +
"\r\n";
outputStream.write(successHeader.getBytes());
response.response(url);
outputStream.flush();
outputStream.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
该类中主要就是定义Socket并绑定了相对应的端口(这里用的是8080端口),接受请求,并解析请求,响应请求头和数据。
4.3 MyHttpRequest类
import java.io.IOException;
import java.io.InputStream;
public class MyHttpRequest {
private InputStream inputStream;
private String url;
public MyHttpRequest() {
}
public MyHttpRequest(InputStream inputStream) {
this.inputStream = inputStream;
}
public MyHttpRequest(InputStream inputStream, String url) {
this.inputStream = inputStream;
this.url = url;
}
/**
* 获取
* @return inputStream
*/
public InputStream getInputStream() {
return inputStream;
}
/**
* 设置
* @param inputStream
*/
public void setInputStream(InputStream inputStream) {
this.inputStream = inputStream;
}
public String toString() {
return "MyHttpRequest{inputStream = " + inputStream + "}";
}
public void parse(){
byte[] bytes = new byte[1024];
try {
inputStream.read(bytes);
String string = new String(bytes);
String s = string.split(" ")[1];
System.out.println(s);
url = s;
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 获取
* @return url
*/
public String getUrl() {
return url;
}
/**
* 设置
* @param url
*/
public void setUrl(String url) {
this.url = url;
}
}
该类主要的作用就是解析请求信息,返回资源信息的路径,通过多次调试查看其获取的请求资源中的信息,后通过split获取到了请求资源的路径信息。
4.4 MyHttpResponse类
import java.io.*;
public class MyHttpResponse {
private OutputStream outputStream;
private String url;
private byte[] bytes = new byte[1024];
public MyHttpResponse() {
}
public MyHttpResponse(OutputStream outputStream) {
this.outputStream = outputStream;
}
/**
* 获取
*
* @return outputStream
*/
public OutputStream getOutputStream() {
return this.outputStream;
}
/**
* 设置
*
* @param outputStream
*/
public void setOutputStream(OutputStream outputStream) {
this.outputStream = outputStream;
}
public String toString() {
return "MyHttpResponse{outputStream = " + outputStream + "}";
}
public void response(String url) throws IOException {
// 判断url是否存在
System.out.println(System.getProperty("user.dir") + "/WebContent" + url);
File urlFile = new File(System.getProperty("user.dir") + "/WebContent" + url);
System.out.println("访问页面是否存在:" + urlFile.exists());
if (urlFile.exists()) {
System.out.println();
FileInputStream inputStream = new FileInputStream(urlFile);
int len = 0;
System.out.println("开始响应...");
while ((len = inputStream.read(bytes)) != -1) {
getOutputStream().write(bytes, 0, len);
}
System.out.println("响应完成...");
} else {
// 判断url是否存在
System.out.println("开始响应...");
File errorFileUrl = new File(System.getProperty("user.dir") + "/WebContent" + "/error.html");
FileInputStream errorFileInputStream = new FileInputStream(errorFileUrl);
errorFileInputStream.read(bytes);
getOutputStream().write(bytes, 0, 1024);
System.out.println("响应完成...");
}
}
public static void main(String[] args) throws IOException {
MyHttpResponse response = new MyHttpResponse();
response.response("/index.html");
}
/**
* 获取
*
* @return url
*/
public String getUrl() {
return url;
}
/**
* 设置
*
* @param url
*/
public void setUrl(String url) {
this.url = url;
}
/**
* 获取
*
* @return bytes
*/
public byte[] getBytes() {
return bytes;
}
/**
* 设置
*
* @param bytes
*/
public void setBytes(byte[] bytes) {
this.bytes = bytes;
}
}
该类中根据前文获取到的请求资源的路径信息,然后判断特定目录下是否存在该资源文件,若存在通过输入输出流,进行响应到浏览器,这里注意需要先响应请求头数据。若不存在,则响应错误页面到浏览器。
5.总结
手写一个Tomcat是一项非常复杂的任务,需要涉及到很多Java Web开发的知识和技术。下面是一个简单的手写Tomcat的总结:
-
理解Servlet规范:Tomcat实现了Servlet规范,因此我们需要了解Servlet规范的相关知识,包括Servlet接口、Servlet生命周期、请求响应流程等。
-
创建ServerSocket:Tomcat需要监听HTTP请求,因此我们需要创建一个ServerSocket对象,并设置端口号和最大连接数等参数。
-
解析HTTP请求:当有客户端发送HTTP请求时,我们需要解析请求头和请求体,获取请求方法、请求路径、请求参数等信息。
-
查找对应的Servlet:根据请求路径,我们需要查找对应的Servlet对象,如果没有找到,则返回404错误。
-
调用Servlet的service方法:找到对应的Servlet对象后,我们需要调用其service方法,处理请求并生成响应。
-
构造HTTP响应:在处理完请求后,我们需要根据响应内容,构造HTTP响应头和响应体,并将其返回客户端。
-
关闭Socket连接:当请求响应完成后,我们需要关闭Socket连接,释放资源。
总之,手写Tomcat是一项非常复杂的任务,需要掌握Java Web开发的相关知识和技术,包括Socket编程、HTTP协议、Servlet规范等。同时,也需要有耐心和细心,对每一个细节进行精细的调试和优化,才能实现一个高质量的Tomcat。
说说我本次实验中遇到的错误吧,就是成员变量与静态变量之间关系有点糊涂,一开始因为设置了成员变量类之间无法进行共享变量,还有就是进行响应页面时,没有设置请求头信息无法获取到资源信息,总的来说学习还是不错的。