beanClass, boolean isIgnoreError) {
+ return fillBean(request, ReflectUtil.newInstanceIfPossible(beanClass), isIgnoreError);
+ }
+ // --------------------------------------------------------- fillBean end
+
+ /**
+ * 获取客户端IP
+ *
+ *
+ * 默认检测的Header:
+ *
+ *
+ * 1、X-Forwarded-For
+ * 2、X-Real-IP
+ * 3、Proxy-Client-IP
+ * 4、WL-Proxy-Client-IP
+ *
+ *
+ *
+ * otherHeaderNames参数用于自定义检测的Header
+ * 需要注意的是,使用此方法获取的客户IP地址必须在Http服务器(例如Nginx)中配置头信息,否则容易造成IP伪造。
+ *
+ *
+ * @param request 请求对象{@link HttpServletRequest}
+ * @param otherHeaderNames 其他自定义头文件,通常在Http服务器(例如Nginx)中配置
+ * @return IP地址
+ */
+ public static String getClientIP(HttpServletRequest request, String... otherHeaderNames) {
+ String[] headers = {"X-Forwarded-For", "X-Real-IP", "Proxy-Client-IP", "WL-Proxy-Client-IP", "HTTP_CLIENT_IP", "HTTP_X_FORWARDED_FOR"};
+ if (ArrayUtil.isNotEmpty(otherHeaderNames)) {
+ headers = ArrayUtil.addAll(headers, otherHeaderNames);
+ }
+
+ return getClientIPByHeader(request, headers);
+ }
+
+ /**
+ * 获取客户端IP
+ *
+ *
+ * headerNames参数用于自定义检测的Header
+ * 需要注意的是,使用此方法获取的客户IP地址必须在Http服务器(例如Nginx)中配置头信息,否则容易造成IP伪造。
+ *
+ *
+ * @param request 请求对象{@link HttpServletRequest}
+ * @param headerNames 自定义头,通常在Http服务器(例如Nginx)中配置
+ * @return IP地址
+ * @since 4.4.1
+ */
+ public static String getClientIPByHeader(HttpServletRequest request, String... headerNames) {
+ String ip;
+ for (String header : headerNames) {
+ ip = request.getHeader(header);
+ if (false == NetUtil.isUnknown(ip)) {
+ return NetUtil.getMultistageReverseProxyIp(ip);
+ }
+ }
+
+ ip = request.getRemoteAddr();
+ return NetUtil.getMultistageReverseProxyIp(ip);
+ }
+
+ /**
+ * 获得MultiPart表单内容,多用于获得上传的文件 在同一次请求中,此方法只能被执行一次!
+ *
+ * @param request {@link ServletRequest}
+ * @return MultipartFormData
+ * @throws IORuntimeException IO异常
+ * @since 4.0.2
+ */
+ public static MultipartFormData getMultipart(ServletRequest request) throws IORuntimeException {
+ return getMultipart(request, new UploadSetting());
+ }
+
+ /**
+ * 获得multipart/form-data 表单内容
+ * 包括文件和普通表单数据
+ * 在同一次请求中,此方法只能被执行一次!
+ *
+ * @param request {@link ServletRequest}
+ * @param uploadSetting 上传文件的设定,包括最大文件大小、保存在内存的边界大小、临时目录、扩展名限定等
+ * @return MultiPart表单
+ * @throws IORuntimeException IO异常
+ * @since 4.0.2
+ */
+ public static MultipartFormData getMultipart(ServletRequest request, UploadSetting uploadSetting) throws IORuntimeException {
+ final MultipartFormData formData = new MultipartFormData(uploadSetting);
+ try {
+ formData.parseRequestStream(request.getInputStream(), CharsetUtil.charset(request.getCharacterEncoding()));
+ } catch (IOException e) {
+ throw new IORuntimeException(e);
+ }
+
+ return formData;
+ }
+
+ // --------------------------------------------------------- Header start
+
+ /**
+ * 获取请求所有的头(header)信息
+ *
+ * @param request 请求对象{@link HttpServletRequest}
+ * @return header值
+ * @since 4.6.2
+ */
+ public static Map getHeaderMap(HttpServletRequest request) {
+ final Map headerMap = new HashMap<>();
+
+ final Enumeration names = request.getHeaderNames();
+ String name;
+ while (names.hasMoreElements()) {
+ name = names.nextElement();
+ headerMap.put(name, request.getHeader(name));
+ }
+
+ return headerMap;
+ }
+
+
+ /**
+ * 忽略大小写获得请求header中的信息
+ *
+ * @param request 请求对象{@link HttpServletRequest}
+ * @param nameIgnoreCase 忽略大小写头信息的KEY
+ * @return header值
+ */
+ public static String getHeaderIgnoreCase(HttpServletRequest request, String nameIgnoreCase) {
+ final Enumeration names = request.getHeaderNames();
+ String name;
+ while (names.hasMoreElements()) {
+ name = names.nextElement();
+ if (name != null && name.equalsIgnoreCase(nameIgnoreCase)) {
+ return request.getHeader(name);
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * 获得请求header中的信息
+ *
+ * @param request 请求对象{@link HttpServletRequest}
+ * @param name 头信息的KEY
+ * @param charsetName 字符集
+ * @return header值
+ */
+ public static String getHeader(HttpServletRequest request, String name, String charsetName) {
+ return getHeader(request, name, CharsetUtil.charset(charsetName));
+ }
+
+ /**
+ * 获得请求header中的信息
+ *
+ * @param request 请求对象{@link HttpServletRequest}
+ * @param name 头信息的KEY
+ * @param charset 字符集
+ * @return header值
+ * @since 4.6.2
+ */
+ public static String getHeader(HttpServletRequest request, String name, Charset charset) {
+ final String header = request.getHeader(name);
+ if (null != header) {
+ return CharsetUtil.convert(header, CharsetUtil.CHARSET_ISO_8859_1, charset);
+ }
+ return null;
+ }
+
+ /**
+ * 客户浏览器是否为IE
+ *
+ * @param request 请求对象{@link HttpServletRequest}
+ * @return 客户浏览器是否为IE
+ */
+ public static boolean isIE(HttpServletRequest request) {
+ String userAgent = getHeaderIgnoreCase(request, "User-Agent");
+ if (StrUtil.isNotBlank(userAgent)) {
+ //noinspection ConstantConditions
+ userAgent = userAgent.toUpperCase();
+ return userAgent.contains("MSIE") || userAgent.contains("TRIDENT");
+ }
+ return false;
+ }
+
+ /**
+ * 是否为GET请求
+ *
+ * @param request 请求对象{@link HttpServletRequest}
+ * @return 是否为GET请求
+ */
+ public static boolean isGetMethod(HttpServletRequest request) {
+ return METHOD_GET.equalsIgnoreCase(request.getMethod());
+ }
+
+ /**
+ * 是否为POST请求
+ *
+ * @param request 请求对象{@link HttpServletRequest}
+ * @return 是否为POST请求
+ */
+ public static boolean isPostMethod(HttpServletRequest request) {
+ return METHOD_POST.equalsIgnoreCase(request.getMethod());
+ }
+
+ /**
+ * 是否为Multipart类型表单,此类型表单用于文件上传
+ *
+ * @param request 请求对象{@link HttpServletRequest}
+ * @return 是否为Multipart类型表单,此类型表单用于文件上传
+ */
+ public static boolean isMultipart(HttpServletRequest request) {
+ if (false == isPostMethod(request)) {
+ return false;
+ }
+
+ String contentType = request.getContentType();
+ if (StrUtil.isBlank(contentType)) {
+ return false;
+ }
+ return contentType.toLowerCase().startsWith("multipart/");
+ }
+ // --------------------------------------------------------- Header end
+
+ // --------------------------------------------------------- Cookie start
+
+ /**
+ * 获得指定的Cookie
+ *
+ * @param httpServletRequest {@link HttpServletRequest}
+ * @param name cookie名
+ * @return Cookie对象
+ */
+ public static Cookie getCookie(HttpServletRequest httpServletRequest, String name) {
+ return readCookieMap(httpServletRequest).get(name);
+ }
+
+ /**
+ * 将cookie封装到Map里面
+ *
+ * @param httpServletRequest {@link HttpServletRequest}
+ * @return Cookie map
+ */
+ public static Map readCookieMap(HttpServletRequest httpServletRequest) {
+ final Cookie[] cookies = httpServletRequest.getCookies();
+ if (ArrayUtil.isEmpty(cookies)) {
+ return MapUtil.empty();
+ }
+
+ return IterUtil.toMap(
+ new ArrayIter<>(httpServletRequest.getCookies()),
+ new CaseInsensitiveMap<>(),
+ Cookie::getName);
+ }
+
+ /**
+ * 设定返回给客户端的Cookie
+ *
+ * @param response 响应对象{@link HttpServletResponse}
+ * @param cookie Servlet Cookie对象
+ */
+ public static void addCookie(HttpServletResponse response, Cookie cookie) {
+ response.addCookie(cookie);
+ }
+
+ /**
+ * 设定返回给客户端的Cookie
+ *
+ * @param response 响应对象{@link HttpServletResponse}
+ * @param name Cookie名
+ * @param value Cookie值
+ */
+ public static void addCookie(HttpServletResponse response, String name, String value) {
+ response.addCookie(new Cookie(name, value));
+ }
+
+ /**
+ * 设定返回给客户端的Cookie
+ *
+ * @param response 响应对象{@link HttpServletResponse}
+ * @param name cookie名
+ * @param value cookie值
+ * @param maxAgeInSeconds -1: 关闭浏览器清除Cookie. 0: 立即清除Cookie. >0 : Cookie存在的秒数.
+ * @param path Cookie的有效路径
+ * @param domain the domain name within which this cookie is visible; form is according to RFC 2109
+ */
+ public static void addCookie(HttpServletResponse response, String name, String value, int maxAgeInSeconds, String path, String domain) {
+ Cookie cookie = new Cookie(name, value);
+ if (domain != null) {
+ cookie.setDomain(domain);
+ }
+ cookie.setMaxAge(maxAgeInSeconds);
+ cookie.setPath(path);
+ addCookie(response, cookie);
+ }
+
+ /**
+ * 设定返回给客户端的Cookie
+ * Path: "/"
+ * No Domain
+ *
+ * @param response 响应对象{@link HttpServletResponse}
+ * @param name cookie名
+ * @param value cookie值
+ * @param maxAgeInSeconds -1: 关闭浏览器清除Cookie. 0: 立即清除Cookie. >0 : Cookie存在的秒数.
+ */
+ public static void addCookie(HttpServletResponse response, String name, String value, int maxAgeInSeconds) {
+ addCookie(response, name, value, maxAgeInSeconds, "/", null);
+ }
+
+ // --------------------------------------------------------- Cookie end
+ // --------------------------------------------------------- Response start
+
+ /**
+ * 获得PrintWriter
+ *
+ * @param response 响应对象{@link HttpServletResponse}
+ * @return 获得PrintWriter
+ * @throws IORuntimeException IO异常
+ */
+ public static PrintWriter getWriter(HttpServletResponse response) throws IORuntimeException {
+ try {
+ return response.getWriter();
+ } catch (IOException e) {
+ throw new IORuntimeException(e);
+ }
+ }
+
+ /**
+ * 返回数据给客户端
+ *
+ * @param response 响应对象{@link HttpServletResponse}
+ * @param text 返回的内容
+ * @param contentType 返回的类型
+ */
+ public static void write(HttpServletResponse response, String text, String contentType) {
+ response.setContentType(contentType);
+ Writer writer = null;
+ try {
+ writer = response.getWriter();
+ writer.write(text);
+ writer.flush();
+ } catch (IOException e) {
+ throw new UtilException(e);
+ } finally {
+ IoUtil.close(writer);
+ }
+ }
+
+ /**
+ * 返回文件给客户端
+ *
+ * @param response 响应对象{@link HttpServletResponse}
+ * @param file 写出的文件对象
+ * @since 4.1.15
+ */
+ public static void write(HttpServletResponse response, File file) {
+ final String fileName = file.getName();
+ final String contentType = ObjectUtil.defaultIfNull(FileUtil.getMimeType(fileName), "application/octet-stream");
+ BufferedInputStream in = null;
+ try {
+ in = FileUtil.getInputStream(file);
+ write(response, in, contentType, fileName);
+ } finally {
+ IoUtil.close(in);
+ }
+ }
+
+ /**
+ * 返回数据给客户端
+ *
+ * @param response 响应对象{@link HttpServletResponse}
+ * @param in 需要返回客户端的内容
+ * @param contentType 返回的类型,可以使用{@link FileUtil#getMimeType(String)}获取对应扩展名的MIME信息
+ *
+ * - application/pdf
+ * - application/vnd.ms-excel
+ * - application/msword
+ * - application/vnd.ms-powerpoint
+ *
+ * docx、xlsx 这种 office 2007 格式 设置 MIME;网页里面docx 文件是没问题,但是下载下来了之后就变成doc格式了
+ * 参考:https://my.oschina.net/shixiaobao17145/blog/32489
+ *
+ * - MIME_EXCELX_TYPE = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
+ * - MIME_PPTX_TYPE = "application/vnd.openxmlformats-officedocument.presentationml.presentation";
+ * - MIME_WORDX_TYPE = "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
+ * - MIME_STREAM_TYPE = "application/octet-stream;charset=utf-8"; #原始字节流
+ *
+ * @param fileName 文件名,自动添加双引号
+ * @since 4.1.15
+ */
+ public static void write(HttpServletResponse response, InputStream in, String contentType, String fileName) {
+ final String charset = ObjectUtil.defaultIfNull(response.getCharacterEncoding(), CharsetUtil.UTF_8);
+ response.setHeader("Content-Disposition", StrUtil.format("attachment;filename=\"{}\"",
+ URLUtil.encode(fileName, CharsetUtil.charset(charset))));
+ response.setContentType(contentType);
+ write(response, in);
+ }
+
+ /**
+ * 返回数据给客户端
+ *
+ * @param response 响应对象{@link HttpServletResponse}
+ * @param in 需要返回客户端的内容
+ * @param contentType 返回的类型
+ */
+ public static void write(HttpServletResponse response, InputStream in, String contentType) {
+ response.setContentType(contentType);
+ write(response, in);
+ }
+
+ /**
+ * 返回数据给客户端
+ *
+ * @param response 响应对象{@link HttpServletResponse}
+ * @param in 需要返回客户端的内容
+ */
+ public static void write(HttpServletResponse response, InputStream in) {
+ write(response, in, IoUtil.DEFAULT_BUFFER_SIZE);
+ }
+
+ /**
+ * 返回数据给客户端
+ *
+ * @param response 响应对象{@link HttpServletResponse}
+ * @param in 需要返回客户端的内容
+ * @param bufferSize 缓存大小
+ */
+ public static void write(HttpServletResponse response, InputStream in, int bufferSize) {
+ ServletOutputStream out = null;
+ try {
+ out = response.getOutputStream();
+ IoUtil.copy(in, out, bufferSize);
+ } catch (IOException e) {
+ throw new UtilException(e);
+ } finally {
+ IoUtil.close(out);
+ IoUtil.close(in);
+ }
+ }
+
+ /**
+ * 设置响应的Header
+ *
+ * @param response 响应对象{@link HttpServletResponse}
+ * @param name 名
+ * @param value 值,可以是String,Date, int
+ */
+ public static void setHeader(HttpServletResponse response, String name, Object value) {
+ if (value instanceof String) {
+ response.setHeader(name, (String) value);
+ } else if (Date.class.isAssignableFrom(value.getClass())) {
+ response.setDateHeader(name, ((Date) value).getTime());
+ } else if (value instanceof Integer || "int".equalsIgnoreCase(value.getClass().getSimpleName())) {
+ response.setIntHeader(name, (int) value);
+ } else {
+ response.setHeader(name, value.toString());
+ }
+ }
+ // --------------------------------------------------------- Response end
+}
diff --git a/hutool-extra/src/main/java/cn/hutool/extra/servlet/ServletUtil.java b/hutool-extra/src/main/java/cn/hutool/extra/servlet/ServletUtil.java
index 5c1391b17..e76942fd2 100644
--- a/hutool-extra/src/main/java/cn/hutool/extra/servlet/ServletUtil.java
+++ b/hutool-extra/src/main/java/cn/hutool/extra/servlet/ServletUtil.java
@@ -561,7 +561,7 @@ public class ServletUtil {
* application/vnd.ms-powerpoint
*
* docx、xlsx 这种 office 2007 格式 设置 MIME;网页里面docx 文件是没问题,但是下载下来了之后就变成doc格式了
- * 参考:https://my.oschina.net/shixiaobao17145/blog/32489
+ * 参考:https://my.oschina.net/shixiaobao17145/blog/32489
*
* - MIME_EXCELX_TYPE = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
* - MIME_PPTX_TYPE = "application/vnd.openxmlformats-officedocument.presentationml.presentation";
diff --git a/hutool-extra/src/test/java/cn/hutool/extra/servlet/ServletUtilTest.java b/hutool-extra/src/test/java/cn/hutool/extra/servlet/ServletUtilTest.java
index 82dd8651e..444b3d9fb 100644
--- a/hutool-extra/src/test/java/cn/hutool/extra/servlet/ServletUtilTest.java
+++ b/hutool-extra/src/test/java/cn/hutool/extra/servlet/ServletUtilTest.java
@@ -1,5 +1,6 @@
package cn.hutool.extra.servlet;
+import cn.hutool.core.util.StrUtil;
import org.junit.Ignore;
import org.junit.Test;
@@ -11,8 +12,8 @@ import java.nio.charset.StandardCharsets;
* ServletUtil工具类测试
*
* @author dazer
- * @date 2021/3/24 15:02
* @see ServletUtil
+ * @see JakartaServletUtil
*/
public class ServletUtilTest {
@@ -20,7 +21,7 @@ public class ServletUtilTest {
@Ignore
public void writeTest() {
HttpServletResponse response = null;
- byte[] bytes = "地球是我们共同的家园,需要大家珍惜.".getBytes(StandardCharsets.UTF_8);
+ byte[] bytes = StrUtil.utf8Bytes("地球是我们共同的家园,需要大家珍惜.");
//下载文件
// 这里没法直接测试,直接写到这里,方便调用;
@@ -32,4 +33,21 @@ public class ServletUtilTest {
ServletUtil.write(response, new ByteArrayInputStream(bytes), contentType, fileName);
}
}
+
+ @Test
+ @Ignore
+ public void jakartaWriteTest() {
+ jakarta.servlet.http.HttpServletResponse response = null;
+ byte[] bytes = StrUtil.utf8Bytes("地球是我们共同的家园,需要大家珍惜.");
+
+ //下载文件
+ // 这里没法直接测试,直接写到这里,方便调用;
+ //noinspection ConstantConditions
+ if (response != null) {
+ String fileName = "签名文件.pdf";
+ String contentType = "application/pdf";// application/octet-stream、image/jpeg、image/gif
+ response.setCharacterEncoding(StandardCharsets.UTF_8.name()); // 必须设置否则乱码; 但是 safari乱码
+ JakartaServletUtil.write(response, new ByteArrayInputStream(bytes), contentType, fileName);
+ }
+ }
}