手写一个民用Tomcat (02)

01 我们已经完成了 基本玩具一样的Tomcat,可以实现这个功能,下面我们在规范一下

先从我们的JxdResponse ,JxdRequest 分别实现ServletRequest ,和ServletResponse

注意下 没有用的到 重写方法我就 直接去掉了,你自己可以在代码中实现以下

public class JxdResponse implements ServletResponse{

private static final int BUFFER_SIZE = 1024;

JxdRequest request;

OutputStream output;

PrintWriter writer;

String contentType = null;

long contentLength = -1;

String charset = null;

String characterEncoding = null;

public OutputStream getOutput() {

return output;

}

public void setOutput(OutputStream output) {

this.output = output;

}

public JxdResponse(OutputStream output) {

this.output = output;

}

public void setRequest(JxdRequest request) {

this.request = request;

}

/**

* 这个方法是静态方法演示

* @throws IOException

*/

public void sendStaticResource() throws IOException {

byte\[\] bytes = new byteBUFFER_SIZE;

FileInputStream fis = null;

try {

File file = new File(JxdHttpServer.FILE_ROOT, request.getUri());

if (file.exists()) {

fis = new FileInputStream(file);

int ch = fis.read(bytes, 0, BUFFER_SIZE);

while (ch != -1) {

output.write(bytes, 0, ch);

ch = fis.read(bytes, 0, BUFFER_SIZE);

}

output.flush();

} else {

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>error未知</h1>";

output.write(errorMessage.getBytes());

}

} catch (Exception e) {

System.out.println(e.toString());

} finally {

if(fis != null) {

fis.close();

}

}

}

@Override

public PrintWriter getWriter() throws IOException {

writer = new PrintWriter(new OutputStreamWriter(output,getCharacterEncoding()), true);

return writer;

}

@Override

public String getCharacterEncoding() {

return characterEncoding;

}

@Override

public void setCharacterEncoding(String characterEncoding) {

this.characterEncoding = characterEncoding;

}

@O

}

import javax.servlet.*;

import java.io.BufferedReader;

import java.io.IOException;

import java.io.InputStream;

import java.io.UnsupportedEncodingException;

import java.util.Enumeration;

import java.util.Locale;

import java.util.Map;

public class JxdRequest implements ServletRequest {

private InputStream input;

private String uri;

public JxdRequest(InputStream input) {

this.input = input;

}

public void parse() {

StringBuffer request = new StringBuffer(2048);

int i;

byte\[\] buffer = new byte2048;

try {

i = input.read(buffer);

} catch (IOException e) {

e.printStackTrace();

i = -1;

}

for (int j = 0; j < i; j++) {

request.append((char) bufferj);

}

uri = parseUri(request.toString());

}

private static 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 String getUri() {

return uri;

}

@Override

public ServletInputStream getInputStream() throws IOException {

return null;

}

@Override

public BufferedReader getReader() throws IOException {

return null;

}

}

JxdHttpConnector 实现Runnable 接口

import java.io.IOException;

import java.net.InetAddress;

import java.net.ServerSocket;

import java.net.Socket;

public class JxdHttpConnector implements Runnable {

@Override

public void run() {

ServerSocket serverSocket = null;

int port = 8080;

try {

serverSocket = new ServerSocket(port, 1, InetAddress.getByName("127.0.0.1"));

} catch (IOException e) {

e.printStackTrace();

System.exit(1);

}

while (true) {

Socket socket = null;

try {

socket = serverSocket.accept();

//交给HttpProcessor 处理

JxdHttpProcessor processor = new JxdHttpProcessor();

processor.process(socket);

//交给HttpProcessor 完成 关闭

socket.close();

} catch (Exception e) {

e.printStackTrace();

}

}

}

public void start() {

Thread thread = new Thread(this);

thread.start();

}

}

JxdHttpProcessor 处理方法 没太大变化

import org.apache.commons.lang.text.StrSubstitutor;

import javax.servlet.Servlet;

import java.io.*;

import java.net.*;

import java.time.ZonedDateTime;

import java.time.format.DateTimeFormatter;

import java.util.HashMap;

import java.util.Map;

public class JxdHttpProcessor {

public void process(Socket socket) { //服务器循环等待请求并处理

while (true) {

InputStream input = null;

OutputStream output = null;

try {

input = socket.getInputStream();

output = socket.getOutputStream();

// create Request object and parse

JxdRequest request = new JxdRequest(input);

request.parse();

// create Response object

JxdResponse response = new JxdResponse(output);

if (request.getUri().startsWith("/servlet/")) {

//加载动态资源

JxdServletProcessor jxdServletProcessor = new JxdServletProcessor();

jxdServletProcessor.process(request, response);

} else {

//加载静态资源

StaticResourceProcessor staticResourceProcessor = new StaticResourceProcessor();

staticResourceProcessor.process(request, response);

}

} catch (Exception ea) {

ea.printStackTrace();

}

}

}

}

