初始代码

This commit is contained in:
wangmingwei
2026-04-21 17:41:09 +08:00
parent 186ec6683a
commit b686ecac5f
493 changed files with 52349 additions and 0 deletions

View File

@@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>yunzhupaas-common</artifactId>
<groupId>com.yunzhupaas</groupId>
<version>5.2.0-RELEASE</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>yunzhupaas-cloud-common</artifactId>
<packaging>pom</packaging>
<modules>
<module>yunzhupaas-common-dubbo</module>
<module>yunzhupaas-common-feign</module>
<module>yunzhupaas-common-seata</module>
<module>yunzhupaas-common-cloudshardingsphere</module>
<module>yunzhupaas-common-mq</module>
</modules>
<dependencyManagement>
<dependencies>
<!--<dependency>
<groupId>com.yunzhupaas</groupId>
<artifactId>yunzhupaas-boot-common</artifactId>
<type>pom</type>
<scope>import</scope>
</dependency>-->
</dependencies>
</dependencyManagement>
</project>

View File

@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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.yunzhupaas</groupId>
<artifactId>yunzhupaas-cloud-common</artifactId>
<version>5.2.0-RELEASE</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>yunzhupaas-common-cloudshardingsphere</artifactId>
<dependencies>
<dependency>
<groupId>com.yunzhupaas</groupId>
<artifactId>yunzhupaas-common-shardingsphere</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,51 @@
package com.yunzhupaas.config;
import com.alibaba.cloud.nacos.NacosConfigManager;
import com.alibaba.nacos.api.exception.NacosException;
import com.baomidou.dynamic.datasource.DynamicRoutingDataSource;
import com.yunzhupaas.constant.GlobalConst;
import org.apache.shardingsphere.driver.api.yaml.YamlShardingSphereDataSourceFactory;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.sql.DataSource;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.sql.SQLException;
/**
* @author 云筑产品开发平台组
* @user N
* @copyright 深圳市乐程软件有限公司
* @date 2024/11/23 16:52
*/
@Configuration
@ConditionalOnClass(name = "org.springframework.cloud.loadbalancer.annotation.LoadBalancerClient")
@ConditionalOnProperty(prefix = "config", name = "sharding-sphere-enabled", havingValue = "true")
public class CloudShardingSphereAutoConfig {
public CloudShardingSphereAutoConfig() {
System.out.println("启用 ShardingSphere");
}
public static final String PREFIX = "shardingsphere";
@Bean
public Object initShardingSphereDataSource(@Qualifier("dataSourceSystem") DynamicRoutingDataSource dataSource,
NacosConfigManager nacosConfigManager) throws SQLException, IOException, NacosException {
String shardingContent = nacosConfigManager.getConfigService().getConfig("sharding-sphere.yaml",
"DEFAULT_GROUP", 3000L);
if (shardingContent != null) {
DataSource SSDataSource = YamlShardingSphereDataSourceFactory
.createDataSource(shardingContent.getBytes(GlobalConst.DEFAULT_CHARSET));
dataSource.addDataSource(PREFIX, SSDataSource);
} else {
System.out.println("ShardingSphere 加载失败,缺少 sharding-sphere.yaml 配置文件");
}
return null;
}
}

View File

@@ -0,0 +1,39 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>yunzhupaas-cloud-common</artifactId>
<groupId>com.yunzhupaas</groupId>
<version>5.2.0-RELEASE</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>yunzhupaas-common-dubbo</artifactId>
<dependencies>
<dependency>
<groupId>com.yunzhupaas</groupId>
<artifactId>yunzhupaas-common-auth</artifactId>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-apache-dubbo-adapter</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,41 @@
package com.yunzhupaas.filter;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.common.constants.CommonConstants;
import org.apache.dubbo.common.extension.Activate;
import org.apache.dubbo.rpc.*;
/**
* Dubbo请求过滤器
*/
@Slf4j
@Activate(group = { CommonConstants.PROVIDER, CommonConstants.CONSUMER }, order = 100)
public class MyDubboRequestFilter implements Filter {
@Override
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
Result result;
// Provider端记录日志
if (RpcContext.getContext().isProviderSide()) {
long startTime = System.currentTimeMillis();
result = invoker.invoke(invocation);
long elapsed = System.currentTimeMillis() - startTime;
String baselog = "Client[" + CommonConstants.PROVIDER + "],InterfaceName=["
+ invocation.getInvoker().getInterface().getSimpleName() + "],MethodName=["
+ invocation.getMethodName() + "]";
if (result.hasException()) {
log.error("DUBBO - 处理异常: {}, Exception = {}", baselog, result.getException());
} else {
if (log.isDebugEnabled()) {
log.debug("DUBBO - 服务响应: {}, Elapsed=[{}ms]", baselog, elapsed);
}
}
} else {
result = invoker.invoke(invocation);
}
return result;
}
}

