feat: aos-web

增加全局异常拦截器
增加全局返回结果集
增加jackson全局配置
This commit is contained in:
王永亮
2022-11-14 19:00:48 +08:00
parent eca6c68372
commit 6ed6535d90
10 changed files with 214 additions and 73 deletions
+6 -1
View File
@@ -26,7 +26,7 @@
<guava.version>30.0-jre</guava.version> <guava.version>30.0-jre</guava.version>
<swagger-ui.version>2.9.2</swagger-ui.version> <swagger-ui.version>2.9.2</swagger-ui.version>
<swagger2.version>2.9.2</swagger2.version> <swagger2.version>2.9.2</swagger2.version>
<swagger-bootstrap-ui.knife4j.version>3.0.2</swagger-bootstrap-ui.knife4j.version> <swagger-bootstrap-ui.knife4j.version>3.0.3</swagger-bootstrap-ui.knife4j.version>
<swagger-annotations.version>1.5.20</swagger-annotations.version> <swagger-annotations.version>1.5.20</swagger-annotations.version>
<spring-cloud-alibaba.version>2.2.7.RELEASE</spring-cloud-alibaba.version> <spring-cloud-alibaba.version>2.2.7.RELEASE</spring-cloud-alibaba.version>
<spring.cloud.version>Hoxton.SR12</spring.cloud.version> <spring.cloud.version>Hoxton.SR12</spring.cloud.version>
@@ -101,6 +101,11 @@
<artifactId>springfox-swagger-ui</artifactId> <artifactId>springfox-swagger-ui</artifactId>
<version>${swagger-ui.version}</version> <version>${swagger-ui.version}</version>
</dependency> </dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-common</artifactId>
<version>${swagger-ui.version}</version>
</dependency>
<dependency> <dependency>
<groupId>com.github.xiaoymin</groupId> <groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-ui</artifactId> <artifactId>knife4j-spring-ui</artifactId>
@@ -6,7 +6,7 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties;
@SpringBootApplication @SpringBootApplication
@EnableSwagger(applicationName = "test", scanPackagesPath = "com.aos.test") @EnableSwagger(applicationName = "test", scanPackagesPath = "com.aos.test.web")
@EnableConfigurationProperties @EnableConfigurationProperties
public class Application { public class Application {
public static void main(String[] args) { public static void main(String[] args) {
@@ -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";
}
}
@@ -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<Long> test3() {
return Arrays.asList(1L, 2L, 3L);
}
@PostMapping("/test4")
@ApiOperation(value = "test4")
public void test4() throws Exception {
throw new Exception();
}
}
@@ -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<String> getListPage() {
return WebResponse.WebResponse.ok(1);
}
@PostMapping("/getListPage12")
@ApiOperation(value = "分页查询活动需求12")
public List<Long> getListPage1() {
return Arrays.asList(1L, 2L);
}
}
+12
View File
@@ -42,5 +42,17 @@
<groupId>com.aos</groupId> <groupId>com.aos</groupId>
<artifactId>aos-common</artifactId> <artifactId>aos-common</artifactId>
</dependency> </dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-common</artifactId>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
</dependency>
</dependencies> </dependencies>
</project> </project>
@@ -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();
}
}
@@ -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.WebResponse;
import com.aos.common.model.result.WebResult; 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.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.RestControllerAdvice; import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice; import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
import springfox.documentation.swagger.web.ApiResourceController;
import springfox.documentation.swagger2.web.Swagger2Controller;
/** /**
* @author: wangyl * @author: wangyl
@@ -28,13 +30,26 @@ public class ControllerResponseAdvice implements ResponseBodyAdvice<Object> {
@Autowired @Autowired
ObjectMapper objectMapper; ObjectMapper objectMapper;
/**
* 返回true 才执行beforeBodyWrite
*/
@Override @Override
public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> converterType) { public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> converterType) {
/** /**
*response是ResultVo类型或者注释了NotControllerResponseAdvice都不进行包装 * 返回值不是 WebResult.class 类型
*/ */
return (!methodParameter.getParameterType().isAssignableFrom(WebResult.class) boolean assignableFrom = !methodParameter.getParameterType().isAssignableFrom(WebResult.class);
|| methodParameter.hasMethodAnnotation(NotControllerResponseAdvice.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);
} }
@@ -1,11 +1,28 @@
package com.aos.web.conf; package com.aos.web.conf;
import com.aos.web.filter.BodyRepeatReaderHttpServletFilter; 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.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration; 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 * @author: wangyl
* @date: 2022/7/26 * @date: 2022/7/26
@@ -30,4 +47,63 @@ public class AosWebConf {
return new BodyRepeatReaderHttpServletFilter(); 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);
};
}
} }
@@ -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.
* <p>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).
* <p>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;
}
}