Merge branch 'cc_20251016_async' into cc_20251010_wxnotice
This commit is contained in:
@@ -26,6 +26,11 @@ public class CommonConstants {
|
|||||||
|
|
||||||
public static final int NORMAL_LOCK_TIMES = 60 * 1000;
|
public static final int NORMAL_LOCK_TIMES = 60 * 1000;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 短期token过期时间,单位秒
|
||||||
|
*/
|
||||||
|
public static final int SHORT_TERM_TOKEN_EXPIRE = 60 * 5;
|
||||||
|
|
||||||
public static final int AN_HOUR_SECONDS = 3600;
|
public static final int AN_HOUR_SECONDS = 3600;
|
||||||
//十秒
|
//十秒
|
||||||
public static final int TEN_SECONDS = 10000;
|
public static final int TEN_SECONDS = 10000;
|
||||||
@@ -55,6 +60,11 @@ public class CommonConstants {
|
|||||||
|
|
||||||
public static final String ZXJP_MINI_PROGRAM_LOGIN_FLAG = "zxjp_mini_program_login_flag:{0}";
|
public static final String ZXJP_MINI_PROGRAM_LOGIN_FLAG = "zxjp_mini_program_login_flag:{0}";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 小程序短期token key
|
||||||
|
*/
|
||||||
|
public static final String ZXJP_MIN_PROGRAM_SHORT_TERM_LOGIN_FLAG = "zxjp_mini_program_short_term_login_flag:{0}";
|
||||||
|
|
||||||
public static final String ROOT_DEPT_ID_STR = "1";
|
public static final String ROOT_DEPT_ID_STR = "1";
|
||||||
|
|
||||||
public static final Integer DEAL_RECORD_MAX_SIZE = 1000;
|
public static final Integer DEAL_RECORD_MAX_SIZE = 1000;
|
||||||
|
|||||||
@@ -302,7 +302,7 @@ public enum ErrorCodeEnum {
|
|||||||
CONFIG_NOT_EXIST(1610006,"配置不存在或被禁用,请确认!",null),
|
CONFIG_NOT_EXIST(1610006,"配置不存在或被禁用,请确认!",null),
|
||||||
MESSAGE_NOT_EXIST(1610007,"消息模板不存在或已被删除",null),
|
MESSAGE_NOT_EXIST(1610007,"消息模板不存在或已被删除",null),
|
||||||
MESSAGE_NOT_HANDLED(1610008,"当前消息无需处理,请确认消息处理类型!",null),
|
MESSAGE_NOT_HANDLED(1610008,"当前消息无需处理,请确认消息处理类型!",null),
|
||||||
|
MESSAGE_PUBLISH(1610009,"您选择通知任务正在发布中,请稍后重试!",null),
|
||||||
|
|
||||||
NOT_FLAGSHIP_STORE(16100005,"非直营店,无法跳过缴费阶段!",null),
|
NOT_FLAGSHIP_STORE(16100005,"非直营店,无法跳过缴费阶段!",null),
|
||||||
NOT_FLAGSHIP_STORE_NOT_EXIST(16100006,"当前阶段加盟类型不能变更!",null),
|
NOT_FLAGSHIP_STORE_NOT_EXIST(16100006,"当前阶段加盟类型不能变更!",null),
|
||||||
|
|||||||
@@ -0,0 +1,80 @@
|
|||||||
|
package com.cool.store.executor;
|
||||||
|
|
||||||
|
|
||||||
|
import com.cool.store.utils.ThreadMdcUtil;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.slf4j.MDC;
|
||||||
|
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.Callable;
|
||||||
|
import java.util.concurrent.Future;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author zhangchenbiao
|
||||||
|
* @FileName: MdcTaskExecutor
|
||||||
|
* @Description:
|
||||||
|
* @date 2021-11-02 21:00
|
||||||
|
*/
|
||||||
|
public class MdcTaskExecutor extends ThreadPoolTaskExecutor {
|
||||||
|
private Logger log = LoggerFactory.getLogger(MdcTaskExecutor.class);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> Future<T> submit(Callable<T> task) {
|
||||||
|
Map<String, String> context = MDC.getCopyOfContextMap();
|
||||||
|
return super.submit(() -> {
|
||||||
|
T result;
|
||||||
|
if (context != null) {
|
||||||
|
//将父线程的MDC内容传给子线程
|
||||||
|
MDC.setContextMap(context);
|
||||||
|
}
|
||||||
|
//直接给子线程设置MDC
|
||||||
|
ThreadMdcUtil.setTraceIdIfAbsent();
|
||||||
|
try {
|
||||||
|
//执行任务
|
||||||
|
result = task.call();
|
||||||
|
} finally {
|
||||||
|
log.info("ThreadMonitor:{}info:ExecutedTasks->{},totalTask->{}, RunningTasks->{}, PendingTasks->{},corePoolSize-{},currentPoolSize->{},LargestPoolSize->{}",
|
||||||
|
this.getThreadNamePrefix(),this.getThreadPoolExecutor().getCompletedTaskCount(),this.getThreadPoolExecutor().getTaskCount(),
|
||||||
|
this.getActiveCount(),this.getThreadPoolExecutor().getQueue().size(),this.getCorePoolSize(),
|
||||||
|
this.getPoolSize(),this.getThreadPoolExecutor().getLargestPoolSize());
|
||||||
|
try {
|
||||||
|
MDC.clear();
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.warn("MDC clear exception", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(Runnable task) {
|
||||||
|
log.info("mdc thread pool task executor execute");
|
||||||
|
Map<String, String> context = MDC.getCopyOfContextMap();
|
||||||
|
super.execute(() -> {
|
||||||
|
if (context != null) {
|
||||||
|
//将父线程的MDC内容传给子线程
|
||||||
|
MDC.setContextMap(context);
|
||||||
|
}
|
||||||
|
//直接给子线程设置MDC
|
||||||
|
ThreadMdcUtil.setTraceIdIfAbsent();
|
||||||
|
try {
|
||||||
|
//执行任务
|
||||||
|
task.run();
|
||||||
|
} finally {
|
||||||
|
log.info("ThreadMonitor:{}info:ExecutedTasks->{},totalTask->{}, RunningTasks->{}, PendingTasks->{},corePoolSize-{},currentPoolSize->{},LargestPoolSize->{}",
|
||||||
|
this.getThreadNamePrefix(),this.getThreadPoolExecutor().getCompletedTaskCount(),this.getThreadPoolExecutor().getTaskCount(),
|
||||||
|
this.getActiveCount(),this.getThreadPoolExecutor().getQueue().size(),this.getCorePoolSize(),
|
||||||
|
this.getPoolSize(),this.getThreadPoolExecutor().getLargestPoolSize());
|
||||||
|
try {
|
||||||
|
MDC.clear();
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.warn("MDC clear exception", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
package com.cool.store.executor;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.core.task.TaskExecutor;
|
||||||
|
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
||||||
|
|
||||||
|
import java.util.concurrent.ThreadPoolExecutor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author suzhuhong
|
||||||
|
* @Date 2025/10/15 17:29
|
||||||
|
* @Version 1.0
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
public class ThreadPoolTask {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public TaskExecutor noticeThreadPool() {
|
||||||
|
int cores = Runtime.getRuntime().availableProcessors();
|
||||||
|
|
||||||
|
ThreadPoolTaskExecutor executor = new MdcTaskExecutor();
|
||||||
|
// 核心线程数目
|
||||||
|
executor.setCorePoolSize(cores*2);
|
||||||
|
// 指定最大线程数
|
||||||
|
executor.setMaxPoolSize(100);
|
||||||
|
// 队列中最大的数目
|
||||||
|
executor.setQueueCapacity(10000);
|
||||||
|
// 线程名称前缀
|
||||||
|
executor.setThreadNamePrefix("noticeThreadPool_");
|
||||||
|
// 对拒绝task的处理策略
|
||||||
|
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
|
||||||
|
// 线程空闲后的最大存活时间
|
||||||
|
executor.setKeepAliveSeconds(60);
|
||||||
|
// 加载
|
||||||
|
executor.initialize();
|
||||||
|
return executor;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
package com.cool.store.utils;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.slf4j.MDC;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author suzhuhong
|
||||||
|
* @Date 2025/10/15 17:32
|
||||||
|
* @Version 1.0
|
||||||
|
*/
|
||||||
|
public class MDCUtils {
|
||||||
|
public MDCUtils() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void putIfAbsent(String key, String value) {
|
||||||
|
String k = MDC.get(key);
|
||||||
|
if (StringUtils.isBlank(value)) {
|
||||||
|
value = UUID.randomUUID().toString().replace("-", "");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (StringUtils.isBlank(k)) {
|
||||||
|
MDC.put(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void put(String key, String value) {
|
||||||
|
MDC.put(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void put(String key) {
|
||||||
|
MDC.put(key, UUID.randomUUID().toString().replace("-", ""));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
package com.cool.store.utils;
|
||||||
|
|
||||||
|
import com.cool.store.constants.CommonConstants;
|
||||||
|
import org.slf4j.MDC;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.Callable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 线程MDC包装类
|
||||||
|
*
|
||||||
|
* @author hetiantian
|
||||||
|
* @version 1.0
|
||||||
|
* @Date 2020/03/18 15:18
|
||||||
|
*/
|
||||||
|
public class ThreadMdcUtil {
|
||||||
|
public static void setTraceIdIfAbsent() {
|
||||||
|
MDCUtils.putIfAbsent(CommonConstants.REQUEST_ID, UUIDUtils.get32UUID());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> Callable<T> wrap(final Callable<T> callable, final Map<String, String> context) {
|
||||||
|
return () -> {
|
||||||
|
if (context == null) {
|
||||||
|
MDC.clear();
|
||||||
|
} else {
|
||||||
|
MDC.setContextMap(context);
|
||||||
|
}
|
||||||
|
setTraceIdIfAbsent();
|
||||||
|
try {
|
||||||
|
return callable.call();
|
||||||
|
} finally {
|
||||||
|
MDC.clear();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Runnable wrap(final Runnable runnable, final Map<String, String> context) {
|
||||||
|
return new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
if (context == null) {
|
||||||
|
MDC.clear();
|
||||||
|
} else {
|
||||||
|
MDC.setContextMap(context);
|
||||||
|
}
|
||||||
|
setTraceIdIfAbsent();
|
||||||
|
try {
|
||||||
|
runnable.run();
|
||||||
|
} finally {
|
||||||
|
MDC.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
package com.cool.store.dto.wx;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import javax.validation.constraints.NotBlank;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* 小程序免登DTO
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author wangff
|
||||||
|
* @since 2025/9/18
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class MiniProgramFreeLoginDTO {
|
||||||
|
@ApiModelProperty("手机号")
|
||||||
|
@NotBlank(message = "手机号不能为空")
|
||||||
|
private String mobile;
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
package com.cool.store.service;
|
package com.cool.store.service;
|
||||||
|
|
||||||
import com.cool.store.dto.wx.MiniAppUrlLinkReqDTO;
|
import com.cool.store.dto.wx.MiniAppUrlLinkReqDTO;
|
||||||
|
import com.cool.store.dto.wx.MiniProgramFreeLoginDTO;
|
||||||
import com.cool.store.dto.wx.MiniProgramLoginDTO;
|
import com.cool.store.dto.wx.MiniProgramLoginDTO;
|
||||||
import com.cool.store.request.MobileUpdateRequest;
|
import com.cool.store.request.MobileUpdateRequest;
|
||||||
import com.cool.store.vo.PartnerUserInfoVO;
|
import com.cool.store.vo.PartnerUserInfoVO;
|
||||||
@@ -28,4 +29,18 @@ public interface WechatMiniAppService {
|
|||||||
String getMiniAppUrl();
|
String getMiniAppUrl();
|
||||||
|
|
||||||
String getMiniAppUrlLink(MiniAppUrlLinkReqDTO miniAppUrlLinkReqDTO);
|
String getMiniAppUrlLink(MiniAppUrlLinkReqDTO miniAppUrlLinkReqDTO);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过手机号获取短期token
|
||||||
|
* @param param 小程序免登DTO
|
||||||
|
* @return Token
|
||||||
|
*/
|
||||||
|
String getShortTermTokenByMobile(MiniProgramFreeLoginDTO param);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过短期token获取用户信息
|
||||||
|
* @param token 短期token
|
||||||
|
* @return 用户信息VO
|
||||||
|
*/
|
||||||
|
PartnerUserInfoVO getUserInfoByShortTermToken(String token);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import com.cool.store.response.bigdata.ApiResponse;
|
|||||||
import com.cool.store.service.MessageTemplateService;
|
import com.cool.store.service.MessageTemplateService;
|
||||||
import com.cool.store.service.StoreService;
|
import com.cool.store.service.StoreService;
|
||||||
import com.cool.store.utils.CoolDateUtils;
|
import com.cool.store.utils.CoolDateUtils;
|
||||||
|
import com.cool.store.utils.RedisUtilPool;
|
||||||
import com.cool.store.vo.PartnerUserInfoVO;
|
import com.cool.store.vo.PartnerUserInfoVO;
|
||||||
import com.cool.store.vo.notice.*;
|
import com.cool.store.vo.notice.*;
|
||||||
import com.github.pagehelper.PageHelper;
|
import com.github.pagehelper.PageHelper;
|
||||||
@@ -31,10 +32,13 @@ import org.apache.commons.collections4.CollectionUtils;
|
|||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.apache.ibatis.annotations.Param;
|
import org.apache.ibatis.annotations.Param;
|
||||||
import org.springframework.beans.BeanUtils;
|
import org.springframework.beans.BeanUtils;
|
||||||
|
import org.springframework.core.task.TaskExecutor;
|
||||||
|
import org.springframework.scheduling.annotation.Async;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
|
import java.time.Duration;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.ThreadLocalRandom;
|
import java.util.concurrent.ThreadLocalRandom;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
@@ -65,6 +69,10 @@ public class MessageTemplateServiceImpl implements MessageTemplateService {
|
|||||||
EnterpriseUserDAO enterpriseUserDAO;
|
EnterpriseUserDAO enterpriseUserDAO;
|
||||||
@Resource
|
@Resource
|
||||||
MatterConfigDAO matterConfigDAO;
|
MatterConfigDAO matterConfigDAO;
|
||||||
|
@Resource
|
||||||
|
RedisUtilPool redisUtilPool;
|
||||||
|
@Resource
|
||||||
|
TaskExecutor noticeThreadPool;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -136,23 +144,40 @@ public class MessageTemplateServiceImpl implements MessageTemplateService {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Boolean batchPublishMessageTemplate(BatchPublishRequest request, String userId) {
|
public Boolean batchPublishMessageTemplate(BatchPublishRequest request, String userId) {
|
||||||
|
log.info("batchPublishMessageTemplate:{}",JSONObject.toJSONString(request));
|
||||||
if (CollectionUtils.isEmpty(request.getIds())||CollectionUtils.isEmpty(request.getStoreInfoList())||CollectionUtils.isEmpty(request.getUserInfoList())){
|
if (CollectionUtils.isEmpty(request.getIds())||CollectionUtils.isEmpty(request.getStoreInfoList())||CollectionUtils.isEmpty(request.getUserInfoList())){
|
||||||
throw new ServiceException(ErrorCodeEnum.PARAMS_REQUIRED);
|
throw new ServiceException(ErrorCodeEnum.PARAMS_REQUIRED);
|
||||||
}
|
}
|
||||||
|
|
||||||
List<StoreAreaDTO> storeAreaDTOS = getStoreRange(request.getStoreInfoList());
|
|
||||||
List<String> storeIds = storeAreaDTOS.stream().map(StoreAreaDTO::getStoreId).collect(Collectors.toList());
|
|
||||||
|
|
||||||
Map<String, List<String>> authUser = getAuthUser(request.getUserInfoList(), storeIds);
|
|
||||||
|
|
||||||
List<MessageTemplateDO> list = messageTemplateDAO.getByIds(request.getIds());
|
List<MessageTemplateDO> list = messageTemplateDAO.getByIds(request.getIds());
|
||||||
//过滤 只保留未发布的
|
//过滤 只保留未发布的
|
||||||
list = list.stream().filter(x -> PublishStatusEnum.UNPUBLISHED.getCode().equals(x.getPublishStatus())).collect(Collectors.toList());
|
list = list.stream().filter(x -> PublishStatusEnum.UNPUBLISHED.getCode().equals(x.getPublishStatus())).collect(Collectors.toList());
|
||||||
|
|
||||||
if (CollUtil.isEmpty(list)){
|
if (CollUtil.isEmpty(list)){
|
||||||
log.info("未找到待发布消息模板");
|
log.info("未找到待发布消息模板");
|
||||||
|
return Boolean.TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
List<String> lockKeys = list.stream()
|
||||||
|
.map(x -> "msg_template_publish:" + x.getId())
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
boolean allLocksAcquired = tryAcquireLocks(lockKeys);
|
||||||
|
if (!allLocksAcquired) {
|
||||||
|
log.warn("存在正在发布的模板,本次操作取消。模板IDs: {}", JSONObject.toJSONString(lockKeys));
|
||||||
|
throw new ServiceException(ErrorCodeEnum.MESSAGE_PUBLISH);
|
||||||
|
}
|
||||||
|
List<MessageTemplateDO> finalList = list;
|
||||||
|
noticeThreadPool.execute(() -> {
|
||||||
|
syncPublish(request, userId, finalList, lockKeys);
|
||||||
|
});
|
||||||
|
return Boolean.TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean syncPublish(BatchPublishRequest request, String userId, List<MessageTemplateDO> list,List<String> lockKeys){
|
||||||
|
try {
|
||||||
|
List<StoreAreaDTO> storeAreaDTOS = getStoreRange(request.getStoreInfoList());
|
||||||
|
List<String> storeIds = storeAreaDTOS.stream().map(StoreAreaDTO::getStoreId).collect(Collectors.toList());
|
||||||
|
Map<String, List<String>> authUser = getAuthUser(request.getUserInfoList(), storeIds);
|
||||||
list.stream().forEach(x -> {
|
list.stream().forEach(x -> {
|
||||||
List<StoreMessageDO> result = new ArrayList<>();
|
List<StoreMessageDO> result = new ArrayList<>();
|
||||||
storeAreaDTOS.forEach(y->{
|
storeAreaDTOS.forEach(y->{
|
||||||
@@ -176,15 +201,76 @@ public class MessageTemplateServiceImpl implements MessageTemplateService {
|
|||||||
storeMessageDAO.batchInsert(result);
|
storeMessageDAO.batchInsert(result);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
//存在第一个成功 第二个失败 会有问题 todo
|
||||||
List<Long> updateIds = list.stream().map(MessageTemplateDO::getId).collect(Collectors.toList());
|
List<Long> updateIds = list.stream().map(MessageTemplateDO::getId).collect(Collectors.toList());
|
||||||
messageTemplateDAO.batchUpdateStoreInfoAndUserInfo(updateIds,
|
messageTemplateDAO.batchUpdateStoreInfoAndUserInfo(updateIds,
|
||||||
JSONObject.toJSONString(request.getStoreInfoList()),
|
JSONObject.toJSONString(request.getStoreInfoList()),
|
||||||
JSONObject.toJSONString(request.getUserInfoList()),
|
JSONObject.toJSONString(request.getUserInfoList()),
|
||||||
userId);
|
userId);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.info("发布流程异常,已取消发布");
|
||||||
|
} finally {
|
||||||
|
releaseLocks(lockKeys);
|
||||||
|
log.info("发布流程结束,已释放Redis锁");
|
||||||
|
}
|
||||||
return Boolean.TRUE;
|
return Boolean.TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 尝试获取所有Redis锁
|
||||||
|
*/
|
||||||
|
private boolean tryAcquireLocks(List<String> lockKeys) {
|
||||||
|
boolean allSuccess = true;
|
||||||
|
List<String> acquiredLocks = new ArrayList<>();
|
||||||
|
|
||||||
|
for (String lockKey : lockKeys) {
|
||||||
|
try {
|
||||||
|
// 设置锁,过期时间设为5分钟,防止死锁
|
||||||
|
Boolean success = redisUtilPool.setNxExpire(lockKey, "locking",1000*60*5);
|
||||||
|
if (success != null && success) {
|
||||||
|
acquiredLocks.add(lockKey);
|
||||||
|
} else {
|
||||||
|
log.warn("获取Redis锁失败: {}", lockKey);
|
||||||
|
allSuccess = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("获取Redis锁异常: {}", lockKey, e);
|
||||||
|
allSuccess = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果任何一个锁获取失败,释放之前已经获取的锁
|
||||||
|
if (!allSuccess) {
|
||||||
|
releaseLocks(acquiredLocks);
|
||||||
|
}
|
||||||
|
|
||||||
|
return allSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 释放Redis锁
|
||||||
|
*/
|
||||||
|
private void releaseLocks(List<String> lockKeys) {
|
||||||
|
if (CollUtil.isEmpty(lockKeys)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (String lockKey : lockKeys) {
|
||||||
|
try {
|
||||||
|
redisUtilPool.delKey(lockKey);
|
||||||
|
log.debug("释放Redis锁成功: {}", lockKey);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("释放Redis锁异常: {}", lockKey, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public ApiResponse<Boolean> thirdMatterHandle(ThirdMatterRequest thirdMatterRequest) {
|
public ApiResponse<Boolean> thirdMatterHandle(ThirdMatterRequest thirdMatterRequest) {
|
||||||
|
|||||||
@@ -244,30 +244,16 @@ public class ShopAccountServiceImpl implements ShopAccountService {
|
|||||||
}
|
}
|
||||||
List<ShopAccountDO> accountDOS = shopAccountDAO.selectByShopId(shopId);
|
List<ShopAccountDO> accountDOS = shopAccountDAO.selectByShopId(shopId);
|
||||||
if (CollectionUtils.isEmpty(accountDOS)) {
|
if (CollectionUtils.isEmpty(accountDOS)) {
|
||||||
throw new ServiceException(ErrorCodeEnum.SYSTEM_DATA_ERROR);
|
return "ZXA8_"+shopInfo.getShopCode();
|
||||||
}
|
}
|
||||||
Map<String, ShopAccountDO> map = accountDOS.stream().collect(Collectors.toMap(ShopAccountDO::getSystemName, data -> data));
|
Map<String, ShopAccountDO> map = accountDOS.stream().collect(Collectors.toMap(ShopAccountDO::getSystemName, data -> data));
|
||||||
ShopAccountDO shopAccountDO = map.get(ShopAccountEnum.YLS.getSystemName());
|
ShopAccountDO shopAccountDO = map.get(ShopAccountEnum.YLS.getSystemName());
|
||||||
if (Objects.isNull(shopAccountDO)) {
|
if (Objects.isNull(shopAccountDO)) {
|
||||||
throw new ServiceException(ErrorCodeEnum.SYSTEM_DATA_ERROR);
|
return "ZXA8_"+shopInfo.getShopCode();
|
||||||
}
|
}
|
||||||
return StringUtil.isEmpty(shopAccountDO.getAccount()) ? shopInfo.getShopCode() : shopAccountDO.getAccount();
|
return StringUtil.isEmpty(shopAccountDO.getAccount()) ? shopInfo.getShopCode() : shopAccountDO.getAccount();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public String shopCodeToYlsCode(String shopCode) {
|
|
||||||
ShopInfoDO shopInfoDO = shopInfoDAO.selectByStoreCode(shopCode);
|
|
||||||
if (!Objects.isNull(shopInfoDO)) {
|
|
||||||
return this.shopIdToYlsCode(shopInfoDO.getId());
|
|
||||||
}
|
|
||||||
//查询老店关联表数据
|
|
||||||
OldShopDO oldShopDO = oldShopDAO.getByCode(shopCode);
|
|
||||||
if (Objects.isNull(oldShopDO)) {
|
|
||||||
throw new ServiceException(ErrorCodeEnum.GET_YLS_CODE_FAIL);
|
|
||||||
}
|
|
||||||
return oldShopDO.getYlsShopCode();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public Boolean handleOldData() {
|
public Boolean handleOldData() {
|
||||||
@@ -316,6 +302,20 @@ public class ShopAccountServiceImpl implements ShopAccountService {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String shopCodeToYlsCode(String shopCode) {
|
||||||
|
ShopInfoDO shopInfoDO = shopInfoDAO.selectByStoreCode(shopCode);
|
||||||
|
if (!Objects.isNull(shopInfoDO)) {
|
||||||
|
return this.shopIdToYlsCode(shopInfoDO.getId());
|
||||||
|
}
|
||||||
|
//查询老店关联表数据
|
||||||
|
OldShopDO oldShopDO = oldShopDAO.getByCode(shopCode);
|
||||||
|
if (Objects.isNull(oldShopDO)) {
|
||||||
|
throw new ServiceException(ErrorCodeEnum.GET_YLS_CODE_FAIL);
|
||||||
|
}
|
||||||
|
return oldShopDO.getYlsShopCode();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public Boolean handleAccountPassword() {
|
public Boolean handleAccountPassword() {
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import com.cool.store.utils.UUIDUtils;
|
|||||||
import com.cool.store.vo.PartnerUserInfoVO;
|
import com.cool.store.vo.PartnerUserInfoVO;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.apache.shiro.crypto.SecureRandomNumberGenerator;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
@@ -259,4 +260,30 @@ public class WechatMiniAppServiceImpl implements WechatMiniAppService {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getShortTermTokenByMobile(MiniProgramFreeLoginDTO param) {
|
||||||
|
HyPartnerUserInfoDO hyPartnerUserInfoDO = hyPartnerUserInfoDAO.selectByMobile(param.getMobile());
|
||||||
|
if (Objects.isNull(hyPartnerUserInfoDO)) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
PartnerUserInfoVO userInfoVO = BeanUtil.toBean(hyPartnerUserInfoDO, PartnerUserInfoVO.class);
|
||||||
|
fillLineInfo(userInfoVO, hyPartnerUserInfoDO.getPartnerId());
|
||||||
|
String token = new SecureRandomNumberGenerator().nextBytes().toHex();
|
||||||
|
String key = MessageFormat.format(CommonConstants.ZXJP_MIN_PROGRAM_SHORT_TERM_LOGIN_FLAG, token);
|
||||||
|
redisUtilPool.setString(key, JSONObject.toJSONString(userInfoVO), CommonConstants.SHORT_TERM_TOKEN_EXPIRE);
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PartnerUserInfoVO getUserInfoByShortTermToken(String token) {
|
||||||
|
String key = MessageFormat.format(CommonConstants.ZXJP_MIN_PROGRAM_SHORT_TERM_LOGIN_FLAG, token);
|
||||||
|
String userStr = redisUtilPool.getString(key);
|
||||||
|
if (StringUtils.isNotBlank(userStr)) {
|
||||||
|
PartnerUserInfoVO userInfoVO = JSONObject.parseObject(userStr, PartnerUserInfoVO.class);
|
||||||
|
redisUtilPool.delKey(key);
|
||||||
|
return userInfoVO;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,7 +59,8 @@ public class SignValidateFilter implements Filter {
|
|||||||
"/zxjp/mini/program/v1/partnerManage/openArea/areaApplyQuery",
|
"/zxjp/mini/program/v1/partnerManage/openArea/areaApplyQuery",
|
||||||
"/zxjp/**/api/audit/result",
|
"/zxjp/**/api/audit/result",
|
||||||
"/zxjp/**/api/license",
|
"/zxjp/**/api/license",
|
||||||
"/zxjp/mini/line/getRegionPayPic"
|
"/zxjp/mini/line/getRegionPayPic",
|
||||||
|
"/zxjp/mini/miniProgram/getUserInfoByToken"
|
||||||
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -59,7 +59,8 @@ public class MessageTemplateController {
|
|||||||
@PostMapping("/batchPublish")
|
@PostMapping("/batchPublish")
|
||||||
@ApiOperation("批量发布")
|
@ApiOperation("批量发布")
|
||||||
public ResponseResult<Boolean> batchPublishMessageTemplate(@RequestBody BatchPublishRequest request) {
|
public ResponseResult<Boolean> batchPublishMessageTemplate(@RequestBody BatchPublishRequest request) {
|
||||||
return ResponseResult.success(messageTemplateService.batchPublishMessageTemplate(request, CurrentUserHolder.getUser().getUserId()));
|
messageTemplateService.batchPublishMessageTemplate(request, CurrentUserHolder.getUser().getUserId());
|
||||||
|
return ResponseResult.success(Boolean.TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping("/getMessageTemplateList")
|
@PostMapping("/getMessageTemplateList")
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import com.alibaba.fastjson.JSONObject;
|
|||||||
import com.cool.store.context.PartnerUserHolder;
|
import com.cool.store.context.PartnerUserHolder;
|
||||||
import com.cool.store.dto.*;
|
import com.cool.store.dto.*;
|
||||||
import com.cool.store.dto.store.StoreUserPositionDTO;
|
import com.cool.store.dto.store.StoreUserPositionDTO;
|
||||||
|
import com.cool.store.dto.wx.MiniProgramFreeLoginDTO;
|
||||||
import com.cool.store.request.OpenApiStoreRequest;
|
import com.cool.store.request.OpenApiStoreRequest;
|
||||||
import com.cool.store.request.StoreCodeDTO;
|
import com.cool.store.request.StoreCodeDTO;
|
||||||
import com.cool.store.request.*;
|
import com.cool.store.request.*;
|
||||||
@@ -49,6 +50,8 @@ public class OpenApiController {
|
|||||||
StoreService storeService;
|
StoreService storeService;
|
||||||
@Resource
|
@Resource
|
||||||
MessageTemplateService messageTemplateService;
|
MessageTemplateService messageTemplateService;
|
||||||
|
@Resource
|
||||||
|
WechatMiniAppService wechatMiniAppService;
|
||||||
|
|
||||||
@PostMapping("/statusRefresh")
|
@PostMapping("/statusRefresh")
|
||||||
public ApiResponse<Boolean> statusRefresh(@RequestBody StatusRefreshDTO statusRefreshDTO){
|
public ApiResponse<Boolean> statusRefresh(@RequestBody StatusRefreshDTO statusRefreshDTO){
|
||||||
@@ -176,4 +179,10 @@ public class OpenApiController {
|
|||||||
public ApiResponse<Boolean> handleMessage(@RequestBody @Validated ThirdHandleMessageRequest request) {
|
public ApiResponse<Boolean> handleMessage(@RequestBody @Validated ThirdHandleMessageRequest request) {
|
||||||
return messageTemplateService.thirdHandleMessage(request);
|
return messageTemplateService.thirdHandleMessage(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ApiOperation("根据手机号获取短期token")
|
||||||
|
@PostMapping("/getShortTermToken")
|
||||||
|
public ApiResponse<String> getTokenByMobile(@RequestBody @Validated MiniProgramFreeLoginDTO param) {
|
||||||
|
return ApiResponse.success(wechatMiniAppService.getShortTermTokenByMobile(param));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import com.cool.store.response.ResponseResult;
|
|||||||
import com.cool.store.service.WechatMiniAppService;
|
import com.cool.store.service.WechatMiniAppService;
|
||||||
import com.cool.store.vo.PartnerUserInfoVO;
|
import com.cool.store.vo.PartnerUserInfoVO;
|
||||||
import io.swagger.annotations.Api;
|
import io.swagger.annotations.Api;
|
||||||
|
import io.swagger.annotations.ApiImplicitParam;
|
||||||
import io.swagger.annotations.ApiOperation;
|
import io.swagger.annotations.ApiOperation;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
@@ -65,4 +66,11 @@ public class MiniProgramAppController {
|
|||||||
PartnerUserInfoVO userInfoVO = PartnerUserHolder.getUser();
|
PartnerUserInfoVO userInfoVO = PartnerUserHolder.getUser();
|
||||||
return ResponseResult.success(userInfoVO);
|
return ResponseResult.success(userInfoVO);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ApiOperation("根据短期token获取用户信息")
|
||||||
|
@ApiImplicitParam(name = "token", value = "短期token", required = true, dataType = "String", paramType = "query")
|
||||||
|
@GetMapping("/getUserInfoByToken")
|
||||||
|
public ResponseResult<PartnerUserInfoVO> getUserInfoByToken(String token) {
|
||||||
|
return ResponseResult.success(wechatMiniAppService.getUserInfoByShortTermToken(token));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user