mysql
mysql-connector-java
diff --git a/spring-cloud-starter/src/main/java/com/jmsoftware/maf/springcloudstarter/MafAutoConfiguration.java b/spring-cloud-starter/src/main/java/com/jmsoftware/maf/springcloudstarter/MafAutoConfiguration.java
index 30c47fbb..9d75123d 100644
--- a/spring-cloud-starter/src/main/java/com/jmsoftware/maf/springcloudstarter/MafAutoConfiguration.java
+++ b/spring-cloud-starter/src/main/java/com/jmsoftware/maf/springcloudstarter/MafAutoConfiguration.java
@@ -1,6 +1,8 @@
package com.jmsoftware.maf.springcloudstarter;
-import com.jmsoftware.maf.springcloudstarter.aspect.ExceptionControllerAdvice;
+import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException;
+import com.jmsoftware.maf.springcloudstarter.aspect.CommonExceptionControllerAdvice;
+import com.jmsoftware.maf.springcloudstarter.aspect.DatabaseExceptionControllerAdvice;
import com.jmsoftware.maf.springcloudstarter.aspect.WebRequestLogAspect;
import com.jmsoftware.maf.springcloudstarter.configuration.*;
import com.jmsoftware.maf.springcloudstarter.controller.CommonController;
@@ -17,10 +19,9 @@
import com.jmsoftware.maf.springcloudstarter.service.impl.CommonServiceImpl;
import com.jmsoftware.maf.springcloudstarter.sftp.SftpConfiguration;
import lombok.extern.slf4j.Slf4j;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
-import org.springframework.boot.autoconfigure.condition.SearchStrategy;
+import org.apache.ibatis.exceptions.PersistenceException;
+import org.mybatis.spring.MyBatisSystemException;
+import org.springframework.boot.autoconfigure.condition.*;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.autoconfigure.web.servlet.error.ErrorViewResolver;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
@@ -71,9 +72,16 @@ public void postConstruct() {
@Bean
@ConditionalOnMissingBean
- public ExceptionControllerAdvice exceptionControllerAdvice() {
- log.warn("Initial bean: '{}'", ExceptionControllerAdvice.class.getSimpleName());
- return new ExceptionControllerAdvice();
+ public CommonExceptionControllerAdvice exceptionControllerAdvice() {
+ log.warn("Initial bean: '{}'", CommonExceptionControllerAdvice.class.getSimpleName());
+ return new CommonExceptionControllerAdvice();
+ }
+
+ @Bean
+ @ConditionalOnClass({MyBatisSystemException.class, MybatisPlusException.class, PersistenceException.class})
+ public DatabaseExceptionControllerAdvice databaseExceptionControllerAdvice() {
+ log.warn("Initial bean: '{}'", DatabaseExceptionControllerAdvice.class.getSimpleName());
+ return new DatabaseExceptionControllerAdvice();
}
@Bean
diff --git a/spring-cloud-starter/src/main/java/com/jmsoftware/maf/springcloudstarter/aspect/ExceptionControllerAdvice.java b/spring-cloud-starter/src/main/java/com/jmsoftware/maf/springcloudstarter/aspect/CommonExceptionControllerAdvice.java
similarity index 85%
rename from spring-cloud-starter/src/main/java/com/jmsoftware/maf/springcloudstarter/aspect/ExceptionControllerAdvice.java
rename to spring-cloud-starter/src/main/java/com/jmsoftware/maf/springcloudstarter/aspect/CommonExceptionControllerAdvice.java
index 218d04ee..84117dd9 100644
--- a/spring-cloud-starter/src/main/java/com/jmsoftware/maf/springcloudstarter/aspect/ExceptionControllerAdvice.java
+++ b/spring-cloud-starter/src/main/java/com/jmsoftware/maf/springcloudstarter/aspect/CommonExceptionControllerAdvice.java
@@ -2,14 +2,11 @@
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
-import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException;
import com.jmsoftware.maf.common.bean.ResponseBodyBean;
import com.jmsoftware.maf.common.exception.BaseException;
import com.jmsoftware.maf.springcloudstarter.util.RequestUtil;
import lombok.extern.slf4j.Slf4j;
import lombok.val;
-import org.apache.ibatis.exceptions.PersistenceException;
-import org.mybatis.spring.MyBatisSystemException;
import org.springframework.context.support.DefaultMessageSourceResolvable;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageNotReadableException;
@@ -40,7 +37,7 @@
**/
@Slf4j
@RestControllerAdvice
-public class ExceptionControllerAdvice {
+public class CommonExceptionControllerAdvice {
/**
* Exception handler.
* ATTENTION: In this method, cannot throw any exception.
@@ -171,37 +168,6 @@ public ResponseBodyBean> handleException(HttpServletRequest request, HttpServl
null);
}
- @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
- @ExceptionHandler(MyBatisSystemException.class)
- public ResponseBodyBean> handleMyBatisSystemException(HttpServletRequest request,
- MyBatisSystemException exception) {
- requestLog(request);
- log.error("MyBatisSystemException message: {}", exception.getMessage());
- return ResponseBodyBean.ofStatus(HttpStatus.INTERNAL_SERVER_ERROR,
- String.format("MyBatisSystemException message: %s",
- removeLineSeparator(exception.getMessage())));
- }
-
- @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
- @ExceptionHandler(MybatisPlusException.class)
- public ResponseBodyBean> handleMybatisPlusException(HttpServletRequest request, MybatisPlusException exception) {
- requestLog(request);
- log.error("MybatisPlusException message: {}", exception.getMessage());
- return ResponseBodyBean.ofStatus(HttpStatus.INTERNAL_SERVER_ERROR,
- String.format("MybatisPlusException message: %s",
- removeLineSeparator(exception.getMessage())));
- }
-
- @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
- @ExceptionHandler(PersistenceException.class)
- public ResponseBodyBean> handlePersistenceException(HttpServletRequest request, PersistenceException exception) {
- requestLog(request);
- log.error("PersistenceException message: {}", exception.getMessage());
- return ResponseBodyBean.ofStatus(HttpStatus.INTERNAL_SERVER_ERROR,
- String.format("PersistenceException message: %s",
- removeLineSeparator(exception.getMessage())));
- }
-
@ExceptionHandler(UndeclaredThrowableException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public ResponseBodyBean> handleError(UndeclaredThrowableException exception) {
diff --git a/spring-cloud-starter/src/main/java/com/jmsoftware/maf/springcloudstarter/aspect/DatabaseExceptionControllerAdvice.java b/spring-cloud-starter/src/main/java/com/jmsoftware/maf/springcloudstarter/aspect/DatabaseExceptionControllerAdvice.java
new file mode 100644
index 00000000..87d43849
--- /dev/null
+++ b/spring-cloud-starter/src/main/java/com/jmsoftware/maf/springcloudstarter/aspect/DatabaseExceptionControllerAdvice.java
@@ -0,0 +1,106 @@
+package com.jmsoftware.maf.springcloudstarter.aspect;
+
+import cn.hutool.core.util.StrUtil;
+import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException;
+import com.jmsoftware.maf.common.bean.ResponseBodyBean;
+import com.jmsoftware.maf.springcloudstarter.util.RequestUtil;
+import lombok.extern.slf4j.Slf4j;
+import lombok.val;
+import org.apache.ibatis.exceptions.PersistenceException;
+import org.mybatis.spring.MyBatisSystemException;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.context.support.DefaultMessageSourceResolvable;
+import org.springframework.http.HttpStatus;
+import org.springframework.web.bind.MethodArgumentNotValidException;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.ResponseStatus;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+
+import javax.servlet.http.HttpServletRequest;
+import java.util.Objects;
+
+/**
+ * DatabaseExceptionControllerAdvice
+ *
+ * Exception advice for database exception.
+ *
+ * @author Johnny Miller (锺俊), email: johnnysviva@outlook.com, date: 6/27/2021 10:41 AM
+ **/
+@Slf4j
+@RestControllerAdvice
+@ConditionalOnClass({MyBatisSystemException.class, MybatisPlusException.class, PersistenceException.class})
+public class DatabaseExceptionControllerAdvice {
+ @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
+ @ExceptionHandler(MyBatisSystemException.class)
+ public ResponseBodyBean> handleMyBatisSystemException(HttpServletRequest request,
+ MyBatisSystemException exception) {
+ requestLog(request);
+ log.error("MyBatisSystemException message: {}", exception.getMessage());
+ return ResponseBodyBean.ofStatus(HttpStatus.INTERNAL_SERVER_ERROR,
+ String.format("MyBatisSystemException message: %s",
+ removeLineSeparator(exception.getMessage())));
+ }
+
+ @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
+ @ExceptionHandler(MybatisPlusException.class)
+ public ResponseBodyBean> handleMybatisPlusException(HttpServletRequest request, MybatisPlusException exception) {
+ requestLog(request);
+ log.error("MybatisPlusException message: {}", exception.getMessage());
+ return ResponseBodyBean.ofStatus(HttpStatus.INTERNAL_SERVER_ERROR,
+ String.format("MybatisPlusException message: %s",
+ removeLineSeparator(exception.getMessage())));
+ }
+
+ @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
+ @ExceptionHandler(PersistenceException.class)
+ public ResponseBodyBean> handlePersistenceException(HttpServletRequest request, PersistenceException exception) {
+ requestLog(request);
+ log.error("PersistenceException message: {}", exception.getMessage());
+ return ResponseBodyBean.ofStatus(HttpStatus.INTERNAL_SERVER_ERROR,
+ String.format("PersistenceException message: %s",
+ removeLineSeparator(exception.getMessage())));
+ }
+
+ private void requestLog(HttpServletRequest request) {
+ log.error("Exception occurred when [{}] requested access. Request URL: [{}] {}",
+ RequestUtil.getRequestIpAndPort(request), request.getMethod(), request.getRequestURL());
+ }
+
+ /**
+ * Get field error message from exception. If two or more fields do not pass Spring Validation check, then will
+ * return the 1st error message of the error field.
+ *
+ * @param exception MethodArgumentNotValidException
+ * @return field error message
+ */
+ private String getFieldErrorMessageFromException(MethodArgumentNotValidException exception) {
+ try {
+ val firstErrorField =
+ (DefaultMessageSourceResolvable) Objects.requireNonNull(exception.getBindingResult()
+ .getAllErrors()
+ .get(0)
+ .getArguments())[0];
+ val firstErrorFieldName = firstErrorField.getDefaultMessage();
+ val firstErrorFieldMessage = exception.getBindingResult().getAllErrors().get(0).getDefaultMessage();
+ return String.format("%s %s", firstErrorFieldName, firstErrorFieldMessage);
+ } catch (Exception e) {
+ log.error("Exception occurred when get field error message from exception. Exception message: {}",
+ e.getMessage(), e);
+ return HttpStatus.BAD_REQUEST.getReasonPhrase();
+ }
+ }
+
+ /**
+ * Remove line separator string.
+ *
+ * @param source the source
+ * @return the string
+ * @author Johnny Miller (锺俊), email: johnnysviva@outlook.com, date: 12/24/2020 11:22 AM
+ */
+ private String removeLineSeparator(String source) {
+ if (StrUtil.isBlank(source)) {
+ return "source is blank";
+ }
+ return source.replaceAll(System.lineSeparator(), " ");
+ }
+}
diff --git a/spring-cloud-starter/src/main/java/com/jmsoftware/maf/springcloudstarter/configuration/AsyncConfiguration.java b/spring-cloud-starter/src/main/java/com/jmsoftware/maf/springcloudstarter/configuration/AsyncConfiguration.java
index 007e5669..f85378cc 100644
--- a/spring-cloud-starter/src/main/java/com/jmsoftware/maf/springcloudstarter/configuration/AsyncConfiguration.java
+++ b/spring-cloud-starter/src/main/java/com/jmsoftware/maf/springcloudstarter/configuration/AsyncConfiguration.java
@@ -3,7 +3,6 @@
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
import org.springframework.core.task.AsyncTaskExecutor;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
@@ -15,7 +14,6 @@
**/
@Slf4j
@EnableAsync
-@Configuration
@RequiredArgsConstructor
public class AsyncConfiguration {
@Bean
diff --git a/spring-cloud-starter/src/main/java/com/jmsoftware/maf/springcloudstarter/configuration/ExcelImportConfiguration.java b/spring-cloud-starter/src/main/java/com/jmsoftware/maf/springcloudstarter/configuration/ExcelImportConfiguration.java
index 70ac28f5..a42307d3 100644
--- a/spring-cloud-starter/src/main/java/com/jmsoftware/maf/springcloudstarter/configuration/ExcelImportConfiguration.java
+++ b/spring-cloud-starter/src/main/java/com/jmsoftware/maf/springcloudstarter/configuration/ExcelImportConfiguration.java
@@ -1,23 +1,14 @@
package com.jmsoftware.maf.springcloudstarter.configuration;
-import cn.hutool.core.util.ObjectUtil;
-import com.google.common.collect.Lists;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
-import lombok.val;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.context.config.annotation.RefreshScope;
-import org.springframework.stereotype.Component;
import org.springframework.validation.annotation.Validated;
import javax.annotation.PostConstruct;
-import javax.validation.Valid;
import javax.validation.constraints.Min;
-import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
-import javax.validation.constraints.Pattern;
-import java.util.ArrayList;
-import java.util.List;
/**
*
CustomConfiguration
@@ -30,7 +21,6 @@
@Data
@Slf4j
@Validated
-@Component
@RefreshScope
@ConfigurationProperties(prefix = "maf.configuration.excel")
public class ExcelImportConfiguration {
diff --git a/spring-cloud-starter/src/main/java/com/jmsoftware/maf/springcloudstarter/configuration/MafConfiguration.java b/spring-cloud-starter/src/main/java/com/jmsoftware/maf/springcloudstarter/configuration/MafConfiguration.java
index 6c04d484..4aa2f36f 100644
--- a/spring-cloud-starter/src/main/java/com/jmsoftware/maf/springcloudstarter/configuration/MafConfiguration.java
+++ b/spring-cloud-starter/src/main/java/com/jmsoftware/maf/springcloudstarter/configuration/MafConfiguration.java
@@ -6,7 +6,6 @@
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.springframework.boot.context.properties.ConfigurationProperties;
-import org.springframework.stereotype.Component;
import org.springframework.validation.annotation.Validated;
import javax.annotation.PostConstruct;
@@ -28,7 +27,6 @@
@Data
@Slf4j
@Validated
-@Component
@ConfigurationProperties(prefix = "maf.configuration")
public class MafConfiguration {
/**
diff --git a/spring-cloud-starter/src/main/java/com/jmsoftware/maf/springcloudstarter/configuration/MafProjectProperty.java b/spring-cloud-starter/src/main/java/com/jmsoftware/maf/springcloudstarter/configuration/MafProjectProperty.java
index d08a145e..949e318b 100644
--- a/spring-cloud-starter/src/main/java/com/jmsoftware/maf/springcloudstarter/configuration/MafProjectProperty.java
+++ b/spring-cloud-starter/src/main/java/com/jmsoftware/maf/springcloudstarter/configuration/MafProjectProperty.java
@@ -4,7 +4,6 @@
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.info.BuildProperties;
-import org.springframework.stereotype.Component;
import org.springframework.validation.annotation.Validated;
import javax.annotation.PostConstruct;
@@ -20,7 +19,6 @@
@Data
@Slf4j
@Validated
-@Component
@SuppressWarnings("jol")
@ConfigurationProperties(prefix = "maf.project-property")
public class MafProjectProperty {
diff --git a/spring-cloud-starter/src/main/java/com/jmsoftware/maf/springcloudstarter/configuration/MinioConfiguration.java b/spring-cloud-starter/src/main/java/com/jmsoftware/maf/springcloudstarter/configuration/MinioConfiguration.java
index 30de15a2..c5011ad5 100644
--- a/spring-cloud-starter/src/main/java/com/jmsoftware/maf/springcloudstarter/configuration/MinioConfiguration.java
+++ b/spring-cloud-starter/src/main/java/com/jmsoftware/maf/springcloudstarter/configuration/MinioConfiguration.java
@@ -4,9 +4,7 @@
import io.minio.MinioClient;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
-import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
/**
@@ -17,7 +15,6 @@
* @author Johnny Miller (锺俊), email: johnnysviva@outlook.com, date: 6/7/21 9:58 PM
**/
@Slf4j
-@Configuration
@Import({
MinioProperty.class
})
diff --git a/spring-cloud-starter/src/main/java/com/jmsoftware/maf/springcloudstarter/configuration/RabbitmqConfiguration.java b/spring-cloud-starter/src/main/java/com/jmsoftware/maf/springcloudstarter/configuration/RabbitmqConfiguration.java
index 404503ff..05e03a77 100644
--- a/spring-cloud-starter/src/main/java/com/jmsoftware/maf/springcloudstarter/configuration/RabbitmqConfiguration.java
+++ b/spring-cloud-starter/src/main/java/com/jmsoftware/maf/springcloudstarter/configuration/RabbitmqConfiguration.java
@@ -3,12 +3,10 @@
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.springframework.amqp.core.TopicExchange;
-import org.springframework.amqp.rabbit.connection.ConnectionFactory;
-import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.amqp.support.converter.MessageConverter;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
/**
* Description: RabbitmqConfiguration, change description here.
@@ -16,7 +14,7 @@
* @author Johnny Miller (锺俊), email: johnnysviva@outlook.com, date: 3/9/2021 11:31 AM
**/
@Slf4j
-@Configuration
+@ConditionalOnClass({TopicExchange.class})
public class RabbitmqConfiguration {
public final String topicExchangeName;
diff --git a/spring-cloud-starter/src/main/java/com/jmsoftware/maf/springcloudstarter/configuration/RestTemplateConfiguration.java b/spring-cloud-starter/src/main/java/com/jmsoftware/maf/springcloudstarter/configuration/RestTemplateConfiguration.java
index 1c539655..cfb98fdf 100644
--- a/spring-cloud-starter/src/main/java/com/jmsoftware/maf/springcloudstarter/configuration/RestTemplateConfiguration.java
+++ b/spring-cloud-starter/src/main/java/com/jmsoftware/maf/springcloudstarter/configuration/RestTemplateConfiguration.java
@@ -6,7 +6,6 @@
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.DefaultResponseErrorHandler;
import org.springframework.web.client.RestTemplate;
@@ -17,7 +16,6 @@
* @author 钟俊(zhongjun), email: zhongjun@toguide.cn, date: 1/29/2021 4:29 PM
**/
@Slf4j
-@Configuration
public class RestTemplateConfiguration {
@Bean
@LoadBalanced
diff --git a/spring-cloud-starter/src/main/java/com/jmsoftware/maf/springcloudstarter/configuration/Swagger2Configuration.java b/spring-cloud-starter/src/main/java/com/jmsoftware/maf/springcloudstarter/configuration/Swagger2Configuration.java
index 9a9c6bf8..f1386b58 100644
--- a/spring-cloud-starter/src/main/java/com/jmsoftware/maf/springcloudstarter/configuration/Swagger2Configuration.java
+++ b/spring-cloud-starter/src/main/java/com/jmsoftware/maf/springcloudstarter/configuration/Swagger2Configuration.java
@@ -4,7 +4,6 @@
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
@@ -25,7 +24,6 @@
* @date 2019-02-07 16:15
**/
@Slf4j
-@Configuration
@EnableSwagger2WebMvc
@RequiredArgsConstructor
public class Swagger2Configuration {
diff --git a/spring-cloud-starter/src/main/java/com/jmsoftware/maf/springcloudstarter/configuration/WebMvcConfiguration.java b/spring-cloud-starter/src/main/java/com/jmsoftware/maf/springcloudstarter/configuration/WebMvcConfiguration.java
index 7c947fae..82ec5f20 100644
--- a/spring-cloud-starter/src/main/java/com/jmsoftware/maf/springcloudstarter/configuration/WebMvcConfiguration.java
+++ b/spring-cloud-starter/src/main/java/com/jmsoftware/maf/springcloudstarter/configuration/WebMvcConfiguration.java
@@ -1,7 +1,6 @@
package com.jmsoftware.maf.springcloudstarter.configuration;
import lombok.RequiredArgsConstructor;
-import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@@ -13,7 +12,6 @@
* @author Johnny Miller (锺俊), email: johnnysviva@outlook.com
* @date 1/23/20 9:02 AM
**/
-@Configuration
@RequiredArgsConstructor
public class WebMvcConfiguration implements WebMvcConfigurer {
/**
diff --git a/spring-cloud-starter/src/main/java/com/jmsoftware/maf/springcloudstarter/configuration/WebSecurityConfiguration.java b/spring-cloud-starter/src/main/java/com/jmsoftware/maf/springcloudstarter/configuration/WebSecurityConfiguration.java
index 4991f93c..f3c4475e 100644
--- a/spring-cloud-starter/src/main/java/com/jmsoftware/maf/springcloudstarter/configuration/WebSecurityConfiguration.java
+++ b/spring-cloud-starter/src/main/java/com/jmsoftware/maf/springcloudstarter/configuration/WebSecurityConfiguration.java
@@ -2,7 +2,6 @@
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
@@ -20,7 +19,6 @@
* @date 5/2/20 11:41 PM
**/
@Slf4j
-@Configuration
@EnableWebSecurity
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
@PostConstruct
diff --git a/spring-cloud-starter/src/main/java/com/jmsoftware/maf/springcloudstarter/database/DataSourceConfiguration.java b/spring-cloud-starter/src/main/java/com/jmsoftware/maf/springcloudstarter/database/DataSourceConfiguration.java
new file mode 100644
index 00000000..9e18ce10
--- /dev/null
+++ b/spring-cloud-starter/src/main/java/com/jmsoftware/maf/springcloudstarter/database/DataSourceConfiguration.java
@@ -0,0 +1,60 @@
+package com.jmsoftware.maf.springcloudstarter.database;
+
+import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
+import com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration;
+import lombok.extern.slf4j.Slf4j;
+import lombok.val;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.boot.autoconfigure.AutoConfigureBefore;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Primary;
+import org.springframework.jdbc.datasource.DataSourceTransactionManager;
+import org.springframework.transaction.PlatformTransactionManager;
+
+import javax.sql.DataSource;
+import java.util.HashMap;
+
+/**
+ * Description: DataSourceConfiguration, change description here.
+ *
+ * @author Johnny Miller (锺俊), email: johnnysviva@outlook.com, date: 6/27/2021 8:15 AM
+ **/
+@Slf4j
+@ConditionalOnClass({MybatisPlusAutoConfiguration.class})
+@AutoConfigureBefore({MybatisPlusAutoConfiguration.class})
+public class DataSourceConfiguration {
+ @Bean
+ @ConfigurationProperties("spring.datasource.dynamic.datasource.master")
+ public DataSource masterDataSource() {
+ log.warn("Initial bean: masterDataSource");
+ return DruidDataSourceBuilder.create().build();
+ }
+
+ @Bean
+ @ConfigurationProperties("spring.datasource.dynamic.datasource.slave1")
+ public DataSource slave1DataSource() {
+ log.warn("Initial bean: slave1DataSource");
+ return DruidDataSourceBuilder.create().build();
+ }
+
+ @Bean
+ @Primary
+ public DynamicRoutingDataSource dynamicDataSource(@Qualifier("masterDataSource") DataSource masterDataSource,
+ @Qualifier("slave1DataSource") DataSource slave1DataSource) {
+ log.warn("Loading masterDataSource and slave1DataSource as DynamicDataSource");
+ val targetDataSources = new HashMap<>(4);
+ targetDataSources.put(DataSourceTypeEnum.MASTER, masterDataSource);
+ targetDataSources.put(DataSourceTypeEnum.SLAVE1, slave1DataSource);
+ val dynamicDataSource = new DynamicRoutingDataSource();
+ dynamicDataSource.setDefaultTargetDataSource(masterDataSource);
+ dynamicDataSource.setTargetDataSources(targetDataSources);
+ return dynamicDataSource;
+ }
+
+ @Bean
+ public PlatformTransactionManager platformTransactionManager(DynamicRoutingDataSource dynamicRoutingDataSource) {
+ return new DataSourceTransactionManager(dynamicRoutingDataSource);
+ }
+}
diff --git a/spring-cloud-starter/src/main/java/com/jmsoftware/maf/springcloudstarter/database/DataSourceContextHolder.java b/spring-cloud-starter/src/main/java/com/jmsoftware/maf/springcloudstarter/database/DataSourceContextHolder.java
new file mode 100644
index 00000000..055f0510
--- /dev/null
+++ b/spring-cloud-starter/src/main/java/com/jmsoftware/maf/springcloudstarter/database/DataSourceContextHolder.java
@@ -0,0 +1,58 @@
+package com.jmsoftware.maf.springcloudstarter.database;
+
+import lombok.extern.slf4j.Slf4j;
+import lombok.val;
+
+import java.util.Optional;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * Description: DatabaseContextHolder, thread-safe
+ *
+ * @author Johnny Miller (锺俊), email: johnnysviva@outlook.com, date: 6/27/2021 12:07 AM
+ **/
+@Slf4j
+public class DataSourceContextHolder {
+ private static final ThreadLocal CONTEXT_HOLDER = new ThreadLocal<>();
+ private static final AtomicInteger COUNTER = new AtomicInteger(-1);
+ private static final int MAX_COUNT = 9999;
+
+ public static DataSourceTypeEnum get() {
+ return Optional.ofNullable(CONTEXT_HOLDER.get()).orElse(DataSourceTypeEnum.MASTER);
+ }
+
+ public static void set(DataSourceTypeEnum dbType) {
+ CONTEXT_HOLDER.set(dbType);
+ }
+
+ static void master() {
+ set(DataSourceTypeEnum.MASTER);
+ if (log.isDebugEnabled()) {
+ log.debug("Current data source -> {}", DataSourceTypeEnum.MASTER);
+ }
+ }
+
+ static void slave() {
+ // Simple load-balance for more slave clusters
+ val index = COUNTER.getAndIncrement() % 2;
+ if (COUNTER.get() > MAX_COUNT) {
+ COUNTER.set(-1);
+ }
+ // if (index == 0) {
+ // set(DataSourceTypeEnum.SLAVE1);
+ // }else {
+ // set(DataSourceTypeEnum.SLAVE2);
+ // }
+ set(DataSourceTypeEnum.SLAVE1);
+ if (log.isDebugEnabled()) {
+ log.debug("Current data source -> {}, index: {}", DataSourceTypeEnum.MASTER, index);
+ }
+ }
+
+ static void clear() {
+ CONTEXT_HOLDER.remove();
+ if (log.isDebugEnabled()) {
+ log.debug("Cleared CONTEXT_HOLDER");
+ }
+ }
+}
diff --git a/spring-cloud-starter/src/main/java/com/jmsoftware/maf/springcloudstarter/database/DataSourceTypeEnum.java b/spring-cloud-starter/src/main/java/com/jmsoftware/maf/springcloudstarter/database/DataSourceTypeEnum.java
new file mode 100644
index 00000000..17088808
--- /dev/null
+++ b/spring-cloud-starter/src/main/java/com/jmsoftware/maf/springcloudstarter/database/DataSourceTypeEnum.java
@@ -0,0 +1,17 @@
+package com.jmsoftware.maf.springcloudstarter.database;
+
+/**
+ * Description: DataSourceTypeEnum, change description here.
+ *
+ * @author Johnny Miller (锺俊), email: johnnysviva@outlook.com, date: 6/27/2021 12:03 AM
+ **/
+public enum DataSourceTypeEnum {
+ /**
+ * Master
+ */
+ MASTER,
+ /**
+ * Slave 1
+ */
+ SLAVE1
+}
diff --git a/spring-cloud-starter/src/main/java/com/jmsoftware/maf/springcloudstarter/database/DynamicDataSourceInterceptor.java b/spring-cloud-starter/src/main/java/com/jmsoftware/maf/springcloudstarter/database/DynamicDataSourceInterceptor.java
new file mode 100644
index 00000000..4fbf44b2
--- /dev/null
+++ b/spring-cloud-starter/src/main/java/com/jmsoftware/maf/springcloudstarter/database/DynamicDataSourceInterceptor.java
@@ -0,0 +1,85 @@
+package com.jmsoftware.maf.springcloudstarter.database;
+
+import lombok.extern.slf4j.Slf4j;
+import lombok.val;
+import org.apache.ibatis.executor.Executor;
+import org.apache.ibatis.executor.keygen.SelectKeyGenerator;
+import org.apache.ibatis.mapping.MappedStatement;
+import org.apache.ibatis.mapping.SqlCommandType;
+import org.apache.ibatis.plugin.*;
+import org.apache.ibatis.session.ResultHandler;
+import org.apache.ibatis.session.RowBounds;
+import org.springframework.transaction.support.TransactionSynchronizationManager;
+
+import java.util.Objects;
+
+/**
+ * Description: DynamicDataSourceInterceptor, change description here.
+ *
+ * @author Johnny Miller (锺俊), email: johnnysviva@outlook.com, date: 6/27/2021 12:26 AM
+ **/
+@Slf4j
+@Intercepts({
+ @Signature(
+ type = Executor.class,
+ method = "update",
+ args = {MappedStatement.class, Object.class}
+ ),
+ @Signature(
+ type = Executor.class,
+ method = "query",
+ args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class
+ })
+})
+public class DynamicDataSourceInterceptor implements Interceptor {
+ /**
+ * The constant WRITE_OPERATION_SQL_REGEX. Preserved this constant for future use.
+ */
+ @SuppressWarnings("unused")
+ private static final String WRITE_OPERATION_SQL_REGEX = ".*INSERT.*|.*UPDATE.*|.*DELETE.*";
+
+ @Override
+ public Object intercept(Invocation invocation) throws Throwable {
+ // Check if the transaction synchronization is active. It it was, would use MASTER data source
+ val actualTransactionActive = TransactionSynchronizationManager.isActualTransactionActive();
+ // MyBatis CRUD args
+ val args = invocation.getArgs();
+ // MappedStatement SqlCommandType
+ val mappedStatement = (MappedStatement) args[0];
+ // Default using master
+ DataSourceContextHolder.master();
+ if (!actualTransactionActive) {
+ // SqlCommandType.SELECT, UNKNOWN|INSERT|UPDATE|DELETE|SELECT|FLUSH
+ if (mappedStatement.getSqlCommandType().equals(SqlCommandType.SELECT)) {
+ // If it's the SQL return primary key as result
+ if (mappedStatement.getId().contains(SelectKeyGenerator.SELECT_KEY_SUFFIX)) {
+ log.warn("Calling ID-return SQL, {}", SelectKeyGenerator.SELECT_KEY_SUFFIX);
+ DataSourceContextHolder.master();
+ } else {
+ if (Objects.deepEquals(SqlCommandType.SELECT, mappedStatement.getSqlCommandType())) {
+ DataSourceContextHolder.slave();
+ } else {
+ DataSourceContextHolder.master();
+ }
+ }
+ }
+ } else {
+ DataSourceContextHolder.master();
+ }
+ log.warn("SQL statement [{}], SqlCommandType: [{}], using 🐬 [{}] data source", mappedStatement.getId(),
+ mappedStatement.getSqlCommandType().name(), DataSourceContextHolder.get());
+ val result = invocation.proceed();
+ DataSourceContextHolder.clear();
+ return result;
+ }
+
+ @Override
+ public Object plugin(Object target) {
+ if (target instanceof Executor) {
+ return Plugin.wrap(target, this);
+ } else {
+ return target;
+ }
+ }
+}
+
diff --git a/spring-cloud-starter/src/main/java/com/jmsoftware/maf/springcloudstarter/database/DynamicRoutingDataSource.java b/spring-cloud-starter/src/main/java/com/jmsoftware/maf/springcloudstarter/database/DynamicRoutingDataSource.java
new file mode 100644
index 00000000..89b5b4fb
--- /dev/null
+++ b/spring-cloud-starter/src/main/java/com/jmsoftware/maf/springcloudstarter/database/DynamicRoutingDataSource.java
@@ -0,0 +1,15 @@
+package com.jmsoftware.maf.springcloudstarter.database;
+
+import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
+
+/**
+ * Description: DynamicDataSource, change description here.
+ *
+ * @author Johnny Miller (锺俊), email: johnnysviva@outlook.com, date: 6/27/2021 12:06 AM
+ **/
+public class DynamicRoutingDataSource extends AbstractRoutingDataSource {
+ @Override
+ protected Object determineCurrentLookupKey() {
+ return DataSourceContextHolder.get();
+ }
+}
diff --git a/spring-cloud-starter/src/main/java/com/jmsoftware/maf/springcloudstarter/database/MyBatisPlusConfiguration.java b/spring-cloud-starter/src/main/java/com/jmsoftware/maf/springcloudstarter/database/MyBatisPlusConfiguration.java
index 64fa1e42..e87593a0 100644
--- a/spring-cloud-starter/src/main/java/com/jmsoftware/maf/springcloudstarter/database/MyBatisPlusConfiguration.java
+++ b/spring-cloud-starter/src/main/java/com/jmsoftware/maf/springcloudstarter/database/MyBatisPlusConfiguration.java
@@ -1,13 +1,15 @@
package com.jmsoftware.maf.springcloudstarter.database;
import com.baomidou.mybatisplus.annotation.DbType;
-import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
+import com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration;
import com.baomidou.mybatisplus.extension.plugins.inner.BlockAttackInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import lombok.extern.slf4j.Slf4j;
import lombok.val;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Import;
import org.springframework.transaction.annotation.EnableTransactionManagement;
/**
@@ -17,6 +19,10 @@
**/
@Slf4j
@Configuration
+@Import({
+ DataSourceConfiguration.class
+})
+@ConditionalOnClass({MybatisPlusAutoConfiguration.class})
@EnableTransactionManagement
public class MyBatisPlusConfiguration {
@Bean
@@ -33,22 +39,10 @@ public BlockAttackInnerInterceptor blockAttackInnerInterceptor() {
return new BlockAttackInnerInterceptor();
}
- /**
- * Mybatis plus interceptor mybatis plus interceptor.
- *
- * @param paginationInnerInterceptor the pagination inner interceptor
- * @param blockAttackInnerInterceptor the block attack inner interceptor
- * @return the mybatis plus interceptor
- * @see MybatisPlusInterceptor
- */
@Bean
- public MybatisPlusInterceptor mybatisPlusInterceptor(PaginationInnerInterceptor paginationInnerInterceptor,
- BlockAttackInnerInterceptor blockAttackInnerInterceptor) {
- log.warn("Initial bean: '{}'", MybatisPlusInterceptor.class.getSimpleName());
- MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
- mybatisPlusInterceptor.addInnerInterceptor(paginationInnerInterceptor);
- mybatisPlusInterceptor.addInnerInterceptor(blockAttackInnerInterceptor);
- return mybatisPlusInterceptor;
+ public DynamicDataSourceInterceptor dynamicDataSourceInterceptor() {
+ log.warn("Initial bean: '{}'", DynamicDataSourceInterceptor.class.getSimpleName());
+ return new DynamicDataSourceInterceptor();
}
@Bean
diff --git a/spring-cloud-starter/src/main/java/com/jmsoftware/maf/springcloudstarter/redis/RedisConfiguration.java b/spring-cloud-starter/src/main/java/com/jmsoftware/maf/springcloudstarter/redis/RedisConfiguration.java
index d8e7de10..c8a181be 100644
--- a/spring-cloud-starter/src/main/java/com/jmsoftware/maf/springcloudstarter/redis/RedisConfiguration.java
+++ b/spring-cloud-starter/src/main/java/com/jmsoftware/maf/springcloudstarter/redis/RedisConfiguration.java
@@ -3,8 +3,8 @@
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.data.redis.connection.ReactiveRedisConnectionFactory;
import org.springframework.data.redis.connection.RedisConnectionFactory;
@@ -23,11 +23,11 @@
* @author 钟俊(zhongjun), email: zhongjun@toguide.cn, date: 12/30/2020 1:08 PM
**/
@Slf4j
-@Configuration
@RequiredArgsConstructor
@Import({
RedisCachingConfiguration.class
})
+@ConditionalOnClass({RedisConnectionFactory.class})
public class RedisConfiguration {
private final ObjectMapper objectMapper;