View File

@@ -0,0 +1,67 @@
package com.yunzhupaas.filter;
import cn.dev33.satoken.same.SaSameUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.yunzhupaas.base.UserInfo;
import com.yunzhupaas.consts.AuthConsts;
import com.yunzhupaas.properties.SecurityProperties;
import com.yunzhupaas.util.Constants;
import com.yunzhupaas.util.UserProvider;
import org.apache.dubbo.common.constants.CommonConstants;
import org.apache.dubbo.common.extension.Activate;
import org.apache.dubbo.rpc.*;
/**
* Dubbo过滤器 自动传递装载UserInfo
*/
@Activate(group = { CommonConstants.PROVIDER, CommonConstants.CONSUMER }, order = 101)
public class MyDubboTokenFilter implements Filter {
private static SecurityProperties securityProperties;
public MyDubboTokenFilter() {
MyDubboTokenFilter.securityProperties = SpringUtil.getBean(SecurityProperties.class);
}
@Override
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
UserInfo userInfo;
Result result;
boolean isProvider;
String url = RpcContext.getContext().getUrl().toString();
if (url.startsWith("injvm")) {
isProvider = url.contains("side=provider");
} else {
isProvider = RpcContext.getContext().isProviderSide();
}
// Provider端
if (isProvider) {
try {
// 设置本地认证信息
userInfo = (UserInfo) RpcContext.getContext().getObjectAttachment(Constants.AUTHORIZATION);
UserProvider.setLocalLoginUser(userInfo);
if (securityProperties.isEnableInnerAuth()) {
String innerToken = invocation.getAttachment(AuthConsts.INNER_TOKEN_KEY);
SaSameUtil.checkToken(innerToken);
}
result = invoker.invoke(invocation);
} finally {
// 清除用户缓存
UserProvider.clearLocalUser();
}
} else {
// Consumer端
// 传递UserInfo
userInfo = UserProvider.getUser();
if (userInfo.getUserId() != null) {
invocation.setAttachment(Constants.AUTHORIZATION, userInfo);
}
if (securityProperties.isEnableInnerAuth()) {
invocation.setAttachment(AuthConsts.INNER_TOKEN_KEY, UserProvider.getInnerAuthToken());
}
result = invoker.invoke(invocation);
}
return result;
}
}

View File

@@ -0,0 +1,2 @@
yunzhupaasDubboToken=com.yunzhupaas.filter.MyDubboTokenFilter
yunzhupaasDubboRequest=com.yunzhupaas.filter.MyDubboRequestFilter

View File

@@ -0,0 +1,2 @@
# security/serialize.allowlist
com.yunzhupaas.base.UserInfo

View File

