新疆后端项目

This commit is contained in:
DESKTOP-BLB5287\FP
2025-06-30 14:31:09 +08:00
commit 0e52aff1f1
2596 changed files with 261030 additions and 0 deletions
@@ -0,0 +1,39 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.renkang</groupId>
<artifactId>functional-modules</artifactId>
<version>2.0.0</version>
</parent>
<artifactId>renkang-starter-batch</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-batch</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
</dependency>
</dependencies>
</project>
@@ -0,0 +1,132 @@
package com.renkang.batch.configure;
import com.baomidou.dynamic.datasource.DynamicRoutingDataSource;
import com.baomidou.dynamic.datasource.provider.DynamicDataSourceProvider;
import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceAutoConfiguration;
import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceProperties;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import org.springframework.batch.core.configuration.annotation.BatchConfigurer;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.batch.BatchDataSource;
import org.springframework.boot.autoconfigure.batch.BatchDataSourceScriptDatabaseInitializer;
import org.springframework.boot.autoconfigure.batch.BatchProperties;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration;
import org.springframework.boot.autoconfigure.transaction.TransactionManagerCustomizers;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Primary;
import org.springframework.core.task.SyncTaskExecutor;
import org.springframework.core.task.TaskExecutor;
import org.springframework.jdbc.support.JdbcTransactionManager;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.transaction.PlatformTransactionManager;
import javax.sql.DataSource;
import java.util.List;
/**
* @author Shunzhi Jiang
* @since 2023/11/9
*/
@AutoConfiguration(
before = {
org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration.class,
DataSourceTransactionManagerAutoConfiguration.class,
DynamicDataSourceAutoConfiguration.class
}
)
@EnableConfigurationProperties({RenkangBatchProperties.class, BatchProperties.class})
@EnableBatchProcessing
public class BatchAutoConfiguration {
private final BatchProperties batchProperties;
private final RenkangBatchProperties renkangBatchProperties;
private final DynamicDataSourceProperties dynamicDataSourceProperties;
public BatchAutoConfiguration(
BatchProperties batchProperties,
RenkangBatchProperties renkangBatchProperties,
DynamicDataSourceProperties dynamicDataSourceProperties
) {
this.batchProperties = batchProperties;
this.renkangBatchProperties = renkangBatchProperties;
this.dynamicDataSourceProperties = dynamicDataSourceProperties;
}
@Bean
@Primary
public PlatformTransactionManager bizTransactionManager(DataSource dataSource, TransactionManagerCustomizers transactionManagerCustomizers) {
JdbcTransactionManager bizTransactionManager = new JdbcTransactionManager(dataSource);
transactionManagerCustomizers.customize(bizTransactionManager);
return bizTransactionManager;
}
@Bean
public BatchConfigurer batchConfigurer(
@BatchDataSource DataSource dataSource,
TransactionManagerCustomizers transactionManagerCustomizers,
@Qualifier("batchTaskExecutor") TaskExecutor taskExecutor) {
return new CustomBatchConfigurer(batchProperties, dataSource, transactionManagerCustomizers, taskExecutor);
}
@Bean("batchTaskExecutor")
@ConditionalOnProperty(prefix = "renkang.batch", name = "async", havingValue = "true", matchIfMissing = false)
public TaskExecutor asyncBatchTaskExecutor() {
ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
taskExecutor.setCorePoolSize(16);
taskExecutor.setThreadNamePrefix("Job-Pool-");
taskExecutor.setMaxPoolSize(32);
taskExecutor.setQueueCapacity(16);
taskExecutor.setWaitForTasksToCompleteOnShutdown(true);
taskExecutor.afterPropertiesSet();
return taskExecutor;
}
@Bean("batchTaskExecutor")
@ConditionalOnProperty(prefix = "renkang.batch", name = "async", havingValue = "false", matchIfMissing = true)
public TaskExecutor syncBatchTaskExecutor() {
return new SyncTaskExecutor();
}
@Bean
@Primary
public DataSource dataSource(List<DynamicDataSourceProvider> providers) {
DynamicRoutingDataSource dataSource = new DynamicRoutingDataSource(providers);
dataSource.setPrimary(dynamicDataSourceProperties.getPrimary());
dataSource.setStrict(dynamicDataSourceProperties.getStrict());
dataSource.setStrategy(dynamicDataSourceProperties.getStrategy());
dataSource.setP6spy(dynamicDataSourceProperties.getP6spy());
dataSource.setSeata(dynamicDataSourceProperties.getSeata());
return dataSource;
}
@Bean
@ConditionalOnProperty(prefix = "renkang.batch", name = "jdbc-url")
@BatchDataSource
public DataSource batchDataSource() {
HikariConfig config = new HikariConfig();
config.setJdbcUrl(renkangBatchProperties.getJdbcUrl());
config.setUsername(renkangBatchProperties.getUsername());
config.setPassword(renkangBatchProperties.getPassword());
config.setDriverClassName(renkangBatchProperties.getDriverClassName());
return new HikariDataSource(config);
}
@Bean
public BatchDataSourceScriptDatabaseInitializer batchDataSourceInitializer(
DataSource dataSource,
@BatchDataSource ObjectProvider<DataSource> batchDataSource,
BatchProperties properties
) {
return new BatchDataSourceScriptDatabaseInitializer(batchDataSource.getIfAvailable(() -> dataSource),
properties.getJdbc());
}
}
@@ -0,0 +1,47 @@
package com.renkang.batch.configure;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.batch.core.launch.support.SimpleJobLauncher;
import org.springframework.boot.autoconfigure.batch.BasicBatchConfigurer;
import org.springframework.boot.autoconfigure.batch.BatchProperties;
import org.springframework.boot.autoconfigure.transaction.TransactionManagerCustomizers;
import org.springframework.core.task.TaskExecutor;
import javax.sql.DataSource;
/**
* @author Shunzhi Jiang
* @since 2023/11/9
*/
public class CustomBatchConfigurer extends BasicBatchConfigurer {
private TaskExecutor taskExecutor;
/**
* Create a new {@link BasicBatchConfigurer} instance.
*
* @param properties the batch properties
* @param dataSource the underlying data source
* @param transactionManagerCustomizers transaction manager customizers (or
* {@code null})
*/
protected CustomBatchConfigurer(BatchProperties properties, DataSource dataSource, TransactionManagerCustomizers transactionManagerCustomizers) {
super(properties, dataSource, transactionManagerCustomizers);
}
public CustomBatchConfigurer(BatchProperties properties, DataSource dataSource, TransactionManagerCustomizers transactionManagerCustomizers, TaskExecutor taskExecutor) {
super(properties, dataSource, transactionManagerCustomizers);
this.taskExecutor = taskExecutor;
}
@Override
protected JobLauncher createJobLauncher() throws Exception {
SimpleJobLauncher jobLauncher = new SimpleJobLauncher();
jobLauncher.setJobRepository(getJobRepository());
if (taskExecutor != null) {
jobLauncher.setTaskExecutor(taskExecutor);
}
jobLauncher.afterPropertiesSet();
return jobLauncher;
}
}
@@ -0,0 +1,26 @@
package com.renkang.batch.configure;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* @author Shunzhi Jiang
* @since 2023/11/9
*/
@ConfigurationProperties("renkang.batch")
@Data
public class RenkangBatchProperties {
private String jdbcUrl;
private String username;
private String password;
private String driverClassName;
private Integer writeSize = 100;
private boolean async = false;
}
@@ -0,0 +1,84 @@
package com.renkang.batch.job;
import org.springframework.batch.core.ExitStatus;
import org.springframework.batch.core.StepContribution;
import org.springframework.batch.core.scope.context.ChunkContext;
import org.springframework.batch.core.step.tasklet.Tasklet;
import org.springframework.batch.item.ExecutionContext;
import org.springframework.batch.repeat.RepeatStatus;
/**
* @author Shunzhi Jiang
* @since 2023/11/11
*/
public abstract class AbstractSimpleTasklet implements Tasklet {
private ExecutionContext jobExecutionContext;
private ExecutionContext stepExecutionContext;
/**
* Task执行方法
*
* @return 返回 {@link ExitStatus#COMPLETED} 视为成功,其他均视为失败,将执行 {@link AbstractSimpleTasklet#onError(Throwable)} 方法
*/
public abstract ExitStatus doExecute();
/**
* 任务执行失败时,执行的方法,可以是 {@link AbstractSimpleTasklet#doExecute()} 方法
* 返回了失败或产生异常
*
* @param throwable 若返回了失败,则 {@link Throwable} 为null
* @throws Exception 抛出的异常,可以抛出自定义异常
*/
public abstract void onError(Throwable throwable) throws Exception;
@Override
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
setExecutionContext(contribution);
try {
ExitStatus exitStatus = doExecute();
if (exitStatus == ExitStatus.COMPLETED) {
return setComplete(contribution, chunkContext);
} else {
contribution.setExitStatus(exitStatus);
onError(null);
}
} catch (Exception e) {
onError(e);
throw e;
}
return RepeatStatus.FINISHED;
}
public ExecutionContext getJobExecutionContext() {
return jobExecutionContext;
}
private void setJobExecutionContext(StepContribution contribution) {
jobExecutionContext = contribution.getStepExecution()
.getJobExecution()
.getExecutionContext();
}
public ExecutionContext getStepExecutionContext() {
return stepExecutionContext;
}
private void setStepExecutionContext(StepContribution contribution) {
stepExecutionContext = contribution.getStepExecution()
.getExecutionContext();
}
private void setExecutionContext(StepContribution contribution) {
setJobExecutionContext(contribution);
setStepExecutionContext(contribution);
}
private RepeatStatus setComplete(StepContribution contribution, ChunkContext chunkContext) {
contribution.setExitStatus(ExitStatus.COMPLETED);
chunkContext.setComplete();
return RepeatStatus.FINISHED;
}
}