新增生产单导入异步处理

This commit is contained in:
gaoqr
2025-02-18 15:28:54 +08:00
parent d50d4772f0
commit b3306405c0
102 changed files with 7054 additions and 209 deletions
@@ -4,6 +4,7 @@ import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.exceptions.ExceptionUtil;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjectUtil;
import com.cf.imes.framework.common.pojo.CommonResult;
import com.cf.imes.framework.common.util.json.JsonUtils;
import com.cf.imes.framework.common.util.monitor.TracerUtils;
@@ -310,7 +311,9 @@ public class OperateLogAspect {
String argName = argNames[i];
Object argValue = argValues[i];
// 被忽略时,标记为 ignore 字符串,避免和 null 混在一起
args.put(argName, !isIgnoreArgs(argValue) ? argValue : "[ignore]");
if (ObjectUtil.isNotNull(argValue)) {
args.put(argName, !isIgnoreArgs(argValue) ? argValue : "[ignore]");
}
}
return JsonUtils.toJsonString(args);
}
@@ -30,7 +30,6 @@
<dependency>
<groupId>org.springframework.amqp</groupId>
<artifactId>spring-rabbit</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.apache.rocketmq</groupId>
@@ -1,12 +1,25 @@
package com.cf.imes.framework.mq.rabbitmq.config;
import cn.hutool.core.util.ReflectUtil;
import com.cf.imes.framework.mq.rabbitmq.constant.RabbitMqConstants;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.utils.SerializationUtils;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.DirectExchange;
import org.springframework.amqp.core.FanoutExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.core.QueueBuilder;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.context.annotation.Bean;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
import static com.cf.imes.framework.mq.rabbitmq.constant.RabbitMqConstants.ORDER_IMPORT_DEAD_LETTER_EXCHANGE;
import static com.cf.imes.framework.mq.rabbitmq.constant.RabbitMqConstants.ORDER_IMPORT_DEAD_LETTER_QUEUE;
import static com.cf.imes.framework.mq.rabbitmq.constant.RabbitMqConstants.ORDER_IMPORT_DEAD_LETTER_ROUTING_KEY;
/**
* RabbitMQ 消息队列配置类
@@ -18,12 +31,75 @@ import java.lang.reflect.Field;
@ConditionalOnClass(name = "org.springframework.amqp.rabbit.core.RabbitTemplate")
public class ChenfengRabbitMQAutoConfiguration {
static {
// 强制设置 SerializationUtils 的 TRUST_ALL 为 true,避免 RabbitMQ Consumer 反序列化消息报错
// 为什么不通过设置 spring.amqp.deserialization.trust.all 呢?因为可能在 SerializationUtils static 初始化后
Field trustAllField = ReflectUtil.getField(SerializationUtils.class, "TRUST_ALL");
ReflectUtil.removeFinalModify(trustAllField);
ReflectUtil.setFieldValue(SerializationUtils.class, trustAllField, true);
/**
* Jackson2JsonMessageConverter Bean:使用 jackson 序列化消息
*/
@Bean
public MessageConverter createMessageConverter() {
return new Jackson2JsonMessageConverter();
}
/**
* 生产单导入交换机、队列、绑定声明
*
* @return
*/
@Bean
public FanoutExchange orderImportFanoutExchange() {
return new FanoutExchange(RabbitMqConstants.ORDER_IMPORT_DEFAULT_EXCEL_EXCHANGE);
}
/**
* 生产单导入队列声明
*
* @return
*/
@Bean
public Queue orderImportQueue() {
Map<String, Object> args = new HashMap<>(1);
// x-dead-letter-exchange 这里声明当前队列绑定的死信交换机
args.put("x-dead-letter-exchange", ORDER_IMPORT_DEAD_LETTER_EXCHANGE);
// 设置死信路由键
args.put("x-dead-letter-routing-key", ORDER_IMPORT_DEAD_LETTER_ROUTING_KEY);
return QueueBuilder.durable(RabbitMqConstants.ORDER_IMPORT_DEFAULT_EXCEL_QUEUE).withArguments(args).build();
}
/**
* 生产单excel导入交换机声明
*
* @return
*/
@Bean
public Binding orderImportDefaultExcelBinding() {
return BindingBuilder.bind(orderImportQueue()).to(orderImportFanoutExchange());
}
/**
* 生产单导入死信交换机声明
* @return
*/
@Bean
public DirectExchange orderImportDeadLetterExchange(){
return new DirectExchange(ORDER_IMPORT_DEAD_LETTER_EXCHANGE);
}
/**
* 生产单导入死信队列声明
* @return
*/
@Bean
public Queue orderImportDeadLetterQueue() {
return new Queue(ORDER_IMPORT_DEAD_LETTER_QUEUE);
}
/**
* 生产单导入死信队列、交换机、绑定声明
* @return
*/
@Bean
public Binding deadLetterBindingA() {
return BindingBuilder.bind(orderImportDeadLetterQueue()).to(orderImportDeadLetterExchange()).with(ORDER_IMPORT_DEAD_LETTER_ROUTING_KEY);
}
}
@@ -0,0 +1,34 @@
package com.cf.imes.framework.mq.rabbitmq.constant;
/**
* rabbitmq常量
*
* @author Gqr
* @since 2025/1/6 11:15
*/
public class RabbitMqConstants {
/**
* 生产单导入交换机
*/
public static final String ORDER_IMPORT_DEFAULT_EXCEL_EXCHANGE = "order_import_default_excel_exchange";
/**
* 生产单导入队列
*/
public static final String ORDER_IMPORT_DEFAULT_EXCEL_QUEUE = "order_import_default_excel_queue";
/**
* 生产单导入死信交换机
*/
public static final String ORDER_IMPORT_DEAD_LETTER_EXCHANGE = "order_import_dead_letter_exchange";
/**
* 生产单导入死信队列
*/
public static final String ORDER_IMPORT_DEAD_LETTER_QUEUE = "order_import_dead_letter_queue";
/**
* 生产单导入死信路由键
*/
public static final String ORDER_IMPORT_DEAD_LETTER_ROUTING_KEY = "order_import_dead_letter_routing_key";
}
@@ -10,6 +10,7 @@ import com.baomidou.mybatisplus.core.incrementer.IKeyGenerator;
import com.baomidou.mybatisplus.extension.incrementer.*;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import com.cf.imes.framework.mybatis.core.injector.MybatisPlusInjector;
import org.apache.ibatis.annotations.Mapper;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Value;
@@ -75,4 +76,9 @@ public class ChenfengMybatisAutoConfiguration {
throw new IllegalArgumentException("DbType为空");
}
@Bean
public MybatisPlusInjector mybatisPlusInjector() {
return new MybatisPlusInjector();
}
}
@@ -0,0 +1,22 @@
package com.cf.imes.framework.mybatis.core.injector;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import java.util.List;
/**
* 基础批量映射器
*
* @author Gqr
* @since 2025/1/14 14:54
*/
public interface BaseBatchMapper<T> extends BaseMapper<T> {
/**
* 批量插入
* 区别于mybatisplus的saveBatch:拼接(a,b,c,...)value(aval,bval,cval,...)而不是把多个insert一次性提交到数据库
*
* @param entityList
* @return
*/
int insertBatchSomeColumn(List<T> entityList);
}
@@ -0,0 +1,22 @@
package com.cf.imes.framework.mybatis.core.injector;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.core.injector.AbstractMethod;
import com.baomidou.mybatisplus.core.injector.DefaultSqlInjector;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import com.baomidou.mybatisplus.extension.injector.methods.InsertBatchSomeColumn;
import java.util.List;
/**
* @author Gqr
* @since 2025/1/14 14:46
*/
public class MybatisPlusInjector extends DefaultSqlInjector {
@Override
public List<AbstractMethod> getMethodList(Class<?> mapperClass, TableInfo tableInfo) {
List<AbstractMethod> methodList = super.getMethodList(mapperClass, tableInfo);
methodList.add(new InsertBatchSomeColumn(i -> i.getFieldFill() != FieldFill.UPDATE));
return methodList;
}
}
@@ -0,0 +1,26 @@
package com.cf.imes.framework.mybatis.core.query;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
/**
* LambdaUpdateWrapper拓展
*
* @author Gqr
* @since 2025/1/22 15:58
*/
public class LambdaUpdateWrapperX<T> extends LambdaUpdateWrapper<T> {
public LambdaUpdateWrapperX<T> eqIfPresent(SFunction<T, ?> column, Object val) {
if (ObjectUtil.isNotEmpty(val)) {
return (LambdaUpdateWrapperX<T>) super.eq(column, val);
}
return this;
}
@Override
public LambdaUpdateWrapperX<T> eq(SFunction<T, ?> column, Object val) {
super.eq(column, val);
return this;
}
}
@@ -82,7 +82,7 @@ public class ChenfengCacheAutoConfiguration {
}
@Bean
public RedisLockUtil lockUtil(ChenfengCacheProperties chenfengCacheProperties, RedissonClient client) {
return new RedisLockUtil(chenfengCacheProperties, client);
public RedisLockUtil lockUtil(ChenfengCacheProperties chenfengCacheProperties, RedissonClient client, RedisTemplate redisTemplate) {
return new RedisLockUtil(chenfengCacheProperties, client, redisTemplate);
}
}
@@ -34,5 +34,5 @@ public class ChenfengCacheProperties {
* 等待获取锁的时间,单位:毫秒(ms)
* 默认0.5秒
*/
private int lockWaitTime = 500;
private int lockWaitTime = 5000;
}
@@ -0,0 +1,14 @@
package com.cf.imes.framework.redis.constants;
/**
* 多模块公用redis key常量
*
* @author Gqr
* @since 2025/1/14 15:22
*/
public class RedisKeyConstants {
/**
* 生产单导入
*/
public static final String ORDER_IMPORT_LOCK_KEY = "order_import:%s";
}
@@ -6,6 +6,7 @@ import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.data.redis.core.RedisTemplate;
import java.util.concurrent.TimeUnit;
@@ -23,6 +24,8 @@ public class RedisLockUtil {
private RedissonClient redissonClient;
private RedisTemplate redisTemplate;
/**
* 加锁
*
@@ -63,6 +66,7 @@ public class RedisLockUtil {
/**
* 解锁
* 使用注意:配合以上两个redisson的lock只能在当前线程中unlock,否则失败!!!
*
* @param key rediskey
*/
@@ -74,4 +78,37 @@ public class RedisLockUtil {
log.error("[RedisLockUtil][unlock]解锁失败", e);
}
}
/**
* 手动set nx ex加锁
* 使用注意:可用于跨服务
*
* @param key
* @param uniqeKey 解锁的时候校验,避免其他任务误解
* @param timeout
* @return
*/
public boolean lock(String key, String uniqeKey, Integer timeout) {
return redisTemplate.opsForValue().setIfAbsent(key, uniqeKey, timeout, TimeUnit.MILLISECONDS);
}
/**
* 解锁
* 校验唯一值后删除key
* 使用注意:可用于跨服务
*
* @param key
* @param uniqeKey 解锁时校验,避免同key下其他任务解锁到
*/
public void unlock(String key, String uniqeKey) {
Object object = redisTemplate.opsForValue().get(key);
if (ObjectUtil.equal(object, uniqeKey)) {
Boolean delete = redisTemplate.delete(key);
if (delete) {
log.info(String.format("[RedisLockUtil][unlock][%s]解锁", key));
} else {
log.error(String.format("[RedisLockUtil][unlock][%s]解锁失败", key));
}
}
}
}
+1
View File
@@ -37,6 +37,7 @@
<module>cf-spring-boot-starter-biz-organ</module>
<module>cf-spring-boot-starter-biz-data-permission</module>
<module>cf-spring-boot-starter-biz-error-code</module>
<module>cf-spring-boot-starter-biz-id</module>
<module>cf-spring-boot-starter-biz-ip</module>
<module>cf-spring-boot-starter-flowable</module>