From 6ed6535d903f79a5cee7562a68508bfcae563d03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=B0=B8=E4=BA=AE?= Date: Mon, 14 Nov 2022 19:00:48 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20aos-web=20=E5=A2=9E=E5=8A=A0=E5=85=A8?= =?UTF-8?q?=E5=B1=80=E5=BC=82=E5=B8=B8=E6=8B=A6=E6=88=AA=E5=99=A8=20?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=85=A8=E5=B1=80=E8=BF=94=E5=9B=9E=E7=BB=93?= =?UTF-8?q?=E6=9E=9C=E9=9B=86=20=E5=A2=9E=E5=8A=A0jackson=E5=85=A8?= =?UTF-8?q?=E5=B1=80=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- aos-dependencies/pom.xml | 7 +- .../main/java/com/aos/test/Application.java | 2 +- .../test/web/ActivityDemandController.java | 31 -------- .../java/com/aos/test/web/TestController.java | 40 ++++++++++ .../test/web2/ActivityDemandController2.java | 36 --------- aos-web/pom.xml | 12 +++ .../advice/ControllerErrorResponseAdvice.java | 26 +++++++ .../ControllerResponseAdvice.java | 23 +++++- .../java/com/aos/web/conf/AosWebConf.java | 76 +++++++++++++++++++ .../jackson/AosJacksonBuilderCustomizer.java | 34 +++++++++ 10 files changed, 214 insertions(+), 73 deletions(-) delete mode 100644 aos-model-test/src/main/java/com/aos/test/web/ActivityDemandController.java create mode 100644 aos-model-test/src/main/java/com/aos/test/web/TestController.java delete mode 100644 aos-model-test/src/main/java/com/aos/test/web2/ActivityDemandController2.java create mode 100644 aos-web/src/main/java/com/aos/web/advice/ControllerErrorResponseAdvice.java rename aos-web/src/main/java/com/aos/web/{conf => advice}/ControllerResponseAdvice.java (68%) create mode 100644 aos-web/src/main/java/com/aos/web/jackson/AosJacksonBuilderCustomizer.java diff --git a/aos-dependencies/pom.xml b/aos-dependencies/pom.xml index 7d45d65..dea5afb 100644 --- a/aos-dependencies/pom.xml +++ b/aos-dependencies/pom.xml @@ -26,7 +26,7 @@ 30.0-jre 2.9.2 2.9.2 - 3.0.2 + 3.0.3 1.5.20 2.2.7.RELEASE Hoxton.SR12 @@ -101,6 +101,11 @@ springfox-swagger-ui ${swagger-ui.version} + + io.springfox + springfox-swagger-common + ${swagger-ui.version} + com.github.xiaoymin knife4j-spring-ui diff --git a/aos-model-test/src/main/java/com/aos/test/Application.java b/aos-model-test/src/main/java/com/aos/test/Application.java index ac7c5f7..3d5f964 100644 --- a/aos-model-test/src/main/java/com/aos/test/Application.java +++ b/aos-model-test/src/main/java/com/aos/test/Application.java @@ -6,7 +6,7 @@ import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.context.properties.EnableConfigurationProperties; @SpringBootApplication -@EnableSwagger(applicationName = "test", scanPackagesPath = "com.aos.test") +@EnableSwagger(applicationName = "test", scanPackagesPath = "com.aos.test.web") @EnableConfigurationProperties public class Application { public static void main(String[] args) { diff --git a/aos-model-test/src/main/java/com/aos/test/web/ActivityDemandController.java b/aos-model-test/src/main/java/com/aos/test/web/ActivityDemandController.java deleted file mode 100644 index c9d73ea..0000000 --- a/aos-model-test/src/main/java/com/aos/test/web/ActivityDemandController.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.aos.test.web; - -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -/** - * @author: zouyang - * @date: 2022/6/1 - * @description: 需求计划入口 - */ -@RestController -@RequestMapping("/") -@Api(value = "ActivityDemandController", tags = "需求计划入口") -public class ActivityDemandController { - - @PostMapping("/保存") - @ApiOperation(value = "分页查询活动需求") - public void save() { - - } - - @PostMapping("/getListPage1") - @ApiOperation(value = "分页查询活动需求1") - public String getListPage1() { - return "2"; - } - -} diff --git a/aos-model-test/src/main/java/com/aos/test/web/TestController.java b/aos-model-test/src/main/java/com/aos/test/web/TestController.java new file mode 100644 index 0000000..d1d8a2a --- /dev/null +++ b/aos-model-test/src/main/java/com/aos/test/web/TestController.java @@ -0,0 +1,40 @@ +package com.aos.test.web; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.Arrays; +import java.util.List; + +@RestController +@RequestMapping("/test") +@Api(tags = "测试接口") +public class TestController { + + @PostMapping("/test1") + @ApiOperation(value = "test1") + public void test1() { + + } + + @PostMapping("/test2") + @ApiOperation(value = "test2") + public String test2() { + return "2"; + } + + @PostMapping("/test3") + @ApiOperation(value = "test3") + public List test3() { + return Arrays.asList(1L, 2L, 3L); + } + + @PostMapping("/test4") + @ApiOperation(value = "test4") + public void test4() throws Exception { + throw new Exception(); + } +} diff --git a/aos-model-test/src/main/java/com/aos/test/web2/ActivityDemandController2.java b/aos-model-test/src/main/java/com/aos/test/web2/ActivityDemandController2.java deleted file mode 100644 index ef14d86..0000000 --- a/aos-model-test/src/main/java/com/aos/test/web2/ActivityDemandController2.java +++ /dev/null @@ -1,36 +0,0 @@ -package com.aos.test.web2; - -import com.aos.common.model.result.WebResponse; -import com.aos.common.model.result.WebResult; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -import java.util.Arrays; -import java.util.List; - -/** - * @author: zouyang - * @date: 2022/6/1 - * @description: 需求计划入口 - */ -@RestController -@RequestMapping("/test") -@Api(value = "ActivityDemandController1", tags = "需求计划入口2") -public class ActivityDemandController2 { - - @PostMapping("/getListPage2") - @ApiOperation(value = "分页查询活动需求2") - public WebResult getListPage() { - return WebResponse.WebResponse.ok(1); - } - - @PostMapping("/getListPage12") - @ApiOperation(value = "分页查询活动需求12") - public List getListPage1() { - return Arrays.asList(1L, 2L); - } - -} diff --git a/aos-web/pom.xml b/aos-web/pom.xml index b51c15a..0f0f244 100644 --- a/aos-web/pom.xml +++ b/aos-web/pom.xml @@ -42,5 +42,17 @@ com.aos aos-common + + io.springfox + springfox-swagger-common + + + io.springfox + springfox-swagger2 + + + org.springframework.boot + spring-boot-autoconfigure + \ No newline at end of file diff --git a/aos-web/src/main/java/com/aos/web/advice/ControllerErrorResponseAdvice.java b/aos-web/src/main/java/com/aos/web/advice/ControllerErrorResponseAdvice.java new file mode 100644 index 0000000..b194ce5 --- /dev/null +++ b/aos-web/src/main/java/com/aos/web/advice/ControllerErrorResponseAdvice.java @@ -0,0 +1,26 @@ +package com.aos.web.advice; + +import com.aos.common.model.result.WebResponse; +import com.aos.common.model.result.WebResult; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +/** + * @author: wangyl + * @date: 2022/11/14 + * @description: 统一返回处理器 + */ +@RestControllerAdvice +@Slf4j +public class ControllerErrorResponseAdvice { + + @ExceptionHandler(Exception.class) + @ResponseStatus(HttpStatus.OK) + public WebResult handleException(Exception ex) { + log.error("Exception", ex); + return WebResponse.WebResponse.error(); + } +} \ No newline at end of file diff --git a/aos-web/src/main/java/com/aos/web/conf/ControllerResponseAdvice.java b/aos-web/src/main/java/com/aos/web/advice/ControllerResponseAdvice.java similarity index 68% rename from aos-web/src/main/java/com/aos/web/conf/ControllerResponseAdvice.java rename to aos-web/src/main/java/com/aos/web/advice/ControllerResponseAdvice.java index c362e1e..bda5a8e 100644 --- a/aos-web/src/main/java/com/aos/web/conf/ControllerResponseAdvice.java +++ b/aos-web/src/main/java/com/aos/web/advice/ControllerResponseAdvice.java @@ -1,4 +1,4 @@ -package com.aos.web.conf; +package com.aos.web.advice; import com.aos.common.model.result.WebResponse; import com.aos.common.model.result.WebResult; @@ -16,6 +16,8 @@ import org.springframework.http.server.ServerHttpRequest; import org.springframework.http.server.ServerHttpResponse; import org.springframework.web.bind.annotation.RestControllerAdvice; import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice; +import springfox.documentation.swagger.web.ApiResourceController; +import springfox.documentation.swagger2.web.Swagger2Controller; /** * @author: wangyl @@ -28,13 +30,26 @@ public class ControllerResponseAdvice implements ResponseBodyAdvice { @Autowired ObjectMapper objectMapper; + /** + * 返回true 才执行beforeBodyWrite + */ @Override public boolean supports(MethodParameter methodParameter, Class> converterType) { /** - *response是ResultVo类型,或者注释了NotControllerResponseAdvice都不进行包装 + * 返回值不是 WebResult.class 类型 */ - return (!methodParameter.getParameterType().isAssignableFrom(WebResult.class) - || methodParameter.hasMethodAnnotation(NotControllerResponseAdvice.class)); + boolean assignableFrom = !methodParameter.getParameterType().isAssignableFrom(WebResult.class); + /** + * 方法被注解 NotControllerResponseAdvice 标注 + */ + boolean hasAnnotation = !methodParameter.hasMethodAnnotation(NotControllerResponseAdvice.class); + /** + * 跳过swagger + */ + boolean apiResourceController = !methodParameter.getDeclaringClass().isAssignableFrom(ApiResourceController.class); + boolean swagger2Controller = !methodParameter.getDeclaringClass().isAssignableFrom(Swagger2Controller.class); + + return apiResourceController && swagger2Controller && (assignableFrom && hasAnnotation); } diff --git a/aos-web/src/main/java/com/aos/web/conf/AosWebConf.java b/aos-web/src/main/java/com/aos/web/conf/AosWebConf.java index 08d5668..2950558 100644 --- a/aos-web/src/main/java/com/aos/web/conf/AosWebConf.java +++ b/aos-web/src/main/java/com/aos/web/conf/AosWebConf.java @@ -1,11 +1,28 @@ package com.aos.web.conf; import com.aos.web.filter.BodyRepeatReaderHttpServletFilter; +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonToken; +import com.fasterxml.jackson.databind.*; +import com.fasterxml.jackson.databind.deser.std.NumberDeserializers; +import com.fasterxml.jackson.databind.deser.std.StringDeserializer; +import com.fasterxml.jackson.databind.introspect.JacksonAnnotationIntrospector; +import com.fasterxml.jackson.databind.module.SimpleModule; +import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; +import java.io.IOException; +import java.math.BigDecimal; +import java.text.SimpleDateFormat; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.format.DateTimeFormatter; + /** * @author: wangyl * @date: 2022/7/26 @@ -30,4 +47,63 @@ public class AosWebConf { return new BodyRepeatReaderHttpServletFilter(); } + @Bean("jackson2ObjectMapperBuilderCustomizer") + public Jackson2ObjectMapperBuilderCustomizer customizer() { + return builder -> { + AnnotationIntrospector primary = new JacksonAnnotationIntrospector(); + builder.failOnUnknownProperties(false); + builder.defaultUseWrapper(true); + + // jackson 统一配置日期转换格式 + builder.dateFormat(new SimpleDateFormat(Convert.DATE_FORMAT_DATETIME)); + builder.timeZone("GMT+8"); + builder.serializerByType(LocalDateTime.class, new MyLocalDateTimeSerializer()); + builder.serializerByType(LocalDate.class, new MyLocalDateSerializer()); + builder.serializerByType(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern(Convert.DATE_FORMAT_TIME))); + builder.deserializerByType(LocalDateTime.class, new MyLocalDateTimeDeserializer()); + builder.deserializerByType(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern(Convert.DATE_FORMAT_DATE))); + builder.deserializerByType(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ofPattern(Convert.DATE_FORMAT_TIME))); + + // 序列化时将所有的long变成string + SimpleModule module = new SimpleModule(); + module.addSerializer(Long.class, ToStringSerializer.instance); + module.addSerializer(Long.TYPE, ToStringSerializer.instance); + // 反序列化时转为long + module.addDeserializer(Long.TYPE, new NumberDeserializers.LongDeserializer(Long.TYPE, 0L)); + module.addDeserializer(Long.class, new NumberDeserializers.LongDeserializer(Long.class, null)); + + // 序列化时将所有的BigDecimal变成string + builder.serializerByType(BigDecimal.class, new BigDecimalSerializer()); + module.addSerializer(BigDecimal.class, new BigDecimalSerializer()); + + // 反序列化时将所有的string变成BigDecimal + builder.deserializerByType(BigDecimal.class, new MyLocalBigDecimalDeserializer()); + module.addDeserializer(BigDecimal.class, new NumberDeserializers.BigDecimalDeserializer()); + + module.addDeserializer(Boolean.class, new JsonDeserializer<>() { + @Override + public Boolean deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { + if (p.hasToken(JsonToken.VALUE_TRUE) || p.hasToken(JsonToken.VALUE_FALSE)) { + return p.getBooleanValue(); + } + return BooleanUtil.toBoolean(p.getText()); + } + }); + module.addDeserializer(String.class, new StringDeserializer() { + @Override + public String deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { + String value = super.deserialize(p, ctxt); + return value == null ? null : value.trim(); + } + }); + + builder.modules(new JavaTimeModule(), new ParameterNamesModule(), new Jdk8Module(), module); + builder.featuresToEnable(JsonGenerator.Feature.WRITE_BIGDECIMAL_AS_PLAIN); + builder.featuresToEnable(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS); + builder.featuresToDisable(SerializationFeature.FAIL_ON_EMPTY_BEANS); + builder.featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); + builder.featuresToDisable(SerializationFeature.WRITE_DURATIONS_AS_TIMESTAMPS); + builder.annotationIntrospector(primary); + }; + } } \ No newline at end of file diff --git a/aos-web/src/main/java/com/aos/web/jackson/AosJacksonBuilderCustomizer.java b/aos-web/src/main/java/com/aos/web/jackson/AosJacksonBuilderCustomizer.java new file mode 100644 index 0000000..25208e9 --- /dev/null +++ b/aos-web/src/main/java/com/aos/web/jackson/AosJacksonBuilderCustomizer.java @@ -0,0 +1,34 @@ +package com.aos.web.jackson; + +import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer; +import org.springframework.core.Ordered; +import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; + +public class AosJacksonBuilderCustomizer implements Jackson2ObjectMapperBuilderCustomizer, Ordered { + /** + * Customize the JacksonObjectMapperBuilder. + * + * @param jacksonObjectMapperBuilder the JacksonObjectMapperBuilder to customize + */ + @Override + public void customize(Jackson2ObjectMapperBuilder jacksonObjectMapperBuilder) { + + } + + /** + * Get the order value of this object. + *

Higher values are interpreted as lower priority. As a consequence, + * the object with the lowest value has the highest priority (somewhat + * analogous to Servlet {@code load-on-startup} values). + *

Same order values will result in arbitrary sort positions for the + * affected objects. + * + * @return the order value + * @see #HIGHEST_PRECEDENCE + * @see #LOWEST_PRECEDENCE + */ + @Override + public int getOrder() { + return 0; + } +}