From f249c53465111bff9ca1bd68a4b8937c5836a02e Mon Sep 17 00:00:00 2001 From: liaozan <378024053@qq.com> Date: Tue, 22 Aug 2023 21:20:57 +0800 Subject: [PATCH] Refactor request wrapper --- .../web/ServletComponentConfiguration.java | 14 ++-- .../BodyParamMethodArgumentResolver.java | 10 +-- .../web/servlet/ContentCachingRequest.java | 50 ++++++++++++++ .../web/servlet/RequestLoggingFilter.java | 8 +-- .../web/servlet/RequestWrapperFilter.java | 4 +- .../servlet/WrappedByteArrayInputStream.java | 62 +++++++++++++++++ ...bstractSignatureValidationInterceptor.java | 4 +- .../web/utils/ContentCachingServletUtils.java | 69 ------------------- .../web/utils/RequestContentCachingUtils.java | 44 ++++++++++++ 9 files changed, 176 insertions(+), 89 deletions(-) create mode 100644 commons/web-common/src/main/java/com/schbrain/common/web/servlet/ContentCachingRequest.java create mode 100644 commons/web-common/src/main/java/com/schbrain/common/web/servlet/WrappedByteArrayInputStream.java delete mode 100644 commons/web-common/src/main/java/com/schbrain/common/web/utils/ContentCachingServletUtils.java create mode 100644 commons/web-common/src/main/java/com/schbrain/common/web/utils/RequestContentCachingUtils.java diff --git a/commons/web-common/src/main/java/com/schbrain/common/web/ServletComponentConfiguration.java b/commons/web-common/src/main/java/com/schbrain/common/web/ServletComponentConfiguration.java index 98b0dd0..b6da03f 100644 --- a/commons/web-common/src/main/java/com/schbrain/common/web/ServletComponentConfiguration.java +++ b/commons/web-common/src/main/java/com/schbrain/common/web/ServletComponentConfiguration.java @@ -33,22 +33,22 @@ public class ServletComponentConfiguration { @Bean @ConditionalOnMissingBean - public RequestWrapperFilter defaukltRequestWrapperFilter() { - return new RequestWrapperFilter(); + public RequestContextFilter requestContextFilter() { + OrderedRequestContextFilter requestContextFilter = new OrderedRequestContextFilter(); + requestContextFilter.setThreadContextInheritable(true); + return requestContextFilter; } @Bean @ConditionalOnMissingBean - public RequestContextFilter defaultRequestContextFilter() { - OrderedRequestContextFilter requestContextFilter = new OrderedRequestContextFilter(); - requestContextFilter.setThreadContextInheritable(true); - return requestContextFilter; + public RequestWrapperFilter requestWrapperFilter() { + return new RequestWrapperFilter(); } @Bean @ConditionalOnMissingBean @ConditionalOnProperty(value = "schbrain.web.enable-request-logging", havingValue = "true", matchIfMissing = true) - public RequestLoggingFilter defaultRequestLoggingFilter() { + public RequestLoggingFilter requestLoggingFilter() { return new RequestLoggingFilter(); } diff --git a/commons/web-common/src/main/java/com/schbrain/common/web/argument/BodyParamMethodArgumentResolver.java b/commons/web-common/src/main/java/com/schbrain/common/web/argument/BodyParamMethodArgumentResolver.java index c2ca55c..e0746fd 100644 --- a/commons/web-common/src/main/java/com/schbrain/common/web/argument/BodyParamMethodArgumentResolver.java +++ b/commons/web-common/src/main/java/com/schbrain/common/web/argument/BodyParamMethodArgumentResolver.java @@ -5,18 +5,18 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.schbrain.common.util.JacksonUtils; import com.schbrain.common.web.annotation.BodyParam; +import com.schbrain.common.web.servlet.ContentCachingRequest; import lombok.Setter; import org.springframework.core.MethodParameter; import org.springframework.util.Assert; import org.springframework.web.context.request.NativeWebRequest; import org.springframework.web.method.annotation.AbstractNamedValueMethodArgumentResolver; -import org.springframework.web.util.ContentCachingRequestWrapper; import javax.servlet.http.HttpServletRequest; import java.io.IOException; import java.lang.reflect.Type; -import static com.schbrain.common.web.utils.ContentCachingServletUtils.wrapRequestIfRequired; +import static com.schbrain.common.web.utils.RequestContentCachingUtils.wrapIfRequired; import static org.springframework.web.context.request.RequestAttributes.SCOPE_REQUEST; /** @@ -68,15 +68,15 @@ public class BodyParamMethodArgumentResolver extends AbstractNamedValueMethodArg private JsonNode getRequestBody(NativeWebRequest nativeWebRequest) throws IOException { JsonNode requestBody = (JsonNode) nativeWebRequest.getAttribute(REQUEST_BODY_CACHE, SCOPE_REQUEST); if (requestBody == null) { - ContentCachingRequestWrapper request = wrapRequest(nativeWebRequest); + ContentCachingRequest request = wrapRequest(nativeWebRequest); requestBody = objectMapper.readTree(request.getInputStream()); nativeWebRequest.setAttribute(REQUEST_BODY_CACHE, requestBody, SCOPE_REQUEST); } return requestBody; } - private ContentCachingRequestWrapper wrapRequest(NativeWebRequest nativeWebRequest) { - return wrapRequestIfRequired(nativeWebRequest.getNativeRequest(HttpServletRequest.class)); + private ContentCachingRequest wrapRequest(NativeWebRequest request) { + return wrapIfRequired(request.getNativeRequest(HttpServletRequest.class)); } } diff --git a/commons/web-common/src/main/java/com/schbrain/common/web/servlet/ContentCachingRequest.java b/commons/web-common/src/main/java/com/schbrain/common/web/servlet/ContentCachingRequest.java new file mode 100644 index 0000000..9e48a53 --- /dev/null +++ b/commons/web-common/src/main/java/com/schbrain/common/web/servlet/ContentCachingRequest.java @@ -0,0 +1,50 @@ +package com.schbrain.common.web.servlet; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.util.StreamUtils; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletRequestWrapper; +import java.io.IOException; + +/** + * @author liaozan + * @since 2023/8/22 + */ +@Slf4j +public class ContentCachingRequest extends HttpServletRequestWrapper { + + private WrappedByteArrayInputStream inputStream; + + public ContentCachingRequest(HttpServletRequest request) { + super(request); + } + + @Override + public WrappedByteArrayInputStream getInputStream() throws IOException { + if (inputStream == null) { + byte[] bytes = StreamUtils.copyToByteArray(super.getInputStream()); + this.inputStream = new WrappedByteArrayInputStream(bytes); + } + return inputStream; + } + + /** + * Return the cached request content as a String. The Charset used to decode the cached content is the same as returned by getCharacterEncoding. + */ + public String getContentAsString() { + return getContentAsString(getCharacterEncoding()); + } + + /** + * Return the cached request content as a String + */ + public String getContentAsString(String charset) { + try { + return getInputStream().getContentAsString(charset); + } catch (IOException e) { + throw new IllegalStateException(e.getMessage(), e); + } + } + +} diff --git a/commons/web-common/src/main/java/com/schbrain/common/web/servlet/RequestLoggingFilter.java b/commons/web-common/src/main/java/com/schbrain/common/web/servlet/RequestLoggingFilter.java index 1b599f7..cf57678 100644 --- a/commons/web-common/src/main/java/com/schbrain/common/web/servlet/RequestLoggingFilter.java +++ b/commons/web-common/src/main/java/com/schbrain/common/web/servlet/RequestLoggingFilter.java @@ -14,8 +14,8 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; -import static com.schbrain.common.web.utils.ContentCachingServletUtils.getRequestBody; -import static com.schbrain.common.web.utils.ContentCachingServletUtils.wrapRequestIfRequired; +import static com.schbrain.common.web.utils.RequestContentCachingUtils.getRequestBody; +import static com.schbrain.common.web.utils.RequestContentCachingUtils.wrapIfRequired; /** * 请求日志拦截器 @@ -35,7 +35,7 @@ public class RequestLoggingFilter extends OncePerRequestFilter implements Ordere return; } - request = wrapRequestIfRequired(request); + request = wrapIfRequired(request); long startTime = System.currentTimeMillis(); try { @@ -55,7 +55,7 @@ public class RequestLoggingFilter extends OncePerRequestFilter implements Ordere String method = request.getMethod(); String requestUri = request.getRequestURI(); String queryString = request.getQueryString(); - String requestBody = getRequestBody(request, false); + String requestBody = getRequestBody(request); StringBuilder builder = new StringBuilder(); builder.append("requestUri: ").append(method).append(CharPool.SPACE).append(requestUri); if (StringUtils.isNotBlank(queryString)) { diff --git a/commons/web-common/src/main/java/com/schbrain/common/web/servlet/RequestWrapperFilter.java b/commons/web-common/src/main/java/com/schbrain/common/web/servlet/RequestWrapperFilter.java index ceb1b29..59c0a84 100644 --- a/commons/web-common/src/main/java/com/schbrain/common/web/servlet/RequestWrapperFilter.java +++ b/commons/web-common/src/main/java/com/schbrain/common/web/servlet/RequestWrapperFilter.java @@ -10,7 +10,7 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; -import static com.schbrain.common.web.utils.ContentCachingServletUtils.wrapRequestIfRequired; +import static com.schbrain.common.web.utils.RequestContentCachingUtils.wrapIfRequired; /** * @author liaozan @@ -25,7 +25,7 @@ public class RequestWrapperFilter extends OncePerRequestFilter implements Ordere @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException { - chain.doFilter(wrapRequestIfRequired(request), response); + chain.doFilter(wrapIfRequired(request), response); } } diff --git a/commons/web-common/src/main/java/com/schbrain/common/web/servlet/WrappedByteArrayInputStream.java b/commons/web-common/src/main/java/com/schbrain/common/web/servlet/WrappedByteArrayInputStream.java new file mode 100644 index 0000000..3f6166d --- /dev/null +++ b/commons/web-common/src/main/java/com/schbrain/common/web/servlet/WrappedByteArrayInputStream.java @@ -0,0 +1,62 @@ +package com.schbrain.common.web.servlet; + +import javax.servlet.ReadListener; +import javax.servlet.ServletInputStream; +import java.io.ByteArrayInputStream; +import java.nio.charset.Charset; + +/** + * @author liaozan + * @since 2023/8/22 + */ +public class WrappedByteArrayInputStream extends ServletInputStream { + + private final ByteArrayInputStreamWrapper delegate; + + public WrappedByteArrayInputStream(byte[] bytes) { + this.delegate = new ByteArrayInputStreamWrapper(bytes); + } + + @Override + public boolean isFinished() { + return delegate.available() == 0; + } + + @Override + public boolean isReady() { + return true; + } + + @Override + public void setReadListener(ReadListener ignore) { + + } + + @Override + public int read() { + return delegate.read(); + } + + /** + * Return the cached request content as a String + */ + public String getContentAsString(String charset) { + return new String(delegate.getBytes(), Charset.forName(charset)); + } + + /** + * Simple {@link ByteArrayInputStream} wrapper that exposes the underlying byte array. + */ + private static class ByteArrayInputStreamWrapper extends ByteArrayInputStream { + + public ByteArrayInputStreamWrapper(byte[] bytes) { + super(bytes); + } + + public byte[] getBytes() { + return buf; + } + + } + +} diff --git a/commons/web-common/src/main/java/com/schbrain/common/web/support/signature/AbstractSignatureValidationInterceptor.java b/commons/web-common/src/main/java/com/schbrain/common/web/support/signature/AbstractSignatureValidationInterceptor.java index 6ba0e28..9a8d965 100644 --- a/commons/web-common/src/main/java/com/schbrain/common/web/support/signature/AbstractSignatureValidationInterceptor.java +++ b/commons/web-common/src/main/java/com/schbrain/common/web/support/signature/AbstractSignatureValidationInterceptor.java @@ -14,7 +14,7 @@ import java.util.List; import java.util.Objects; import static cn.hutool.core.text.StrPool.UNDERLINE; -import static com.schbrain.common.web.utils.ContentCachingServletUtils.getRequestBody; +import static com.schbrain.common.web.utils.RequestContentCachingUtils.getRequestBody; import static org.springframework.web.util.WebUtils.getNativeRequest; public abstract class AbstractSignatureValidationInterceptor extends BaseHandlerInterceptor { @@ -51,7 +51,7 @@ public abstract class AbstractSignatureValidationInterceptor