> headers) {
- getHeaders().putAll(headers);
- return this;
- }
-
- /**
- * 设置Content-Type头,类似于:text/html;charset=utf-8
- * 如果用户传入的信息无charset信息,自动根据charset补充,charset设置见{@link #setCharset(Charset)}
- *
- * @param contentType Content-Type头内容
- * @return this
- */
- public HttpServerResponse setContentType(String contentType) {
- if (null != contentType && null != this.charset) {
- if (!contentType.contains(";charset=")) {
- contentType = ContentType.build(contentType, this.charset);
- }
- }
-
- return setHeader(HeaderName.CONTENT_TYPE, contentType);
- }
-
- /**
- * 设置Content-Length头
- *
- * @param contentLength Content-Length头内容
- * @return this
- */
- public HttpServerResponse setContentLength(final long contentLength) {
- return setHeader(HeaderName.CONTENT_LENGTH, String.valueOf(contentLength));
- }
-
- /**
- * 设置响应的编码
- *
- * @param charset 编码
- * @return this
- */
- public HttpServerResponse setCharset(final Charset charset) {
- this.charset = charset;
- return this;
- }
-
- /**
- * 设置属性
- *
- * @param name 属性名
- * @param value 属性值
- * @return this
- */
- public HttpServerResponse setAttr(final String name, final Object value) {
- this.httpExchange.setAttribute(name, value);
- return this;
- }
-
- /**
- * 获取响应数据流
- *
- * @return 响应数据流
- */
- public OutputStream getOut() {
- if (!this.isSendCode) {
- sendOk();
- }
- return this.httpExchange.getResponseBody();
- }
-
- /**
- * 获取响应数据流
- *
- * @return 响应数据流
- */
- public PrintWriter getWriter() {
- final Charset charset = ObjUtil.defaultIfNull(this.charset, DEFAULT_CHARSET);
- return new PrintWriter(new OutputStreamWriter(getOut(), charset));
- }
-
- /**
- * 写出数据到客户端
- *
- * @param data 数据
- * @param contentType Content-Type类型
- * @return this
- */
- public HttpServerResponse write(final String data, final String contentType) {
- setContentType(contentType);
- return write(data);
- }
-
- /**
- * 写出数据到客户端
- *
- * @param data 数据
- * @return this
- */
- public HttpServerResponse write(final String data) {
- final Charset charset = ObjUtil.defaultIfNull(this.charset, DEFAULT_CHARSET);
- return write(ByteUtil.toBytes(data, charset));
- }
-
- /**
- * 写出数据到客户端
- *
- * @param data 数据
- * @param contentType 返回的类型
- * @return this
- */
- public HttpServerResponse write(final byte[] data, final String contentType) {
- setContentType(contentType);
- return write(data);
- }
-
- /**
- * 写出数据到客户端
- *
- * @param data 数据
- * @return this
- */
- public HttpServerResponse write(final byte[] data) {
- final ByteArrayInputStream in = new ByteArrayInputStream(data);
- return write(in, in.available());
- }
-
- /**
- * 返回数据给客户端
- *
- * @param in 需要返回客户端的内容
- * @param contentType 返回的类型
- * @return this
- * @since 5.2.6
- */
- public HttpServerResponse write(final InputStream in, final String contentType) {
- return write(in, 0, contentType);
- }
-
- /**
- * 返回数据给客户端
- *
- * @param in 需要返回客户端的内容
- * @param length 内容长度,默认0表示不定长度,会输出Transfer-encoding: chunked
- * @param contentType 返回的类型
- * @return this
- * @since 5.2.7
- */
- public HttpServerResponse write(final InputStream in, final int length, final String contentType) {
- setContentType(contentType);
- return write(in, length);
- }
-
- /**
- * 写出数据到客户端
- *
- * @param in 数据流
- * @return this
- */
- public HttpServerResponse write(final InputStream in) {
- return write(in, 0);
- }
-
- /**
- * 写出数据到客户端
- *
- * @param in 数据流
- * @param length 指定响应内容长度,默认0表示不定长度,会输出Transfer-encoding: chunked
- * @return this
- */
- public HttpServerResponse write(final InputStream in, final int length) {
- if (!isSendCode) {
- sendOk(Math.max(0, length));
- }
- OutputStream out = null;
- try {
- out = this.httpExchange.getResponseBody();
- IoUtil.copy(in, out);
- } finally {
- IoUtil.closeQuietly(out);
- IoUtil.closeQuietly(in);
- }
- return this;
- }
-
- /**
- * 返回文件给客户端(文件下载)
- *
- * @param file 写出的文件对象
- * @return this
- * @since 5.2.6
- */
- public HttpServerResponse write(final File file) {
- return write(file, null);
- }
-
- /**
- * 返回文件给客户端(文件下载)
- *
- * @param file 写出的文件对象
- * @param fileName 文件名
- * @return this
- * @since 5.5.8
- */
- public HttpServerResponse write(final File file, String fileName) {
- final long fileSize = file.length();
- if(fileSize > Integer.MAX_VALUE){
- throw new IllegalArgumentException("File size is too bigger than " + Integer.MAX_VALUE);
- }
-
- if(StrUtil.isBlank(fileName)){
- fileName = file.getName();
- }
- final String contentType = FileUtil.getMimeType(fileName, ContentType.OCTET_STREAM.getValue());
- BufferedInputStream in = null;
- try {
- in = FileUtil.getInputStream(file);
- write(in, (int)fileSize, contentType, fileName);
- } finally {
- IoUtil.closeQuietly(in);
- }
- return this;
- }
-
- /**
- * 返回文件数据给客户端(文件下载)
- *
- * @param in 需要返回客户端的内容
- * @param contentType 返回的类型
- * @param fileName 文件名
- * @since 5.2.6
- */
- public void write(final InputStream in, final String contentType, final String fileName) {
- write(in, 0, contentType, fileName);
- }
-
- /**
- * 返回文件数据给客户端(文件下载)
- *
- * @param in 需要返回客户端的内容
- * @param length 长度
- * @param contentType 返回的类型
- * @param fileName 文件名
- * @return this
- * @since 5.2.7
- */
- public HttpServerResponse write(final InputStream in, final int length, final String contentType, final String fileName) {
- final Charset charset = ObjUtil.defaultIfNull(this.charset, DEFAULT_CHARSET);
-
- if (!contentType.startsWith("text/")) {
- // 非文本类型数据直接走下载
- setHeader(HeaderName.CONTENT_DISPOSITION, StrUtil.format("attachment;filename={}", UrlEncoder.encodeAll(fileName, charset)));
- }
- return write(in, length, contentType);
- }
-}
diff --git a/hutool-http/src/main/java/org/dromara/hutool/http/server/ServerConfig.java b/hutool-http/src/main/java/org/dromara/hutool/http/server/ServerConfig.java
new file mode 100644
index 000000000..0d9641c19
--- /dev/null
+++ b/hutool-http/src/main/java/org/dromara/hutool/http/server/ServerConfig.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2024 Hutool Team and hutool.cn
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.dromara.hutool.http.server;
+
+import javax.net.ssl.SSLContext;
+
+/**
+ * 服务器配置
+ *
+ * @author Looly
+ */
+public class ServerConfig {
+
+ /**
+ * 创建配置
+ *
+ * @return 配置
+ */
+ public static ServerConfig of(){
+ return new ServerConfig();
+ }
+
+ private String host = "localhost";
+ private int port = 8888;
+ private String root;
+ private SSLContext sslContext;
+
+ /**
+ * 获取服务器地址,默认127.0.0.1
+ *
+ * @return 服务器地址
+ */
+ public String getHost() {
+ return host;
+ }
+
+ /**
+ * 设置服务器地址,默认127.0.0.1
+ *
+ * @param host 服务器地址
+ * @return this
+ */
+ public ServerConfig setHost(final String host) {
+ this.host = host;
+ return this;
+ }
+
+ /**
+ * 获取服务器端口
+ *
+ * @return 服务器端口
+ */
+ public int getPort() {
+ return port;
+ }
+
+ /**
+ * 设置服务器端口
+ *
+ * @param port 服务器端口
+ * @return this
+ */
+ public ServerConfig setPort(final int port) {
+ this.port = port;
+ return this;
+ }
+
+ /**
+ * 获取服务器根目录
+ *
+ * @return 服务器根目录
+ */
+ public String getRoot() {
+ return root;
+ }
+
+ /**
+ * 设置服务器根目录
+ *
+ * @param root 服务器根目录
+ * @return this
+ */
+ public ServerConfig setRoot(final String root) {
+ this.root = root;
+ return this;
+ }
+
+ /**
+ * 获取SSL上下文
+ *
+ * @return SSL上下文
+ */
+ public SSLContext getSslContext() {
+ return sslContext;
+ }
+
+ /**
+ * 设置SSL上下文
+ *
+ * @param sslContext SSL上下文
+ * @return this
+ */
+ public ServerConfig setSslContext(final SSLContext sslContext) {
+ this.sslContext = sslContext;
+ return this;
+ }
+}
diff --git a/hutool-http/src/main/java/org/dromara/hutool/http/server/ServerRequest.java b/hutool-http/src/main/java/org/dromara/hutool/http/server/ServerRequest.java
new file mode 100644
index 000000000..785963336
--- /dev/null
+++ b/hutool-http/src/main/java/org/dromara/hutool/http/server/ServerRequest.java
@@ -0,0 +1,328 @@
+/*
+ * Copyright (c) 2024 Hutool Team and hutool.cn
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.dromara.hutool.http.server;
+
+import org.dromara.hutool.core.io.IORuntimeException;
+import org.dromara.hutool.core.io.IoUtil;
+import org.dromara.hutool.core.map.multi.ListValueMap;
+import org.dromara.hutool.core.net.url.UrlQueryUtil;
+import org.dromara.hutool.core.text.StrUtil;
+import org.dromara.hutool.core.util.CharsetUtil;
+import org.dromara.hutool.core.util.ObjUtil;
+import org.dromara.hutool.http.meta.ContentTypeUtil;
+import org.dromara.hutool.http.meta.HeaderName;
+import org.dromara.hutool.http.meta.Method;
+import org.dromara.hutool.http.multipart.MultipartFormData;
+import org.dromara.hutool.http.multipart.UploadSetting;
+import org.dromara.hutool.http.useragent.UserAgent;
+import org.dromara.hutool.http.useragent.UserAgentUtil;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.Charset;
+import java.util.Collection;
+
+/**
+ * 服务端请求对象,用于获取请求参数等
+ *
+ * @author looly
+ * @since 6.0.0
+ */
+public interface ServerRequest {
+
+ /**
+ * 默认编码,用于获取请求头和响应头编码,默认为UTF-8
+ */
+ Charset DEFAULT_CHARSET = CharsetUtil.UTF_8;
+
+ // region ----- method
+
+ /**
+ * 获取请求方法
+ *
+ * @return 请求方法
+ */
+ String getMethod();
+
+ /**
+ * 是否为GET请求
+ *
+ * @return 是否为GET请求
+ */
+ default boolean isGetMethod() {
+ return Method.GET.name().equalsIgnoreCase(getMethod());
+ }
+
+ /**
+ * 是否为POST请求
+ *
+ * @return 是否为POST请求
+ */
+ default boolean isPostMethod() {
+ return Method.POST.name().equalsIgnoreCase(getMethod());
+ }
+ // endregion
+
+ /**
+ * 获取请求路径,包含请求参数部分
+ *
+ * @return 请求路径,包含请求参数部分
+ */
+ String getPath();
+
+ /**
+ * 获取请求参数,包括pathVariable和queryString
+ *
+ * @return 请求参数,包括pathVariable和queryString
+ */
+ String getQuery();
+
+ // region ----- header
+
+ /**
+ * 获取请求头
+ *
+ * @param name 请求头名
+ * @return 请求头
+ */
+ String getHeader(final String name);
+
+ /**
+ * 获得请求header中的信息
+ *
+ * @param headerNameKey 头信息的KEY
+ * @return header值
+ */
+ default String getHeader(final HeaderName headerNameKey) {
+ return getHeader(headerNameKey.toString());
+ }
+
+ /**
+ * 获得请求header中的信息
+ *
+ * @param headerKey 头信息的KEY
+ * @param charset 字符集
+ * @return header值
+ */
+ default String getHeader(final String headerKey, final Charset charset) {
+ final String header = getHeader(headerKey);
+ if (null != header) {
+ return CharsetUtil.convert(header, CharsetUtil.ISO_8859_1, charset);
+ }
+ return null;
+ }
+
+ /**
+ * 获取Content-Type头信息
+ *
+ * @return Content-Type头信息
+ */
+ default String getContentType() {
+ return getHeader(HeaderName.CONTENT_TYPE);
+ }
+
+ /**
+ * 获取Content-Length头信息,单位:字节
+ *
+ * @return Content-Length头信息,单位:字节
+ */
+ default long getContentLength() {
+ final String contentLength = getHeader(HeaderName.CONTENT_LENGTH);
+ return StrUtil.isEmpty(contentLength) ? -1 : Long.parseLong(contentLength);
+ }
+
+ /**
+ * 获取编码,获取失败默认使用UTF-8,获取规则如下:
+ *
+ *
+ * 1、从Content-Type头中获取编码,类似于:text/html;charset=utf-8
+ *
+ *
+ * @return 编码,默认UTF-8
+ */
+ default Charset getCharset() {
+ final String contentType = getContentType();
+ return ObjUtil.defaultIfNull(ContentTypeUtil.getCharset(contentType), DEFAULT_CHARSET);
+ }
+
+ /**
+ * 获得User-Agent
+ *
+ * @return User-Agent字符串
+ */
+ default String getUserAgentStr() {
+ return getHeader(HeaderName.USER_AGENT);
+ }
+
+ /**
+ * 获得User-Agent,未识别返回null
+ *
+ * @return User-Agent字符串,未识别返回null
+ */
+ default UserAgent getUserAgent() {
+ return UserAgentUtil.parse(getUserAgentStr());
+ }
+
+ /**
+ * 获得Cookie信息字符串
+ *
+ * @return cookie字符串
+ */
+ default String getCookiesStr() {
+ return getHeader(HeaderName.COOKIE);
+ }
+
+ /**
+ * 是否为Multipart类型表单,此类型表单用于文件上传
+ *
+ * @return 是否为Multipart类型表单,此类型表单用于文件上传
+ */
+ default boolean isMultipart() {
+ if (!isPostMethod()) {
+ return false;
+ }
+
+ final String contentType = getContentType();
+ if (StrUtil.isBlank(contentType)) {
+ return false;
+ }
+ return contentType.toLowerCase().startsWith("multipart/");
+ }
+ // endregion
+
+ // region ----- body
+
+ /**
+ * 获取请求体流
+ *
+ * @return 请求体流
+ */
+ InputStream getBodyStream();
+
+ /**
+ * 获取请求体文本,可以是form表单、json、xml等任意内容
+ * 使用{@link #getCharset()}判断编码,判断失败使用UTF-8编码
+ *
+ * @return 请求
+ */
+ default String getBody() {
+ return getBody(getCharset());
+ }
+
+ /**
+ * 获取请求体文本,可以是form表单、json、xml等任意内容
+ *
+ * @param charset 编码
+ * @return 请求
+ */
+ default String getBody(final Charset charset) {
+ return StrUtil.str(getBodyBytes(), charset);
+ }
+
+ /**
+ * 获取body的bytes数组
+ *
+ * @return body的bytes数组
+ */
+ default byte[] getBodyBytes() {
+ return IoUtil.readBytes(getBodyStream(), true);
+ }
+
+ /**
+ * 获得MultiPart表单内容,多用于获得上传的文件
+ *
+ * @return MultipartFormData
+ * @throws IORuntimeException IO异常
+ * @since 5.3.0
+ */
+ default MultipartFormData getMultipart() throws IORuntimeException {
+ return parseMultipart(new UploadSetting());
+ }
+
+ /**
+ * 获得multipart/form-data 表单内容
+ * 包括文件和普通表单数据
+ * 在同一次请求中,此方法只能被执行一次!
+ *
+ * @param uploadSetting 上传文件的设定,包括最大文件大小、保存在内存的边界大小、临时目录、扩展名限定等
+ * @return MultiPart表单
+ * @throws IORuntimeException IO异常
+ * @since 5.3.0
+ */
+ default MultipartFormData parseMultipart(final UploadSetting uploadSetting) throws IORuntimeException {
+ final MultipartFormData formData = new MultipartFormData(uploadSetting);
+ try {
+ formData.parseRequestStream(getBodyStream(), getCharset());
+ } catch (final IOException e) {
+ throw new IORuntimeException(e);
+ }
+
+ return formData;
+ }
+ // endregion
+
+ // region ----- param
+ /**
+ * 获取指定名称的参数值,取第一个值
+ * @param name 参数名
+ * @return 参数值
+ * @since 5.5.8
+ */
+ default String getParam(final String name){
+ return getParams().getValue(name, 0);
+ }
+
+ /**
+ * 获取指定名称的参数值
+ *
+ * @param name 参数名
+ * @return 参数值
+ * @since 5.5.8
+ */
+ default Collection getParams(final String name){
+ return getParams().get(name);
+ }
+
+ /**
+ * 获取参数Map
+ *
+ * @return 参数map
+ */
+ default ListValueMap getParams() {
+ final ListValueMap params = new ListValueMap<>();
+ final Charset charset = getCharset();
+
+ //解析URL中的参数
+ final String query = getQuery();
+ if(StrUtil.isNotBlank(query)){
+ params.putAll(UrlQueryUtil.decodeQueryList(query, charset));
+ }
+
+ // 解析multipart中的参数
+ if(isMultipart()){
+ params.putAll(getMultipart().getParamListMap());
+ } else{
+ // 解析body中的参数
+ final String body = getBody();
+ if(StrUtil.isNotBlank(body)){
+ params.putAll(UrlQueryUtil.decodeQueryList(body, charset));
+ }
+ }
+ return params;
+ }
+ // endregion
+}
diff --git a/hutool-http/src/main/java/org/dromara/hutool/http/server/ServerResponse.java b/hutool-http/src/main/java/org/dromara/hutool/http/server/ServerResponse.java
new file mode 100644
index 000000000..5522b7d22
--- /dev/null
+++ b/hutool-http/src/main/java/org/dromara/hutool/http/server/ServerResponse.java
@@ -0,0 +1,334 @@
+/*
+ * Copyright (c) 2024 Hutool Team and hutool.cn
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.dromara.hutool.http.server;
+
+import org.dromara.hutool.core.io.IoUtil;
+import org.dromara.hutool.core.io.file.FileUtil;
+import org.dromara.hutool.core.net.url.UrlEncoder;
+import org.dromara.hutool.core.text.StrUtil;
+import org.dromara.hutool.core.util.ByteUtil;
+import org.dromara.hutool.core.util.CharsetUtil;
+import org.dromara.hutool.core.util.ObjUtil;
+import org.dromara.hutool.http.meta.ContentType;
+import org.dromara.hutool.http.meta.HeaderName;
+
+import java.io.*;
+import java.nio.charset.Charset;
+import java.util.List;
+
+/**
+ * 服务端响应接口,用于写出数据
+ *
+ * @author Looly
+ */
+public interface ServerResponse {
+
+ /**
+ * 默认编码,用于获取请求头和响应头编码,默认为UTF-8
+ */
+ Charset DEFAULT_CHARSET = CharsetUtil.UTF_8;
+
+ /**
+ * 设置状态码
+ *
+ * @param statusCode 状态码
+ * @return this
+ */
+ ServerResponse setStatus(int statusCode);
+
+ /**
+ * 设置编码,默认为UTF-8
+ *
+ * @param charset 编码
+ * @return this
+ */
+ ServerResponse setCharset(Charset charset);
+
+ /**
+ * 获取编码,默认为UTF-8
+ *
+ * @return 编码
+ */
+ Charset getCharset();
+
+ /**
+ * 添加响应头,如果已经存在,则追加
+ *
+ * @param header 头key
+ * @param value 值
+ * @return this
+ */
+ ServerResponse addHeader(final String header, final String value);
+
+ /**
+ * 设置响应头,如果已经存在,则覆盖
+ *
+ * @param header 头key
+ * @param value 值
+ * @return this
+ */
+ ServerResponse setHeader(final String header, final String value);
+
+ /**
+ * 设置响应头,如果已经存在,则覆盖
+ *
+ * @param headerName 头key
+ * @param value 值
+ * @return this
+ */
+ default ServerResponse setHeader(final HeaderName headerName, final String value) {
+ return setHeader(headerName.getValue(), value);
+ }
+
+ /**
+ * 设置响应头,如果已经存在,则覆盖
+ *
+ * @param header 头key
+ * @param value 值列表,如果为空,删除该header
+ * @return this
+ */
+ default ServerResponse setHeader(final String header, final List value) {
+ // 去除原有header
+ setHeader(header, (String) null);
+ if(null == value){
+ return this;
+ }
+
+ // 加入新的header
+ for (final String valueItem : value) {
+ addHeader(header, valueItem);
+ }
+ return this;
+ }
+
+ /**
+ * 设置Content-Type头,类似于:text/html;charset=utf-8
+ * 如果用户传入的信息无charset信息,自动根据charset补充,charset设置见{@link #setCharset(Charset)}
+ *
+ * @param contentType Content-Type头内容
+ * @return this
+ */
+ default ServerResponse setContentType(String contentType) {
+ if (null != contentType) {
+ final Charset charset = getCharset();
+ if (null != charset && !contentType.contains(";charset=")) {
+ contentType = ContentType.build(contentType, charset);
+ }
+ }
+
+ return setHeader(HeaderName.CONTENT_TYPE, contentType);
+ }
+
+ /**
+ * 设置Content-Length头,-1表示移除头
+ *
+ * @param contentLength Content-Length头内容
+ * @return this
+ */
+ default ServerResponse setContentLength(final long contentLength) {
+ return setHeader(HeaderName.CONTENT_LENGTH,
+ contentLength < 0 ? null : String.valueOf(contentLength));
+ }
+
+ /**
+ * 获取输出流,用于写出数据
+ *
+ * @return 输出流
+ */
+ OutputStream getOutputStream();
+
+ /**
+ * 获取响应数据流
+ *
+ * @return 响应数据流
+ */
+ default PrintWriter getWriter() {
+ final Charset charset = ObjUtil.defaultIfNull(getCharset(), DEFAULT_CHARSET);
+ return new PrintWriter(new OutputStreamWriter(getOutputStream(), charset));
+ }
+
+ /**
+ * 写出数据到客户端
+ *
+ * @param data 数据
+ * @param contentType Content-Type类型
+ * @return this
+ */
+ default ServerResponse write(final String data, final String contentType) {
+ setContentType(contentType);
+ return write(data);
+ }
+
+ /**
+ * 写出数据到客户端
+ *
+ * @param data 数据
+ * @return this
+ */
+ default ServerResponse write(final String data) {
+ final Charset charset = ObjUtil.defaultIfNull(getCharset(), DEFAULT_CHARSET);
+ return write(ByteUtil.toBytes(data, charset));
+ }
+
+ /**
+ * 写出数据到客户端
+ *
+ * @param data 数据
+ * @param contentType 返回的类型
+ * @return this
+ */
+ default ServerResponse write(final byte[] data, final String contentType) {
+ setContentType(contentType);
+ return write(data);
+ }
+
+ /**
+ * 写出数据到客户端
+ *
+ * @param data 数据
+ * @return this
+ */
+ default ServerResponse write(final byte[] data) {
+ final ByteArrayInputStream in = new ByteArrayInputStream(data);
+ return write(in, in.available());
+ }
+
+ /**
+ * 返回数据给客户端
+ *
+ * @param in 需要返回客户端的内容
+ * @param contentType 返回的类型
+ * @return this
+ * @since 5.2.6
+ */
+ default ServerResponse write(final InputStream in, final String contentType) {
+ return write(in, 0, contentType);
+ }
+
+ /**
+ * 返回数据给客户端
+ *
+ * @param in 需要返回客户端的内容
+ * @param length 内容长度,默认0表示不定长度,会输出Transfer-encoding: chunked
+ * @param contentType 返回的类型
+ * @return this
+ * @since 5.2.7
+ */
+ default ServerResponse write(final InputStream in, final int length, final String contentType) {
+ setContentType(contentType);
+ return write(in, length);
+ }
+
+ /**
+ * 写出数据到客户端
+ *
+ * @param in 数据流
+ * @return this
+ */
+ default ServerResponse write(final InputStream in) {
+ return write(in, 0);
+ }
+
+ /**
+ * 写出数据到客户端
+ *
+ * @param in 数据流
+ * @param length 指定响应内容长度,默认0表示不定长度,会输出Transfer-encoding: chunked
+ * @return this
+ */
+ default ServerResponse write(final InputStream in, final int length) {
+ setContentLength(length);
+ OutputStream out = null;
+ try {
+ out = getOutputStream();
+ IoUtil.copy(in, out);
+ } finally {
+ IoUtil.closeQuietly(out);
+ IoUtil.closeQuietly(in);
+ }
+ return this;
+ }
+
+ /**
+ * 返回文件给客户端(文件下载)
+ *
+ * @param file 写出的文件对象
+ * @return this
+ * @since 5.2.6
+ */
+ default ServerResponse write(final File file) {
+ return write(file, null);
+ }
+
+ /**
+ * 返回文件给客户端(文件下载)
+ *
+ * @param file 写出的文件对象
+ * @param fileName 文件名
+ * @return this
+ */
+ default ServerResponse write(final File file, String fileName) {
+ final long fileSize = file.length();
+ if (fileSize > Integer.MAX_VALUE) {
+ throw new IllegalArgumentException("File size is too bigger than " + Integer.MAX_VALUE);
+ }
+
+ if (StrUtil.isBlank(fileName)) {
+ fileName = file.getName();
+ }
+ final String contentType = FileUtil.getMimeType(fileName, ContentType.OCTET_STREAM.getValue());
+ BufferedInputStream in = null;
+ try {
+ in = FileUtil.getInputStream(file);
+ write(in, (int) fileSize, contentType, fileName);
+ } finally {
+ IoUtil.closeQuietly(in);
+ }
+ return this;
+ }
+
+ /**
+ * 返回文件数据给客户端(文件下载)
+ *
+ * @param in 需要返回客户端的内容
+ * @param contentType 返回的类型
+ * @param fileName 文件名
+ * @return this
+ */
+ default ServerResponse write(final InputStream in, final String contentType, final String fileName) {
+ return write(in, 0, contentType, fileName);
+ }
+
+ /**
+ * 返回文件数据给客户端(文件下载)
+ *
+ * @param in 需要返回客户端的内容
+ * @param length 长度
+ * @param contentType 返回的类型
+ * @param fileName 文件名
+ * @return this
+ */
+ default ServerResponse write(final InputStream in, final int length, final String contentType, final String fileName) {
+ final Charset charset = ObjUtil.defaultIfNull(getCharset(), DEFAULT_CHARSET);
+
+ if (!contentType.startsWith("text/")) {
+ // 非文本类型数据直接走下载
+ setHeader(HeaderName.CONTENT_DISPOSITION, StrUtil.format("attachment;filename={}", UrlEncoder.encodeAll(fileName, charset)));
+ }
+ return write(in, length, contentType);
+ }
+}
diff --git a/hutool-http/src/main/java/org/dromara/hutool/http/server/engine/AbstractServerEngine.java b/hutool-http/src/main/java/org/dromara/hutool/http/server/engine/AbstractServerEngine.java
new file mode 100644
index 000000000..4568cd0be
--- /dev/null
+++ b/hutool-http/src/main/java/org/dromara/hutool/http/server/engine/AbstractServerEngine.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2024 Hutool Team and hutool.cn
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.dromara.hutool.http.server.engine;
+
+import org.dromara.hutool.http.server.ServerConfig;
+import org.dromara.hutool.http.server.handler.HttpHandler;
+
+/**
+ * 服务端引擎抽象类,实现重置引擎功能
+ *
+ * @author looly
+ */
+public abstract class AbstractServerEngine implements ServerEngine {
+
+ protected ServerConfig config;
+ protected HttpHandler handler;
+
+ @Override
+ public AbstractServerEngine init(final ServerConfig config) {
+ this.config = config;
+ reset();
+ return this;
+ }
+
+ @Override
+ public AbstractServerEngine setHandler(final HttpHandler handler) {
+ this.handler = handler;
+ return this;
+ }
+
+ /**
+ * 重置引擎
+ */
+ protected abstract void reset();
+
+ /**
+ * 初始化引擎,实现逻辑中如果初始化完成,不再重新初始化
+ */
+ protected abstract void initEngine();
+}
diff --git a/hutool-http/src/main/java/org/dromara/hutool/http/server/engine/ServerEngine.java b/hutool-http/src/main/java/org/dromara/hutool/http/server/engine/ServerEngine.java
new file mode 100644
index 000000000..90c04191b
--- /dev/null
+++ b/hutool-http/src/main/java/org/dromara/hutool/http/server/engine/ServerEngine.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2024 Hutool Team and hutool.cn
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.dromara.hutool.http.server.engine;
+
+import org.dromara.hutool.http.server.ServerConfig;
+import org.dromara.hutool.http.server.handler.HttpHandler;
+
+/**
+ * HTTP服务器引擎
+ *
+ * @author looly
+ * @since 6.0.0
+ */
+public interface ServerEngine {
+
+ /**
+ * 初始化HTTP服务器
+ *
+ * @param config 配置项
+ * @return this
+ */
+ ServerEngine init(ServerConfig config);
+
+ /**
+ * 设置请求处理器
+ *
+ * @param handler 请求处理器
+ * @return this
+ */
+ ServerEngine setHandler(HttpHandler handler);
+
+ /**
+ * 启动HTTP服务器
+ */
+ void start();
+
+ /**
+ * 获取原始引擎的钩子方法,用于自定义特殊属性,如插件等
+ *
+ * @return 对应HTTP服务器实现的引擎对象
+ * @since 6.0.0
+ */
+ Object getRawEngine();
+}
diff --git a/hutool-http/src/main/java/org/dromara/hutool/http/server/action/package-info.java b/hutool-http/src/main/java/org/dromara/hutool/http/server/engine/jetty/package-info.java
similarity index 77%
rename from hutool-http/src/main/java/org/dromara/hutool/http/server/action/package-info.java
rename to hutool-http/src/main/java/org/dromara/hutool/http/server/engine/jetty/package-info.java
index 68eb1ef52..8675fed66 100644
--- a/hutool-http/src/main/java/org/dromara/hutool/http/server/action/package-info.java
+++ b/hutool-http/src/main/java/org/dromara/hutool/http/server/engine/jetty/package-info.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013-2024 Hutool Team and hutool.cn
+ * Copyright (c) 2024 Hutool Team and hutool.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,8 +15,8 @@
*/
/**
- * {@link com.sun.net.httpserver.HttpServer} 封装
+ * Jetty引擎实现
*
- * @author looly
+ * @author Looly
*/
-package org.dromara.hutool.http.server.action;
+package org.dromara.hutool.http.server.engine.jetty;
diff --git a/hutool-http/src/main/java/org/dromara/hutool/http/server/engine/package-info.java b/hutool-http/src/main/java/org/dromara/hutool/http/server/engine/package-info.java
new file mode 100644
index 000000000..ca7898b93
--- /dev/null
+++ b/hutool-http/src/main/java/org/dromara/hutool/http/server/engine/package-info.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2024 Hutool Team and hutool.cn
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * HTTP服务器引擎包
+ *
+ * @author Looly
+ * @since 6.0.0
+ */
+package org.dromara.hutool.http.server.engine;
diff --git a/hutool-http/src/main/java/org/dromara/hutool/http/server/HttpExchangeWrapper.java b/hutool-http/src/main/java/org/dromara/hutool/http/server/engine/sun/HttpExchangeWrapper.java
similarity index 91%
rename from hutool-http/src/main/java/org/dromara/hutool/http/server/HttpExchangeWrapper.java
rename to hutool-http/src/main/java/org/dromara/hutool/http/server/engine/sun/HttpExchangeWrapper.java
index eb5383c57..d17f88fac 100644
--- a/hutool-http/src/main/java/org/dromara/hutool/http/server/HttpExchangeWrapper.java
+++ b/hutool-http/src/main/java/org/dromara/hutool/http/server/engine/sun/HttpExchangeWrapper.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package org.dromara.hutool.http.server;
+package org.dromara.hutool.http.server.engine.sun;
import com.sun.net.httpserver.Headers;
import com.sun.net.httpserver.HttpContext;
@@ -36,8 +36,8 @@ import java.net.URI;
public class HttpExchangeWrapper extends HttpExchange implements Wrapper {
private final HttpExchange raw;
- private final HttpServerRequest request;
- private final HttpServerResponse response;
+ private final SunServerRequest request;
+ private final SunServerResponse response;
/**
* 构造
@@ -46,8 +46,8 @@ public class HttpExchangeWrapper extends HttpExchange implements Wrapper filters;
+ private final SunHttpServerEngine engine;
/**
* 构造
@@ -71,39 +65,23 @@ public class SimpleServer {
* @param address 监听地址
*/
public SimpleServer(final InetSocketAddress address) {
- this(address, (HttpsConfigurator) null);
+ this(address, null);
}
/**
* 构造
*
- * @param address 监听地址
+ * @param address 监听地址
* @param sslContext ssl配置
*/
public SimpleServer(final InetSocketAddress address, final SSLContext sslContext) {
- this(address, new HttpsConfigurator(sslContext));
- }
+ this.engine = new SunHttpServerEngine();
- /**
- * 构造
- *
- * @param address 监听地址
- * @param configurator https配置信息,用于使用自定义SSL(TLS)证书等
- */
- public SimpleServer(final InetSocketAddress address, final HttpsConfigurator configurator) {
- try {
- if(null != configurator){
- final HttpsServer server = HttpsServer.create(address, 0);
- server.setHttpsConfigurator(configurator);
- this.server = server;
- } else{
- this.server = HttpServer.create(address, 0);
- }
- } catch (final IOException e) {
- throw new IORuntimeException(e);
- }
- setExecutor(GlobalThreadPool.getExecutor());
- filters = new ArrayList<>();
+ final ServerConfig serverConfig = ServerConfig.of()
+ .setHost(address.getHostName())
+ .setPort(address.getPort())
+ .setSslContext(sslContext);
+ this.engine.init(serverConfig);
}
/**
@@ -115,7 +93,6 @@ public class SimpleServer {
* {@link #setRoot(String)}
* {@link #createContext(String, HttpHandler)}
* {@link #addHandler(String, HttpHandler)}
- * {@link #addAction(String, Action)}
*
*
* @param filter {@link Filter} 请求过滤器
@@ -123,7 +100,7 @@ public class SimpleServer {
* @since 5.5.7
*/
public SimpleServer addFilter(final Filter filter) {
- this.filters.add(filter);
+ this.engine.addFilter(filter);
return this;
}
@@ -136,7 +113,6 @@ public class SimpleServer {
* {@link #setRoot(String)}
* {@link #createContext(String, HttpHandler)}
* {@link #addHandler(String, HttpHandler)}
- * {@link #addAction(String, Action)}
*
*
* @param filter {@link Filter} 请求过滤器
@@ -177,10 +153,22 @@ public class SimpleServer {
public HttpContext createContext(String path, final HttpHandler handler) {
// 非/开头的路径会报错
path = StrUtil.addPrefixIfNot(path, StrUtil.SLASH);
- final HttpContext context = this.server.createContext(path, handler);
- // 增加整体过滤器
- context.getFilters().addAll(this.filters);
- return context;
+ return this.engine.createContext(path, handler);
+ }
+
+ /**
+ * 增加请求处理规则,使用默认的{@link RootHandler},默认从当前项目根目录读取页面
+ *
+ * @param path 路径,例如:/a/b 或者 a/b
+ * @param action 处理器,包括请求和响应处理
+ * @return this
+ * @since 6.0.0
+ */
+ public SimpleServer addAction(final String path, final org.dromara.hutool.http.server.handler.HttpHandler action) {
+ return addHandler(path, exchange -> {
+ final HttpExchangeWrapper exchangeWrapper = new HttpExchangeWrapper(exchange);
+ action.handle(exchangeWrapper.getRequest(), exchangeWrapper.getResponse());
+ });
}
/**
@@ -200,18 +188,8 @@ public class SimpleServer {
* @return this
*/
public SimpleServer setRoot(final File root) {
- return addAction("/", new RootAction(root));
- }
-
- /**
- * 增加请求处理规则
- *
- * @param path 路径
- * @param action 处理器
- * @return this
- */
- public SimpleServer addAction(final String path, final Action action) {
- return addHandler(path, new ActionHandler(action));
+ this.engine.setHandler(new RootHandler(root));
+ return this;
}
/**
@@ -221,7 +199,7 @@ public class SimpleServer {
* @return this
*/
public SimpleServer setExecutor(final Executor executor) {
- this.server.setExecutor(executor);
+ this.engine.setExecutor(executor);
return this;
}
@@ -231,7 +209,7 @@ public class SimpleServer {
* @return {@link HttpServer}
*/
public HttpServer getRawServer() {
- return this.server;
+ return this.engine.getRawEngine();
}
/**
@@ -240,7 +218,7 @@ public class SimpleServer {
* @return {@link InetSocketAddress}
*/
public InetSocketAddress getAddress() {
- return this.server.getAddress();
+ return getRawServer().getAddress();
}
/**
@@ -249,6 +227,6 @@ public class SimpleServer {
public void start() {
final InetSocketAddress address = getAddress();
Console.log("Hutool Simple Http Server listen on 【{}:{}】", address.getHostName(), address.getPort());
- this.server.start();
+ this.engine.start();
}
}
diff --git a/hutool-http/src/main/java/org/dromara/hutool/http/server/engine/sun/SunHttpServerEngine.java b/hutool-http/src/main/java/org/dromara/hutool/http/server/engine/sun/SunHttpServerEngine.java
new file mode 100644
index 000000000..53ad8fdd9
--- /dev/null
+++ b/hutool-http/src/main/java/org/dromara/hutool/http/server/engine/sun/SunHttpServerEngine.java
@@ -0,0 +1,163 @@
+/*
+ * Copyright (c) 2024 Hutool Team and hutool.cn
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.dromara.hutool.http.server.engine.sun;
+
+import com.sun.net.httpserver.*;
+import org.dromara.hutool.core.io.IORuntimeException;
+import org.dromara.hutool.core.text.StrUtil;
+import org.dromara.hutool.core.thread.GlobalThreadPool;
+import org.dromara.hutool.http.server.engine.AbstractServerEngine;
+import org.dromara.hutool.http.server.ServerConfig;
+import org.dromara.hutool.http.server.engine.sun.filter.HttpFilter;
+import org.dromara.hutool.http.server.engine.sun.filter.SimpleFilter;
+
+import javax.net.ssl.SSLContext;
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Executor;
+
+/**
+ * 基于Sun HttpServer的HTTP服务器引擎实现
+ *
+ * @author looly
+ * @since 6.0.0
+ */
+public class SunHttpServerEngine extends AbstractServerEngine {
+
+ private HttpServer server;
+ private List filters;
+
+ /**
+ * 构造
+ */
+ public SunHttpServerEngine() {
+ }
+
+ @Override
+ public void start() {
+ initEngine();
+ this.server.start();
+ }
+
+ @Override
+ public HttpServer getRawEngine() {
+ return this.server;
+ }
+
+ /**
+ * 增加请求过滤器,此过滤器对所有请求有效
+ * 此方法需在以下方法前之前调用:
+ *
+ *
+ * - {@link #createContext(String, HttpHandler)}
+ *
+ *
+ * @param filter {@link Filter} 请求过滤器
+ * @return this
+ * @since 5.5.7
+ */
+ public SunHttpServerEngine addFilter(final Filter filter) {
+ if (null == this.filters) {
+ this.filters = new ArrayList<>();
+ }
+ this.filters.add(filter);
+ return this;
+ }
+
+ /**
+ * 增加请求过滤器,此过滤器对所有请求有效
+ * 此方法需在以下方法前之前调用:
+ *
+ *
+ * - {@link #createContext(String, HttpHandler)}
+ *
+ *
+ * @param filter {@link Filter} 请求过滤器
+ * @return this
+ * @since 5.5.7
+ */
+ public SunHttpServerEngine addFilter(final HttpFilter filter) {
+ return addFilter(new SimpleFilter() {
+ @Override
+ public void doFilter(final HttpExchange httpExchange, final Chain chain) throws IOException {
+ final HttpExchangeWrapper httpExchangeWrapper = new HttpExchangeWrapper(httpExchange);
+ filter.doFilter(httpExchangeWrapper.getRequest(), httpExchangeWrapper.getResponse(), chain);
+ }
+ });
+ }
+
+ /**
+ * 创建请求映射上下文,创建后,用户访问指定路径可使用{@link HttpHandler} 中的规则进行处理
+ *
+ * @param path 路径,例如:/a/b 或者 a/b
+ * @param handler 处理器,包括请求和响应处理
+ * @return {@link HttpContext}
+ * @since 5.5.7
+ */
+ public HttpContext createContext(String path, final HttpHandler handler) {
+ // 非/开头的路径会报错
+ path = StrUtil.addPrefixIfNot(path, StrUtil.SLASH);
+ final HttpContext context = this.server.createContext(path, handler);
+ // 增加整体过滤器
+ context.getFilters().addAll(this.filters);
+ return context;
+ }
+
+ /**
+ * 设置自定义线程池
+ *
+ * @param executor {@link Executor}
+ * @return this
+ */
+ public SunHttpServerEngine setExecutor(final Executor executor) {
+ this.server.setExecutor(executor);
+ return this;
+ }
+
+ @Override
+ protected void reset() {
+ if (null != this.server) {
+ this.server.stop(0);
+ this.server = null;
+ }
+ }
+
+ @Override
+ protected void initEngine() {
+ final ServerConfig config = this.config;
+ final InetSocketAddress address = new InetSocketAddress(config.getHost(), config.getPort());
+ final SSLContext sslContext = config.getSslContext();
+ try {
+ if (null != sslContext) {
+ final HttpsServer server = HttpsServer.create(address, 0);
+ server.setHttpsConfigurator(new HttpsConfigurator(sslContext));
+ this.server = server;
+ } else {
+ this.server = HttpServer.create(address, 0);
+ }
+ } catch (final IOException e) {
+ throw new IORuntimeException(e);
+ }
+ setExecutor(GlobalThreadPool.getExecutor());
+ createContext("/", exchange -> SunHttpServerEngine.this.handler.handle(
+ new SunServerRequest(exchange),
+ new SunServerResponse(exchange)
+ ));
+ }
+}
diff --git a/hutool-http/src/main/java/org/dromara/hutool/http/server/HttpServerBase.java b/hutool-http/src/main/java/org/dromara/hutool/http/server/engine/sun/SunServerBase.java
similarity index 76%
rename from hutool-http/src/main/java/org/dromara/hutool/http/server/HttpServerBase.java
rename to hutool-http/src/main/java/org/dromara/hutool/http/server/engine/sun/SunServerBase.java
index 50f6275b9..98e5ab952 100644
--- a/hutool-http/src/main/java/org/dromara/hutool/http/server/HttpServerBase.java
+++ b/hutool-http/src/main/java/org/dromara/hutool/http/server/engine/sun/SunServerBase.java
@@ -14,14 +14,12 @@
* limitations under the License.
*/
-package org.dromara.hutool.http.server;
+package org.dromara.hutool.http.server.engine.sun;
-import org.dromara.hutool.core.util.CharsetUtil;
import com.sun.net.httpserver.HttpContext;
import com.sun.net.httpserver.HttpExchange;
import java.io.Closeable;
-import java.nio.charset.Charset;
/**
* HttpServer公用对象,提供HttpExchange包装和公用方法
@@ -29,18 +27,16 @@ import java.nio.charset.Charset;
* @author looly
* @since 5.2.6
*/
-public class HttpServerBase implements Closeable {
+public class SunServerBase implements Closeable {
- final static Charset DEFAULT_CHARSET = CharsetUtil.UTF_8;
-
- final HttpExchange httpExchange;
+ protected final HttpExchange httpExchange;
/**
* 构造
*
* @param httpExchange {@link HttpExchange}
*/
- public HttpServerBase(final HttpExchange httpExchange) {
+ public SunServerBase(final HttpExchange httpExchange) {
this.httpExchange = httpExchange;
}
@@ -49,7 +45,7 @@ public class HttpServerBase implements Closeable {
*
* @return {@link HttpExchange}对象
*/
- public HttpExchange getHttpExchange() {
+ public HttpExchange getExchange() {
return this.httpExchange;
}
@@ -60,7 +56,7 @@ public class HttpServerBase implements Closeable {
* @since 5.5.7
*/
public HttpContext getHttpContext() {
- return getHttpExchange().getHttpContext();
+ return getExchange().getHttpContext();
}
/**
diff --git a/hutool-http/src/main/java/org/dromara/hutool/http/server/HttpServerRequest.java b/hutool-http/src/main/java/org/dromara/hutool/http/server/engine/sun/SunServerRequest.java
similarity index 55%
rename from hutool-http/src/main/java/org/dromara/hutool/http/server/HttpServerRequest.java
rename to hutool-http/src/main/java/org/dromara/hutool/http/server/engine/sun/SunServerRequest.java
index 1906dae7c..c9432d758 100644
--- a/hutool-http/src/main/java/org/dromara/hutool/http/server/HttpServerRequest.java
+++ b/hutool-http/src/main/java/org/dromara/hutool/http/server/engine/sun/SunServerRequest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013-2024 Hutool Team and hutool.cn
+ * Copyright (c) 2024 Hutool Team and hutool.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package org.dromara.hutool.http.server;
+package org.dromara.hutool.http.server.engine.sun;
import com.sun.net.httpserver.Headers;
import com.sun.net.httpserver.HttpExchange;
@@ -26,19 +26,15 @@ import org.dromara.hutool.core.map.CaseInsensitiveMap;
import org.dromara.hutool.core.map.MapUtil;
import org.dromara.hutool.core.map.multi.ListValueMap;
import org.dromara.hutool.core.net.NetUtil;
-import org.dromara.hutool.http.multipart.MultipartFormData;
-import org.dromara.hutool.http.multipart.UploadSetting;
import org.dromara.hutool.core.net.url.UrlQueryUtil;
import org.dromara.hutool.core.text.StrUtil;
-import org.dromara.hutool.core.util.CharsetUtil;
import org.dromara.hutool.core.util.ObjUtil;
import org.dromara.hutool.http.meta.ContentTypeUtil;
import org.dromara.hutool.http.meta.HeaderName;
-import org.dromara.hutool.http.meta.Method;
-import org.dromara.hutool.http.useragent.UserAgent;
-import org.dromara.hutool.http.useragent.UserAgentUtil;
+import org.dromara.hutool.http.multipart.MultipartFormData;
+import org.dromara.hutool.http.multipart.UploadSetting;
+import org.dromara.hutool.http.server.ServerRequest;
-import java.io.IOException;
import java.io.InputStream;
import java.net.HttpCookie;
import java.net.URI;
@@ -47,12 +43,11 @@ import java.util.Collection;
import java.util.Map;
/**
- * Http请求对象,对{@link HttpExchange}封装
+ * Sun Http请求包装
*
- * @author looly
- * @since 5.2.6
+ * @author Looly
*/
-public class HttpServerRequest extends HttpServerBase {
+public class SunServerRequest extends SunServerBase implements ServerRequest {
private Map cookieCache;
private ListValueMap paramsCache;
@@ -65,37 +60,15 @@ public class HttpServerRequest extends HttpServerBase {
*
* @param httpExchange {@link HttpExchange}
*/
- public HttpServerRequest(final HttpExchange httpExchange) {
+ public SunServerRequest(final HttpExchange httpExchange) {
super(httpExchange);
}
- /**
- * 获得Http Method
- *
- * @return Http Method
- */
+ @Override
public String getMethod() {
return this.httpExchange.getRequestMethod();
}
- /**
- * 是否为GET请求
- *
- * @return 是否为GET请求
- */
- public boolean isGetMethod() {
- return Method.GET.name().equalsIgnoreCase(getMethod());
- }
-
- /**
- * 是否为POST请求
- *
- * @return 是否为POST请求
- */
- public boolean isPostMethod() {
- return Method.POST.name().equalsIgnoreCase(getMethod());
- }
-
/**
* 获得请求URI
*
@@ -105,20 +78,12 @@ public class HttpServerRequest extends HttpServerBase {
return this.httpExchange.getRequestURI();
}
- /**
- * 获得请求路径Path
- *
- * @return 请求路径
- */
+ @Override
public String getPath() {
return getURI().getPath();
}
- /**
- * 获取请求参数
- *
- * @return 参数字符串
- */
+ @Override
public String getQuery() {
return getURI().getQuery();
}
@@ -132,59 +97,12 @@ public class HttpServerRequest extends HttpServerBase {
return this.httpExchange.getRequestHeaders();
}
- /**
- * 获得请求header中的信息
- *
- * @param headerNameKey 头信息的KEY
- * @return header值
- */
- public String getHeader(final HeaderName headerNameKey) {
- return getHeader(headerNameKey.toString());
+ @Override
+ public String getHeader(final String name) {
+ return getHeaders().getFirst(name);
}
- /**
- * 获得请求header中的信息
- *
- * @param headerKey 头信息的KEY
- * @return header值
- */
- public String getHeader(final String headerKey) {
- return getHeaders().getFirst(headerKey);
- }
-
- /**
- * 获得请求header中的信息
- *
- * @param headerKey 头信息的KEY
- * @param charset 字符集
- * @return header值
- */
- public String getHeader(final String headerKey, final Charset charset) {
- final String header = getHeader(headerKey);
- if (null != header) {
- return CharsetUtil.convert(header, CharsetUtil.ISO_8859_1, charset);
- }
- return null;
- }
-
- /**
- * 获取Content-Type头信息
- *
- * @return Content-Type头信息
- */
- public String getContentType() {
- return getHeader(HeaderName.CONTENT_TYPE);
- }
-
- /**
- * 获取编码,获取失败默认使用UTF-8,获取规则如下:
- *
- *
- * 1、从Content-Type头中获取编码,类似于:text/html;charset=utf-8
- *
- *
- * @return 编码,默认UTF-8
- */
+ @Override
public Charset getCharset() {
if(null == this.charsetCache){
final String contentType = getContentType();
@@ -194,33 +112,6 @@ public class HttpServerRequest extends HttpServerBase {
return this.charsetCache;
}
- /**
- * 获得User-Agent
- *
- * @return User-Agent字符串
- */
- public String getUserAgentStr() {
- return getHeader(HeaderName.USER_AGENT);
- }
-
- /**
- * 获得User-Agent,未识别返回null
- *
- * @return User-Agent字符串,未识别返回null
- */
- public UserAgent getUserAgent() {
- return UserAgentUtil.parse(getUserAgentStr());
- }
-
- /**
- * 获得Cookie信息字符串
- *
- * @return cookie字符串
- */
- public String getCookiesStr() {
- return getHeader(HeaderName.COOKIE);
- }
-
/**
* 获得Cookie信息列表
*
@@ -238,9 +129,9 @@ public class HttpServerRequest extends HttpServerBase {
public Map getCookieMap() {
if (null == this.cookieCache) {
cookieCache = MapUtil.view(MapUtil.putAll(
- new CaseInsensitiveMap<>(),
- NetUtil.parseCookies(getCookiesStr()),
- HttpCookie::getName));
+ new CaseInsensitiveMap<>(),
+ NetUtil.parseCookies(getCookiesStr()),
+ HttpCookie::getName));
}
return cookieCache;
}
@@ -255,60 +146,7 @@ public class HttpServerRequest extends HttpServerBase {
return getCookieMap().get(cookieName);
}
- /**
- * 是否为Multipart类型表单,此类型表单用于文件上传
- *
- * @return 是否为Multipart类型表单,此类型表单用于文件上传
- */
- public boolean isMultipart() {
- if (!isPostMethod()) {
- return false;
- }
-
- final String contentType = getContentType();
- if (StrUtil.isBlank(contentType)) {
- return false;
- }
- return contentType.toLowerCase().startsWith("multipart/");
- }
-
- /**
- * 获取请求体文本,可以是form表单、json、xml等任意内容
- * 使用{@link #getCharset()}判断编码,判断失败使用UTF-8编码
- *
- * @return 请求
- */
- public String getBody() {
- return getBody(getCharset());
- }
-
- /**
- * 获取请求体文本,可以是form表单、json、xml等任意内容
- *
- * @param charset 编码
- * @return 请求
- */
- public String getBody(final Charset charset) {
- return StrUtil.str(getBodyBytes(), charset);
- }
-
- /**
- * 获取body的bytes数组
- *
- * @return body的bytes数组
- */
- public byte[] getBodyBytes(){
- if(null == this.bodyCache){
- this.bodyCache = IoUtil.readBytes(getBodyStream(), true);
- }
- return this.bodyCache;
- }
-
- /**
- * 获取请求体的流,流中可以读取请求内容,包括请求表单数据或文件上传数据
- *
- * @return 流
- */
+ @Override
public InputStream getBodyStream() {
InputStream bodyStream = this.httpExchange.getRequestBody();
@@ -330,32 +168,23 @@ public class HttpServerRequest extends HttpServerBase {
return bodyStream;
}
- /**
- * 获取指定名称的参数值,取第一个值
- * @param name 参数名
- * @return 参数值
- * @since 5.5.8
- */
- public String getParam(final String name){
- return getParams().getValue(name, 0);
+ @Override
+ public byte[] getBodyBytes(){
+ if(null == this.bodyCache){
+ this.bodyCache = IoUtil.readBytes(getBodyStream(), true);
+ }
+ return this.bodyCache;
}
- /**
- * 获取指定名称的参数值
- *
- * @param name 参数名
- * @return 参数值
- * @since 5.5.8
- */
- public Collection getParams(final String name){
- return getParams().get(name);
+ @Override
+ public MultipartFormData getMultipart() throws IORuntimeException {
+ if(null == this.multipartFormDataCache){
+ this.multipartFormDataCache = parseMultipart(new UploadSetting());
+ }
+ return this.multipartFormDataCache;
}
- /**
- * 获取参数Map
- *
- * @return 参数map
- */
+ @Override
public ListValueMap getParams() {
if (null == this.paramsCache) {
this.paramsCache = new ListValueMap<>();
@@ -436,39 +265,4 @@ public class HttpServerRequest extends HttpServerBase {
ip = this.httpExchange.getRemoteAddress().getHostName();
return NetUtil.getMultistageReverseProxyIp(ip);
}
-
- /**
- * 获得MultiPart表单内容,多用于获得上传的文件
- *
- * @return MultipartFormData
- * @throws IORuntimeException IO异常
- * @since 5.3.0
- */
- public MultipartFormData getMultipart() throws IORuntimeException {
- if(null == this.multipartFormDataCache){
- this.multipartFormDataCache = parseMultipart(new UploadSetting());
- }
- return this.multipartFormDataCache;
- }
-
- /**
- * 获得multipart/form-data 表单内容
- * 包括文件和普通表单数据
- * 在同一次请求中,此方法只能被执行一次!
- *
- * @param uploadSetting 上传文件的设定,包括最大文件大小、保存在内存的边界大小、临时目录、扩展名限定等
- * @return MultiPart表单
- * @throws IORuntimeException IO异常
- * @since 5.3.0
- */
- public MultipartFormData parseMultipart(final UploadSetting uploadSetting) throws IORuntimeException {
- final MultipartFormData formData = new MultipartFormData(uploadSetting);
- try {
- formData.parseRequestStream(getBodyStream(), getCharset());
- } catch (final IOException e) {
- throw new IORuntimeException(e);
- }
-
- return formData;
- }
}
diff --git a/hutool-http/src/main/java/org/dromara/hutool/http/server/engine/sun/SunServerResponse.java b/hutool-http/src/main/java/org/dromara/hutool/http/server/engine/sun/SunServerResponse.java
new file mode 100644
index 000000000..acec7524a
--- /dev/null
+++ b/hutool-http/src/main/java/org/dromara/hutool/http/server/engine/sun/SunServerResponse.java
@@ -0,0 +1,227 @@
+/*
+ * Copyright (c) 2024 Hutool Team and hutool.cn
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.dromara.hutool.http.server.engine.sun;
+
+import com.sun.net.httpserver.Headers;
+import com.sun.net.httpserver.HttpExchange;
+import org.dromara.hutool.core.io.IORuntimeException;
+import org.dromara.hutool.core.io.IoUtil;
+import org.dromara.hutool.http.meta.ContentType;
+import org.dromara.hutool.http.meta.HttpStatus;
+import org.dromara.hutool.http.server.ServerResponse;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.charset.Charset;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * SunHttp服务器响应对象
+ *
+ * @author looly
+ * @since 6.0.0
+ */
+public class SunServerResponse extends SunServerBase implements ServerResponse {
+
+ private Charset charset;
+ /**
+ * 是否已经发送了Http状态码,如果没有,提前写出状态码
+ */
+ private boolean isSendCode;
+
+ /**
+ * 构造
+ *
+ * @param httpExchange {@link HttpExchange}
+ */
+ public SunServerResponse(final HttpExchange httpExchange) {
+ super(httpExchange);
+ }
+
+ @Override
+ public SunServerResponse setStatus(final int statusCode) {
+ return send(statusCode, 0);
+ }
+
+ /**
+ * 发送成功状态码
+ *
+ * @return this
+ */
+ public SunServerResponse sendOk() {
+ return setStatus(HttpStatus.HTTP_OK);
+ }
+
+ /**
+ * 发送成功状态码
+ *
+ * @param bodyLength 响应体长度,默认0表示不定长度,会输出Transfer-encoding: chunked
+ * @return this
+ * @since 5.5.7
+ */
+ public SunServerResponse sendOk(final int bodyLength) {
+ return send(HttpStatus.HTTP_OK, bodyLength);
+ }
+
+ /**
+ * 发送404错误页
+ *
+ * @param content 错误页页面内容,默认text/html类型
+ * @return this
+ */
+ public SunServerResponse send404(final String content) {
+ return sendError(HttpStatus.HTTP_NOT_FOUND, content);
+ }
+
+ /**
+ * 发送错误页
+ *
+ * @param errorCode HTTP错误状态码,见HttpStatus
+ * @param content 错误页页面内容,默认text/html类型
+ * @return this
+ */
+ @SuppressWarnings("resource")
+ public SunServerResponse sendError(final int errorCode, final String content) {
+ setStatus(errorCode);
+ setContentType(ContentType.TEXT_HTML.toString());
+ write(content);
+ return this;
+ }
+
+ /**
+ * 发送HTTP状态码
+ *
+ * @param httpStatusCode HTTP状态码,见HttpStatus
+ * @param bodyLength 响应体长度,默认0表示不定长度,会输出Transfer-encoding: chunked
+ * @return this
+ */
+ public SunServerResponse send(final int httpStatusCode, final long bodyLength) {
+ if (this.isSendCode) {
+ throw new IORuntimeException("Http status code has been send!");
+ }
+
+ try {
+ this.httpExchange.sendResponseHeaders(httpStatusCode, bodyLength);
+ } catch (final IOException e) {
+ throw new IORuntimeException(e);
+ }
+
+ this.isSendCode = true;
+ return this;
+ }
+
+ @Override
+ public SunServerResponse setCharset(final Charset charset) {
+ this.charset = charset;
+ return this;
+ }
+
+ @Override
+ public Charset getCharset() {
+ return this.charset;
+ }
+
+ /**
+ * 获得所有响应头,获取后可以添加新的响应头
+ *
+ * @return 响应头
+ */
+ public Headers getHeaders() {
+ return this.httpExchange.getResponseHeaders();
+ }
+
+ @Override
+ public SunServerResponse addHeader(final String header, final String value) {
+ getHeaders().add(header, value);
+ return this;
+ }
+
+ @Override
+ public SunServerResponse setHeader(final String header, final String value) {
+ getHeaders().set(header, value);
+ return this;
+ }
+
+ /**
+ * 设置响应头,如果已经存在,则覆盖
+ *
+ * @param header 头key
+ * @param value 值列表
+ * @return this
+ */
+ public SunServerResponse setHeader(final String header, final List value) {
+ getHeaders().put(header, value);
+ return this;
+ }
+
+ /**
+ * 设置所有响应头,如果已经存在,则覆盖
+ *
+ * @param headers 响应头map
+ * @return this
+ */
+ public SunServerResponse setHeaders(final Map> headers) {
+ getHeaders().putAll(headers);
+ return this;
+ }
+
+ /**
+ * 设置属性
+ *
+ * @param name 属性名
+ * @param value 属性值
+ * @return this
+ */
+ public SunServerResponse setAttr(final String name, final Object value) {
+ this.httpExchange.setAttribute(name, value);
+ return this;
+ }
+
+ @SuppressWarnings("resource")
+ @Override
+ public OutputStream getOutputStream() {
+ if (!this.isSendCode) {
+ sendOk();
+ }
+ return this.httpExchange.getResponseBody();
+ }
+
+ /**
+ * 写出数据到客户端
+ *
+ * @param in 数据流
+ * @param length 指定响应内容长度,默认0表示不定长度,会输出Transfer-encoding: chunked
+ * @return this
+ */
+ @SuppressWarnings("resource")
+ public SunServerResponse write(final InputStream in, final int length) {
+ if (!isSendCode) {
+ sendOk(Math.max(0, length));
+ }
+ OutputStream out = null;
+ try {
+ out = this.httpExchange.getResponseBody();
+ IoUtil.copy(in, out);
+ } finally {
+ IoUtil.closeQuietly(out);
+ IoUtil.closeQuietly(in);
+ }
+ return this;
+ }
+}
diff --git a/hutool-http/src/main/java/org/dromara/hutool/http/server/filter/DefaultExceptionFilter.java b/hutool-http/src/main/java/org/dromara/hutool/http/server/engine/sun/filter/DefaultExceptionFilter.java
similarity index 82%
rename from hutool-http/src/main/java/org/dromara/hutool/http/server/filter/DefaultExceptionFilter.java
rename to hutool-http/src/main/java/org/dromara/hutool/http/server/engine/sun/filter/DefaultExceptionFilter.java
index 0fd9f74f9..02e1d3eb0 100644
--- a/hutool-http/src/main/java/org/dromara/hutool/http/server/filter/DefaultExceptionFilter.java
+++ b/hutool-http/src/main/java/org/dromara/hutool/http/server/engine/sun/filter/DefaultExceptionFilter.java
@@ -14,12 +14,12 @@
* limitations under the License.
*/
-package org.dromara.hutool.http.server.filter;
+package org.dromara.hutool.http.server.engine.sun.filter;
import org.dromara.hutool.core.exception.ExceptionUtil;
import org.dromara.hutool.core.text.StrUtil;
-import org.dromara.hutool.http.server.HttpServerRequest;
-import org.dromara.hutool.http.server.HttpServerResponse;
+import org.dromara.hutool.http.server.engine.sun.SunServerRequest;
+import org.dromara.hutool.http.server.engine.sun.SunServerResponse;
/**
* 默认异常处理拦截器
@@ -31,7 +31,7 @@ public class DefaultExceptionFilter extends ExceptionFilter{
private final static String TEMPLATE_ERROR = "Hutool - Error reportHTTP Status {} - {}
{}
Hutool
";
@Override
- public void afterException(final HttpServerRequest req, final HttpServerResponse res, final Throwable e) {
+ public void afterException(final SunServerRequest req, final SunServerResponse res, final Throwable e) {
String content = ExceptionUtil.stacktraceToString(e);
content = content.replace("\n", "
\n");
content = StrUtil.format(TEMPLATE_ERROR, 500, req.getURI(), content);
diff --git a/hutool-http/src/main/java/org/dromara/hutool/http/server/filter/ExceptionFilter.java b/hutool-http/src/main/java/org/dromara/hutool/http/server/engine/sun/filter/ExceptionFilter.java
similarity index 63%
rename from hutool-http/src/main/java/org/dromara/hutool/http/server/filter/ExceptionFilter.java
rename to hutool-http/src/main/java/org/dromara/hutool/http/server/engine/sun/filter/ExceptionFilter.java
index d4a71aa56..967a9ba6a 100644
--- a/hutool-http/src/main/java/org/dromara/hutool/http/server/filter/ExceptionFilter.java
+++ b/hutool-http/src/main/java/org/dromara/hutool/http/server/engine/sun/filter/ExceptionFilter.java
@@ -14,11 +14,11 @@
* limitations under the License.
*/
-package org.dromara.hutool.http.server.filter;
+package org.dromara.hutool.http.server.engine.sun.filter;
import com.sun.net.httpserver.Filter;
-import org.dromara.hutool.http.server.HttpServerRequest;
-import org.dromara.hutool.http.server.HttpServerResponse;
+import org.dromara.hutool.http.server.engine.sun.SunServerRequest;
+import org.dromara.hutool.http.server.engine.sun.SunServerResponse;
/**
* 异常处理过滤器
@@ -28,9 +28,9 @@ import org.dromara.hutool.http.server.HttpServerResponse;
public abstract class ExceptionFilter implements HttpFilter {
@Override
- public void doFilter(final HttpServerRequest req, final HttpServerResponse res, final Filter.Chain chain) {
+ public void doFilter(final SunServerRequest req, final SunServerResponse res, final Filter.Chain chain) {
try {
- chain.doFilter(req.getHttpExchange());
+ chain.doFilter(req.getExchange());
} catch (final Throwable e) {
afterException(req, res, e);
}
@@ -39,9 +39,9 @@ public abstract class ExceptionFilter implements HttpFilter {
/**
* 异常之后的处理逻辑
*
- * @param req {@link HttpServerRequest}
- * @param res {@link HttpServerResponse}
+ * @param req {@link SunServerRequest}
+ * @param res {@link SunServerResponse}
* @param e 异常
*/
- public abstract void afterException(final HttpServerRequest req, final HttpServerResponse res, final Throwable e);
+ public abstract void afterException(final SunServerRequest req, final SunServerResponse res, final Throwable e);
}
diff --git a/hutool-http/src/main/java/org/dromara/hutool/http/server/filter/HttpFilter.java b/hutool-http/src/main/java/org/dromara/hutool/http/server/engine/sun/filter/HttpFilter.java
similarity index 67%
rename from hutool-http/src/main/java/org/dromara/hutool/http/server/filter/HttpFilter.java
rename to hutool-http/src/main/java/org/dromara/hutool/http/server/engine/sun/filter/HttpFilter.java
index b72cf2640..f2b19b490 100644
--- a/hutool-http/src/main/java/org/dromara/hutool/http/server/filter/HttpFilter.java
+++ b/hutool-http/src/main/java/org/dromara/hutool/http/server/engine/sun/filter/HttpFilter.java
@@ -14,11 +14,11 @@
* limitations under the License.
*/
-package org.dromara.hutool.http.server.filter;
+package org.dromara.hutool.http.server.engine.sun.filter;
-import org.dromara.hutool.http.server.HttpServerRequest;
-import org.dromara.hutool.http.server.HttpServerResponse;
import com.sun.net.httpserver.Filter;
+import org.dromara.hutool.http.server.engine.sun.SunServerRequest;
+import org.dromara.hutool.http.server.engine.sun.SunServerResponse;
import java.io.IOException;
@@ -33,10 +33,10 @@ public interface HttpFilter {
/**
* 执行过滤
- * @param req {@link HttpServerRequest} 请求对象,用于获取请求内容
- * @param res {@link HttpServerResponse} 响应对象,用于写出内容
+ * @param req {@link SunServerRequest} 请求对象,用于获取请求内容
+ * @param res {@link SunServerResponse} 响应对象,用于写出内容
* @param chain {@link Filter.Chain}
* @throws IOException IO异常
*/
- void doFilter(HttpServerRequest req, HttpServerResponse res, Filter.Chain chain) throws IOException;
+ void doFilter(SunServerRequest req, SunServerResponse res, Filter.Chain chain) throws IOException;
}
diff --git a/hutool-http/src/main/java/org/dromara/hutool/http/server/filter/SimpleFilter.java b/hutool-http/src/main/java/org/dromara/hutool/http/server/engine/sun/filter/SimpleFilter.java
similarity index 93%
rename from hutool-http/src/main/java/org/dromara/hutool/http/server/filter/SimpleFilter.java
rename to hutool-http/src/main/java/org/dromara/hutool/http/server/engine/sun/filter/SimpleFilter.java
index 4227e94f4..8d3397944 100644
--- a/hutool-http/src/main/java/org/dromara/hutool/http/server/filter/SimpleFilter.java
+++ b/hutool-http/src/main/java/org/dromara/hutool/http/server/engine/sun/filter/SimpleFilter.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package org.dromara.hutool.http.server.filter;
+package org.dromara.hutool.http.server.engine.sun.filter;
import com.sun.net.httpserver.Filter;
diff --git a/hutool-http/src/main/java/org/dromara/hutool/http/server/filter/package-info.java b/hutool-http/src/main/java/org/dromara/hutool/http/server/engine/sun/filter/package-info.java
similarity index 92%
rename from hutool-http/src/main/java/org/dromara/hutool/http/server/filter/package-info.java
rename to hutool-http/src/main/java/org/dromara/hutool/http/server/engine/sun/filter/package-info.java
index 843e34056..6b7878427 100644
--- a/hutool-http/src/main/java/org/dromara/hutool/http/server/filter/package-info.java
+++ b/hutool-http/src/main/java/org/dromara/hutool/http/server/engine/sun/filter/package-info.java
@@ -17,4 +17,4 @@
/**
* {@link com.sun.net.httpserver.Filter} 实现包装
*/
-package org.dromara.hutool.http.server.filter;
+package org.dromara.hutool.http.server.engine.sun.filter;
diff --git a/hutool-http/src/main/java/org/dromara/hutool/http/server/engine/sun/package-info.java b/hutool-http/src/main/java/org/dromara/hutool/http/server/engine/sun/package-info.java
new file mode 100644
index 000000000..e7ed11d51
--- /dev/null
+++ b/hutool-http/src/main/java/org/dromara/hutool/http/server/engine/sun/package-info.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2024 Hutool Team and hutool.cn
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * {@link com.sun.net.httpserver.HttpServer}引擎实现包
+ *
+ * @author Looly
+ */
+package org.dromara.hutool.http.server.engine.sun;
diff --git a/hutool-http/src/main/java/org/dromara/hutool/http/server/engine/tomcat/package-info.java b/hutool-http/src/main/java/org/dromara/hutool/http/server/engine/tomcat/package-info.java
new file mode 100644
index 000000000..09d7d4963
--- /dev/null
+++ b/hutool-http/src/main/java/org/dromara/hutool/http/server/engine/tomcat/package-info.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2024 Hutool Team and hutool.cn
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Tomcat引擎实现
+ *
+ * @author Looly
+ */
+package org.dromara.hutool.http.server.engine.tomcat;
diff --git a/hutool-http/src/main/java/org/dromara/hutool/http/server/engine/undertow/UndertowEngine.java b/hutool-http/src/main/java/org/dromara/hutool/http/server/engine/undertow/UndertowEngine.java
new file mode 100644
index 000000000..66ee18676
--- /dev/null
+++ b/hutool-http/src/main/java/org/dromara/hutool/http/server/engine/undertow/UndertowEngine.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2024 Hutool Team and hutool.cn
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.dromara.hutool.http.server.engine.undertow;
+
+import io.undertow.Undertow;
+import org.dromara.hutool.core.lang.Assert;
+import org.dromara.hutool.http.server.engine.AbstractServerEngine;
+
+import javax.net.ssl.SSLContext;
+
+/**
+ * Undertow引擎实现
+ *
+ * @author looly
+ */
+public class UndertowEngine extends AbstractServerEngine {
+
+ private Undertow undertow;
+
+ /**
+ * 构造
+ */
+ public UndertowEngine() {
+ // issue#IABWBL JDK8下,在IDEA旗舰版加载Spring boot插件时,启动应用不会检查字段类是否存在
+ // 此处构造时调用下这个类,以便触发类是否存在的检查
+ Assert.notNull(Undertow.class);
+ }
+
+ @Override
+ public void start() {
+ initEngine();
+ undertow.start();
+ }
+
+ @Override
+ public Undertow getRawEngine() {
+ return this.undertow;
+ }
+
+ @Override
+ protected void reset() {
+ if(null != this.undertow){
+ this.undertow.stop();
+ this.undertow = null;
+ }
+ }
+
+ @Override
+ protected void initEngine() {
+ if (null != this.undertow) {
+ return;
+ }
+ final Undertow.Builder builder = Undertow.builder()
+ .setHandler(exchange -> {
+ this.handler.handle(
+ new UndertowRequest(exchange),
+ new UndertowResponse(exchange));
+ });
+
+ final SSLContext sslContext = this.config.getSslContext();
+ if(null != sslContext){
+ builder.addHttpsListener(this.config.getPort(), this.config.getHost(), sslContext);
+ }else{
+ builder.addHttpListener(this.config.getPort(), this.config.getHost());
+ }
+ this.undertow = builder.build();
+ }
+}
diff --git a/hutool-http/src/main/java/org/dromara/hutool/http/server/engine/undertow/UndertowExchangeBase.java b/hutool-http/src/main/java/org/dromara/hutool/http/server/engine/undertow/UndertowExchangeBase.java
new file mode 100644
index 000000000..2490b37ea
--- /dev/null
+++ b/hutool-http/src/main/java/org/dromara/hutool/http/server/engine/undertow/UndertowExchangeBase.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2024 Hutool Team and hutool.cn
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.dromara.hutool.http.server.engine.undertow;
+
+import io.undertow.server.HttpServerExchange;
+
+/**
+ * Undertow请求对象基类,用于获取原始Undertow请求对象
+ *
+ * @author looly
+ * @since 6.0.0
+ */
+public class UndertowExchangeBase {
+
+ final HttpServerExchange exchange;
+
+ /**
+ * 构造
+ *
+ * @param exchange Undertow请求对象
+ */
+ public UndertowExchangeBase(final HttpServerExchange exchange) {
+ this.exchange = exchange;
+ }
+
+ /**
+ * 获取原始Undertow请求对象
+ *
+ * @return 原始Undertow请求对象
+ */
+ public HttpServerExchange getExchange(){
+ return this.exchange;
+ }
+}
diff --git a/hutool-http/src/main/java/org/dromara/hutool/http/server/engine/undertow/UndertowRequest.java b/hutool-http/src/main/java/org/dromara/hutool/http/server/engine/undertow/UndertowRequest.java
new file mode 100644
index 000000000..88241be4e
--- /dev/null
+++ b/hutool-http/src/main/java/org/dromara/hutool/http/server/engine/undertow/UndertowRequest.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2024 Hutool Team and hutool.cn
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.dromara.hutool.http.server.engine.undertow;
+
+import io.undertow.server.HttpServerExchange;
+import io.undertow.util.HeaderMap;
+import org.dromara.hutool.core.util.CharsetUtil;
+import org.dromara.hutool.http.server.ServerRequest;
+
+import java.io.InputStream;
+import java.nio.charset.Charset;
+
+/**
+ * Undertow请求对象
+ *
+ * @author looly
+ * @since 6.0.0
+ */
+public class UndertowRequest extends UndertowExchangeBase implements ServerRequest {
+
+ /**
+ * 构造
+ *
+ * @param exchange Undertow请求对象
+ */
+ public UndertowRequest(final HttpServerExchange exchange) {
+ super(exchange);
+ }
+
+ @Override
+ public String getMethod() {
+ return this.exchange.getRequestMethod().toString();
+ }
+
+ @Override
+ public String getPath() {
+ return this.exchange.getRelativePath();
+ }
+
+ @Override
+ public String getQuery() {
+ return this.exchange.getQueryString();
+ }
+
+ @Override
+ public String getHeader(final String name) {
+ return this.exchange.getRequestHeaders().getFirst(name);
+ }
+
+ /**
+ * 获取所有请求头
+ *
+ * @return 请求头
+ */
+ public HeaderMap getHeaders() {
+ return this.exchange.getRequestHeaders();
+ }
+
+ @Override
+ public Charset getCharset() {
+ return CharsetUtil.charset(this.exchange.getRequestCharset());
+ }
+
+ @Override
+ public InputStream getBodyStream() {
+ return this.exchange.getInputStream();
+ }
+}
diff --git a/hutool-http/src/main/java/org/dromara/hutool/http/server/engine/undertow/UndertowResponse.java b/hutool-http/src/main/java/org/dromara/hutool/http/server/engine/undertow/UndertowResponse.java
new file mode 100644
index 000000000..4c660b8d7
--- /dev/null
+++ b/hutool-http/src/main/java/org/dromara/hutool/http/server/engine/undertow/UndertowResponse.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2024 Hutool Team and hutool.cn
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.dromara.hutool.http.server.engine.undertow;
+
+import io.undertow.io.Sender;
+import io.undertow.server.HttpServerExchange;
+import io.undertow.util.HttpString;
+import org.dromara.hutool.http.server.ServerResponse;
+
+import java.io.OutputStream;
+import java.nio.ByteBuffer;
+import java.nio.charset.Charset;
+import java.util.List;
+
+/**
+ * Undertow响应对象
+ *
+ * @author looly
+ * @since 6.0.0
+ */
+public class UndertowResponse extends UndertowExchangeBase implements ServerResponse {
+
+ private Charset charset;
+
+ /**
+ * 构造
+ *
+ * @param exchange Undertow exchange
+ */
+ public UndertowResponse(final HttpServerExchange exchange) {
+ super(exchange);
+ this.charset = DEFAULT_CHARSET;
+ }
+
+ /**
+ * 获取原始的HttpServerExchange对象
+ *
+ * @return HttpServerExchange对象
+ */
+ public HttpServerExchange getExchange() {
+ return exchange;
+ }
+
+ @Override
+ public ServerResponse setStatus(final int statusCode) {
+ this.exchange.setStatusCode(statusCode);
+ return this;
+ }
+
+ @Override
+ public ServerResponse setCharset(final Charset charset) {
+ this.charset = charset;
+ return this;
+ }
+
+ @Override
+ public Charset getCharset() {
+ return this.charset;
+ }
+
+ @Override
+ public ServerResponse addHeader(final String header, final String value) {
+ this.exchange.getResponseHeaders().add(new HttpString(header), value);
+ return this;
+ }
+
+ @Override
+ public ServerResponse setHeader(final String header, final String value) {
+ this.exchange.getResponseHeaders().put(new HttpString(header), value);
+ return this;
+ }
+
+ @Override
+ public ServerResponse setHeader(final String header, final List value) {
+ this.exchange.getResponseHeaders().putAll(new HttpString(header), value);
+ return this;
+ }
+
+ /**
+ * 获取Sender对象,用于发送数据
+ *
+ * @return Sender对象
+ */
+ public Sender getSender() {
+ return this.exchange.getResponseSender();
+ }
+
+ @Override
+ public OutputStream getOutputStream() {
+ return this.exchange.getOutputStream();
+ }
+
+ @Override
+ public ServerResponse write(final byte[] data) {
+ getSender().send(ByteBuffer.wrap(data));
+ return this;
+ }
+}
diff --git a/hutool-http/src/main/java/org/dromara/hutool/http/server/engine/undertow/package-info.java b/hutool-http/src/main/java/org/dromara/hutool/http/server/engine/undertow/package-info.java
new file mode 100644
index 000000000..73038ce8c
--- /dev/null
+++ b/hutool-http/src/main/java/org/dromara/hutool/http/server/engine/undertow/package-info.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2024 Hutool Team and hutool.cn
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Undertow引擎实现
+ *
+ * @author Looly
+ * @since 6.0.0
+ */
+package org.dromara.hutool.http.server.engine.undertow;
diff --git a/hutool-http/src/main/java/org/dromara/hutool/http/server/handler/ActionHandler.java b/hutool-http/src/main/java/org/dromara/hutool/http/server/handler/ActionHandler.java
deleted file mode 100644
index 5e1dbe398..000000000
--- a/hutool-http/src/main/java/org/dromara/hutool/http/server/handler/ActionHandler.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (c) 2013-2024 Hutool Team and hutool.cn
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.dromara.hutool.http.server.handler;
-
-import org.dromara.hutool.http.server.HttpExchangeWrapper;
-import org.dromara.hutool.http.server.HttpServerRequest;
-import org.dromara.hutool.http.server.HttpServerResponse;
-import org.dromara.hutool.http.server.action.Action;
-import com.sun.net.httpserver.HttpExchange;
-import com.sun.net.httpserver.HttpHandler;
-
-import java.io.IOException;
-
-/**
- * Action处理器,用于将HttpHandler转换为Action形式
- *
- * @author looly
- * @since 5.2.6
- */
-public class ActionHandler implements HttpHandler {
-
- private final Action action;
-
- /**
- * 构造
- *
- * @param action Action
- */
- public ActionHandler(final Action action) {
- this.action = action;
- }
-
- @Override
- public void handle(final HttpExchange httpExchange) throws IOException {
- final HttpServerRequest request;
- final HttpServerResponse response;
- if (httpExchange instanceof HttpExchangeWrapper) {
- // issue#3343 当使用Filter时,可能读取了请求参数,此时使用共享的req和res,可复用缓存
- final HttpExchangeWrapper wrapper = (HttpExchangeWrapper) httpExchange;
- request = wrapper.getRequest();
- response = wrapper.getResponse();
- } else {
- request = new HttpServerRequest(httpExchange);
- response = new HttpServerResponse(httpExchange);
- }
- action.doAction(request, response);
- httpExchange.close();
- }
-}
diff --git a/hutool-http/src/main/java/org/dromara/hutool/http/server/action/Action.java b/hutool-http/src/main/java/org/dromara/hutool/http/server/handler/HttpHandler.java
similarity index 56%
rename from hutool-http/src/main/java/org/dromara/hutool/http/server/action/Action.java
rename to hutool-http/src/main/java/org/dromara/hutool/http/server/handler/HttpHandler.java
index 460c1b33e..b24678fff 100644
--- a/hutool-http/src/main/java/org/dromara/hutool/http/server/action/Action.java
+++ b/hutool-http/src/main/java/org/dromara/hutool/http/server/handler/HttpHandler.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013-2024 Hutool Team and hutool.cn
+ * Copyright (c) 2024 Hutool Team and hutool.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,29 +14,23 @@
* limitations under the License.
*/
-package org.dromara.hutool.http.server.action;
+package org.dromara.hutool.http.server.handler;
-import org.dromara.hutool.http.server.HttpServerRequest;
-import org.dromara.hutool.http.server.HttpServerResponse;
-
-import java.io.IOException;
+import org.dromara.hutool.http.server.ServerRequest;
+import org.dromara.hutool.http.server.ServerResponse;
/**
- * 请求处理接口
- * 当用户请求某个Path,则调用相应Action的doAction方法
+ * HTTP请求处理器
*
* @author Looly
- * @since 5.2.6
*/
-@FunctionalInterface
-public interface Action {
+public interface HttpHandler {
/**
* 处理请求
*
* @param request 请求对象
* @param response 响应对象
- * @throws IOException IO异常
*/
- void doAction(HttpServerRequest request, HttpServerResponse response) throws IOException;
+ void handle(ServerRequest request, ServerResponse response);
}
diff --git a/hutool-http/src/main/java/org/dromara/hutool/http/server/action/RootAction.java b/hutool-http/src/main/java/org/dromara/hutool/http/server/handler/RootHandler.java
similarity index 75%
rename from hutool-http/src/main/java/org/dromara/hutool/http/server/action/RootAction.java
rename to hutool-http/src/main/java/org/dromara/hutool/http/server/handler/RootHandler.java
index 51b3d05cb..4c2504c27 100644
--- a/hutool-http/src/main/java/org/dromara/hutool/http/server/action/RootAction.java
+++ b/hutool-http/src/main/java/org/dromara/hutool/http/server/handler/RootHandler.java
@@ -14,12 +14,13 @@
* limitations under the License.
*/
-package org.dromara.hutool.http.server.action;
+package org.dromara.hutool.http.server.handler;
import org.dromara.hutool.core.collection.ListUtil;
import org.dromara.hutool.core.io.file.FileUtil;
-import org.dromara.hutool.http.server.HttpServerRequest;
-import org.dromara.hutool.http.server.HttpServerResponse;
+import org.dromara.hutool.http.meta.HttpStatus;
+import org.dromara.hutool.http.server.ServerRequest;
+import org.dromara.hutool.http.server.ServerResponse;
import java.io.File;
import java.util.List;
@@ -30,8 +31,11 @@ import java.util.List;
* @author looly
* @since 5.2.6
*/
-public class RootAction implements Action {
+public class RootHandler implements HttpHandler {
+ /**
+ * 默认主页文件名
+ */
public static final String DEFAULT_INDEX_FILE_NAME = "index.html";
private final File rootDir;
@@ -42,7 +46,7 @@ public class RootAction implements Action {
*
* @param rootDir 网页根目录
*/
- public RootAction(final String rootDir) {
+ public RootHandler(final String rootDir) {
this(new File(rootDir));
}
@@ -51,7 +55,7 @@ public class RootAction implements Action {
*
* @param rootDir 网页根目录
*/
- public RootAction(final File rootDir) {
+ public RootHandler(final File rootDir) {
this(rootDir, DEFAULT_INDEX_FILE_NAME);
}
@@ -61,7 +65,7 @@ public class RootAction implements Action {
* @param rootDir 网页根目录
* @param indexFileNames 主页文件名列表
*/
- public RootAction(final String rootDir, final String... indexFileNames) {
+ public RootHandler(final String rootDir, final String... indexFileNames) {
this(new File(rootDir), indexFileNames);
}
@@ -72,13 +76,13 @@ public class RootAction implements Action {
* @param indexFileNames 主页文件名列表
* @since 5.4.0
*/
- public RootAction(final File rootDir, final String... indexFileNames) {
+ public RootHandler(final File rootDir, final String... indexFileNames) {
this.rootDir = rootDir;
this.indexFileNames = ListUtil.of(indexFileNames);
}
@Override
- public void doAction(final HttpServerRequest request, final HttpServerResponse response) {
+ public void handle(final ServerRequest request, final ServerResponse response) {
final String path = request.getPath();
File file = FileUtil.file(rootDir, path);
@@ -99,6 +103,7 @@ public class RootAction implements Action {
}
}
- response.send404("404 Not Found !");
+ response.setStatus(HttpStatus.HTTP_NOT_FOUND);
+ response.write("404 Not Found !");
}
}
diff --git a/hutool-http/src/test/java/org/dromara/hutool/http/server/ExceptionServerTest.java b/hutool-http/src/test/java/org/dromara/hutool/http/server/ExceptionServerTest.java
index 2cb694847..d17b0a13a 100644
--- a/hutool-http/src/test/java/org/dromara/hutool/http/server/ExceptionServerTest.java
+++ b/hutool-http/src/test/java/org/dromara/hutool/http/server/ExceptionServerTest.java
@@ -16,17 +16,16 @@
package org.dromara.hutool.http.server;
+import org.dromara.hutool.core.io.IORuntimeException;
import org.dromara.hutool.http.HttpUtil;
-import org.dromara.hutool.http.server.filter.DefaultExceptionFilter;
-
-import java.io.IOException;
+import org.dromara.hutool.http.server.engine.sun.filter.DefaultExceptionFilter;
public class ExceptionServerTest {
public static void main(final String[] args) {
HttpUtil.createServer(8888)
.addFilter(new DefaultExceptionFilter())
.addAction("/", (req, res) -> {
- throw new IOException("Test Exception");
+ throw new IORuntimeException("Test Exception");
})
.start();
}
diff --git a/hutool-http/src/test/java/org/dromara/hutool/http/server/Issue3343Test.java b/hutool-http/src/test/java/org/dromara/hutool/http/server/Issue3343Test.java
index 383f4afdf..662bd8f35 100644
--- a/hutool-http/src/test/java/org/dromara/hutool/http/server/Issue3343Test.java
+++ b/hutool-http/src/test/java/org/dromara/hutool/http/server/Issue3343Test.java
@@ -20,6 +20,7 @@ import org.dromara.hutool.core.date.DateUtil;
import org.dromara.hutool.core.lang.Console;
import org.dromara.hutool.core.map.multi.ListValueMap;
import org.dromara.hutool.http.HttpUtil;
+import org.dromara.hutool.http.server.engine.sun.SimpleServer;
/**
* http://localhost:8888/?name=hutool
@@ -33,7 +34,7 @@ public class Issue3343Test {
Console.log(" > from : " + req.getClientIP());
// 过滤器中获取请求参数
Console.log(" > params : " + req.getParams());
- chain.doFilter(req.getHttpExchange());
+ chain.doFilter(req.getExchange());
});
server.addAction("/", Issue3343Test::index);
@@ -41,9 +42,9 @@ public class Issue3343Test {
server.start();
}
- private static void index(HttpServerRequest request, HttpServerResponse response) {
+ private static void index(final ServerRequest request, final ServerResponse response) {
// 具体逻辑中再次获取请求参数
- ListValueMap params = request.getParams();
+ final ListValueMap params = request.getParams();
Console.log("index params: " + params);
response.getWriter().write("GOT: " + params);
}
diff --git a/hutool-http/src/test/java/org/dromara/hutool/http/server/Issue3723Test.java b/hutool-http/src/test/java/org/dromara/hutool/http/server/Issue3723Test.java
index 3b26e1801..f87f99d3f 100644
--- a/hutool-http/src/test/java/org/dromara/hutool/http/server/Issue3723Test.java
+++ b/hutool-http/src/test/java/org/dromara/hutool/http/server/Issue3723Test.java
@@ -19,18 +19,19 @@ package org.dromara.hutool.http.server;
import org.dromara.hutool.core.data.id.IdUtil;
import org.dromara.hutool.http.HttpUtil;
import org.dromara.hutool.http.meta.ContentType;
+import org.dromara.hutool.http.server.engine.sun.SimpleServer;
public class Issue3723Test {
public static void main(final String[] args) {
final SimpleServer server = HttpUtil.createServer(8888);
server.addFilter((req, res, chain) -> {
final String requestId = IdUtil.fastSimpleUUID();
- req.getHttpExchange().setAttribute("requestId", requestId);
+ req.getExchange().setAttribute("requestId", requestId);
res.addHeader("X-Request-Id", requestId);
res.write("new Content");
- chain.doFilter(req.getHttpExchange());
+ chain.doFilter(req.getExchange());
});
server.addAction("/", (req, res)-> res.write("Hello Hutool Server", ContentType.JSON.getValue()));
server.start();
diff --git a/hutool-http/src/test/java/org/dromara/hutool/http/server/IssueI6Q30XTest.java b/hutool-http/src/test/java/org/dromara/hutool/http/server/IssueI6Q30XTest.java
index 5d81aca97..bb6d14062 100644
--- a/hutool-http/src/test/java/org/dromara/hutool/http/server/IssueI6Q30XTest.java
+++ b/hutool-http/src/test/java/org/dromara/hutool/http/server/IssueI6Q30XTest.java
@@ -19,8 +19,10 @@ package org.dromara.hutool.http.server;
import org.dromara.hutool.core.date.DateUtil;
import org.dromara.hutool.core.date.StopWatch;
import org.dromara.hutool.core.lang.Console;
-import org.dromara.hutool.http.multipart.MultipartFormData;
import org.dromara.hutool.http.HttpUtil;
+import org.dromara.hutool.http.multipart.MultipartFormData;
+import org.dromara.hutool.http.server.engine.sun.SimpleServer;
+import org.dromara.hutool.http.server.engine.sun.SunServerRequest;
import java.util.concurrent.TimeUnit;
@@ -35,7 +37,7 @@ public class IssueI6Q30XTest {
public static void main(String[] args) {
final SimpleServer server = HttpUtil.createServer(8888);
server.addAction("/file", (request, response) -> {
- Console.log(request.getHeaders().entrySet());
+ Console.log(((SunServerRequest)request).getHeaders().entrySet());
final StopWatch stopWatch = DateUtil.createStopWatch();
stopWatch.start();
diff --git a/hutool-http/src/test/java/org/dromara/hutool/http/server/RedirectServerTest.java b/hutool-http/src/test/java/org/dromara/hutool/http/server/RedirectServerTest.java
index a9859c7e6..5f3e6a816 100644
--- a/hutool-http/src/test/java/org/dromara/hutool/http/server/RedirectServerTest.java
+++ b/hutool-http/src/test/java/org/dromara/hutool/http/server/RedirectServerTest.java
@@ -19,25 +19,26 @@ package org.dromara.hutool.http.server;
import org.dromara.hutool.core.lang.Console;
import org.dromara.hutool.http.HttpUtil;
import org.dromara.hutool.http.meta.HeaderName;
+import org.dromara.hutool.http.meta.HttpStatus;
public class RedirectServerTest {
public static void main(final String[] args) {
HttpUtil.createServer(8888).addAction("/redirect1", (request, response) -> {
response.addHeader(HeaderName.LOCATION.getValue(),"http://localhost:8888/redirect2");
response.addHeader(HeaderName.SET_COOKIE.getValue(),"redirect1=1; path=/; HttpOnly");
- response.send(301);
+ response.setStatus(301);
}).addAction("/redirect2", (request, response) -> {
response.addHeader(HeaderName.LOCATION.getValue(),"http://localhost:8888/redirect3");
response.addHeader(HeaderName.SET_COOKIE.getValue(), "redirect2=2; path=/; HttpOnly");
- response.send(301);
+ response.setStatus(301);
}).addAction("/redirect3", (request, response) -> {
response.addHeader(HeaderName.LOCATION.getValue(),"http://localhost:8888/redirect4");
response.addHeader(HeaderName.SET_COOKIE.getValue(),"redirect3=3; path=/; HttpOnly");
- response.send(301);
+ response.setStatus(301);
}).addAction("/redirect4", (request, response) -> {
final String cookie = request.getHeader(HeaderName.COOKIE);
Console.log(cookie);
- response.sendOk();
+ response.setStatus(HttpStatus.HTTP_OK);
}).start();
}
}
diff --git a/hutool-http/src/test/java/org/dromara/hutool/http/server/SimpleServerTest.java b/hutool-http/src/test/java/org/dromara/hutool/http/server/SimpleServerTest.java
index 35bd6ddf8..b11fd8148 100644
--- a/hutool-http/src/test/java/org/dromara/hutool/http/server/SimpleServerTest.java
+++ b/hutool-http/src/test/java/org/dromara/hutool/http/server/SimpleServerTest.java
@@ -19,10 +19,11 @@ package org.dromara.hutool.http.server;
import org.dromara.hutool.core.collection.ListUtil;
import org.dromara.hutool.core.io.file.FileUtil;
import org.dromara.hutool.core.lang.Console;
-import org.dromara.hutool.http.multipart.UploadFile;
+import org.dromara.hutool.http.HttpUtil;
import org.dromara.hutool.http.meta.ContentType;
import org.dromara.hutool.http.meta.HeaderName;
-import org.dromara.hutool.http.HttpUtil;
+import org.dromara.hutool.http.multipart.UploadFile;
+import org.dromara.hutool.http.server.engine.sun.SunServerRequest;
import org.dromara.hutool.json.JSONUtil;
import java.net.HttpCookie;
@@ -33,13 +34,13 @@ public class SimpleServerTest {
HttpUtil.createServer(8888)
.addFilter(((req, res, chain) -> {
Console.log("Filter: " + req.getPath());
- chain.doFilter(req.getHttpExchange());
+ chain.doFilter(req.getExchange());
}))
// 设置默认根目录,classpath/html
.setRoot(FileUtil.file("html"))
// get数据测试,返回请求的PATH
.addAction("/get", (request, response) ->
- response.write(request.getURI().toString(), ContentType.TEXT_PLAIN.toString())
+ response.write(((SunServerRequest)request).getURI().toString(), ContentType.TEXT_PLAIN.toString())
)
// 返回JSON数据测试
.addAction("/restTest", (request, response) -> {
diff --git a/hutool-http/src/test/java/org/dromara/hutool/http/server/engine/UndertowTest.java b/hutool-http/src/test/java/org/dromara/hutool/http/server/engine/UndertowTest.java
new file mode 100644
index 000000000..0e5c34207
--- /dev/null
+++ b/hutool-http/src/test/java/org/dromara/hutool/http/server/engine/UndertowTest.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2024 Hutool Team and hutool.cn
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.dromara.hutool.http.server.engine;
+
+import org.dromara.hutool.core.lang.Console;
+import org.dromara.hutool.http.server.ServerConfig;
+import org.dromara.hutool.http.server.engine.undertow.UndertowEngine;
+
+public class UndertowTest {
+ public static void main(String[] args) {
+ final UndertowEngine undertowEngine = new UndertowEngine();
+ undertowEngine.init(ServerConfig.of());
+ undertowEngine.setHandler((request, response) -> {
+ Console.log(request.getPath());
+ response.write("Hutool Undertow response test");
+ });
+ undertowEngine.start();
+ }
+}