写程序一定要有思路,思路很重要!
一、我们分两步第一步先实现手写tomcat,第二部写servlet
所用技术:
1、soket通信 IO流
2、http请求与相应
3、解析xml
4、java反射技术
导入所需要的jar:
<dependencies>
<!-- https://mvnrepository.com/artifact/dom4j/dom4j -->
<dependency>
<groupId>dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>1.6.1</version>
</dependency>
</dependencies>
项目目录结构:
现在开始我们的第一步,手写tomcat
新建 Request 类:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
public class Request {
private String method;
private String url;
public Request(InputStream inputStream) throws IOException {
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
String[] methodAndUrl = bufferedReader.readLine().split(" ");
this.method= methodAndUrl[0];
this.url=methodAndUrl[1];
System.out.println(method);
System.out.println(url);
}
public String getMethod() {
return method;
}
public void setMethod(String method) {
this.method = method;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
}
Response 类:
import java.io.IOException;
import java.io.OutputStream;
public class Response {
public OutputStream outputStream;
public String wirte;
public static final String responseHeader="HTTP/1.1 200 \r\n"
+ "Content-Type: text/html\r\n"
+ "\r\n";
public Response(OutputStream outputStream) throws IOException {
this.outputStream= outputStream;
}
public String getWirte() {
return wirte;
}
public void setWirte(String wirte) {
this.wirte = wirte;
}
}
SocketProcess 类:
import java.io.OutputStream;
import java.net.Socket;
import java.util.Map;
public class SocketProcess extends Thread{
protected Socket socket;
public SocketProcess(Socket socket){
this.socket = socket;
}
@Override
public void run() {
try {
Request request = new Request(socket.getInputStream());
Response response = new Response(socket.getOutputStream());
// Map<String, Object> map = Mytomcat.servletMapping;
//
// System.out.println("map大小为:"+map.size());
// for (Map.Entry<String, Object> entry : map.entrySet()) {
// System.out.println("Key = " + entry.getKey() + ", Value = " + entry.getValue());
// }
//从映射中找
System.out.println(request.getUrl());
String servelName = (String) Mytomcat.servletMapping.get(request.getUrl());
System.out.println(servelName);
if(servelName!=null && !servelName.isEmpty()) {
//映射有的话找到对应的对象
Servelt servlet = (Servelt) Mytomcat.servlet.get(servelName);
if(servlet!=null) {
servlet.doGet(request, response);
}else {
System.out.println("找不到对应的servlet");
}
}else {
System.out.println("找不到对应的servletMapping");
}
String res = Response.responseHeader+response.getWirte();
OutputStream outputStream = socket.getOutputStream();
outputStream.write(res.getBytes("GBK"));
outputStream.flush();
outputStream.close();
}catch (Exception ex){
ex.printStackTrace();
}finally {
if (socket != null) {
try {
socket.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
Mytomcat
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.List;
import org.dom4j.Element;
public class Mytomcat {
private static final int port = 8099;
public static final HashMap<String, Object> servletMapping = new HashMap<String, Object>();
public static final HashMap<String, Object> servlet = new HashMap<String, Object>();
private void init() {
InputStream io = null;
String basePath;
try {
System.out.println("加载配置文件开始");
//读取web.xml
UtilsXml xml = new UtilsXml(UtilsXml.class.getResource("/")+"web.xml");
//讲所有的类都存储到容器中 并且创造对象
List<Element> list = xml.getNodes("servlet");
for (Element element : list) {
servlet.put(element.element("servlet-name").getText(), Class.forName(element.element("servlet-class").getText()).newInstance());
}
//映射关系创建
List<Element> list2 = xml.getNodes("servlet-mapping");
for (Element element : list2) {
servletMapping.put(element.element("url-pattern").getText(), element.element("servlet-name").getText());
}
System.out.println("加载配置文件结束");
} catch (Exception ex) {
ex.printStackTrace();
} finally {
if (io != null) {
try {
io.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
private void start() {
try {
ServerSocket serverSocket = new ServerSocket(port);
System.out.println("Tomcat 服务已启动,地址:localhost ,端口:" + port);
this.init();
//持续监听
do {
Socket socket = serverSocket.accept();
System.out.println(socket);
//处理任务
Thread thread = new SocketProcess(socket);
thread.start();
} while (true);
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
Mytomcat tomcat = new Mytomcat();
tomcat.start();
}
}
UtilsXml:
import java.util.List;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
public class UtilsXml {
//定义解析器和文档对象
public SAXReader saxReader;
public Document document;
public UtilsXml(String path){
//获取解析器
saxReader = new SAXReader();
try {
//获取文档对象
document = saxReader.read(path);
} catch (DocumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* 根据节点名称获取内容
* @param name 节点名称
* @return 节点内容
*/
public String getElementText(String name){
//定位根节点
Element root = document.getRootElement();
List<Element> mapp = root.elements("servlet-mapping");
List<Element> servlet = root.elements("servlet");
String serveltName = "";
String classpath = "";
for (Element e : mapp) {
// System.out.println(e.element("url-pattern").getText());
if(e.element("url-pattern").getText().equals(name)){
serveltName = e.element("servlet-name").getText();
break;
}
}
for (Element e : servlet) {
// System.out.println(e.element("servlet-name").getText());
if(e.element("servlet-name").getText().equals(serveltName)){
classpath = e.element("servlet-class").getText();
break;
}
}
return classpath;
// //根据名称定位节点
// Element element = root.element(name);
// //返回节点内容
// return element.getText();
}
/**
* 获取节点下的所有节点
* @param root
* @param name
* @return
*/
public List<Element> getNodes(String name){
Element root = document.getRootElement();
return root.elements(name);
}
public static void main(String[] args) {
UtilsXml xml = new UtilsXml(UtilsXml.class.getResource("/")+"web.xml");
//System.out.println(xml.getElementText("/myhtml.html"));
List<Element> list = xml.getNodes("servlet");
for (Element element : list) {
System.out.println(element.element("servlet-name").getText() );
System.out.println(element.element("servlet-class").getText() );
}
}
Servelt 抽象类:
import com.siyuan.http.Request;
import com.siyuan.http.Response;
public abstract class Servelt {
public void service(Request request, Response response) {
//判断是调用doget 还是 dopost
if ("get".equalsIgnoreCase(request.getMethod())) {
this.doGet(request, response);
} else {
this.doPost(request, response);
}
}
public abstract void doGet(Request request, Response response);
public abstract void doPost(Request request, Response response);
}
第一个servlet :
import com.siyuan.http.Request;
import com.siyuan.http.Response;
public class MyfisrtServlet extends Servelt {
@Override
public void doGet(Request request, Response response) {
System.out.println("进入了我的第一个servlet");
response.setWirte("进入了第一个servlet");
}
@Override
public void doPost(Request request, Response response) {
}
}
第二个servlet:
import com.siyuan.http.Request;
import com.siyuan.http.Response;
public class ScoendServlet extends Servelt{
@Override
public void doGet(Request request, Response response) {
System.out.println("进入了我的第二个servlet");
response.setWirte("进入了第二个servlet");
}
@Override
public void doPost(Request request, Response response) {
// TODO Auto-generated method stub
}
}
新建web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5">
<servlet>
<servlet-name>myhtml.html</servlet-name>
<servlet-class>com.siyuan.servlet.MyfisrtServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>myhtml.html</servlet-name>
<url-pattern>/myhtml.html</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>myhtml2.html</servlet-name>
<servlet-class>com.siyuan.servlet.ScoendServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>myhtml2.html</servlet-name>
<url-pattern>/myhtml2.html</url-pattern>
</servlet-mapping>
</web-app>
运行效果: