80 | // */
81 | // //Xpath表达式:从/web-app/servlet-mapping下查询,查询出servlet-name=servletName的元素
82 | // Element servletMapping = (Element) rootElement.selectSingleNode("/web-app/servlet-mapping[servlet-name='" + servletName + "']'");
83 | //
84 | // String urlPattern = servletMapping.selectSingleNode("url-pattern").getStringValue();
85 | // Class servletClazz = servletClassHandler.handle(servletClass);
86 | // HttpServlet httpServlet = (HttpServlet) servletClazz.newInstance();
87 | //
88 | // this.register(urlPrefix + urlPattern, httpServlet);
89 | // }
90 | //
91 | // } catch (Exception e) {
92 | // logger.error("[MiniCat] read web.xml failed", e);
93 | //
94 | // throw new MiniCatException(e);
95 | // }
96 | // }
97 | //}
98 |
--------------------------------------------------------------------------------
/src/main/java/com/github/houbb/minicat/support/servlet/manager/LocalServletManager.java:
--------------------------------------------------------------------------------
1 | //package com.github.houbb.minicat.support.servlet.manager;
2 | //
3 | //import com.github.houbb.heaven.util.lang.StringUtil;
4 | //import com.github.houbb.log.integration.core.Log;
5 | //import com.github.houbb.log.integration.core.LogFactory;
6 | //import com.github.houbb.minicat.exception.MiniCatException;
7 | //import org.dom4j.Document;
8 | //import org.dom4j.Element;
9 | //import org.dom4j.io.SAXReader;
10 | //
11 | //import javax.servlet.Filter;
12 | //import javax.servlet.http.HttpServlet;
13 | //import java.io.File;
14 | //import java.io.InputStream;
15 | //import java.util.HashMap;
16 | //import java.util.List;
17 | //import java.util.Map;
18 | //
19 | ///**
20 | // * servlet 管理
21 | // *
22 | // * 基于 web.xml 的读取解析
23 | // *
24 | // * 默认根路径
25 | // *
26 | // * @since 0.6.0
27 | // */
28 | //public class LocalServletManager extends DefaultServletManager {
29 | //
30 | // private static final Log logger = LogFactory.getLog(LocalServletManager.class);
31 | //
32 | // /**
33 | // * web 文件地址
34 | // */
35 | // protected final File webXmlFile;
36 | //
37 | // /**
38 | // * 请求地址前缀
39 | // */
40 | // private final String urlPrefix;
41 | //
42 | // public LocalServletManager(String webXmlPath, String urlPrefix) {
43 | // this.webXmlFile = new File(webXmlPath);
44 | // this.urlPrefix = urlPrefix;
45 | // }
46 | //
47 | // public LocalServletManager(String webXmlPath) {
48 | // this(webXmlPath, "");
49 | // }
50 | //
51 | // @Override
52 | // protected void doInit(String baseDir) {
53 | // InputStream resourceAsStream = this.getClass().getClassLoader().getResourceAsStream("web.xml");
54 | //
55 | // this.processWebXml();
56 | // }
57 | //
58 | //
59 | //
60 | //}
61 |
--------------------------------------------------------------------------------
/src/main/java/com/github/houbb/minicat/support/servlet/manager/WarsServletManager.java:
--------------------------------------------------------------------------------
1 | //package com.github.houbb.minicat.support.servlet.manager;
2 | //
3 | //import com.github.houbb.heaven.util.lang.StringUtil;
4 | //import com.github.houbb.log.integration.core.Log;
5 | //import com.github.houbb.log.integration.core.LogFactory;
6 | //import com.github.houbb.minicat.exception.MiniCatException;
7 | //import com.github.houbb.minicat.support.classloader.WebAppClassLoader;
8 | //import com.github.houbb.minicat.support.war.WarExtractorDefault;
9 | //import com.github.houbb.minicat.util.InnerResourceUtil;
10 | //import org.dom4j.Document;
11 | //import org.dom4j.Element;
12 | //import org.dom4j.io.SAXReader;
13 | //
14 | //import javax.servlet.http.HttpServlet;
15 | //import java.io.File;
16 | //import java.nio.file.Path;
17 | //import java.nio.file.Paths;
18 | //import java.util.HashMap;
19 | //import java.util.List;
20 | //import java.util.Map;
21 | //
22 | ///**
23 | // * servlet 管理
24 | // *
25 | // * 基于 web.xml 的读取解析
26 | // *
27 | // * @since 0.5.0
28 | // */
29 | //public class WarsServletManager extends DefaultServletManager {
30 | //
31 | // private static final Log logger = LogFactory.getLog(WarExtractorDefault.class);
32 | //
33 | // private String baseDirStr;
34 | //
35 | // @Override
36 | // protected void doInit(String baseDirStr) {
37 | // logger.info("[MiniCat] servlet init with baseDir={}", baseDirStr);
38 | // this.baseDirStr = baseDirStr;
39 | //
40 | // // 分别解析 war 包
41 | // File baseDir = new File(baseDirStr);
42 | //
43 | // File[] files = baseDir.listFiles();
44 | // for (File file : files) {
45 | // if (file.isDirectory()) {
46 | // handleWarPackage(file);
47 | // }
48 | // }
49 | // }
50 | //
51 | // /**
52 | // * 处理单个 war 包
53 | // *
54 | // * @param warDir 文件夹
55 | // */
56 | // protected void handleWarPackage(File warDir) {
57 | // logger.info("[MiniCat] handleWarPackage baseDirStr={}, file={}", baseDirStr, warDir);
58 | // String prefix = "/" + warDir.getName();
59 | // // 模拟 tomcat,如果在根目录下,war 的名字为 root。则认为是根路径项目。
60 | // if ("ROOT".equalsIgnoreCase(prefix)) {
61 | // // 这里需要 / 吗?
62 | // prefix = "";
63 | // }
64 | //
65 | // String webXmlPath = getWebXmlPath(warDir);
66 | // File webXmlFile = new File(webXmlPath);
67 | // if (!webXmlFile.exists()) {
68 | // logger.warn("[MiniCat] webXmlPath={} not found", webXmlPath);
69 | // return;
70 | // }
71 | //
72 | // loadUrlAndServletClass(prefix, webXmlFile, warDir);
73 | // }
74 | //
75 | // //1. 解析 web.xml
76 | // //2. 读取对应的 servlet mapping
77 | // //3. 保存对应的 url + servlet 示例到 servletMap
78 | // protected void loadUrlAndServletClass(String urlPrefix,
79 | // File webXmlFile,
80 | // File warDir) {
81 | // try {
82 | // SAXReader reader = new SAXReader();
83 | // Document document = reader.read(webXmlFile);
84 | //
85 | // Element root = document.getRootElement();
86 | //
87 | // Map servletClassNameMap = new HashMap<>();
88 | // Map urlPatternMap = new HashMap<>();
89 | // List servletElements = root.elements("servlet");
90 | // for (Element servletElement : servletElements) {
91 | // String servletName = servletElement.elementText("servlet-name");
92 | // String servletClass = servletElement.elementText("servlet-class");
93 | // servletClassNameMap.put(servletName, servletClass);
94 | // }
95 | //
96 | // List urlMappingElements = root.elements("servlet-mapping");
97 | // for (Element urlElem : urlMappingElements) {
98 | // String servletName = urlElem.elementText("servlet-name");
99 | // String urlPattern = urlElem.elementText("url-pattern");
100 | // urlPatternMap.put(servletName, urlPattern);
101 | // }
102 | //
103 | // // 自定义 class loader
104 | // Path classesPath = buildClassesPath(baseDirStr, warDir);
105 | // Path libPath = buildLibPath(baseDirStr, warDir);
106 | //
107 | // // 这个是以 web.xml 为主题。
108 | // try(WebAppClassLoader webAppClassLoader = new WebAppClassLoader(classesPath, libPath)) {
109 | // // 循环处理
110 | // for(Map.Entry urlPatternEntry : urlPatternMap.entrySet()) {
111 | // String servletName = urlPatternEntry.getKey();
112 | // String urlPattern = urlPatternEntry.getValue();
113 | //
114 | // String className = servletClassNameMap.get(servletName);
115 | // if(StringUtil.isEmpty(className)) {
116 | // throw new MiniCatException("className not found for servletName: " + servletName);
117 | // }
118 | //
119 | // // 构建
120 | // handleUrlAndClass(urlPrefix, urlPattern, className, webAppClassLoader);
121 | // }
122 | // };
123 | // } catch (Exception e) {
124 | // throw new MiniCatException(e);
125 | // }
126 | // }
127 | //
128 | // protected void handleUrlAndClass(String urlPrefix,
129 | // String urlPattern,
130 | // String className,
131 | // WebAppClassLoader webAppClassLoader) throws InstantiationException, IllegalAccessException, ClassNotFoundException {
132 | // Class> servletClazz = webAppClassLoader.loadClass(className);
133 | // HttpServlet httpServlet = (HttpServlet) servletClazz.newInstance();
134 | //
135 | // super.register(urlPrefix + urlPattern, httpServlet);
136 | // }
137 | //
138 | //
139 | // protected Path buildClassesPath(String baseDirStr, File warDir) {
140 | // String path = InnerResourceUtil.buildFullPath(baseDirStr, warDir.getName() + "/WEB-INF/classes/");
141 | // return Paths.get(path);
142 | // }
143 | //
144 | // protected Path buildLibPath(String baseDirStr, File warDir) {
145 | // String path = InnerResourceUtil.buildFullPath(baseDirStr, warDir.getName() + "WEB-INF/lib/");
146 | // return Paths.get(path);
147 | // }
148 | //
149 | // protected String buildClassFullPath(String baseDirStr,
150 | // String className) {
151 | // String prefix = InnerResourceUtil.buildFullPath(baseDirStr, "WEB-INF/classes/");
152 | //
153 | // String classNamePath = StringUtil.packageToPath(className) + ".class";
154 | //
155 | // return prefix + classNamePath;
156 | // }
157 | //
158 | // protected String getWebXmlPath(File file) {
159 | // return file.getAbsolutePath() + "/WEB-INF/web.xml";
160 | // }
161 | //
162 | //}
163 |
--------------------------------------------------------------------------------
/src/main/java/com/github/houbb/minicat/support/war/IWarExtractor.java:
--------------------------------------------------------------------------------
1 | package com.github.houbb.minicat.support.war;
2 |
3 | public interface IWarExtractor {
4 |
5 | /**
6 | * 解压处理
7 | * @param baseDir 基本文件夹
8 | */
9 | void extract(String baseDir);
10 |
11 |
12 | }
13 |
--------------------------------------------------------------------------------
/src/main/java/com/github/houbb/minicat/support/war/WarExtractorDefault.java:
--------------------------------------------------------------------------------
1 | package com.github.houbb.minicat.support.war;
2 |
3 | import com.github.houbb.heaven.util.io.FileUtil;
4 | import com.github.houbb.heaven.util.util.ArrayUtil;
5 | import com.github.houbb.log.integration.core.Log;
6 | import com.github.houbb.log.integration.core.LogFactory;
7 | import com.github.houbb.minicat.exception.MiniCatException;
8 | import com.github.houbb.minicat.util.InnerResourceUtil;
9 | import com.github.houbb.minicat.util.InnerWarUtil;
10 |
11 | import java.io.File;
12 | import java.io.IOException;
13 |
14 | /**
15 | * 默认的 war 处理
16 | *
17 | * @since 0.5.0
18 | */
19 | public class WarExtractorDefault implements IWarExtractor {
20 |
21 | private static final Log logger = LogFactory.getLog(WarExtractorDefault.class);
22 |
23 | @Override
24 | public void extract(String baseDirStr) {
25 | logger.info("[MiniCat] start extract baseDirStr={}", baseDirStr);
26 |
27 | //1. check
28 | // Path baseDir = Paths.get(baseDirStr);
29 | File baseDirFile = new File(baseDirStr);
30 | if (!baseDirFile.exists()) {
31 | logger.error("[MiniCat] base dir not found!");
32 | throw new MiniCatException("baseDir not found!");
33 | }
34 |
35 | //2. list war
36 | File[] files = baseDirFile.listFiles();
37 | if (ArrayUtil.isNotEmpty(files)) {
38 | for (File file : files) {
39 | String fileName = file.getName();
40 | if (fileName.endsWith(".war")) {
41 | logger.error("[MiniCat] start extract war={}", fileName);
42 | handleWarFile(baseDirStr, file);
43 | }
44 | }
45 | }
46 |
47 | // handle war package
48 | logger.info("[MiniCat] end extract baseDir={}", baseDirStr);
49 | }
50 |
51 | /**
52 | * 处理 war 文件
53 | *
54 | * @param baseDirStr 基础
55 | * @param warFile war 文件
56 | */
57 | private void handleWarFile(String baseDirStr,
58 | File warFile) {
59 | //1. 删除历史的 war 解压包
60 | String warPackageName = FileUtil.getFileName(warFile.getName());
61 | String fullWarPackagePath = InnerResourceUtil.buildFullPath(baseDirStr, warPackageName);
62 | FileUtil.deleteFileRecursive(fullWarPackagePath);
63 |
64 | //2. 解压文件
65 | try {
66 | InnerWarUtil.extractWar(warFile.getAbsolutePath(), fullWarPackagePath);
67 | } catch (IOException e) {
68 | logger.error("[MiniCat] handleWarFile failed, warPackageName={}", warFile.getAbsoluteFile(), e);
69 | throw new MiniCatException(e);
70 | }
71 | }
72 |
73 | }
74 |
--------------------------------------------------------------------------------
/src/main/java/com/github/houbb/minicat/support/writer/MyPrintWriter.java:
--------------------------------------------------------------------------------
1 | package com.github.houbb.minicat.support.writer;
2 |
3 | import com.github.houbb.log.integration.core.Log;
4 | import com.github.houbb.log.integration.core.LogFactory;
5 | import com.github.houbb.minicat.util.InnerHttpUtil;
6 | import io.netty.buffer.ByteBuf;
7 | import io.netty.buffer.Unpooled;
8 | import io.netty.channel.ChannelFutureListener;
9 | import io.netty.channel.ChannelHandlerContext;
10 |
11 | import java.io.*;
12 | import java.nio.charset.Charset;
13 |
14 | public class MyPrintWriter extends PrintWriter {
15 |
16 | private static final Log logger = LogFactory.getLog(MyPrintWriter.class);
17 |
18 | public MyPrintWriter(Writer out) {
19 | super(out);
20 | }
21 |
22 | public MyPrintWriter(Writer out, boolean autoFlush) {
23 | super(out, autoFlush);
24 | }
25 |
26 | public MyPrintWriter(OutputStream out) {
27 | super(out);
28 | }
29 |
30 | public MyPrintWriter(OutputStream out, boolean autoFlush) {
31 | super(out, autoFlush);
32 | }
33 |
34 | public MyPrintWriter(String fileName) throws FileNotFoundException {
35 | super(fileName);
36 | }
37 |
38 | public MyPrintWriter(String fileName, String csn) throws FileNotFoundException, UnsupportedEncodingException {
39 | super(fileName, csn);
40 | }
41 |
42 | public MyPrintWriter(File file) throws FileNotFoundException {
43 | super(file);
44 | }
45 |
46 | public MyPrintWriter(File file, String csn) throws FileNotFoundException, UnsupportedEncodingException {
47 | super(file, csn);
48 | }
49 |
50 | private ChannelHandlerContext ctx;
51 |
52 | public ChannelHandlerContext getCtx() {
53 | return ctx;
54 | }
55 |
56 | public void setCtx(ChannelHandlerContext ctx) {
57 | this.ctx = ctx;
58 | }
59 |
60 | public void print(String text) {
61 | text = InnerHttpUtil.http200Resp(text);
62 | Charset charset = Charset.forName("UTF-8");
63 | ByteBuf responseBuf = Unpooled.copiedBuffer(text, charset);
64 | ctx.writeAndFlush(responseBuf)
65 | .addListener(ChannelFutureListener.CLOSE); // Close the channel after sending the response
66 | logger.info("[MiniCat] channelRead writeAndFlush DONE");
67 | }
68 |
69 | }
70 |
--------------------------------------------------------------------------------
/src/main/java/com/github/houbb/minicat/util/CostTimeUtil.java:
--------------------------------------------------------------------------------
1 | package com.github.houbb.minicat.util;
2 |
3 | @Deprecated
4 | public class CostTimeUtil {
5 |
6 | public static long costTimeMock() {
7 | long start = System.currentTimeMillis();
8 | // 避免是 sleep 影响判断
9 | String text = "111111111111111111111111111111111111111";
10 |
11 | for(int i = 0; i < 10000000; i++) {
12 | String text1 = text+i;
13 | text1.matches("123[0-9]");
14 | }
15 |
16 | return System.currentTimeMillis() - start;
17 | }
18 |
19 | public static void main(String[] args) {
20 | System.out.println(costTimeMock());;
21 | }
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/src/main/java/com/github/houbb/minicat/util/InnerClassLoaderUtil.java:
--------------------------------------------------------------------------------
1 | package com.github.houbb.minicat.util;
2 |
3 | import com.github.houbb.minicat.exception.MiniCatException;
4 |
5 | import java.io.File;
6 | import java.net.MalformedURLException;
7 | import java.net.URL;
8 | import java.net.URLClassLoader;
9 | import java.util.LinkedHashSet;
10 | import java.util.Set;
11 |
12 | /**
13 | * 类加载
14 | *
15 | * @since 0.5.0
16 | */
17 | public class InnerClassLoaderUtil {
18 |
19 | public static Class> loadClass(String classFilePath, String classFullName) {
20 | // 确保类名与文件路径匹配
21 | // 如果类名是com.example.YourClass,则.class文件应该位于com/example/目录下
22 |
23 | try {
24 | // 创建一个URL对象,表示该class文件的路径
25 | File file = new File(classFilePath);
26 | URL url = file.toURI().toURL();
27 |
28 | // 创建一个URLClassLoader对象,加载指定的URL
29 | // 使用当前线程的上下文类加载器作为父类加载器
30 | URLClassLoader classLoader = new URLClassLoader(new URL[]{url}, Thread.currentThread().getContextClassLoader());
31 |
32 | // 使用加载的类
33 | return classLoader.loadClass(classFullName);
34 | } catch (MalformedURLException e) {
35 | // 更好的异常处理,记录异常信息
36 | e.printStackTrace();
37 | throw new RuntimeException("Failed to convert file to URL", e);
38 | } catch (ClassNotFoundException e) {
39 | e.printStackTrace();
40 | throw new RuntimeException("Class not found: " + classFullName, e);
41 | }
42 | }
43 |
44 | /**
45 | * 加载指定路径的.class文件对应的Class对象
46 | *
47 | * @param classFilePath 绝对路径的.class文件路径
48 | * @return Class对象
49 | * @throws MalformedURLException 异常
50 | */
51 | public static Class> loadClassFromFile(String classFilePath) throws MalformedURLException {
52 | if (classFilePath == null || classFilePath.isEmpty()) {
53 | throw new IllegalArgumentException("Class file path must not be null or empty.");
54 | }
55 |
56 | // 将文件路径转换为URL
57 | File file = new File(classFilePath);
58 | URL url = file.toURI().toURL();
59 |
60 | // 创建URLClassLoader实例
61 | URLClassLoader classLoader = new URLClassLoader(new URL[]{url});
62 |
63 | try {
64 | // 获取文件名,去除.class扩展名,得到类名
65 | String className = file.getName().substring(0, file.getName().length() - 6);
66 | // 加载Class对象
67 | return classLoader.loadClass(className);
68 | } catch (ClassNotFoundException e) {
69 | throw new RuntimeException("Class not found: " + classFilePath, e);
70 | }
71 | }
72 |
73 | public static void main(String[] args) throws MalformedURLException, ClassNotFoundException {
74 | String classFilePath = "D:\\github\\minicat\\src\\test\\webapps\\servlet\\WEB-INF\\classes\\com\\github\\houbb\\servlet\\webxml\\IndexServlet.class";
75 |
76 | // 创建一个URL对象,表示该class文件的路径
77 | File file = new File(classFilePath);
78 | URL url = file.toURI().toURL();
79 |
80 | URLClassLoader urlClassLoader = URLClassLoader.newInstance(new URL[] {url});
81 |
82 | Class clazz = urlClassLoader.loadClass("com.github.houbb.servlet.webxml.IndexServlet");
83 | System.out.println(clazz.getName());
84 | }
85 |
86 |
87 | }
88 |
--------------------------------------------------------------------------------
/src/main/java/com/github/houbb/minicat/util/InnerHttpUtil.java:
--------------------------------------------------------------------------------
1 | package com.github.houbb.minicat.util;
2 |
3 | public class InnerHttpUtil {
4 |
5 | /**
6 | * 符合 http 标准的字符串
7 | * @param rawText 原始文本
8 | * @return 结果
9 | */
10 | public static String http200Resp(String rawText) {
11 | String format = "HTTP/1.1 200 OK\r\n" +
12 | "Content-Type: text/plain\r\n" +
13 | "\r\n" +
14 | "%s";
15 |
16 | return String.format(format, rawText);
17 | }
18 |
19 | /**
20 | * 400 响应
21 | * @return 结果
22 | * @since 0.2.0
23 | */
24 | public static String http400Resp() {
25 | return "HTTP/1.1 400 Bad Request\r\n" +
26 | "Content-Type: text/plain\r\n" +
27 | "\r\n" +
28 | "400 Bad Request: The request could not be understood by the server due to malformed syntax.";
29 | }
30 |
31 | /**
32 | * 404 响应
33 | * @return 结果
34 | * @since 0.2.0
35 | */
36 | public static String http404Resp() {
37 | String response = "HTTP/1.1 404 Not Found\r\n" +
38 | "Content-Type: text/plain\r\n" +
39 | "\r\n" +
40 | "404 Not Found: The requested resource was not found on this server.";
41 |
42 | return response;
43 | }
44 |
45 | /**
46 | * 500 响应
47 | * @return 结果
48 | * @since 0.2.0
49 | */
50 | public static String http500Resp() {
51 | return "HTTP/1.1 500 Internal Server Error\r\n" +
52 | "Content-Type: text/plain\r\n" +
53 | "\r\n" +
54 | "500 Internal Server Error: The server encountered an unexpected condition that prevented it from fulfilling the request.";
55 | }
56 |
57 | }
58 |
--------------------------------------------------------------------------------
/src/main/java/com/github/houbb/minicat/util/InnerRequestUtil.java:
--------------------------------------------------------------------------------
1 | package com.github.houbb.minicat.util;
2 |
3 | import com.github.houbb.minicat.bo.RequestInfoBo;
4 |
5 | import java.io.IOException;
6 | import java.io.InputStream;
7 |
8 | public class InnerRequestUtil {
9 |
10 | /**
11 | *
12 | * Server read: GET /my HTTP/1.1
13 | * Host: localhost:8080
14 | * Connection: keep-alive
15 | * Cache-Control: max-age=0
16 | * sec-ch-ua: "Google Chrome";v="123", "Not:A-Brand";v="8", "Chromium";v="123"
17 | * sec-ch-ua-mobile: ?0
18 | * sec-ch-ua-platform: "Windows"
19 | * Upgrade-Insecure-Requests: 1
20 | * User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36
21 | *
22 | * @param text 文本
23 | * @return 结果
24 | * @since 0.4.0
25 | */
26 | public static RequestInfoBo buildRequestInfoBo(String text) {
27 | // 使用正则表达式按行分割请求字符串
28 | String[] requestLines = text.split("\r\n");
29 |
30 | // 获取第一行请求行
31 | String firstLine = requestLines[0];
32 |
33 | String[] strings = firstLine.split(" ");
34 | String method = strings[0];
35 | String url = strings[1];
36 |
37 | return new RequestInfoBo(url, method);
38 | }
39 |
40 | public static RequestInfoBo buildRequestInfoBo(final InputStream inputStream) {
41 | byte[] buffer = new byte[1024]; // 使用固定大小的缓冲区
42 | int bytesRead = 0;
43 |
44 | try {
45 | while ((bytesRead = inputStream.read(buffer)) != -1) { // 循环读取数据直到EOF
46 | String inputStr = new String(buffer, 0, bytesRead);
47 |
48 | // 检查是否读取到完整的HTTP请求行
49 | if (inputStr.contains("\n")) {
50 | // 获取第一行数据
51 | String firstLineStr = inputStr.split("\\n")[0];
52 |
53 | return buildRequestInfoBo(firstLineStr);
54 | }
55 | }
56 |
57 | return null;
58 | } catch (IOException e) {
59 | throw new RuntimeException(e);
60 | }
61 | }
62 |
63 | }
64 |
--------------------------------------------------------------------------------
/src/main/java/com/github/houbb/minicat/util/InnerResourceUtil.java:
--------------------------------------------------------------------------------
1 | package com.github.houbb.minicat.util;
2 |
3 | public class InnerResourceUtil {
4 |
5 | // 获取当前线程的上下文类加载器的资源路径
6 | public static String getCurrentThreadContextClassLoaderResource() {
7 | return Thread.currentThread().getContextClassLoader().getResource("").getPath();
8 | }
9 |
10 | // 获取系统类加载器的资源路径
11 | public static String getSystemClassLoaderResource() {
12 | return ClassLoader.getSystemResource("").getPath();
13 | }
14 |
15 | // 获取指定类加载器的资源路径
16 | public static String getClassLoaderResource(Class> clazz) {
17 | return clazz.getClassLoader().getResource("").getPath();
18 | }
19 |
20 | // 获取指定类的根路径
21 | public static String getClassRootResource(Class> clazz) {
22 | return clazz.getResource("/").getPath();
23 | }
24 |
25 | // 获取指定类的路径
26 | public static String getClassResource(Class> clazz) {
27 | return clazz.getResource("").getPath();
28 | }
29 |
30 | // 获取当前工作目录的路径
31 | public static String getCurrentWorkingDirectory() {
32 | return System.getProperty("user.dir");
33 | }
34 |
35 | // 获取类路径的路径
36 | public static String getClassPath() {
37 | return System.getProperty("java.class.path");
38 | }
39 |
40 |
41 | /**
42 | * 构建完整的路径。
43 | * 给定一个前缀和路径,此方法将两者结合形成一个完整的URL或文件路径。
44 | * 如果前缀末尾没有斜杠,则会在两者之间添加一个斜杠,确保路径的正确拼接。
45 | *
46 | * @param prefix 路径前缀。例如,http://example.com或C:\Users。
47 | * @param path 相对路径。例如,path/to/resource或test.txt。
48 | * @return 拼接后的完整路径。确保路径正确连接,不会因缺少斜杠而导致路径错误。
49 | */
50 | public static String buildFullPath(String prefix, String path) {
51 | // 检查前缀是否已以斜杠结尾,如果是,则直接拼接路径;如果不是,则在前缀后添加斜杠再拼接路径
52 | if(path.startsWith("/")) {
53 | path = path.substring(1);
54 | }
55 |
56 | if(prefix.endsWith("/")) {
57 | return prefix + path;
58 | } else {
59 | return prefix + "/" + path;
60 | }
61 | }
62 |
63 | public static void main(String[] args) {
64 | // 示例用法
65 | System.out.println("Current Thread Context ClassLoader Resource: " + getCurrentThreadContextClassLoaderResource());
66 | System.out.println("System ClassLoader Resource: " + getSystemClassLoaderResource());
67 | System.out.println("Class Loader Resource: " + getClassLoaderResource(InnerResourceUtil.class));
68 | System.out.println("Class Root Resource: " + getClassRootResource(InnerResourceUtil.class));
69 | System.out.println("Class Resource: " + getClassResource(InnerResourceUtil.class));
70 | System.out.println("Current Working Directory: " + getCurrentWorkingDirectory());
71 | System.out.println("Class Path: " + getClassPath());
72 | }
73 |
74 | }
75 |
--------------------------------------------------------------------------------
/src/main/java/com/github/houbb/minicat/util/InnerWarUtil.java:
--------------------------------------------------------------------------------
1 | package com.github.houbb.minicat.util;
2 |
3 | import com.github.houbb.heaven.util.io.FileUtil;
4 |
5 | import java.io.File;
6 | import java.io.FileOutputStream;
7 | import java.io.IOException;
8 | import java.nio.file.Files;
9 | import java.nio.file.Paths;
10 | import java.util.zip.ZipEntry;
11 | import java.util.zip.ZipInputStream;
12 |
13 | /**
14 | *
15 | * @since 0.5.0
16 | */
17 | public class InnerWarUtil {
18 |
19 | public static void main(String[] args) {
20 | String warFilePath = "C:\\Users\\Administrator\\Downloads\\simple-servlet-master\\simple-servlet-master\\target\\servlet.war"; // 要解压的 WAR 文件路径
21 | String destinationDirectory = "C:\\Users\\Administrator\\Downloads\\simple-servlet-master\\simple-servlet-master\\target\\servlet"; // 解压后的目标目录
22 |
23 | try {
24 | extractWar(warFilePath, destinationDirectory);
25 | System.out.println("WAR 文件解压成功!");
26 | } catch (IOException e) {
27 | System.err.println("解压 WAR 文件时出错:" + e.getMessage());
28 | }
29 | }
30 |
31 | public static void extractWar(String warFilePath, String destinationDirectory) throws IOException {
32 | File destinationDir = new File(destinationDirectory);
33 | if (!destinationDir.exists()) {
34 | destinationDir.mkdirs();
35 | }
36 |
37 | try (ZipInputStream zipInputStream = new ZipInputStream(Files.newInputStream(Paths.get(warFilePath)))) {
38 | ZipEntry entry = zipInputStream.getNextEntry();
39 | while (entry != null) {
40 | String filePath = destinationDirectory + File.separator + entry.getName();
41 | if (!entry.isDirectory()) {
42 | extractFile(zipInputStream, filePath);
43 | } else {
44 | File dir = new File(filePath);
45 | dir.mkdir();
46 | }
47 | zipInputStream.closeEntry();
48 | entry = zipInputStream.getNextEntry();
49 | }
50 | }
51 | }
52 |
53 | private static void extractFile(ZipInputStream zipInputStream, String filePath) throws IOException {
54 | FileUtil.createFile(filePath);
55 |
56 | try (FileOutputStream fos = new FileOutputStream(filePath)) {
57 | byte[] buffer = new byte[1024];
58 | int length;
59 | while ((length = zipInputStream.read(buffer)) > 0) {
60 | fos.write(buffer, 0, length);
61 | }
62 | }
63 | }
64 | }
65 |
66 |
--------------------------------------------------------------------------------
/src/main/resources/index.html:
--------------------------------------------------------------------------------
1 | mini cat index html!
--------------------------------------------------------------------------------
/src/main/resources/web.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | my
7 | com.github.houbb.minicat.support.servlet.MyMiniCatHttpServlet
8 |
9 |
10 | my
11 | /my
12 |
13 |
14 |
15 |
16 | LoggingFilter
17 | com.github.houbb.minicat.support.filter.MyMiniCatLoggingHttpFilter
18 |
19 |
20 | LoggingFilter
21 | /*
22 |
23 |
24 |
25 |
26 | com.github.houbb.minicat.support.listener.foo.MyServletContextAttrListener
27 |
28 |
29 | com.github.houbb.minicat.support.listener.foo.MyServletContextListener
30 |
31 |
32 | com.github.houbb.minicat.support.listener.foo.MyServletReadListener
33 |
34 |
35 | com.github.houbb.minicat.support.listener.foo.MyServletWriteListener
36 |
37 |
38 | com.github.houbb.minicat.support.listener.foo.MyServletRequestListener
39 |
40 |
41 | com.github.houbb.minicat.support.listener.foo.MyServletRequestAttrListener
42 |
43 |
44 |
--------------------------------------------------------------------------------
/src/test/java/com/github/houbb/minicat/bs/MiniCatBootstrapMainTest.java:
--------------------------------------------------------------------------------
1 | package com.github.houbb.minicat.bs;
2 |
3 | public class MiniCatBootstrapMainTest {
4 |
5 | public static void main(String[] args) throws InterruptedException {
6 | MiniCatBootstrap bootstrap = new MiniCatBootstrap();
7 | bootstrap.start();
8 | }
9 |
10 | }
11 |
--------------------------------------------------------------------------------
/src/test/java/com/github/houbb/minicat/bs/MiniCatBootstrapMainWithWarsTest.java:
--------------------------------------------------------------------------------
1 | package com.github.houbb.minicat.bs;
2 |
3 | public class MiniCatBootstrapMainWithWarsTest {
4 |
5 | public static void main(String[] args) throws InterruptedException {
6 | String baseWarDir = "D:\\github\\minicat\\src\\test\\webapps";
7 | MiniCatBootstrap bootstrap = new MiniCatBootstrap(8080, baseWarDir);
8 | bootstrap.start();
9 | }
10 |
11 | }
12 |
--------------------------------------------------------------------------------
/src/test/java/com/github/houbb/minicat/bs/ResourceUtilTest.java:
--------------------------------------------------------------------------------
1 | package com.github.houbb.minicat.bs;
2 |
3 | public class ResourceUtilTest {
4 |
5 | // 获取当前线程的上下文类加载器的资源路径
6 | public static String getCurrentThreadContextClassLoaderResource() {
7 | return Thread.currentThread().getContextClassLoader().getResource("").getPath();
8 | }
9 |
10 | // 获取系统类加载器的资源路径
11 | public static String getSystemClassLoaderResource() {
12 | return ClassLoader.getSystemResource("").getPath();
13 | }
14 |
15 | // 获取指定类加载器的资源路径
16 | public static String getClassLoaderResource(Class> clazz) {
17 | return clazz.getClassLoader().getResource("").getPath();
18 | }
19 |
20 | // 获取指定类的根路径
21 | public static String getClassRootResource(Class> clazz) {
22 | return clazz.getResource("/").getPath();
23 | }
24 |
25 | // 获取指定类的路径
26 | public static String getClassResource(Class> clazz) {
27 | return clazz.getResource("").getPath();
28 | }
29 |
30 | // 获取当前工作目录的路径
31 | public static String getCurrentWorkingDirectory() {
32 | return System.getProperty("user.dir");
33 | }
34 |
35 | // 获取类路径的路径
36 | public static String getClassPath() {
37 | return System.getProperty("java.class.path");
38 | }
39 |
40 |
41 | /**
42 | * 构建完整的路径。
43 | * 给定一个前缀和路径,此方法将两者结合形成一个完整的URL或文件路径。
44 | * 如果前缀末尾没有斜杠,则会在两者之间添加一个斜杠,确保路径的正确拼接。
45 | *
46 | * @param prefix 路径前缀。例如,http://example.com或C:\Users。
47 | * @param path 相对路径。例如,path/to/resource或test.txt。
48 | * @return 拼接后的完整路径。确保路径正确连接,不会因缺少斜杠而导致路径错误。
49 | */
50 | public static String buildFullPath(String prefix, String path) {
51 | // 检查前缀是否已以斜杠结尾,如果是,则直接拼接路径;如果不是,则在前缀后添加斜杠再拼接路径
52 | if(path.startsWith("/")) {
53 | path = path.substring(1);
54 | }
55 |
56 | if(prefix.endsWith("/")) {
57 | return prefix + path;
58 | } else {
59 | return prefix + "/" + path;
60 | }
61 | }
62 |
63 | public static void main(String[] args) {
64 | // 示例用法
65 | System.out.println("Current Thread Context ClassLoader Resource: " + getCurrentThreadContextClassLoaderResource());
66 | System.out.println("System ClassLoader Resource: " + getSystemClassLoaderResource());
67 | System.out.println("Class Loader Resource: " + getClassLoaderResource(ResourceUtilTest.class));
68 | System.out.println("Class Root Resource: " + getClassRootResource(ResourceUtilTest.class));
69 | System.out.println("Class Resource: " + getClassResource(ResourceUtilTest.class));
70 | System.out.println("Current Working Directory: " + getCurrentWorkingDirectory());
71 | System.out.println("Class Path: " + getClassPath());
72 | }
73 |
74 | }
75 |
--------------------------------------------------------------------------------
/src/test/java/com/github/houbb/minicat/bs/socket/MiniCatBootstrapBioServletTest.java:
--------------------------------------------------------------------------------
1 | package com.github.houbb.minicat.bs.socket;
2 |
3 | import com.github.houbb.minicat.bs.servlet.MiniCatBootstrapBioSocket;
4 |
5 | public class MiniCatBootstrapBioServletTest {
6 |
7 | public static void main(String[] args) throws InterruptedException {
8 | MiniCatBootstrapBioSocket bootstrap = new MiniCatBootstrapBioSocket();
9 | bootstrap.start();
10 | }
11 |
12 | }
13 |
--------------------------------------------------------------------------------
/src/test/java/com/github/houbb/minicat/bs/socket/MiniCatBootstrapBioThreadServletTest.java:
--------------------------------------------------------------------------------
1 | package com.github.houbb.minicat.bs.socket;
2 |
3 | import com.github.houbb.minicat.bs.servlet.MiniCatBootstrapBioThreadSocket;
4 |
5 | public class MiniCatBootstrapBioThreadServletTest {
6 |
7 | public static void main(String[] args) throws InterruptedException {
8 | MiniCatBootstrapBioThreadSocket bootstrap = new MiniCatBootstrapBioThreadSocket();
9 | bootstrap.start();
10 | }
11 |
12 | }
13 |
--------------------------------------------------------------------------------
/src/test/java/com/github/houbb/minicat/bs/socket/MiniCatBootstrapNettyTest.java:
--------------------------------------------------------------------------------
1 | package com.github.houbb.minicat.bs.socket;
2 |
3 | import com.github.houbb.minicat.bs.servlet.MiniCatBootstrapNetty;
4 |
5 | public class MiniCatBootstrapNettyTest {
6 |
7 | public static void main(String[] args) throws InterruptedException {
8 | MiniCatBootstrapNetty bootstrap = new MiniCatBootstrapNetty();
9 | bootstrap.start();
10 | }
11 |
12 | }
13 |
--------------------------------------------------------------------------------
/src/test/java/com/github/houbb/minicat/bs/socket/MiniCatBootstrapNioSocketTest.java:
--------------------------------------------------------------------------------
1 | package com.github.houbb.minicat.bs.socket;
2 |
3 | import com.github.houbb.minicat.bs.servlet.MiniCatBootstrapNioSocket;
4 |
5 | public class MiniCatBootstrapNioSocketTest {
6 |
7 | public static void main(String[] args) {
8 | MiniCatBootstrapNioSocket nioSocket = new MiniCatBootstrapNioSocket();
9 | nioSocket.start();
10 | }
11 |
12 | }
13 |
--------------------------------------------------------------------------------
/src/test/java/com/github/houbb/minicat/bs/socket/MiniCatBootstrapNioThreadSocketTest.java:
--------------------------------------------------------------------------------
1 | package com.github.houbb.minicat.bs.socket;
2 |
3 | import com.github.houbb.minicat.bs.servlet.MiniCatBootstrapNioThreadSocket;
4 |
5 | public class MiniCatBootstrapNioThreadSocketTest {
6 |
7 | public static void main(String[] args) {
8 | MiniCatBootstrapNioThreadSocket nioSocket = new MiniCatBootstrapNioThreadSocket();
9 | nioSocket.start();
10 | }
11 |
12 | }
13 |
--------------------------------------------------------------------------------
/src/test/resources/reqest_demo.txt:
--------------------------------------------------------------------------------
1 | Server read: GET /my HTTP/1.1
2 | Host: localhost:8080
3 | Connection: keep-alive
4 | Cache-Control: max-age=0
5 | sec-ch-ua: "Google Chrome";v="123", "Not:A-Brand";v="8", "Chromium";v="123"
6 | sec-ch-ua-mobile: ?0
7 | sec-ch-ua-platform: "Windows"
8 | Upgrade-Insecure-Requests: 1
9 | User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36
10 | Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
11 | Sec-Fetch-Site: none
12 | Sec-Fetch-Mode: navigate
13 | Sec-Fetch-User: ?1
14 | Sec-Fetch-Dest: document
15 | Accept-Encoding: gzip, deflate, br, zstd
16 | Accept-Language: zh-CN,zh;q=0.9
--------------------------------------------------------------------------------
/src/test/webapps/servlet.war:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/houbb/minicat/a999267461725148272d8d043828003f25be7592/src/test/webapps/servlet.war
--------------------------------------------------------------------------------
/src/test/webapps/servlet/META-INF/MANIFEST.MF:
--------------------------------------------------------------------------------
1 | Manifest-Version: 1.0
2 | Archiver-Version: Plexus Archiver
3 | Built-By: Administrator
4 | Created-By: Apache Maven 3.6.3
5 | Build-Jdk: 1.8.0_192
6 |
7 |
--------------------------------------------------------------------------------
/src/test/webapps/servlet/META-INF/maven/com.github.houbb/servlet-webxml/pom.properties:
--------------------------------------------------------------------------------
1 | #Generated by Maven
2 | #Sat Apr 06 16:11:54 CST 2024
3 | version=1.0-SNAPSHOT
4 | groupId=com.github.houbb
5 | artifactId=servlet-webxml
6 |
--------------------------------------------------------------------------------
/src/test/webapps/servlet/META-INF/maven/com.github.houbb/servlet-webxml/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | com.github.houbb
8 | servlet-webxml
9 | 1.0-SNAPSHOT
10 |
11 |
12 | 8
13 | 8
14 | UTF-8
15 | 2.2
16 |
17 |
18 | war
19 |
20 |
21 |
22 | javax.servlet
23 | servlet-api
24 | 2.5
25 | provided
26 |
27 |
28 |
29 | org.apache.tomcat
30 | tomcat-servlet-api
31 | 9.0.0.M8
32 | provided
33 |
34 |
35 |
36 |
37 | servlet
38 |
39 |
40 | org.apache.tomcat.maven
41 | tomcat7-maven-plugin
42 | ${plugin.tomcat.version}
43 |
44 | 8080
45 | /
46 | ${project.build.sourceEncoding}
47 |
48 |
49 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/src/test/webapps/servlet/WEB-INF/classes/com/github/houbb/servlet/webxml/IndexServlet.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/houbb/minicat/a999267461725148272d8d043828003f25be7592/src/test/webapps/servlet/WEB-INF/classes/com/github/houbb/servlet/webxml/IndexServlet.class
--------------------------------------------------------------------------------
/src/test/webapps/servlet/WEB-INF/web.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 | /index.html
10 |
11 |
12 |
13 | index
14 | com.github.houbb.servlet.webxml.IndexServlet
15 |
16 |
17 |
18 | index
19 | /index
20 |
21 |
22 |
--------------------------------------------------------------------------------
/src/test/webapps/servlet/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Hello Servlet!
5 |
6 |
--------------------------------------------------------------------------------