上一篇文章我们实现了Http请求与响应,封装了Request与Response对象。这篇文章我们来实现Tomcat服务器的核心功能,web.xml读取,映射,页面跳转等功能。
web.xml文件定义如下:
一、读取web.xml文件
读取xml文件的方式有很多,有DOM,SAX,Stax等。这里采用的是SAX读取方式。
二、提取标签信息
将servlet标签和servlet-mapping标签以及子标签提取出来并存储到Mapping和Entity中
Entity源码:
package org.wrf.httpServer.server.core;
/**
* <servlet>
<servlet-name>login</servlet-name>
<servlet-class>com.shsxt.server.LoginServlet</servlet-class>
</servlet>
* Copyright © 2019 WRF. All rights reserved.
* 功能描述:
* @Package: org.wrf.httpServer.servlet
* @author: knight
* @date: 2019年3月26日 下午7:36:58
*/
public class Entity {
private String name;
private String clz;
public Entity() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getClz() {
return clz;
}
public void setClz(String clz) {
this.clz = clz;
}
@Override
public String toString() {
return "Entity [name=" + name + ", clz=" + clz + "]";
}
}
Mapping源码:
package org.wrf.httpServer.server.core;
import java.util.HashSet;
import java.util.Set;
/**
*<servlet-mapping>
<servlet-name>others</servlet-name>
<url-pattern>/o</url-pattern>
</servlet-mapping>
* Copyright © 2019 WRF. All rights reserved.
* 功能描述:
* @Package: org.wrf.httpServer.servlet
* @author: knight
* @date: 2019年3月26日 下午7:37:42
*/
public class Mapping {
private String name;
private Set<String>patterns;
public Mapping() {
patterns=new HashSet<String>();
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Set<String> getPatterns() {
return patterns;
}
public void setPatterns(Set<String> patterns) {
this.patterns = patterns;
}
public void addPattern(String pattern) {
this.patterns.add(pattern);
}
}
三、提取信息转化为Map并提供反射
转化为Map
提供反射:
四、定义Servlet接口以及其实现类
Servlet接口
LoginServlet
RegisterServlet
五、定义url至Servlet接口或其实现类的映射
六、重构Server,实现Url请求转发至指定类功能
至此,Tomcat基本框架已经搭建完毕。运行功能正常,但是笔者测试的时候发现一个小bug,那就是服务器响应浏览器请求后程序就会停止。这个并不符合我们日常的需求。该如何解决呢?答案是多线程。通过配置一个分发器,实现一台服务器可以响应多个客户端请求。
package org.wrf.httpServer.server.core;
import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;
/**
* 实现404,500,主页面
* Copyright © 2019 WRF. All rights reserved.
* 功能描述:
* @Package: org.wrf.httpServer.server
* @author: knight
* @date: 2019年3月27日 下午10:47:51
*/
public class Dispatcher implements Runnable {
private Socket client;
private Request request;
private Response response;
public Dispatcher(Socket client) {
this.client = client;
try {
// 获取协议内容
request = new Request(client);
System.out.println(request.getParamtersMap());
// 返回Response
response = new Response(client);
} catch (IOException e) {
e.printStackTrace();
release();
}
}
@Override
public void run() {
// 关注状态码
Servlet servlet = WebApp.getServletFromUrl(request.getUrl());
try {
if(request.getUrl()==null||request.getUrl().equals("")) {
InputStream is=Thread.currentThread().getContextClassLoader().getResourceAsStream("org/wrf/httpServer/server/index.html");
byte []buff=new byte[1024*1024];
int len=is.read(buff);
response.print(new String(buff,0,len));
response.pushToBrowser(200);
}
if (servlet != null) {
servlet.service(request, response);
response.pushToBrowser(200);
} else {
InputStream is=Thread.currentThread().getContextClassLoader().getResourceAsStream("org/wrf/httpServer/server/error.html");
byte []buff=new byte[1024*1024];
int len=is.read(buff);
response.print(new String(buff,0,len));
response.pushToBrowser(404);
}
} catch (IOException e) {
e.printStackTrace();
try {
response.println("服务器崩溃了。。。。。。");
response.pushToBrowser(500);
} catch (IOException e1) {
e1.printStackTrace();
}
release();
}
release();
}
private void release() {
try {
client.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
最后,完善Server代码。
package org.wrf.httpServer.server.core;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
/**
* HttpServer服务器
* Copyright © 2019 WRF. All rights reserved.
* 功能描述:
* 1.通过ServerSocket与浏览器建立连接,
* 2.获取协议内容 返回内容
* 3.封装response实现动态添加内容,状态码
* 4.封装Request
* 5.解析参数
* 6.引入Servlet
* 7.整合web.xml
* 8.加入多线程实现分发器
* 9.实现404,500,主页等页面
* @Package: org.wrf.httpServer.server
* @author: knight
* @date: 2019年3月26日 下午9:58:32
*/
public class Server {
private ServerSocket serverSocket;
private boolean isRunning;
public static void main(String[] args) {
Server server=new Server();
server.start();
}
//启动服务器
public void start() {
try {
serverSocket=new ServerSocket(8888);
isRunning=true;
receive();
} catch (IOException e) {
e.printStackTrace();
System.out.println("服务器启动失败........");
this.stop();
}
}
//接收浏览器请求
public void receive() {
//建立连接
while(isRunning) {
try {
Socket client = serverSocket.accept();
System.out.println("一个客户端建立了连接");
new Thread(new Dispatcher(client)).start();
} catch (IOException e) {
e.printStackTrace();
System.out.println("客户端连接失败.......");
}
}
}
//停止服务器
public void stop() {
isRunning=false;
System.out.println("服务器已停止.......");
try {
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
最终效果:
需要项目源码的可以私信我哈![email protected]