diff --git a/framework-core/pom.xml b/framework-core/pom.xml index a601fb9..16187ea 100644 --- a/framework-core/pom.xml +++ b/framework-core/pom.xml @@ -5,7 +5,7 @@ com.unionmed unionmed-framework - 0.0.14 + 0.0.15 4.0.0 diff --git a/framework-core/src/main/java/com/unionmed/framework/spring/mvc/response/ResponseBodyConfiguration.java b/framework-core/src/main/java/com/unionmed/framework/spring/mvc/MvcConfiguration.java similarity index 70% rename from framework-core/src/main/java/com/unionmed/framework/spring/mvc/response/ResponseBodyConfiguration.java rename to framework-core/src/main/java/com/unionmed/framework/spring/mvc/MvcConfiguration.java index 93f999b..371dc95 100644 --- a/framework-core/src/main/java/com/unionmed/framework/spring/mvc/response/ResponseBodyConfiguration.java +++ b/framework-core/src/main/java/com/unionmed/framework/spring/mvc/MvcConfiguration.java @@ -1,11 +1,16 @@ -package com.unionmed.framework.spring.mvc.response; +package com.unionmed.framework.spring.mvc; +import com.unionmed.framework.spring.mvc.filter.RequestFilterWrapper; +import com.unionmed.framework.spring.mvc.response.RequestResponseBodyCryptProperties; +import com.unionmed.framework.spring.mvc.response.ResponseBodyProcessor; +import com.unionmed.framework.spring.mvc.response.ResponseBodyProcessorChain; import com.unionmed.framework.spring.mvc.response.datatemplate.DataTemplateResponseBodyInterceptor; import com.unionmed.framework.spring.mvc.response.interceptor.EncryptionResponseBodyInterceptor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.boot.web.servlet.FilterRegistrationBean; +import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.ImportResource; import org.springframework.web.method.support.HandlerMethodReturnValueHandler; import org.springframework.web.servlet.mvc.method.annotation.HttpEntityMethodProcessor; import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter; @@ -20,7 +25,7 @@ import java.util.List; */ @EnableConfigurationProperties({RequestResponseBodyCryptProperties.class}) @Configuration -public class ResponseBodyConfiguration { +public class MvcConfiguration { @Autowired private RequestResponseBodyCryptProperties requestResponseBodyCryptProperties; @@ -31,7 +36,7 @@ public class ResponseBodyConfiguration { ResponseBodyProcessorChain chain = new ResponseBodyProcessorChain(); chain.add(new DataTemplateResponseBodyInterceptor(), new EncryptionResponseBodyInterceptor(requestResponseBodyCryptProperties)); - return new ResponseBodyProcessor(requestMappingHandlerAdapter.getMessageConverters(), chain);//初始化过滤器 + return new ResponseBodyProcessor(requestMappingHandlerAdapter.getMessageConverters(), chain); } @PostConstruct @@ -51,4 +56,14 @@ public class ResponseBodyConfiguration { } return -1; } + + @Bean + public FilterRegistrationBean repeatRequestFilter() { + FilterRegistrationBean registration = new FilterRegistrationBean(); + registration.setFilter(new RequestFilterWrapper(requestResponseBodyCryptProperties)); + registration.addUrlPatterns("/*"); + registration.setName("repeatRequestFilter"); + registration.setOrder(1); + return registration; + } } diff --git a/framework-core/src/main/java/com/unionmed/framework/spring/mvc/filter/RepeatHttpServletRequestWrapper.java b/framework-core/src/main/java/com/unionmed/framework/spring/mvc/filter/RepeatHttpServletRequestWrapper.java new file mode 100644 index 0000000..3dedacc --- /dev/null +++ b/framework-core/src/main/java/com/unionmed/framework/spring/mvc/filter/RepeatHttpServletRequestWrapper.java @@ -0,0 +1,106 @@ +package com.unionmed.framework.spring.mvc.filter; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.unionmed.framework.http.HttpHeaders; +import com.unionmed.framework.spring.mvc.response.BodyCryptUtils; +import com.unionmed.framework.spring.mvc.response.RequestResponseBodyCryptProperties; +import com.unionmed.framework.util.ObjectUtils; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.io.IOUtils; + +import javax.servlet.ReadListener; +import javax.servlet.ServletInputStream; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletRequestWrapper; +import java.io.*; +import java.nio.charset.Charset; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Map; + +/** + * @author ianChen + * @date 2023/6/27 16:49 + */ +@Slf4j +public class RepeatHttpServletRequestWrapper extends HttpServletRequestWrapper { + + private ServletInputStream is; + + public RepeatHttpServletRequestWrapper(RequestResponseBodyCryptProperties requestResponseBodyCryptProperties, HttpServletRequest request) throws IOException { + super(request); + try { + String body; + if (ObjectUtils.startWithIgnore(request.getHeader(HttpHeaders.CONTENT_TYPE), HttpHeaders.FORM_DATA)) { + is = request.getInputStream(); + body = "StreamBody"; + } else { + body = IOUtils.toString(request.getInputStream(), Charset.defaultCharset()); + if (ObjectUtils.notEmpty(body) && requestResponseBodyCryptProperties.isEnabled() && ObjectUtils.equalsIgnore(request.getHeader(HttpHeaders.X_DATA_CRYPT_E), HttpHeaders.X_DATA_CRYPT_E_VALUE_TRUE)) { + if (log.isDebugEnabled()) + log.debug("InputMessage Body: {}", body); + body = BodyCryptUtils.decrypt(requestResponseBodyCryptProperties.getSk(), body); + } + is = new RepeatServletInputStreamWrapper(new ByteArrayInputStream(body.getBytes(Charset.defaultCharset()))); + } + if (log.isDebugEnabled()) { + log.debug("URI: {}, Method: {}", request.getRequestURI(), request.getMethod()); + Map headers = new HashMap<>(); + String headerKey; + Enumeration headerNames = request.getHeaderNames(); + while (headerNames.hasMoreElements()) { + headers.put(headerKey = headerNames.nextElement(), request.getHeader(headerKey)); + } + log.debug("Headers: {}", new JSONObject(headers).toJSONString()); + log.debug("RequestParameter: {}", request.getParameterMap() == null ? "" : JSON.toJSONString(request.getParameterMap())); + log.debug("RequestBody: {}", body); + } + } catch (IOException ex) { + log.error("获取Request Body数据异常", ex); + is = request.getInputStream(); + } + } + + @Override + public ServletInputStream getInputStream() throws IOException { + return is; + } + + @Override + public BufferedReader getReader() throws IOException { + return new BufferedReader(new InputStreamReader(getInputStream())); + } + + class RepeatServletInputStreamWrapper extends ServletInputStream { + + private final InputStream is; + + public RepeatServletInputStreamWrapper(InputStream is) { + this.is = is; + } + + @Override + public boolean isFinished() { + return false; + } + + @Override + public boolean isReady() { + return false; + } + + @Override + public void setReadListener(ReadListener readListener) { + } + + @Override + public int read() throws IOException { + return this.is.read(); + } + + public synchronized void reset() throws IOException { + this.is.reset(); + } + } +} diff --git a/framework-core/src/main/java/com/unionmed/framework/spring/mvc/filter/RequestFilterWrapper.java b/framework-core/src/main/java/com/unionmed/framework/spring/mvc/filter/RequestFilterWrapper.java new file mode 100644 index 0000000..4e327bc --- /dev/null +++ b/framework-core/src/main/java/com/unionmed/framework/spring/mvc/filter/RequestFilterWrapper.java @@ -0,0 +1,28 @@ +package com.unionmed.framework.spring.mvc.filter; + +import com.unionmed.framework.spring.mvc.response.RequestResponseBodyCryptProperties; +import org.springframework.web.filter.OncePerRequestFilter; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +/** + * @author ianChen + * @date 2023/6/27 16:47 + */ +public class RequestFilterWrapper extends OncePerRequestFilter { + + private RequestResponseBodyCryptProperties requestResponseBodyCryptProperties; + + public RequestFilterWrapper(RequestResponseBodyCryptProperties requestResponseBodyCryptProperties) { + this.requestResponseBodyCryptProperties = requestResponseBodyCryptProperties; + } + + @Override + protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException { + filterChain.doFilter(new RepeatHttpServletRequestWrapper(requestResponseBodyCryptProperties, httpServletRequest), httpServletResponse); + } +} diff --git a/framework-core/src/main/java/com/unionmed/framework/spring/mvc/response/DecryptRequestBodyAdvice.java b/framework-core/src/main/java/com/unionmed/framework/spring/mvc/request/DecryptRequestBodyAdvice.java similarity index 86% rename from framework-core/src/main/java/com/unionmed/framework/spring/mvc/response/DecryptRequestBodyAdvice.java rename to framework-core/src/main/java/com/unionmed/framework/spring/mvc/request/DecryptRequestBodyAdvice.java index 6379938..58b10e7 100644 --- a/framework-core/src/main/java/com/unionmed/framework/spring/mvc/response/DecryptRequestBodyAdvice.java +++ b/framework-core/src/main/java/com/unionmed/framework/spring/mvc/request/DecryptRequestBodyAdvice.java @@ -1,7 +1,9 @@ -package com.unionmed.framework.spring.mvc.response; +package com.unionmed.framework.spring.mvc.request; import com.alibaba.fastjson.JSON; import com.unionmed.framework.http.HttpHeaders; +import com.unionmed.framework.spring.mvc.response.BodyCryptUtils; +import com.unionmed.framework.spring.mvc.response.RequestResponseBodyCryptProperties; import com.unionmed.framework.util.ObjectUtils; import lombok.extern.slf4j.Slf4j; import org.apache.commons.io.IOUtils; @@ -17,13 +19,14 @@ import org.springframework.web.servlet.mvc.method.annotation.RequestBodyAdvice; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.Type; +import java.nio.charset.Charset; /** * @author ianChen * @date 2023/6/26 14:02 */ @Slf4j -@ControllerAdvice +//@ControllerAdvice public class DecryptRequestBodyAdvice implements RequestBodyAdvice { @Autowired @@ -36,8 +39,10 @@ public class DecryptRequestBodyAdvice implements RequestBodyAdvice { @Override public HttpInputMessage beforeBodyRead(final HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class> converterType) throws IOException { - String body = IOUtils.toString(inputMessage.getBody(), HttpHeaders.CHARSET_UTF8); + String body = IOUtils.toString(inputMessage.getBody(), Charset.defaultCharset()); if (ObjectUtils.notEmpty(body) && requestResponseBodyCryptProperties.isEnabled() && ObjectUtils.equalsIgnore(inputMessage.getHeaders().getFirst(HttpHeaders.X_DATA_CRYPT_E), HttpHeaders.X_DATA_CRYPT_E_VALUE_TRUE)) { + if (log.isDebugEnabled()) + log.debug("InputMessage Body: {}", body); body = BodyCryptUtils.decrypt(requestResponseBodyCryptProperties.getSk(), body); } @@ -49,7 +54,7 @@ public class DecryptRequestBodyAdvice implements RequestBodyAdvice { log.debug("RequestBody: {}", body); } - InputStream is = IOUtils.toInputStream(body, HttpHeaders.CHARSET_UTF8); + InputStream is = IOUtils.toInputStream(body, Charset.defaultCharset()); return new HttpInputMessage() { @Override public InputStream getBody() throws IOException { diff --git a/framework-core/src/main/java/com/unionmed/framework/util/ObjectUtils.java b/framework-core/src/main/java/com/unionmed/framework/util/ObjectUtils.java index 63b932c..33e82c1 100644 --- a/framework-core/src/main/java/com/unionmed/framework/util/ObjectUtils.java +++ b/framework-core/src/main/java/com/unionmed/framework/util/ObjectUtils.java @@ -157,6 +157,30 @@ public class ObjectUtils { return !equals(o, o2); } + public static boolean startWith(String source, String target) { + return notEmptyAnd(source, target) && source.trim().startsWith(target.trim()); + } + + public static boolean startWith(String source, String target, int offset) { + return notEmptyAnd(source, target) && source.trim().startsWith(target.trim(), offset); + } + + public static boolean startWithIgnore(String source, String target) { + return notEmptyAnd(source, target) && source.trim().toLowerCase().startsWith(target.trim().toLowerCase()); + } + + public static boolean startWithIgnore(String source, String target, int offset) { + return notEmptyAnd(source, target) && source.trim().toLowerCase().startsWith(target.trim().toLowerCase(), offset); + } + + public static boolean endWith(String source, String target) { + return notEmptyAnd(source, target) && source.trim().endsWith(target.trim()); + } + + public static boolean endWithIgnore(String source, String target) { + return notEmptyAnd(source, target) && source.trim().toLowerCase().endsWith(target.trim().toLowerCase()); + } + public static boolean arrayNotEquals(Object o1, Object o2) { return !arrayEquals(o1, o2); } @@ -169,9 +193,9 @@ public class ObjectUtils { if (isEmpty(s)) return false; String _s = s.trim(); - if (_s.startsWith("{") && _s.endsWith("}")) + if (_s.charAt(0) == '{' && _s.charAt(_s.length() - 1) == '}') return true; - if (_s.startsWith("[") && _s.endsWith("]")) + if (_s.charAt(0) == '[' && _s.charAt(_s.length() - 1) == ']') return true; return false; } @@ -179,7 +203,7 @@ public class ObjectUtils { /** * 打马赛克 * - * @param s 要打码的字符串 + * @param s 要打码的字符串 * @param start * @param endHold * @param mosaicLength diff --git a/framework-orm/pom.xml b/framework-orm/pom.xml index d56e485..5e57b3f 100644 --- a/framework-orm/pom.xml +++ b/framework-orm/pom.xml @@ -5,7 +5,7 @@ unionmed-framework com.unionmed - 0.0.14 + 0.0.15 4.0.0 diff --git a/framework-test/pom.xml b/framework-test/pom.xml index 073f469..155dd9e 100644 --- a/framework-test/pom.xml +++ b/framework-test/pom.xml @@ -5,7 +5,7 @@ com.unionmed unionmed-framework - 0.0.14 + 0.0.15 4.0.0 diff --git a/pom.xml b/pom.xml index 771ea65..fd44909 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ 4.0.0 com.unionmed unionmed-framework - 0.0.14 + 0.0.15 pom unionmed-framework