feat: aos-web 完善
aos-log开发
This commit is contained in:
@@ -33,6 +33,7 @@
|
||||
<spring.boot.vsersion>2.3.12.RELEASE</spring.boot.vsersion>
|
||||
<jjwt.version>0.9.1</jjwt.version>
|
||||
<ttl.version>2.11.4</ttl.version>
|
||||
<hutools.version>5.8.9</hutools.version>
|
||||
</properties>
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
@@ -57,6 +58,15 @@
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
<!-- https://mvnrepository.com/artifact/cn.hutool/hutool-bom -->
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-bom</artifactId>
|
||||
<version>${hutools.version}</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
|
||||
<!--Mybatis plus-->
|
||||
<dependency>
|
||||
<groupId>com.baomidou</groupId>
|
||||
|
||||
@@ -11,6 +11,32 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>aos-log</artifactId>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>transmittable-thread-local</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.tomcat.embed</groupId>
|
||||
<artifactId>tomcat-embed-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-autoconfigure</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>8</maven.compiler.source>
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.aos.log.conf;
|
||||
|
||||
import com.aos.log.filter.AosRequestLogFilter;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import javax.servlet.ServletRequest;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* @author: wangyl
|
||||
* @date: 2022/11/14
|
||||
* @description: log自动加载
|
||||
*/
|
||||
@Configuration
|
||||
public class AosLogAutoConfig {
|
||||
@Bean
|
||||
@ConditionalOnClass(value = {FilterRegistrationBean.class, ServletRequest.class})
|
||||
public FilterRegistrationBean<AosRequestLogFilter> registryBaseFilter() {
|
||||
FilterRegistrationBean<AosRequestLogFilter> filterRegistrationBean = new FilterRegistrationBean();
|
||||
filterRegistrationBean.setFilter(new AosRequestLogFilter());
|
||||
filterRegistrationBean.setUrlPatterns(Arrays.asList("/*"));
|
||||
filterRegistrationBean.setName("aosRequestLogFilter");
|
||||
filterRegistrationBean.setOrder(0);
|
||||
return filterRegistrationBean;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.aos.log.constant;
|
||||
|
||||
/**
|
||||
* @author: wangyl
|
||||
* @date: 2022/11/14
|
||||
* @description: 日志常量
|
||||
*/
|
||||
public interface LogConstant {
|
||||
String TRACE_ID = "traceId";
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package com.aos.log.filter;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.aos.log.constant.LogConstant;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.slf4j.MDC;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @author: wangyl
|
||||
* @date: 2022/11/14
|
||||
* @description: Servlet日志拦截器, 添加traceId信息
|
||||
*/
|
||||
@Slf4j
|
||||
public class AosRequestLogFilter implements Filter {
|
||||
|
||||
@Override
|
||||
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
|
||||
try {
|
||||
HttpServletRequest originalRequest = (HttpServletRequest) request;
|
||||
String tracId = originalRequest.getHeader(LogConstant.TRACE_ID);
|
||||
if (!StrUtil.isNotEmpty(tracId)) {
|
||||
tracId = UUID.randomUUID().toString();
|
||||
}
|
||||
MDC.put(LogConstant.TRACE_ID, tracId);
|
||||
} finally {
|
||||
MDC.remove(LogConstant.TRACE_ID);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,145 @@
|
||||
package org.slf4j;
|
||||
|
||||
import com.alibaba.ttl.TransmittableThreadLocal;
|
||||
import org.slf4j.spi.MDCAdapter;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author: wangyl
|
||||
* @date: 2022/11/14
|
||||
* @description: 处理MDC 无法再多线种传递问题
|
||||
*/
|
||||
public class AosLogLogbackTTLMdcAdapter implements MDCAdapter {
|
||||
|
||||
final ThreadLocal<Map<String, String>> copyOnInheritThreadLocal = new TransmittableThreadLocal<>();
|
||||
|
||||
private static final int WRITE_OPERATION = 1;
|
||||
private static final int READ_OPERATION = 2;
|
||||
|
||||
private static AosLogLogbackTTLMdcAdapter mdcMDCAdapter;
|
||||
|
||||
// keeps track of the last operation performed
|
||||
final ThreadLocal<Integer> lastOperation = new ThreadLocal<>();
|
||||
|
||||
static {
|
||||
mdcMDCAdapter = new AosLogLogbackTTLMdcAdapter();
|
||||
MDC.mdcAdapter = mdcMDCAdapter;
|
||||
}
|
||||
|
||||
public static MDCAdapter getInstance() {
|
||||
return mdcMDCAdapter;
|
||||
}
|
||||
|
||||
private Integer getAndSetLastOperation(int op) {
|
||||
Integer lastOp = lastOperation.get();
|
||||
lastOperation.set(op);
|
||||
return lastOp;
|
||||
}
|
||||
|
||||
private static boolean wasLastOpReadOrNull(Integer lastOp) {
|
||||
return lastOp == null || lastOp == READ_OPERATION;
|
||||
}
|
||||
|
||||
private Map<String, String> duplicateAndInsertNewMap(Map<String, String> oldMap) {
|
||||
Map<String, String> newMap = Collections.synchronizedMap(new HashMap<String, String>());
|
||||
if (oldMap != null) {
|
||||
// we don't want the parent thread modifying oldMap while we are
|
||||
// iterating over it
|
||||
synchronized (oldMap) {
|
||||
newMap.putAll(oldMap);
|
||||
}
|
||||
}
|
||||
|
||||
copyOnInheritThreadLocal.set(newMap);
|
||||
return newMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(String key, String val) {
|
||||
if (key == null) {
|
||||
throw new IllegalArgumentException("key cannot be null");
|
||||
}
|
||||
|
||||
Map<String, String> oldMap = copyOnInheritThreadLocal.get();
|
||||
Integer lastOp = getAndSetLastOperation(WRITE_OPERATION);
|
||||
|
||||
if (wasLastOpReadOrNull(lastOp) || oldMap == null) {
|
||||
Map<String, String> newMap = duplicateAndInsertNewMap(oldMap);
|
||||
newMap.put(key, val);
|
||||
} else {
|
||||
oldMap.put(key, val);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(String key) {
|
||||
if (key == null) {
|
||||
return;
|
||||
}
|
||||
Map<String, String> oldMap = copyOnInheritThreadLocal.get();
|
||||
if (oldMap == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Integer lastOp = getAndSetLastOperation(WRITE_OPERATION);
|
||||
|
||||
if (wasLastOpReadOrNull(lastOp)) {
|
||||
Map<String, String> newMap = duplicateAndInsertNewMap(oldMap);
|
||||
newMap.remove(key);
|
||||
} else {
|
||||
oldMap.remove(key);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
lastOperation.set(WRITE_OPERATION);
|
||||
copyOnInheritThreadLocal.remove();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String get(String key) {
|
||||
Map<String, String> map = getPropertyMap();
|
||||
if ((map != null) && (key != null)) {
|
||||
return map.get(key);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public Map<String, String> getPropertyMap() {
|
||||
lastOperation.set(READ_OPERATION);
|
||||
return copyOnInheritThreadLocal.get();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Map getCopyOfContextMap() {
|
||||
lastOperation.set(READ_OPERATION);
|
||||
Map<String, String> hashMap = copyOnInheritThreadLocal.get();
|
||||
if (hashMap == null) {
|
||||
return null;
|
||||
} else {
|
||||
return new HashMap<>(hashMap);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public void setContextMap(Map<String, String> contextMap) {
|
||||
lastOperation.set(WRITE_OPERATION);
|
||||
|
||||
Map<String, String> newMap = Collections.synchronizedMap(new HashMap<>());
|
||||
newMap.putAll(contextMap);
|
||||
|
||||
// the newMap replaces the old one for serialisation's sake
|
||||
copyOnInheritThreadLocal.set(newMap);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.aos.log.conf.AosLogAutoConfig
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.aos.web.conf;
|
||||
|
||||
import com.aos.web.filter.BodyRepeatReaderHttpServletFilter;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import javax.servlet.ServletRequest;
|
||||
|
||||
/**
|
||||
* @author: wangyl
|
||||
* @date: 2022/7/26
|
||||
* @description: web自动加载
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnClass(value = {FilterRegistrationBean.class, ServletRequest.class})
|
||||
public class AosWebAutoConf {
|
||||
|
||||
@Bean
|
||||
public FilterRegistrationBean<BodyRepeatReaderHttpServletFilter> registerLoginCheckFilter(BodyRepeatReaderHttpServletFilter requireLoginFilter) {
|
||||
FilterRegistrationBean registrationBean = new FilterRegistrationBean();
|
||||
registrationBean.setFilter(requireLoginFilter);
|
||||
registrationBean.addUrlPatterns("/*");
|
||||
registrationBean.setName("bodyRepeatReaderHttpServletFilter");
|
||||
registrationBean.setOrder(10);
|
||||
return registrationBean;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public BodyRepeatReaderHttpServletFilter bodyRepeatReaderHttpServletFilter() {
|
||||
return new BodyRepeatReaderHttpServletFilter();
|
||||
}
|
||||
}
|
||||
@@ -1,109 +0,0 @@
|
||||
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
|
||||
* @description: mybatis-plus配置
|
||||
*/
|
||||
@Configuration
|
||||
@ComponentScan()
|
||||
public class AosWebConf {
|
||||
|
||||
@Bean
|
||||
public FilterRegistrationBean<BodyRepeatReaderHttpServletFilter> registerLoginCheckFilter(BodyRepeatReaderHttpServletFilter requireLoginFilter) {
|
||||
FilterRegistrationBean registrationBean = new FilterRegistrationBean();
|
||||
registrationBean.setFilter(requireLoginFilter);
|
||||
registrationBean.addUrlPatterns("/*");
|
||||
registrationBean.setName("bodyRepeatReaderHttpServletFilter");
|
||||
registrationBean.setOrder(0);
|
||||
return registrationBean;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public BodyRepeatReaderHttpServletFilter 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);
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1 +1 @@
|
||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.aos.web.conf.AosWebConf
|
||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.aos.web.conf.AosWebAutoConf
|
||||
Reference in New Issue
Block a user