@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>yunzhupaas-cloud-common</artifactId>
<groupId>com.yunzhupaas</groupId>
<version>5.2.0-RELEASE</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>yunzhupaas-common-feign</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>com.yunzhupaas</groupId>
<artifactId>yunzhupaas-common-auth</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,85 @@
package com.yunzhupaas;
import feign.Logger;
import feign.RequestInterceptor;
import feign.RequestTemplate;
import com.yunzhupaas.base.UserInfo;
import com.yunzhupaas.constant.GlobalConst;
import com.yunzhupaas.consts.AuthConsts;
import com.yunzhupaas.properties.SecurityProperties;
import com.yunzhupaas.util.Constants;
import com.yunzhupaas.util.ServletUtil;
import com.yunzhupaas.util.UserProvider;
import com.yunzhupaas.utils.FeignHolder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import jakarta.servlet.http.HttpServletRequest;
import java.util.Map;
/**
*
* @author 云筑产品开发平台组
* @version V3.1.0
* @copyright 深圳市乐程软件有限公司
* @date 2024/3/16 10:51
*/
@Configuration
public class FeignConfig implements RequestInterceptor {
@Autowired
private SecurityProperties securityProperties;
@Override
public void apply(RequestTemplate template) {
// 添加token
Map<String, String> headers = FeignHolder.get();
String token = null;
if (headers != null) {
// 通过FeignHolder调用
template.header("User-Agent", headers.get("user-agent"));
template.header(Constants.AUTHORIZATION, headers.get(Constants.AUTHORIZATION));
template.header("X-Real-IP", headers.get("x-real-ip"));
template.header("X-Forwarded-For", headers.get("x-forwarded-for"));
/*
* headers.entrySet().forEach((k)->{
* template.header(k.getKey(), k.getValue());
* });
*/
} else {
// 先获取当前本地缓存中UserInfo的TOKEN
// 适配临时切换用户
UserInfo userInfo = UserProvider.getLocalLoginUser();
if (userInfo != null && userInfo.getToken() != null) {
token = userInfo.getToken();
template.header(Constants.AUTHORIZATION, token);
}
// Web环境直接调用
HttpServletRequest request = ServletUtil.getRequest();
if (request != null) {
if (token == null) {
template.header(Constants.AUTHORIZATION, request.getHeader(Constants.AUTHORIZATION));
}
template.header("User-Agent", request.getHeader("User-Agent"));
template.header("X-Real-IP", request.getHeader("X-Real-IP"));
template.header("X-Forwarded-For", request.getHeader("X-Forwarded-For"));
}
}
if (securityProperties.isEnableInnerAuth() || securityProperties.isEnablePreAuth()) {
template.header(AuthConsts.INNER_TOKEN_KEY, UserProvider.getInnerAuthToken());
}
template.header(GlobalConst.HEADER_HOST, ServletUtil.getRequestHost());
}
/**
* Openfeign调用日志
* NONE,BASIC,HEADERS,FULL共有四种等级
*
* @return
*/
@Bean
Logger.Level feignLoggerLeave() {
return Logger.Level.FULL;
}
}

View File

@@ -0,0 +1,68 @@
package com.yunzhupaas.utils;
import com.yunzhupaas.util.ThreadPoolExecutorUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.Future;
import java.util.function.Supplier;
/**
* 异步FEIGN请求 把当前REQUEST的HEADER存入新线程中 在新线程中调用feign请求 FeignConfig
* 中取当前headers发送到新服务
* 使用方式:
* 1、直接调用set设置Header, Feign请求全部调用完之后调用clear清除线程变量
* 2、调用asyncFeign、sendFeign 调用完后自动清除线程变量
*/
// @ConditionalOnBean(ThreadPoolTaskExecutor.class)
@Component
@Slf4j
public class FeignHolder {
private static ThreadLocal<Map<String, String>> feignHeader = new ThreadLocal<>();
public static void set(Map<String, String> headers) {
TreeMap map = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
map.putAll(headers);
feignHeader.set(map);
}
public static Map<String, String> get() {
return feignHeader.get();
}
public static void clear() {
feignHeader.remove();
}
/**
* Async异步发送请求, 完成后清空线程变量
*
* @param headers
* @param supplier
* @return
*/
public static Future<?> asyncFeign(Map<String, String> headers, Supplier supplier) {
return ThreadPoolExecutorUtil.getExecutor().submit(() -> sendFeign(headers, supplier));
}
/**
* 同步发送请求, 完成后清空线程变量
*
* @param headers
* @param supplier
*/
public static <R> R sendFeign(Map<String, String> headers, Supplier<R> supplier) {
try {
set(headers);
return supplier.get();
} catch (Exception e) {
log.error("同步发送Feign请求失败", e);
return null;
} finally {
clear();
}
}
}

View File