import org.apache.commons.lang.text.StrSubstitutor;

import javax.servlet.Servlet;

import java.io.*;

import java.net.*;

import java.time.ZonedDateTime;

import java.time.format.DateTimeFormatter;

import java.util.HashMap;

import java.util.Map;

public class JxdServletProcessor {

//根据HTTP协议响应头定义,里面包含变量

private static String OKMessage = "HTTP/1.1 {StatusCode} {StatusName}\r\n" +

"Content-Type: ${ContentType}\r\n" +

"Server: minit\r\n" +

"Date: ${ZonedDateTime}\r\n" +

"\r\n";

public void process(JxdRequest request, JxdResponse response) {

//首先根据uri最后一个/号来定位,后面的字符串认为是servlet名字

String uri = request.getUri();

String servletName = uri.substring(uri.lastIndexOf("/") + 1);

URLClassLoader loader = null;

PrintWriter printWriter =null;

try {

// create a URLClassLoader

URL\[\] urls = new URL1;

URLStreamHandler streamHandler = null;

File classPath = new File(JxdHttpServer.WEB_ROOT);

String repository = (new URL("file", null, classPath.getCanonicalPath() + File.separator)).toString();

urls0 = new URL(null, repository, streamHandler);

loader = new URLClassLoader(urls);

} catch (IOException e) {

System.out.println(e.toString());

}

//由上面的URLClassLoader加载这个servlet

Class<?> servletClass = null;

try {

//获取PrintWriter

response.setCharacterEncoding("UTF-8");

printWriter = response.getWriter();

servletClass = loader.loadClass(servletName);

} catch (ClassNotFoundException | IOException e) {

System.out.println(e.toString());

}

//创建servlet新实例,然后调用

// service(),由它来写动态内容到响应体

Servlet servlet = null;

try {

//写响应头

String head = composeResponseHead();

printWriter.println(head);

servlet = (Servlet) servletClass.newInstance();

servlet.service(request, response);

} catch (Exception e) {

System.out.println(e.toString());

} catch (Throwable e) {

System.out.println(e.toString());

}

}

//生成响应头,填充变量值

private String composeResponseHead() {

Map<String, Object> valuesMap = new HashMap<>();

valuesMap.put("StatusCode", "200");

valuesMap.put("StatusName", "OK");

valuesMap.put("ContentType", "text/html;charset=UTF-8");

valuesMap.put("ZonedDateTime", DateTimeFormatter.ISO_ZONED_DATE_TIME.format(ZonedDateTime.now()));

StrSubstitutor sub = new StrSubstitutor(valuesMap);

String responseHead = sub.replace(OKMessage);

return responseHead;

}

}

最后看一下实现类 helloWorld 实现规范的Servlet ,没必要的方法不展示,

import javax.servlet.*;

import java.io.IOException;

public class HelloWorldServlet implements Servlet {

//http://localhost:8080/servlet/com.yixin.HelloWorldServlet

@Override

public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {

servletResponse.setCharacterEncoding("UTF-8");

System.out.println("进入>>>>>>HelloWorldServlet.service方法");

String doc = "Hello World !!!";

String doc1 = "Happy Day!!!";

servletResponse.getWriter().println(doc);

servletResponse.getWriter().println(doc1);

}

}

运行一下就可以了

public class JxdHttpServer {

public static final String WEB_ROOT = System.getProperty("user.dir");

public static final String FILE_ROOT = "D:\\";

public static void main(String\[\] args) {

JxdHttpConnector connector = new JxdHttpConnector();

connector.start();

}

}

相关推荐
ShirleyWang0122 分钟前
DAY01 K3s 私有化部署排障复盘与 SOP
linux·服务器·k8s·k3s·企业部署
野生风长4 分钟前
c++类和对象(this指针,重载operator,习题总结)
java·开发语言·c++
●VON8 分钟前
鸿蒙 PC Markdown 编辑器搜索选项响应式布局:220 vp 侧栏中的完整中文控件
服务器·华为·编辑器·harmonyos·鸿蒙
霸道流氓气质13 分钟前
基于 Spring 事务同步机制的事务后置动作收集器 Starter 实践
java·后端·spring
过期动态19 分钟前
【LeetCode 热题 100】找到字符串中所有字母异位词
java·数据结构·算法·leetcode·职场和发展·rabbitmq
AbandonForce21 分钟前
Linux进程(WHAT HOW)
linux·运维·服务器
静默追光26 分钟前
服务器——看门狗
linux·运维·服务器
nVisual35 分钟前
巡检任务与工单闭环方案
运维·服务器·数据库·数据中心基础设施
刘小八1 小时前
Spring AI Tool Calling 生产化:参数校验、权限控制与超时隔离
java·人工智能·spring
奶糖 肥晨1 小时前
一次Spring Boot编译报错排查:三元运算符与包装类型的“隐形陷阱”
java·spring boot·后端