systemProperties = environment.getSystemProperties();
+ // 读取配置文件,从配置文件中加载这个变量。
+ String database = System.getProperty("user.home") + "/.config/eric-config/database.json";
+ try {
+ File file = new File(database);
+ if (file.exists()) {
+ ObjectMapper objectMapper = new ObjectMapper();
+ JsonNode jsonObject = objectMapper.readTree(file);
+ if (!jsonObject.isEmpty()) {
+ String databaseUrl = jsonObject.get("spring.datasource.url").textValue();
+ String databaseUsername = jsonObject.get("spring.datasource.username").textValue();
+ String password = jsonObject.get("spring.datasource.password").textValue();
+ if (databaseUrl.contains("jdbc:p6spy:mysql")) {
+ systemProperties.put("spring.datasource.driver-class-name", "com.p6spy.engine.spy.P6SpyDriver");
+ } else {
+ systemProperties.put("spring.datasource.driver-class-name", "com.mysql.cj.jdbc.Driver");
+ }
+ systemProperties.put("spring.datasource.url", databaseUrl);
+ systemProperties.put("spring.datasource.username", databaseUsername);
+ systemProperties.put("spring.datasource.password", password);
+
+ String r2dbcDatabaseUrl = jsonObject.get("spring.r2dbc.url").textValue();
+ systemProperties.put("spring.r2dbc.url", r2dbcDatabaseUrl);
+ systemProperties.put("spring.r2dbc.username", databaseUsername);
+ systemProperties.put("spring.r2dbc.password", password);
+ } else {
+ log.warn("数据库配置文件没有信息 {}", database);
+ }
+ } else {
+ log.error("没有数据库配置文件,那就配置yaml文件吧 {}", database);
+ }
+
+ } catch (JsonProcessingException e) {
+ log.error("{}", e.getMessage(), e);
+ } catch (IOException e) {
+ log.error("{}", e.getMessage(), e);
+ }
+ }
+ }
+ return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);
+ }
+}
diff --git a/common/src/main/java/hxy/dream/common/configuration/FilterConfiguration.java b/common/src/main/java/hxy/dream/common/configuration/FilterConfiguration.java
new file mode 100644
index 0000000000000000000000000000000000000000..099ceb1bcb47a983cadaa18c118f0f62451d2444
--- /dev/null
+++ b/common/src/main/java/hxy/dream/common/configuration/FilterConfiguration.java
@@ -0,0 +1,55 @@
+package hxy.dream.common.configuration;
+
+import hxy.dream.common.filter.RequestTrimFilter;
+import hxy.dream.common.filter.RepeatableFilter;
+import hxy.dream.common.filter.TokenFilter;
+import jakarta.servlet.DispatcherType;
+import org.springframework.boot.web.servlet.FilterRegistrationBean;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class FilterConfiguration {
+
+ @Bean
+ public FilterRegistrationBean someFilterRegistration() {
+ FilterRegistrationBean registration = new FilterRegistrationBean();
+ registration.setFilter(new TokenFilter());
+ registration.addUrlPatterns("/*");
+ registration.setAsyncSupported(true);
+ registration.setName("tokenFilter");
+ registration.setOrder(FilterRegistrationBean.LOWEST_PRECEDENCE);
+ return registration;
+ }
+
+ /**
+ * 添加去除参数头尾空格过滤器
+ *
+ * @return
+ */
+ @Bean
+ public FilterRegistrationBean trimFilter() {
+ FilterRegistrationBean registration = new FilterRegistrationBean();
+ registration.setDispatcherTypes(DispatcherType.REQUEST);
+ registration.setFilter(new RequestTrimFilter());
+ registration.addUrlPatterns("/*");
+ registration.setName("requestTrimFilter");
+ registration.setOrder(Integer.MAX_VALUE - 1);
+ return registration;
+ }
+
+ /**
+ * 让request可重复读取
+ *
+ * @return
+ */
+ @Bean
+ public FilterRegistrationBean streamFilter() {
+ FilterRegistrationBean streamBean = new FilterRegistrationBean();
+ streamBean.setDispatcherTypes(DispatcherType.REQUEST);
+ streamBean.setFilter(new RepeatableFilter());
+ streamBean.setName("repeatableFilter");
+ streamBean.setOrder(FilterRegistrationBean.LOWEST_PRECEDENCE);
+ return streamBean;
+ }
+}
diff --git a/common/src/main/java/hxy/dream/common/configuration/MybatisAuditHandler.java b/common/src/main/java/hxy/dream/common/configuration/MybatisAuditHandler.java
index 11cabe678d836f59531a205d6e1cb8d9028803f0..8b63d185828a0a44171de4ffd09a53ec92cf5135 100644
--- a/common/src/main/java/hxy/dream/common/configuration/MybatisAuditHandler.java
+++ b/common/src/main/java/hxy/dream/common/configuration/MybatisAuditHandler.java
@@ -17,25 +17,29 @@ public class MybatisAuditHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
- if (LOG.isDebugEnabled()){
- LOG.debug("\n====>mybatis自动填充创建时间字段");
+ LocalDateTime now = LocalDateTime.now();
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("\n====>mybatis自动填充创建时间字段 ,当前时间 {}", now);
}
// 声明自动填充字段的逻辑。
// String userId = AuthHolder.getCurrentUserId();
String userId = "";
// this.strictInsertFill(metaObject,"creator",String.class, userId);
- this.strictInsertFill(metaObject,"createTime", LocalDateTime.class,LocalDateTime.now());
+ this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, now);
}
@Override
public void updateFill(MetaObject metaObject) {
- if (LOG.isDebugEnabled()){
- LOG.debug("\n====>mybatis自动填充更新时间字段");
+ LocalDateTime now = LocalDateTime.now();
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("\n====>mybatis自动填充更新时间字段 ,当前时间 {}", now);
}
// 声明自动填充字段的逻辑。
// String userId = AuthHolder.getCurrentUserId();
String userId = "";
// this.strictUpdateFill(metaObject,"updater",String.class,userId);
- this.strictUpdateFill(metaObject,"updateTime", LocalDateTime.class,LocalDateTime.now());
+ this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, now);
}
}
\ No newline at end of file
diff --git a/common/src/main/java/hxy/dream/common/configuration/RemoteApiConfig.java b/common/src/main/java/hxy/dream/common/configuration/RemoteApiConfig.java
new file mode 100644
index 0000000000000000000000000000000000000000..9c2c58f908cd4817cd13989e2424bb3f0124eaee
--- /dev/null
+++ b/common/src/main/java/hxy/dream/common/configuration/RemoteApiConfig.java
@@ -0,0 +1,22 @@
+package hxy.dream.common.configuration;
+
+
+import hxy.dream.common.manager.RemoteApi;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.reactive.function.client.WebClient;
+import org.springframework.web.reactive.function.client.support.WebClientAdapter;
+import org.springframework.web.service.invoker.HttpServiceProxyFactory;
+
+@Configuration(proxyBeanMethods = false)
+public class RemoteApiConfig {
+
+ @Bean
+ RemoteApi remoteApiService() {
+ WebClient client = WebClient.builder().baseUrl("https://httpbin.org/").build();
+ HttpServiceProxyFactory httpServiceProxyFactory = HttpServiceProxyFactory.builderFor(WebClientAdapter.create(client)).build();
+ // 后期会自动扫描注入,不需要手动指定注入了。但是上面host配置肯定还是需要的。
+ return httpServiceProxyFactory.createClient(RemoteApi.class);
+ }
+
+}
diff --git a/common/src/main/java/hxy/dream/common/configuration/RemoteEnvironmentPostProcessor.java b/common/src/main/java/hxy/dream/common/configuration/RemoteEnvironmentPostProcessor.java
index 24947bce93ff3b9b6669589cfe088de9b7fadefc..be9e3ed20489cec0e8407570a9bc2336e9356cd6 100644
--- a/common/src/main/java/hxy/dream/common/configuration/RemoteEnvironmentPostProcessor.java
+++ b/common/src/main/java/hxy/dream/common/configuration/RemoteEnvironmentPostProcessor.java
@@ -1,40 +1,83 @@
package hxy.dream.common.configuration;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.env.EnvironmentPostProcessor;
-import org.springframework.context.annotation.Profile;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.PropertiesPropertySource;
-import org.springframework.stereotype.Component;
+import java.io.File;
+import java.io.IOException;
+import java.util.Map;
import java.util.Properties;
/**
- * @author Raina
- * @description 远程存储环境变量修改本地
+ * @description bean初始化之前,Spring环境变量修改 https://blog.csdn.net/weixin_43827985/article/details/114368232
+ * 1. 可以读取Azue KeyValue
+ * 2. 可以读取本机的配置文件
+ *
+ * 这个类生效靠:app/src/main/resources/META-INF/spring.factories
* @date 2022/2/25
*/
-@Component
-@Profile(value = {"prod", "beta"})
+//@Profile(value = {"prod", "beta"}) // 貌似这个没啥用,其他环境变量的时候也跑了程序
public class RemoteEnvironmentPostProcessor implements EnvironmentPostProcessor {
+
private static final Logger log = LoggerFactory.getLogger(RemoteEnvironmentPostProcessor.class);
+
@Override
public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
String currentProfile = environment.getProperty("spring.profiles.active");
- if (currentProfile == null || currentProfile.equalsIgnoreCase("dev")) {
- log.debug("本地调试,直接忽略");
- return;
+ if (currentProfile == null) {
+ // 这里需要带特定环境变量的配置文件,即没有 dev,beta,prod都是可以的
+ Map systemProperties = environment.getSystemProperties();
+ systemProperties.put("key", "value");
} else {
- String url = environment.getProperty("azure.keyvault.url");
- final Properties properties = new Properties();
- if (url == null) {
- // 从远程vault这种管理工具或者redis里面获取配置信息,然后再更新到本地的配置中
- properties.put("password", "vault获取的值");
- PropertiesPropertySource propertySource = new PropertiesPropertySource("prod", properties);
+ if (currentProfile.equalsIgnoreCase("dev")) {
+ log.warn("本地调试,直接忽略读取本地配置文件信息");
+ } else {
+ final Properties properties = new Properties();
+
+ // 读取配置文件,从配置文件中加载这个变量。 【腾讯文档】系统配置信息 https://docs.qq.com/doc/DSFdLamxuUXNWRVZJ
+ String database = System.getProperty("user.home") + "/.config/eric-config/database.json";
+ try {
+ File file = new File(database);
+ if (file.exists()) {
+ ObjectMapper objectMapper = new ObjectMapper();
+ JsonNode jsonObject = objectMapper.readTree(file);
+ if (!jsonObject.isEmpty()) {
+ String databaseUsername = jsonObject.get("spring.datasource.username").textValue();
+ String databaseUrl = jsonObject.get("spring.datasource.url").textValue();
+ String password = jsonObject.get("spring.datasource.password").textValue();
+ properties.put("spring.datasource.url", databaseUrl);
+ properties.put("spring.datasource.username", databaseUsername);
+ properties.put("spring.datasource.password", password);
+ } else {
+ log.error("数据库配置文件没有信息 {}", database);
+ }
+ } else {
+ log.error("没有数据库配置文件,那就配置yaml文件吧 {}", database);
+ }
+ } catch (JsonProcessingException e) {
+ log.error("{}", e.getMessage(), e);
+ } catch (IOException e) {
+ log.error("{}", e.getMessage(), e);
+ }
+
+ String url = environment.getProperty("azure.keyvault.url");
+ if (url == null) {
+ // 从远程vault这种管理工具或者redis里面获取配置信息,然后再更新到本地的配置中 https://learn.microsoft.com/zh-cn/azure/developer/java/spring-framework/configure-spring-boot-starter-java-app-with-azure-key-vault
+ properties.put("password", "vault获取的值");
+ }
+
+ PropertiesPropertySource propertySource = new PropertiesPropertySource(currentProfile, properties);
+// PropertiesPropertySource propertySource = new PropertiesPropertySource("prod", properties); // 只修改指定环境变量的配置信息
environment.getPropertySources().addFirst(propertySource);
+
}
}
}
diff --git a/common/src/main/java/hxy/dream/common/configuration/RequestLoggingConfig.java b/common/src/main/java/hxy/dream/common/configuration/RequestLoggingConfig.java
new file mode 100644
index 0000000000000000000000000000000000000000..d5d56c51ead4d62bf90d800eb1b993e84950aaa7
--- /dev/null
+++ b/common/src/main/java/hxy/dream/common/configuration/RequestLoggingConfig.java
@@ -0,0 +1,24 @@
+package hxy.dream.common.configuration;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.filter.CommonsRequestLoggingFilter;
+
+@Configuration
+public class RequestLoggingConfig {
+ /**
+ * 类似gin的一样的请求log,不是详细的
+ *
+ * @return
+ */
+ @Bean
+ public CommonsRequestLoggingFilter logFilter() {
+ CommonsRequestLoggingFilter filter = new CommonsRequestLoggingFilter();
+ filter.setIncludeQueryString(true);
+ filter.setIncludePayload(true);
+ filter.setIncludeHeaders(true);
+ filter.setIncludeClientInfo(true);
+ filter.setAfterMessagePrefix("REQUEST DATA-");
+ return filter;
+ }
+}
\ No newline at end of file
diff --git a/common/src/main/java/hxy/dream/common/configuration/WebMvcConfig.java b/common/src/main/java/hxy/dream/common/configuration/WebMvcConfig.java
index 618da7ecbd8fe2c18e39bd6ed67aee95956381d1..41bfb45e44c35c97bedc94f93b0a3d2f455a3b23 100644
--- a/common/src/main/java/hxy/dream/common/configuration/WebMvcConfig.java
+++ b/common/src/main/java/hxy/dream/common/configuration/WebMvcConfig.java
@@ -3,6 +3,7 @@ package hxy.dream.common.configuration;
import hxy.dream.common.converter.IntegerCodeToEnumConverterFactory;
import hxy.dream.common.converter.StringCodeToEnumConverterFactory;
import hxy.dream.common.converter.StringToDateConverterFactory;
+import hxy.dream.common.converter.StringToStringConverter;
import org.springframework.context.annotation.Configuration;
import org.springframework.format.FormatterRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@@ -23,6 +24,7 @@ public class WebMvcConfig implements WebMvcConfigurer {
*/
@Override
public void addFormatters(FormatterRegistry registry) {
+ registry.addConverter(new StringToStringConverter());
registry.addConverterFactory(new IntegerCodeToEnumConverterFactory());
registry.addConverterFactory(new StringCodeToEnumConverterFactory());
registry.addConverterFactory(new StringToDateConverterFactory());
diff --git a/common/src/main/java/hxy/dream/common/converter/StringToDateConverterFactory.java b/common/src/main/java/hxy/dream/common/converter/StringToDateConverterFactory.java
index e33cd4c83b61bdedf68b534dbf613a9ccdb49ee6..485b8af0a6b85e882adcfbe5240c6f1f61b6db83 100644
--- a/common/src/main/java/hxy/dream/common/converter/StringToDateConverterFactory.java
+++ b/common/src/main/java/hxy/dream/common/converter/StringToDateConverterFactory.java
@@ -9,8 +9,6 @@ public class StringToDateConverterFactory implements ConverterFactory Converter getConverter(Class targetType) {
-
-
return new StringToDateConverter();
}
}
diff --git a/common/src/main/java/hxy/dream/common/converter/StringToStringConverter.java b/common/src/main/java/hxy/dream/common/converter/StringToStringConverter.java
new file mode 100644
index 0000000000000000000000000000000000000000..c5617782fb8a3c9dd0a450bbd26ccbebcb9220d9
--- /dev/null
+++ b/common/src/main/java/hxy/dream/common/converter/StringToStringConverter.java
@@ -0,0 +1,27 @@
+package hxy.dream.common.converter;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.core.convert.converter.Converter;
+
+/**
+ * 这个转换器,可以去掉前端参数里的"null"值。
+ * 【腾讯文档】SpringMVC学习
+ * https://docs.qq.com/doc/DeXNEanBlc09MWG9C
+ *
+ * GET {{host}}/file/list?pageNum=1&pageSize=20&searchValue=null
+ * 等于下面这个
+ * GET {{host}}/file/list?pageNum=1&pageSize=20&searchValue=
+ */
+public class StringToStringConverter implements Converter {
+ private static final Logger log = LoggerFactory.getLogger(StringToStringConverter.class);
+
+ @Override
+ public String convert(String source) {
+ log.info("convert source: {}", source);
+ if (source != null && "null".equals(source.toLowerCase())) {
+ return "";
+ }
+ return source;
+ }
+}
diff --git a/common/src/main/java/hxy/dream/common/extend/GlobalExceptionHandler.java b/common/src/main/java/hxy/dream/common/extend/GlobalExceptionHandler.java
index d4c90adf349e1a0ea86b144b95998ce10c0fce23..057c28b8996bd15e2bf7d3d75e40840fcff26af1 100644
--- a/common/src/main/java/hxy/dream/common/extend/GlobalExceptionHandler.java
+++ b/common/src/main/java/hxy/dream/common/extend/GlobalExceptionHandler.java
@@ -24,17 +24,18 @@ import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.NoHandlerFoundException;
import org.springframework.web.servlet.view.json.MappingJackson2JsonView;
-import javax.annotation.PostConstruct;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import javax.validation.ConstraintViolationException;
-import javax.validation.ValidationException;
+import jakarta.annotation.PostConstruct;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import jakarta.validation.ConstraintViolationException;
+import jakarta.validation.ValidationException;
+
import java.io.IOException;
import java.util.Map;
/**
- * Description:全局异常处理,采用@RestControllerAdvice + @ExceptionHandler解决
- *
自定义异常处理类
+ * Description:全局异常处理,采用@RestControllerAdvice + @ExceptionHandler解决
+ * 自定义异常处理类
*
* @author eric
*/
@@ -53,7 +54,8 @@ public class GlobalExceptionHandler implements InitializingBean {
return new DefaultErrorAttributes() {
@Override
public Map getErrorAttributes(WebRequest webRequest, ErrorAttributeOptions options) {
- return super.getErrorAttributes(webRequest, ErrorAttributeOptions.defaults().excluding(ErrorAttributeOptions.Include.EXCEPTION));
+ return super.getErrorAttributes(webRequest,
+ ErrorAttributeOptions.defaults().excluding(ErrorAttributeOptions.Include.EXCEPTION));
}
};
}
@@ -64,7 +66,6 @@ public class GlobalExceptionHandler implements InitializingBean {
res.sendError(ex.getHttpStatus().value(), ex.getMessage());
}
-
/**
* 参数校验异常捕获 包括各种自定义的参数异常
*
@@ -75,7 +76,8 @@ public class GlobalExceptionHandler implements InitializingBean {
*/
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(ConstraintViolationException.class)
- public BaseResponseVO> constraintViolationExceptionHandler(HttpServletRequest request, ConstraintViolationException e) {
+ public BaseResponseVO> constraintViolationExceptionHandler(HttpServletRequest request,
+ ConstraintViolationException e) {
log.warn("\n====>{} Exception Message: {}", request.getRequestURI(), e.getMessage(), e);
return BaseResponseVO.error("参数错误", e.getMessage());
}
@@ -98,16 +100,14 @@ public class GlobalExceptionHandler implements InitializingBean {
}
/**
- * 方法参数校验
- * https://blog.csdn.net/chengliqu4475/article/details/100834090
+ * 方法参数校验 https://blog.csdn.net/chengliqu4475/article/details/100834090
*/
@ExceptionHandler(MethodArgumentNotValidException.class)
public BaseResponseVO> handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
- log.warn(e.getMessage(), e);
+ log.warn("{}", e.getMessage(), e);
return BaseResponseVO.error("参数检验出错啦!", e.getBindingResult().getFieldError().getDefaultMessage());
}
-
/**
* 处理400参数错误
*
@@ -129,8 +129,10 @@ public class GlobalExceptionHandler implements InitializingBean {
*/
@ResponseStatus(HttpStatus.METHOD_NOT_ALLOWED)
@ExceptionHandler(HttpRequestMethodNotSupportedException.class)
- public BaseResponseVO handleHttpRequestMethodNotSupportedException(HttpServletRequest request, HttpRequestMethodNotSupportedException e) {
- log.warn("\n====>[{}]不支持当前[{}]请求方法,应该是[{},{}]", request.getRequestURI(), e.getMethod(), e.getSupportedHttpMethods(), e.getSupportedMethods(), e);
+ public BaseResponseVO handleHttpRequestMethodNotSupportedException(HttpServletRequest request,
+ HttpRequestMethodNotSupportedException e) {
+ log.warn("\n====>[{}]不支持当前[{}]请求方法,应该是[{},{}]", request.getRequestURI(), e.getMethod(),
+ e.getSupportedHttpMethods(), e.getSupportedMethods(), e);
return BaseResponseVO.badrequest("请求方法不支持", e.getMessage());
}
@@ -149,9 +151,7 @@ public class GlobalExceptionHandler implements InitializingBean {
}
/**
- * 这个应该放在最下面比较好,最后加载
- * 处理未定义的其他异常信息
- * 参数为空等
+ * 这个应该放在最下面比较好,最后加载 处理未定义的其他异常信息 参数为空等
*
* @param request
* @param exception
@@ -179,9 +179,11 @@ public class GlobalExceptionHandler implements InitializingBean {
log.info("\n====>全局异常注入正常");
}
+ /**
+ * bean注入初始化
+ */
@PostConstruct
public void init() {
log.info("\n====>@PostConstruct 全局异常注入正常");
}
}
-
diff --git a/common/src/main/java/hxy/dream/common/extend/InteractiveRecord.java b/common/src/main/java/hxy/dream/common/extend/InteractiveRecord.java
new file mode 100644
index 0000000000000000000000000000000000000000..355dc5961cb198949afe0474fc86232ec73e703e
--- /dev/null
+++ b/common/src/main/java/hxy/dream/common/extend/InteractiveRecord.java
@@ -0,0 +1,50 @@
+package hxy.dream.common.extend;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.core.MethodParameter;
+import org.springframework.http.HttpInputMessage;
+import org.springframework.http.MediaType;
+import org.springframework.http.converter.HttpMessageConverter;
+import org.springframework.http.server.ServerHttpRequest;
+import org.springframework.http.server.ServerHttpResponse;
+import org.springframework.stereotype.Component;
+import org.springframework.web.servlet.mvc.method.annotation.RequestBodyAdviceAdapter;
+import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
+import reactor.netty.http.server.HttpServerRequest;
+
+import java.lang.reflect.Type;
+
+/**
+ * 非AOP方式记录参数,严重依赖Servlet
+ *
+ * 有待再次调试 https://www.bilibili.com/video/BV1ZW4y1Q7yG/
+ *
+ */
+//@Component
+public class InteractiveRecord extends RequestBodyAdviceAdapter implements ResponseBodyAdvice