@@ -0,0 +1,38 @@
package com.yunzhupaas.utils;
import com.yunzhupaas.constant.ModuleName;
import lombok.Data;
/**
* @author 云筑产品开发平台组
* @version V3.1.0
* @copyright 深圳市乐程软件有限公司
* @date 2024/3/16 10:51
*/
@Data
public class FeignName {
public static final String SYSTEM_SERVER_NAME = ModuleName.SYSTEM_SERVER_NAME;
public static final String MESSAGE_SERVER_NAME = ModuleName.MESSAGE_SERVER_NAME;
public static final String VUSUALDEV_SERVER_NAME = ModuleName.VUSUALDEV_SERVER_NAME;
public static final String EXAMPLE_SERVER_NAME = ModuleName.EXAMPLE_SERVER_NAME;
public static final String EXTEND_SERVER_NAME = ModuleName.EXTEND_SERVER_NAME;
public static final String APP_SERVER_NAME = ModuleName.APP_SERVER_NAME;
public static final String WORKFLOW_SERVER_NAME = ModuleName.WORKFLOW_SERVER_NAME;
public static final String FILE_SERVER_NAME = ModuleName.FILE_SERVER_NAME;
public static final String PERMISSION_SERVER_NAME = ModuleName.PERMISSION_SERVER_NAME;
public static final String FORM_SERVER_NAME = ModuleName.FORM_SERVER_NAME;
public static final String OAUTH_SERVER_NAME = ModuleName.OAUTH_SERVER_NAME;
public static final String SCHEDULE_SERVER_NAME = ModuleName.SCHEDULE_SERVER_NAME;
}

View File

@@ -0,0 +1,40 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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.yunzhupaas</groupId>
<artifactId>yunzhupaas-cloud-common</artifactId>
<version>5.2.0-RELEASE</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>yunzhupaas-common-mq</artifactId>
<dependencies>
<dependency>
<groupId>com.yunzhupaas</groupId>
<artifactId>yunzhupaas-common-event</artifactId>
</dependency>
<!--RocketMQ-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-stream-rocketmq</artifactId>
</dependency>
<!--RabbitMQ-->
<!--<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-stream-rabbit</artifactId>
</dependency>-->
<!--Kafka-->
<!--<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-stream-kafka</artifactId>
</dependency>-->
</dependencies>
</project>

View File

@@ -0,0 +1,33 @@
package com.yunzhupaas.config;
import com.baomidou.lock.LockTemplate;
import com.yunzhupaas.consts.ProjectEventConst;
import com.yunzhupaas.handler.ProjectEventMQMessageHandler;
import com.yunzhupaas.handler.ProjectEventMQSender;
import com.yunzhupaas.properties.EventProperty;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.cloud.stream.function.StreamBridge;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.Message;
import java.util.function.Consumer;
@Configuration(proxyBeanMethods = false)
public class MqAutoConfiguration {
@Bean(ProjectEventConst.DEFAULT_TOPIC_NAME)
@ConditionalOnProperty(prefix = "event", name = "event-publish-type", havingValue = ProjectEventConst.EVENT_PUBLISH_TYPE_QUEUE)
public Consumer<Message<?>> getDefaultMqConsumer(LockTemplate lockTemplate) {
return new ProjectEventMQMessageHandler(lockTemplate);
}
/**
* 自定义事件发布渠道为QUEUE
*/
@Bean
@ConditionalOnProperty(prefix = "event", name = "event-publish-type", havingValue = ProjectEventConst.EVENT_PUBLISH_TYPE_QUEUE)
public ProjectEventMQSender getProjectEventMQSender(StreamBridge streamBridge, EventProperty eventProperties) {
return new ProjectEventMQSender(streamBridge, eventProperties);
}
}

View File

