手写一个民用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 byte[BUFFER_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 byte[2048];

try {

i = input.read(buffer);

} catch (IOException e) {

e.printStackTrace();

i = -1;

}

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

request.append((char) buffer[j]);

}

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 URL[1];

URLStreamHandler streamHandler = null;

File classPath = new File(JxdHttpServer.WEB_ROOT);

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

urls[0] = 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();

}

}

相关推荐
Themberfue11 分钟前
基础算法之双指针--Java实现(下)--LeetCode题解:有效三角形的个数-查找总价格为目标值的两个商品-三数之和-四数之和
java·开发语言·学习·算法·leetcode·双指针
深山夕照深秋雨mo20 分钟前
在Java中操作Redis
java·开发语言·redis
努力的布布26 分钟前
SpringMVC源码-AbstractHandlerMethodMapping处理器映射器将@Controller修饰类方法存储到处理器映射器
java·后端·spring
xujinwei_gingko26 分钟前
Spring MVC 常用注解
java·spring·mvc
PacosonSWJTU31 分钟前
spring揭秘25-springmvc03-其他组件(文件上传+拦截器+处理器适配器+异常统一处理)
java·后端·springmvc
PacosonSWJTU32 分钟前
spring揭秘26-springmvc06-springmvc注解驱动的web应用
java·spring·springmvc
原野心存1 小时前
java基础进阶——继承、多态、异常捕获(2)
java·java基础知识·java代码审计
进阶的架构师1 小时前
互联网Java工程师面试题及答案整理(2024年最新版)
java·开发语言
黄俊懿1 小时前
【深入理解SpringCloud微服务】手写实现各种限流算法——固定时间窗、滑动时间窗、令牌桶算法、漏桶算法
java·后端·算法·spring cloud·微服务·架构
sp_wxf1 小时前
Stream流
linux·服务器·windows