Looly 5 年 前
コミット
0a768ad2c6

+ 4 - 4
CHANGELOG.md

@@ -14,12 +14,12 @@
 * 【setting】     新增setByGroup和putByGroup,set和put标记为过期(issue#I2C42H@Gitee)
 * 【crypto 】     修改SymmetricAlgorithm注释(issue#1360@Github)
 * 【all    】     pom中将META-INF/maven下全部exclude(pr#1355@Github)
-* 【core   】     pom中将META-INF/maven下全部exclude(pr#1355@Github)
+* 【http   】     SimpleServer中增加addFilter等方法,并使用全局线程池
 
 ### Bug修复
-* 【core   】     修复CsvReader读取双引号未转义问题(issur#I2BMP1@Gitee)
-* 【json   】     JSONUtil.parse修复config无效问题(issur#1363@Github)
-* 【http   】     修复SimpleServer返回响应内容Content-Lenth不正确的问题(issur#1358@Github)
+* 【core   】     修复CsvReader读取双引号未转义问题(issue#I2BMP1@Gitee)
+* 【json   】     JSONUtil.parse修复config无效问题(issue#1363@Github)
+* 【http   】     修复SimpleServer返回响应内容Content-Length不正确的问题(issue#1358@Github)
 
 -------------------------------------------------------------------------------------------------------------
 

+ 11 - 0
hutool-http/src/main/java/cn/hutool/http/server/HttpServerBase.java

@@ -1,6 +1,7 @@
 package cn.hutool.http.server;
 
 import cn.hutool.core.util.CharsetUtil;
+import com.sun.net.httpserver.HttpContext;
 import com.sun.net.httpserver.HttpExchange;
 
 import java.nio.charset.Charset;
@@ -34,4 +35,14 @@ public class HttpServerBase {
 	public HttpExchange getHttpExchange() {
 		return this.httpExchange;
 	}
+
+	/**
+	 * 获取{@link HttpContext}
+	 *
+	 * @return {@link HttpContext}
+	 * @since 5.5.7
+	 */
+	public HttpContext getHttpContext() {
+		return getHttpExchange().getHttpContext();
+	}
 }

+ 95 - 6
hutool-http/src/main/java/cn/hutool/http/server/SimpleServer.java

@@ -6,13 +6,22 @@ import cn.hutool.core.thread.GlobalThreadPool;
 import cn.hutool.core.util.StrUtil;
 import cn.hutool.http.server.action.Action;
 import cn.hutool.http.server.action.RootAction;
+import cn.hutool.http.server.filter.HttpFilter;
+import cn.hutool.http.server.filter.SimpleFilter;
 import cn.hutool.http.server.handler.ActionHandler;
+import com.sun.net.httpserver.Filter;
+import com.sun.net.httpserver.HttpContext;
+import com.sun.net.httpserver.HttpExchange;
 import com.sun.net.httpserver.HttpHandler;
 import com.sun.net.httpserver.HttpServer;
+import com.sun.net.httpserver.HttpsConfigurator;
+import com.sun.net.httpserver.HttpsServer;
 
 import java.io.File;
 import java.io.IOException;
 import java.net.InetSocketAddress;
+import java.util.ArrayList;
+import java.util.List;
 import java.util.concurrent.Executor;
 
 /**
@@ -23,7 +32,8 @@ import java.util.concurrent.Executor;
  */
 public class SimpleServer {
 
-	HttpServer server;
+	private final HttpServer server;
+	private final List<Filter> filters;
 
 	/**
 	 * 构造
@@ -50,26 +60,105 @@ public class SimpleServer {
 	 * @param address 监听地址
 	 */
 	public SimpleServer(InetSocketAddress address) {
+		this(address, null);
+	}
+
+	/**
+	 * 构造
+	 *
+	 * @param address 监听地址
+	 * @param configurator https配置信息,用于使用自定义SSL(TLS)证书等
+	 */
+	public SimpleServer(InetSocketAddress address, HttpsConfigurator configurator) {
 		try {
-			this.server = HttpServer.create(address, 0);
+			if(null != configurator){
+				final HttpsServer server = HttpsServer.create(address, 0);
+				server.setHttpsConfigurator(configurator);
+				this.server = server;
+			} else{
+				this.server = HttpServer.create(address, 0);
+			}
 		} catch (IOException e) {
 			throw new IORuntimeException(e);
 		}
 		setExecutor(GlobalThreadPool.getExecutor());
+		filters = new ArrayList<>();
+	}
+
+	/**
+	 * 增加请求过滤器,此过滤器对所有请求有效<br>
+	 * 此方法需在以下方法前之前调用:
+	 *
+	 * <ul>
+	 *     <li>{@link #setRoot(File)}  </li>
+	 *     <li>{@link #setRoot(String)}  </li>
+	 *     <li>{@link #createContext(String, HttpHandler)} </li>
+	 *     <li>{@link #addHandler(String, HttpHandler)}</li>
+	 *     <li>{@link #addAction(String, Action)} </li>
+	 * </ul>
+	 *
+	 * @param filter {@link Filter} 请求过滤器
+	 * @return this
+	 * @since 5.5.7
+	 */
+	public SimpleServer addFilter(Filter filter) {
+		this.filters.add(filter);
+		return this;
+	}
+
+	/**
+	 * 增加请求过滤器,此过滤器对所有请求有效<br>
+	 * 此方法需在以下方法前之前调用:
+	 *
+	 * <ul>
+	 *     <li>{@link #setRoot(File)}  </li>
+	 *     <li>{@link #setRoot(String)}  </li>
+	 *     <li>{@link #createContext(String, HttpHandler)} </li>
+	 *     <li>{@link #addHandler(String, HttpHandler)}</li>
+	 *     <li>{@link #addAction(String, Action)} </li>
+	 * </ul>
+	 *
+	 * @param filter {@link Filter} 请求过滤器
+	 * @return this
+	 * @since 5.5.7
+	 */
+	public SimpleServer addFilter(HttpFilter filter) {
+		return addFilter(new SimpleFilter() {
+			@Override
+			public void doFilter(HttpExchange httpExchange, Chain chain) throws IOException {
+				filter.doFilter(new HttpServerRequest(httpExchange), new HttpServerResponse(httpExchange), chain);
+			}
+		});
 	}
 
 	/**
 	 * 增加请求处理规则
 	 *
-	 * @param path    路径
-	 * @param handler 处理器
+	 * @param path    路径,例如:/a/b 或者 a/b
+	 * @param handler 处理器,包括请求和响应处理
 	 * @return this
+	 * @see #createContext(String, HttpHandler)
 	 */
 	public SimpleServer addHandler(String path, HttpHandler handler) {
+		createContext(path, handler);
+		return this;
+	}
+
+	/**
+	 * 创建请求映射上下文,创建后,用户访问指定路径可使用{@link HttpHandler} 中的规则进行处理
+	 *
+	 * @param path    路径,例如:/a/b 或者 a/b
+	 * @param handler 处理器,包括请求和响应处理
+	 * @return {@link HttpContext}
+	 * @since 5.5.7
+	 */
+	public HttpContext createContext(String path, HttpHandler handler) {
 		// 非/开头的路径会报错
 		path = StrUtil.addPrefixIfNot(path, StrUtil.SLASH);
-		this.server.createContext(path, handler);
-		return this;
+		final HttpContext context = this.server.createContext(path, handler);
+		// 增加整体过滤器
+		context.getFilters().addAll(this.filters);
+		return context;
 	}
 
 	/**

+ 26 - 0
hutool-http/src/main/java/cn/hutool/http/server/filter/HttpFilter.java

@@ -0,0 +1,26 @@
+package cn.hutool.http.server.filter;
+
+import cn.hutool.http.server.HttpServerRequest;
+import cn.hutool.http.server.HttpServerResponse;
+import com.sun.net.httpserver.Filter;
+
+import java.io.IOException;
+
+/**
+ * 过滤器接口,用于简化{@link Filter} 使用
+ *
+ * @author looly
+ * @since 5.5.7
+ */
+@FunctionalInterface
+public interface HttpFilter {
+
+	/**
+	 * 执行过滤
+	 * @param req {@link HttpServerRequest} 请求对象,用于获取请求内容
+	 * @param res {@link HttpServerResponse} 响应对象,用于写出内容
+	 * @param chain {@link Filter.Chain}
+	 * @throws IOException IO异常
+	 */
+	void doFilter(HttpServerRequest req, HttpServerResponse res, Filter.Chain chain) throws IOException;
+}

+ 17 - 0
hutool-http/src/main/java/cn/hutool/http/server/filter/SimpleFilter.java

@@ -0,0 +1,17 @@
+package cn.hutool.http.server.filter;
+
+import com.sun.net.httpserver.Filter;
+
+/**
+ * 匿名简单过滤器,跳过了描述
+ *
+ * @author looly
+ * @since 5.5.7
+ */
+public abstract class SimpleFilter extends Filter {
+
+	@Override
+	public String description() {
+		return "Anonymous Filter";
+	}
+}

+ 4 - 0
hutool-http/src/main/java/cn/hutool/http/server/filter/package-info.java

@@ -0,0 +1,4 @@
+/**
+ * {@link com.sun.net.httpserver.Filter} 实现包装
+ */
+package cn.hutool.http.server.filter;

+ 8 - 1
hutool-http/src/test/java/cn/hutool/http/server/SimpleServerTest.java

@@ -11,6 +11,10 @@ public class SimpleServerTest {
 
 	public static void main(String[] args) {
 		HttpUtil.createServer(8888)
+				.addFilter(((req, res, chain) -> {
+					Console.log("Filter: " + req.getPath());
+					chain.doFilter(req.getHttpExchange());
+				}))
 				// 设置默认根目录,classpath/html
 				.setRoot(FileUtil.file("html"))
 				// get数据测试,返回请求的PATH
@@ -46,7 +50,10 @@ public class SimpleServerTest {
 						}
 				)
 				// 测试输出响应内容是否能正常返回Content-Length头信息
-				.addAction("test/zeroStr", (req, res)-> res.write("0"))
+				.addAction("test/zeroStr", (req, res)-> {
+					res.write("0");
+					Console.log("Write 0 OK");
+				})
 				.start();
 	}
 }