mirror of
https://github.com/continew-org/continew-starter.git
synced 2026-01-13 20:57:12 +08:00
feat(core): ServletUtils 新增 isMultipart、isForm、isStream 方法
This commit is contained in:
@@ -18,6 +18,7 @@ package top.continew.starter.core.util;
|
|||||||
|
|
||||||
import cn.hutool.core.map.MapUtil;
|
import cn.hutool.core.map.MapUtil;
|
||||||
import cn.hutool.core.text.CharSequenceUtil;
|
import cn.hutool.core.text.CharSequenceUtil;
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
import cn.hutool.extra.servlet.JakartaServletUtil;
|
import cn.hutool.extra.servlet.JakartaServletUtil;
|
||||||
import cn.hutool.http.useragent.UserAgent;
|
import cn.hutool.http.useragent.UserAgent;
|
||||||
import cn.hutool.http.useragent.UserAgentUtil;
|
import cn.hutool.http.useragent.UserAgentUtil;
|
||||||
@@ -189,5 +190,38 @@ public class ServletUtils extends JakartaServletUtil {
|
|||||||
write(response, data, MediaType.APPLICATION_JSON_VALUE);
|
write(response, data, MediaType.APPLICATION_JSON_VALUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查请求是否为 {@code multipart/form-data} 格式(常用于文件上传)
|
||||||
|
*
|
||||||
|
* @param request 请求对象
|
||||||
|
* @return true: 是; false: 否
|
||||||
|
* @since 2.15.1
|
||||||
|
*/
|
||||||
|
public static boolean isMultipart(HttpServletRequest request) {
|
||||||
|
return StrUtil.startWithIgnoreCase(request.getContentType(), "multipart/");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查 HTTP 请求是否为 {@code application/x-www-form-urlencoded} 格式(标准表单提交)
|
||||||
|
*
|
||||||
|
* @param request 请求对象
|
||||||
|
* @return true: 是; false: 否
|
||||||
|
* @see MediaType#APPLICATION_FORM_URLENCODED_VALUE
|
||||||
|
* @since 2.15.1
|
||||||
|
*/
|
||||||
|
public static boolean isForm(HttpServletRequest request) {
|
||||||
|
return StrUtil.contains(request.getContentType(), MediaType.APPLICATION_FORM_URLENCODED_VALUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查 HTTP 响应是否为 {@code Server-Sent Events (SSE)} 流格式
|
||||||
|
*
|
||||||
|
* @param response 响应对象
|
||||||
|
* @return true: 是; false: 否
|
||||||
|
* @see MediaType#TEXT_EVENT_STREAM_VALUE
|
||||||
|
* @since 2.15.1
|
||||||
|
*/
|
||||||
|
public static boolean isStream(HttpServletResponse response) {
|
||||||
|
return StrUtil.contains(response.getContentType(), MediaType.TEXT_EVENT_STREAM_VALUE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,13 +18,12 @@ package top.continew.starter.core.wrapper;
|
|||||||
|
|
||||||
import jakarta.servlet.ReadListener;
|
import jakarta.servlet.ReadListener;
|
||||||
import jakarta.servlet.ServletInputStream;
|
import jakarta.servlet.ServletInputStream;
|
||||||
import jakarta.servlet.ServletRequest;
|
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import jakarta.servlet.http.HttpServletRequestWrapper;
|
import jakarta.servlet.http.HttpServletRequestWrapper;
|
||||||
import org.springframework.http.MediaType;
|
|
||||||
import org.springframework.util.FastByteArrayOutputStream;
|
import org.springframework.util.FastByteArrayOutputStream;
|
||||||
import org.springframework.util.StreamUtils;
|
import org.springframework.util.StreamUtils;
|
||||||
import top.continew.starter.core.constant.StringConstants;
|
import top.continew.starter.core.constant.StringConstants;
|
||||||
|
import top.continew.starter.core.util.ServletUtils;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.net.URLEncoder;
|
import java.net.URLEncoder;
|
||||||
@@ -77,8 +76,8 @@ public class RepeatReadRequestWrapper extends HttpServletRequestWrapper {
|
|||||||
? new FastByteArrayOutputStream(contentLength)
|
? new FastByteArrayOutputStream(contentLength)
|
||||||
: new FastByteArrayOutputStream();
|
: new FastByteArrayOutputStream();
|
||||||
// 判断是否为文件上传请求
|
// 判断是否为文件上传请求
|
||||||
if (!isMultipartContent(request)) {
|
if (!ServletUtils.isMultipart(request)) {
|
||||||
if (isFormRequest()) {
|
if (ServletUtils.isForm(request)) {
|
||||||
writeRequestParametersToCachedContent();
|
writeRequestParametersToCachedContent();
|
||||||
} else {
|
} else {
|
||||||
StreamUtils.copy(request.getInputStream(), cachedContent);
|
StreamUtils.copy(request.getInputStream(), cachedContent);
|
||||||
@@ -90,7 +89,7 @@ public class RepeatReadRequestWrapper extends HttpServletRequestWrapper {
|
|||||||
@Override
|
@Override
|
||||||
public ServletInputStream getInputStream() throws IOException {
|
public ServletInputStream getInputStream() throws IOException {
|
||||||
// 如果是文件上传,直接返回原始输入流
|
// 如果是文件上传,直接返回原始输入流
|
||||||
if (isMultipartContent(super.getRequest())) {
|
if (ServletUtils.isMultipart((HttpServletRequest)super.getRequest())) {
|
||||||
return super.getRequest().getInputStream();
|
return super.getRequest().getInputStream();
|
||||||
}
|
}
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
@@ -102,7 +101,7 @@ public class RepeatReadRequestWrapper extends HttpServletRequestWrapper {
|
|||||||
@Override
|
@Override
|
||||||
public BufferedReader getReader() throws IOException {
|
public BufferedReader getReader() throws IOException {
|
||||||
// 如果是文件上传,直接返回原始Reader
|
// 如果是文件上传,直接返回原始Reader
|
||||||
if (isMultipartContent(super.getRequest())) {
|
if (ServletUtils.isMultipart((HttpServletRequest)super.getRequest())) {
|
||||||
return super.getRequest().getReader();
|
return super.getRequest().getReader();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -153,22 +152,6 @@ public class RepeatReadRequestWrapper extends HttpServletRequestWrapper {
|
|||||||
return cachedContent;
|
return cachedContent;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 判断当前请求是否为 multipart/form-data 类型的文件上传请求。 该类型一般用于表单上传文件的场景,例如 enctype="multipart/form-data"。
|
|
||||||
*
|
|
||||||
* @param request 当前 HTTP 请求对象
|
|
||||||
* @return true 表示为 multipart 文件上传请求;否则为 false
|
|
||||||
*/
|
|
||||||
public boolean isMultipartContent(ServletRequest request) {
|
|
||||||
String contentType = request.getContentType();
|
|
||||||
return contentType != null && contentType.toLowerCase().startsWith("multipart/");
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isFormRequest() {
|
|
||||||
String contentType = getContentType();
|
|
||||||
return (contentType != null && contentType.contains(MediaType.APPLICATION_FORM_URLENCODED_VALUE));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Body 缓存的ServletInputStream实现 DefaultServerRequestBuilder.BodyInputStream
|
* Body 缓存的ServletInputStream实现 DefaultServerRequestBuilder.BodyInputStream
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ import jakarta.servlet.ServletOutputStream;
|
|||||||
import jakarta.servlet.WriteListener;
|
import jakarta.servlet.WriteListener;
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
import jakarta.servlet.http.HttpServletResponseWrapper;
|
import jakarta.servlet.http.HttpServletResponseWrapper;
|
||||||
import org.springframework.http.MediaType;
|
import top.continew.starter.core.util.ServletUtils;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@@ -46,30 +46,11 @@ public class RepeatReadResponseWrapper extends HttpServletResponseWrapper {
|
|||||||
|
|
||||||
public RepeatReadResponseWrapper(HttpServletResponse response) {
|
public RepeatReadResponseWrapper(HttpServletResponse response) {
|
||||||
super(response);
|
super(response);
|
||||||
checkStreamingResponse();
|
isStreamingResponse = ServletUtils.isStream(response);
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setContentType(String type) {
|
|
||||||
super.setContentType(type);
|
|
||||||
// 根据 Content-Type 判断是否为流式响应
|
|
||||||
if (type != null) {
|
|
||||||
String lowerType = type.toLowerCase();
|
|
||||||
isStreamingResponse = lowerType.contains(MediaType.TEXT_EVENT_STREAM_VALUE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void checkStreamingResponse() {
|
|
||||||
String contentType = getContentType();
|
|
||||||
if (contentType != null) {
|
|
||||||
String lowerType = contentType.toLowerCase();
|
|
||||||
isStreamingResponse = lowerType.contains(MediaType.TEXT_EVENT_STREAM_VALUE);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ServletOutputStream getOutputStream() throws IOException {
|
public ServletOutputStream getOutputStream() throws IOException {
|
||||||
checkStreamingResponse();
|
|
||||||
// 对于 SSE 流式响应,直接返回原始响应流,不做额外处理
|
// 对于 SSE 流式响应,直接返回原始响应流,不做额外处理
|
||||||
if (isStreamingResponse) {
|
if (isStreamingResponse) {
|
||||||
return super.getOutputStream();
|
return super.getOutputStream();
|
||||||
@@ -103,7 +84,6 @@ public class RepeatReadResponseWrapper extends HttpServletResponseWrapper {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PrintWriter getWriter() throws IOException {
|
public PrintWriter getWriter() throws IOException {
|
||||||
checkStreamingResponse();
|
|
||||||
if (isStreamingResponse) {
|
if (isStreamingResponse) {
|
||||||
// 对于 SSE 流式响应,直接返回原始响应写入器,不做额外处理
|
// 对于 SSE 流式响应,直接返回原始响应写入器,不做额外处理
|
||||||
return super.getWriter();
|
return super.getWriter();
|
||||||
|
|||||||
@@ -17,12 +17,12 @@
|
|||||||
package top.continew.starter.log.http.servlet;
|
package top.continew.starter.log.http.servlet;
|
||||||
|
|
||||||
import cn.hutool.core.text.CharSequenceUtil;
|
import cn.hutool.core.text.CharSequenceUtil;
|
||||||
import cn.hutool.extra.servlet.JakartaServletUtil;
|
|
||||||
import cn.hutool.json.JSONUtil;
|
import cn.hutool.json.JSONUtil;
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import org.springframework.web.util.UriUtils;
|
import org.springframework.web.util.UriUtils;
|
||||||
import org.springframework.web.util.WebUtils;
|
import org.springframework.web.util.WebUtils;
|
||||||
import top.continew.starter.core.constant.StringConstants;
|
import top.continew.starter.core.constant.StringConstants;
|
||||||
|
import top.continew.starter.core.util.ServletUtils;
|
||||||
import top.continew.starter.core.wrapper.RepeatReadRequestWrapper;
|
import top.continew.starter.core.wrapper.RepeatReadRequestWrapper;
|
||||||
import top.continew.starter.log.http.RecordableHttpRequest;
|
import top.continew.starter.log.http.RecordableHttpRequest;
|
||||||
|
|
||||||
@@ -75,7 +75,7 @@ public final class RecordableServletHttpRequest implements RecordableHttpRequest
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Map<String, String> getHeaders() {
|
public Map<String, String> getHeaders() {
|
||||||
return JakartaServletUtil.getHeaderMap(request);
|
return ServletUtils.getHeaderMap(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -83,7 +83,7 @@ public final class RecordableServletHttpRequest implements RecordableHttpRequest
|
|||||||
try {
|
try {
|
||||||
RepeatReadRequestWrapper wrappedRequest = WebUtils
|
RepeatReadRequestWrapper wrappedRequest = WebUtils
|
||||||
.getNativeRequest(request, RepeatReadRequestWrapper.class);
|
.getNativeRequest(request, RepeatReadRequestWrapper.class);
|
||||||
if (wrappedRequest == null || wrappedRequest.isMultipartContent(request)) {
|
if (wrappedRequest == null || ServletUtils.isMultipart(request)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
String body = wrappedRequest.getContentAsString();
|
String body = wrappedRequest.getContentAsString();
|
||||||
@@ -96,12 +96,12 @@ public final class RecordableServletHttpRequest implements RecordableHttpRequest
|
|||||||
@Override
|
@Override
|
||||||
public String getParams() {
|
public String getParams() {
|
||||||
String body = this.getBody();
|
String body = this.getBody();
|
||||||
return CharSequenceUtil.isNotBlank(body) ? body : JSONUtil.toJsonStr(JakartaServletUtil.getParamMap(request));
|
return CharSequenceUtil.isNotBlank(body) ? body : JSONUtil.toJsonStr(ServletUtils.getParamMap(request));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getIp() {
|
public String getIp() {
|
||||||
return JakartaServletUtil.getClientIP(request);
|
return ServletUtils.getClientIP(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user