自定义简易版tomcat
项目目录结构
核心代码
package com.yc.web.core;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import javax.sound.sampled.ReverbType;
import org.jaxen.function.StringFunction;
import com.yc.tomcat.core.ConstantInfo;
import com.yc.tomcat.core.ParseWebXml;
import com.yc.utils.StringUtil;
/**
*
* @author : 外哥
* 邮箱 : liwai2012220663@163.com
* 创建时间:2021年1月2日 下午9:30:43
*/
public class HttpServletResponse implements ServletResponse {
private OutputStream os = null ;
private String basePath = ConstantInfo.BASE_PATH ;
private String projectName ; // 项目名
public HttpServletResponse(OutputStream os , String projectName ) {
this.os = os ;
this.projectName = "/" + projectName ;
}
@Override
public void sendRedirect(String url) {
if ( StringUtil.checkNull( url )) {
// TODO 404错误
error404( url );
return ;
}
// 如果不是访问路径不是以项目名开头
if ( !url.startsWith(projectName)) {
send302(projectName + "/" + url );
return ;
}
// 一般访问路径格式 /项目名/文件名
if ( url.startsWith("/") && url.indexOf("/") == url.lastIndexOf("/") ) {
// 表示这个路径的格式为:/项目名
send302(url + "/");
return ;
} else {
if ( url.endsWith("/")) {
// 表示这个路径的格式为: /项目名/
// 获取默认资源,通过解析配置文件得到
String defaultPath = ConstantInfo.DEFAULT_RESOURCE;
File fl = new File( basePath , url.substring(1).replace("/", "\\") + defaultPath ) ;
if ( !fl.exists() || !fl.isFile() ) {
error404(url);
return ;
}
send200( readFile(fl) , url.substring( url.lastIndexOf(".") + 1 ).toLowerCase() );
return ;
}
// 表示这个路径的格式为/项目名/文件名
File fl = new File( basePath , url.substring(1).replace("/", "\\")) ;
if ( !fl.exists() || !fl.isFile() ) {
error404(url);
return ;
}
send200( readFile(fl) , url.substring( url.lastIndexOf(".") + 1 ).toLowerCase() );
}
}
/**
* 发送
* @param bt 要发送的数据
* @param extension 扩展名
*/
private void send200(byte[] bt, String extension) {
String contentType = "text/html;charset=utf-8" ;
String type = ParseWebXml.getContentType( extension ) ;
if ( !StringUtil.checkNull( type )) {
contentType = type ;
}
try {
String responseHeader = "HTTP/1.1 200 OK\r\nContent-Type: " + contentType + "\r\nContent-Length:"+ bt.length +"\r\n\r\n" ;
os.write( responseHeader.getBytes() );
os.write(bt);
os.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
if ( os!= null ) {
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/**
* 302重定向
* @param url
*/
private void send302( String url ) {
try {
String responseHeader = "HTTP/1.1 302 Moved Temporarily\r\nContent-Type: text/html;charset=utf-8\r\nLocation:"+ url +"\r\n\r\n" ;
os.write( responseHeader.getBytes() );
os.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
if ( os!= null ) {
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/**
* 读取指定文件
* @param fl
* @return
*/
private byte[] readFile( File fl ) {
byte[] bt = null ;
FileInputStream fis = null ;
try {
fis = new FileInputStream(fl) ;
bt = new byte[ fis.available() ] ;
fis.read(bt) ;
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if ( fis != null ) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return bt ;
}
/**
* 404报错
* @param url
*/
private void error404(String url) {
try {
String data = "<h1> HTTP Status 404 - " + url + "</h1>" ;
String responseHeader = "HTTP/1.1 404 File Not Found\r\nContent-Type: text/html;charset=utf-8\r\nContent-Length:" + data.length() + "\r\n\r\n" ;
os.write(responseHeader.getBytes());
os.write(data.getBytes());
os.flush();
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
@Override
public PrintWriter getWriter() throws IOException {
String responseHeader = "HTTP/1.1 200 OK\r\nContent-Type: text/html;charset=utf-8\r\n\r\n" ;
os.write( responseHeader.getBytes() );
os.flush();
return new PrintWriter(os);
}
}
package com.yc.tomcat.core;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.Socket;
import java.net.URL;
import java.net.URLClassLoader;
import java.net.URLDecoder;
import com.yc.utils.StringUtil;
import com.yc.web.core.HttpServletRequest;
import com.yc.web.core.HttpServletResponse;
import com.yc.web.core.Servlet;
import com.yc.web.core.ServletRequest;
import com.yc.web.core.ServletResponse;
/**
* 负责处理请求信息的类
* @author : 外哥
* 邮箱 : liwai2012220663@163.com
* 创建时间:2021年1月2日 下午7:33:36
*/
public class ServerService implements Runnable {
private Socket sk = null ;
private InputStream is = null ;
private OutputStream os = null ;
public ServerService(Socket sk) {
this.sk = sk ;
}
@Override
public void run() {
try {
this.is = sk.getInputStream() ;
this.os = sk.getOutputStream() ;
} catch (IOException e) {
e.printStackTrace();
}
// 解析请求头信息
ServletRequest request = new HttpServletRequest( is );
// 从请求头中获取请求地址 /tickets/index.html
String url = request.getUrl();
// 去掉最前边的斜杠 tickets/index.html
String temp = url.substring(1) ;
// 获取项目名称
String projectName = temp.contains("/")? temp.substring( 0 , temp.indexOf("/")) : temp ;
try {
url = URLDecoder.decode(url,"UTF-8") ;
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
ServletResponse response = new HttpServletResponse( os , projectName ) ;
// 是不是动态访问
String clazz = ParseUrlPattern.getClass(url) ;
if ( StringUtil.checkNull( clazz )) {
// 如果没有这个类,说明是静态资源,直接重定位即可
response.sendRedirect(url);
return ;
}
URLClassLoader loader = null ;
URL classPath = null ;
try {
// 获取资源的路径 协议 IP地址 路径
classPath = new URL("file" , null , ConstantInfo.BASE_PATH + "\\" + projectName + "\\bin") ;
// 创建类加载器
loader = new URLClassLoader( new URL[] {classPath} ) ;
// 到指定路径下加载指定的类
Class<?> cls = loader.loadClass(clazz);
// 获取类的对象
Servlet servlet = (Servlet) cls.newInstance() ;
// 调用service方法
servlet.service(request, response);
} catch (Exception e) {
send500( e ) ;
e.printStackTrace();
}
}
private void send500(Exception e) {
try {
String responseHeader = "HTTP/1.1 500 Error\r\n\r\n" + e.getMessage() ;
os.write( responseHeader.getBytes() );
os.flush();
} catch (IOException e1) {
e1.printStackTrace();
} finally {
if ( os != null ) {
try {
os.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
}
}
小编提供了源码,有兴趣的小伙伴可以下载了解
自定义tomcat源码https://download.csdn.net/download/Simple__Code/14090571