@@ -0,0 +1,57 @@
package com.yunzhupaas.handler;
import com.alibaba.fastjson.JSON;
import com.baomidou.lock.LockTemplate;
import com.yunzhupaas.consts.ProjectEventConst;
import com.yunzhupaas.module.ProjectEventInstance;
import com.yunzhupaas.util.JsonUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.messaging.Message;
import java.util.function.Consumer;
/**
* 自定义事件监听, MQ渠道, 收到通知后发送Spring事件(RedisEventInstance)
*/
@Slf4j
public class ProjectEventMQMessageHandler implements Consumer<Message<?>>, ApplicationEventPublisherAware {
private ApplicationEventPublisher applicationEventPublisher;
private final LockTemplate lockTemplate;
public ProjectEventMQMessageHandler(LockTemplate lockTemplate) {
this.lockTemplate = lockTemplate;
log.info("初始化自定义事件MQ监听器");
}
@Override
public void accept(Message<?> o) {
if (log.isDebugEnabled()) {
log.debug("事件监听收到MQ消息:{}", JSON.toJSONString(o));
}
// 是否存在自定义事件的标识
if (o.getHeaders().get(ProjectEventConst.DEFAULT_CHANNEL_PREFIX) == null) {
if (log.isDebugEnabled()) {
log.debug("事件监听忽略MQ消息:{}", JSON.toJSONString(o));
}
return;
}
Object payload = o.getPayload();
ProjectEventInstance instance;
if (payload instanceof byte[]) {
instance = JSON.parseObject((byte[]) payload, ProjectEventInstance.class);
} else if (payload instanceof String) {
instance = JSON.parseObject((String) payload, ProjectEventInstance.class);
} else {
instance = JsonUtil.getJsonToBean(payload, ProjectEventInstance.class);
}
applicationEventPublisher.publishEvent(instance);
}
@Override
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
this.applicationEventPublisher = applicationEventPublisher;
}
}

View File

@@ -0,0 +1,37 @@
package com.yunzhupaas.handler;
import com.alibaba.fastjson.JSON;
import com.yunzhupaas.consts.ProjectEventConst;
import com.yunzhupaas.module.ProjectEvent;
import com.yunzhupaas.event.ProjectEventSender;
import com.yunzhupaas.properties.EventProperty;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.stream.function.StreamBridge;
import org.springframework.messaging.support.MessageBuilder;
/**
* 自定义事件发布 MQ渠道
*/
@Slf4j
public class ProjectEventMQSender implements ProjectEventSender {
private StreamBridge streamBridge;
private EventProperty eventProperty;
public ProjectEventMQSender(StreamBridge streamBridge, EventProperty eventProperty) {
this.streamBridge = streamBridge;
this.eventProperty = eventProperty;
}
@Override
public void send(ProjectEvent event) {
streamBridge.send(ProjectEventConst.DEFAULT_TOPIC_NAME + "-out-0", MessageBuilder.withPayload(event)
// 添加自定义事件标识
.setHeader(ProjectEventConst.DEFAULT_CHANNEL_PREFIX, event.getChannel())
.build());
if (log.isDebugEnabled()) {
log.debug("发送MQ自定义事件: {}", JSON.toJSONString(event));
}
}
}

View File

