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();
}
}