feat: aos-web 完善

aos-log开发
This commit is contained in:
wyl
2022-11-14 23:10:45 +08:00
parent 6ed6535d90
commit 965c7c52ec
10 changed files with 293 additions and 110 deletions
+10
View File
@@ -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>
+26
View File
@@ -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