@@ -0,0 +1,35 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>yunzhupaas-cloud-common</artifactId>
<groupId>com.yunzhupaas</groupId>
<version>5.2.0-RELEASE</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>yunzhupaas-common-seata</artifactId>
<dependencies>
<!-- seata -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-seata</artifactId>
</dependency>
<dependency>
<groupId>io.seata</groupId>
<artifactId>seata-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.esotericsoftware</groupId>
<artifactId>kryo</artifactId>
</dependency>
<dependency>
<groupId>de.javakaffee</groupId>
<artifactId>kryo-serializers</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,159 @@
package io.seata.rm.datasource;
import io.seata.rm.datasource.sql.struct.Field;
import io.seata.sqlparser.util.ColumnUtils;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;
/**
* generate sql and set value to sql
*
* @author JerryYin
*/
public class SqlGenerateUtils {
private static final int MAX_IN_SIZE = 1000;
private SqlGenerateUtils() {
}
public static String buildWhereConditionByPKs(List<String> pkNameList, int rowSize, String dbType)
throws SQLException {
return "sqlserver".equals(dbType) ? buildWhereConditionByPKsBySqlServer(pkNameList, rowSize, dbType, MAX_IN_SIZE) : buildWhereConditionByPKs(pkNameList, rowSize, dbType, MAX_IN_SIZE);
}
/**
* each pk is a condition.the result will like :" (id,userCode) in ((?,?),(?,?)) or (id,userCode) in ((?,?),(?,?)
* ) or (id,userCode) in ((?,?))"
* Build where condition by pks string.
*
* @param pkNameList pk column name list
* @param rowSize the row size of records
* @param dbType the type of database
* @param maxInSize the max in size
* @return return where condition sql string.the sql can search all related records not just one.
* @throws SQLException the sql exception
*/
public static String buildWhereConditionByPKs(List<String> pkNameList, int rowSize, String dbType, int maxInSize)
throws SQLException {
StringBuilder whereStr = new StringBuilder();
//we must consider the situation of composite primary key
int batchSize = rowSize % maxInSize == 0 ? rowSize / maxInSize : (rowSize / maxInSize) + 1;
for (int batch = 0; batch < batchSize; batch++) {
if (batch > 0) {
whereStr.append(" or ");
}
whereStr.append("(");
for (int i = 0; i < pkNameList.size(); i++) {
if (i > 0) {
whereStr.append(",");
}
whereStr.append(ColumnUtils.addEscape(pkNameList.get(i), dbType));
}
whereStr.append(") in ( ");
int eachSize = (batch == batchSize - 1) ? (rowSize % maxInSize == 0 ? maxInSize : rowSize % maxInSize)
: maxInSize;
for (int i = 0; i < eachSize; i++) {
//each row is a bracket
if (i > 0) {
whereStr.append(",");
}
whereStr.append("(");
for (int x = 0; x < pkNameList.size(); x++) {
if (x > 0) {
whereStr.append(",");
}
whereStr.append("?");
}
whereStr.append(")");
}
whereStr.append(" )");
}
return whereStr.toString();
}
/**
* each pk is a condition.the result will like :" (id = ? and userCode = ?) or (id = ? and userCode = ?)"
* Build where condition by pks string.
*
* @param pkNameList pk column name list
* @param rowSize the row size of records
* @param dbType the type of database
* @param maxInSize the max in size
* @return return where condition sql string.the sql can search all related records not just one.
* @throws SQLException the sql exception
*/
public static String buildWhereConditionByPKsBySqlServer(List<String> pkNameList, int rowSize, String dbType, int maxInSize)
throws SQLException {
StringBuilder whereStr = new StringBuilder();
//we must consider the situation of composite primary key
for (int batch = 0; batch < rowSize; batch++) {
if (batch > 0) {
whereStr.append(" or ");
}
whereStr.append("(");
for (int i = 0; i < pkNameList.size(); i++) {
if (i > 0) {
whereStr.append(" and ");
}
whereStr.append(ColumnUtils.addEscape(pkNameList.get(i), dbType));
whereStr.append(" = ? ");
}
whereStr.append(")");
}
return whereStr.toString();
}
/**
* set parameter for PreparedStatement, this is only used in pk sql.
*
* @param pkRowsList pkRowsList
* @param pkColumnNameList pkColumnNameList
* @param pst preparedStatement
* @throws SQLException SQLException
*/
public static void setParamForPk(List<Map<String, Field>> pkRowsList, List<String> pkColumnNameList,
PreparedStatement pst) throws SQLException {
int paramIndex = 1;
for (int i = 0; i < pkRowsList.size(); i++) {
Map<String, Field> rowData = pkRowsList.get(i);
for (String columnName : pkColumnNameList) {
Field pkField = rowData.get(columnName);
pst.setObject(paramIndex, pkField.getValue(), pkField.getType());
paramIndex++;
}
}
}
/**
* each pk is a condition.the result will like :" id =? and userCode =?"
*
* @param pkNameList pkNameList
* @param dbType dbType
* @return return where condition sql string.the sql can just search one related record.
*/
public static String buildWhereConditionByPKs(List<String> pkNameList, String dbType) {
StringBuilder whereStr = new StringBuilder();
//we must consider the situation of composite primary key
for (int i = 0; i < pkNameList.size(); i++) {
if (i > 0) {
whereStr.append(" and ");
}
String pkName = pkNameList.get(i);
whereStr.append(ColumnUtils.addEscape(pkName, dbType));
whereStr.append(" = ? ");
}
return whereStr.toString();
}
}