fix notify fail

This commit is contained in:
Timi
2026-09-10 12:47:29 +08:00
parent cdf8a426e9
commit 66c13062b2
9 changed files with 159 additions and 144 deletions
@@ -20,11 +20,11 @@ public class Notify extends UUIDEntity {
/** 业务类型 */
private String bizType;
/** 提醒业务类型 */
/** 业务提醒类型 */
private String bizRemindedType;
/** 提醒业务 ID */
private String bizRemindedId;
/** 业务提醒查重键 */
private String bizRemindedKey;
/** 参数 */
private String args;
@@ -2,9 +2,8 @@ package com.imyeyu.api.modules.common.mapper;
import com.imyeyu.api.modules.common.entity.Notify;
import com.imyeyu.api.modules.common.vo.NotifyManagementItem;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import com.imyeyu.spring.mapper.BaseMapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
@@ -16,9 +15,8 @@ import java.util.List;
*/
public interface NotifyMapper extends BaseMapper<Notify, String> {
/// 查询业务提醒是否已创建
@Select("SELECT EXISTS (SELECT 1 FROM `notify` WHERE `biz_type` = #{bizType} AND `biz_reminded_type` = #{bizRemindedType} AND `biz_reminded_id` = #{bizRemindedId} AND `deleted_at` IS NULL)")
boolean existsByBizReminded(@Param("bizType") String bizType, @Param("bizRemindedType") String bizRemindedType, @Param("bizRemindedId") String bizRemindedId);
/// 原子创建业务提醒
int insertIfAbsent(Notify notify);
/// 分页查询管理端通知
///
@@ -14,13 +14,10 @@ import com.imyeyu.spring.service.BaseService;
*/
public interface NotifyService extends BaseService<Notify, String> {
/// 查询业务提醒是否已创建
/// 原子创建业务提醒,重复查重键不会创建通知详情
///
/// @param bizType 业务类型
/// @param bizRemindedType 被提醒业务类型
/// @param bizRemindedId 被提醒业务 ID
/// @return true 为已创建
boolean existsByBizReminded(String bizType, String bizRemindedType, String bizRemindedId);
/// @param notify 通知
void createIfAbsent(Notify notify);
/// 分页查询当前用户创建的通知
///
@@ -7,9 +7,8 @@ import com.imyeyu.api.modules.common.mapper.NotifyMapper;
import com.imyeyu.api.modules.common.service.NotifyDetailService;
import com.imyeyu.api.modules.common.service.NotifyService;
import com.imyeyu.api.modules.common.vo.NotifyManagementItem;
import com.imyeyu.api.modules.system.entity.Logger;
import com.imyeyu.api.modules.system.service.LoggerService;
import com.imyeyu.api.modules.user.service.UserLoginService;
import com.imyeyu.api.modules.system.audit.AuditOperation;
import com.imyeyu.api.modules.system.audit.OperationAudit;
import com.imyeyu.java.TimiJava;
import com.imyeyu.java.bean.timi.TimiCode;
import com.imyeyu.java.bean.timi.TimiException;
@@ -17,12 +16,13 @@ import com.imyeyu.spring.bean.Page;
import com.imyeyu.spring.bean.PageResult;
import com.imyeyu.spring.mapper.BaseMapper;
import com.imyeyu.spring.service.AbstractEntityService;
import com.imyeyu.utils.Time;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import java.util.UUID;
/**
* 通知服务实现
@@ -30,13 +30,10 @@ import java.util.List;
* @author 夜雨
* @since 2026-05-13 14:46
*/
@Slf4j
@Service
@RequiredArgsConstructor
public class NotifyServiceImplement extends AbstractEntityService<Notify, String> implements NotifyService {
private final LoggerService loggerService;
private final UserLoginService userLoginService;
private final NotifyDetailService detailService;
private final NotifyMapper mapper;
@@ -46,43 +43,53 @@ public class NotifyServiceImplement extends AbstractEntityService<Notify, String
return mapper;
}
@Override
public boolean existsByBizReminded(String bizType, String bizRemindedType, String bizRemindedId) {
return mapper.existsByBizReminded(bizType, bizRemindedType, bizRemindedId);
}
/// 创建通知并级联创建通知详情
///
/// @param notify 通知
@OperationAudit(AuditOperation.COMMON_NOTIFY_CREATE)
@Transactional(TimiServerDBConfig.ROLLBACKER)
@Override
public void create(Notify notify) {
Logger logger = new Logger(Logger.Module.COMMON, "COMMON_NOTIFY_CREATE");
try {
TimiException.required(notify, "未找到通知");
TimiException.required(notify.getDetailList(), "未找到通知详情列表");
prepareCreate(notify);
super.create(notify);
createDetails(notify);
}
notify.setCreatedBy(TimiJava.defaultIfEmpty(notify.getCreatedBy(), TimiJava.ZERO_UUID));
super.create(notify);
/// 原子创建业务提醒并级联创建通知详情
///
/// @param notify 通知
@OperationAudit(AuditOperation.COMMON_NOTIFY_CREATE)
@Transactional(TimiServerDBConfig.ROLLBACKER)
@Override
public void createIfAbsent(Notify notify) {
prepareCreate(notify);
if (mapper.insertIfAbsent(notify) == 0) {
return;
}
createDetails(notify);
}
for (NotifyDetail detail : notify.getDetailList()) {
detail.setNotifyId(notify.getId());
detail.setSendFrom(TimiJava.defaultIfEmpty(detail.getSendFrom(), TimiJava.ZERO_UUID));
detailService.create(detail);
}
logger.setLevel(Logger.Level.INFO);
logger.setResult(notify.getId());
} catch (TimiException e) {
logger.setLevel(Logger.Level.WARN);
logger.setException(e.getMessage());
throw e;
} catch (Exception e) {
logger.setLevel(Logger.Level.ERROR);
logger.setException(TimiJava.serializeThrowable(e));
log.error("创建通知失败", e);
throw new TimiException(TimiCode.ERROR, "创建通知失败", e);
} finally {
loggerService.create(logger);
/// 校验并补全通知创建字段
///
/// @param notify 通知
private void prepareCreate(Notify notify) {
TimiException.required(notify, "未找到通知");
TimiException.required(notify.getDetailList(), "未找到通知详情列表");
notify.setId(TimiJava.defaultIfEmpty(notify.getId(), UUID.randomUUID().toString()));
notify.setCreatedBy(TimiJava.defaultIfEmpty(notify.getCreatedBy(), TimiJava.ZERO_UUID));
notify.setCreatedAt(TimiJava.defaultIfNull(notify.getCreatedAt(), Time.now()));
notify.setUpdatedAt(null);
notify.setDeletedAt(null);
}
/// 创建通知详情
///
/// @param notify 通知
private void createDetails(Notify notify) {
for (NotifyDetail detail : notify.getDetailList()) {
detail.setNotifyId(notify.getId());
detail.setSendFrom(TimiJava.defaultIfEmpty(detail.getSendFrom(), TimiJava.ZERO_UUID));
detailService.create(detail);
}
}
@@ -120,6 +127,8 @@ public class NotifyServiceImplement extends AbstractEntityService<Notify, String
/// @param notifyId 通知 ID
/// @param userId 用户 ID
@Override
@Transactional(TimiServerDBConfig.ROLLBACKER)
@OperationAudit(AuditOperation.COMMON_NOTIFY_DELETE)
public void deleteManagement(String notifyId, String userId) {
getManagement(notifyId, userId);
delete(notifyId);
@@ -130,6 +139,7 @@ public class NotifyServiceImplement extends AbstractEntityService<Notify, String
/// @param notifyId 通知 ID
/// @param userId 用户 ID
@Override
@Transactional(TimiServerDBConfig.ROLLBACKER)
public void cancelManagement(String notifyId, String userId) {
getManagement(notifyId, userId);
cancel(notifyId);
@@ -138,32 +148,17 @@ public class NotifyServiceImplement extends AbstractEntityService<Notify, String
/// 删除通知并级联软删除通知详情
///
/// @param notifyId 通知 ID
@OperationAudit(AuditOperation.COMMON_NOTIFY_DELETE)
@Transactional(TimiServerDBConfig.ROLLBACKER)
@Override
public void delete(String notifyId) {
Logger logger = new Logger(Logger.Module.COMMON, "COMMON_NOTIFY_DELETE");
try {
TimiException.required(notifyId, "未找到通知 ID");
TimiException.required(get(notifyId), "未找到通知");
List<NotifyDetail> detailList = detailService.listByNotifyId(notifyId);
for (NotifyDetail detail : detailList) {
detailService.delete(detail.getId());
}
super.delete(notifyId);
logger.setLevel(Logger.Level.INFO);
logger.setResult(notifyId);
} catch (TimiException e) {
logger.setLevel(Logger.Level.WARN);
logger.setException(e.getMessage());
throw e;
} catch (Exception e) {
logger.setLevel(Logger.Level.ERROR);
logger.setException(TimiJava.serializeThrowable(e));
log.error("删除通知失败", e);
throw new TimiException(TimiCode.ERROR, "删除通知失败", e);
} finally {
loggerService.create(logger);
TimiException.required(notifyId, "未找到通知 ID");
TimiException.required(get(notifyId), "未找到通知");
List<NotifyDetail> detailList = detailService.listByNotifyId(notifyId);
for (NotifyDetail detail : detailList) {
detailService.delete(detail.getId());
}
super.delete(notifyId);
}
/// 取消通知中尚未成功发送的通知详情
@@ -103,20 +103,17 @@ public class GaoOrderReminderServiceImplement implements GaoOrderReminderService
log.warn("GAO 订单提醒跳过不存在的店长用户: storeId[{}], userId[{}]", storeId, manager.getUserId());
continue;
}
String remindedId = "%s:%s:%s:%s".formatted(LocalDate.now(ZoneId.of(ZONE_ID)), storeId, manager.getUserId(), reminderType);
if (notifyService.existsByBizReminded(NOTIFY_BIZ_TYPE, reminderType, remindedId)) {
continue;
}
String remindedKey = "%s:%s:%s:%s".formatted(LocalDate.now(ZoneId.of(ZONE_ID)), storeId, manager.getUserId(), reminderType);
long sendAt = Time.now();
Notify notify = new Notify();
notify.setBizType(NOTIFY_BIZ_TYPE);
notify.setBizRemindedType(reminderType);
notify.setBizRemindedId(remindedId);
notify.setBizRemindedKey(remindedKey);
notify.setDetailList(List.of(
createInternalDetail(manager.getUserId(), content, sendAt),
createSmsDetail(user.getPhoneNo(), customerNames, action, content, sendAt)
));
notifyService.create(notify);
notifyService.createIfAbsent(notify);
} catch (Exception e) {
log.error("GAO 订单提醒发送失败: storeId[{}], userId[{}], reminderType[{}]", storeId, manager.getUserId(), reminderType, e);
}
@@ -1,66 +1,51 @@
package com.imyeyu.api.modules.system.audit;
import com.imyeyu.api.modules.system.entity.Logger;
import lombok.AllArgsConstructor;
import lombok.Getter;
/// 操作审计编码
///
/// @author Codex
/// @since 2026-09-09
@Getter
@AllArgsConstructor
public enum AuditOperation {
GAO_CUSTOMER_PACKAGE_PURCHASE(Logger.Module.GAO, "GAO_CUSTOMER_PACKAGE_PURCHASE"),
GAO_CUSTOMER_PACKAGE_CANCEL(Logger.Module.GAO, "GAO_CUSTOMER_PACKAGE_CANCEL"),
GAO_SALES_ORDER_PAYMENT_RECEIVE(Logger.Module.GAO, "GAO_SALES_ORDER_PAYMENT_RECEIVE"),
GAO_SALES_ORDER_PAYMENT_VERIFY(Logger.Module.GAO, "GAO_SALES_ORDER_PAYMENT_VERIFY"),
GAO_SALES_ORDER_REFUND(Logger.Module.GAO, "GAO_SALES_ORDER_REFUND"),
GAO_SALES_ORDER_CONFIRM_NO_REFUND(Logger.Module.GAO, "GAO_SALES_ORDER_CONFIRM_NO_REFUND"),
GAO_SALES_ORDER_FUND_REVOKE(Logger.Module.GAO, "GAO_SALES_ORDER_FUND_REVOKE"),
GAO_ORDER_FULFILLMENT_CREATE(Logger.Module.GAO, "GAO_ORDER_FULFILLMENT_CREATE"),
GAO_ORDER_FULFILLMENT_PREPARE_STOCK(Logger.Module.GAO, "GAO_ORDER_FULFILLMENT_PREPARE_STOCK"),
GAO_ORDER_FULFILLMENT_VERIFY(Logger.Module.GAO, "GAO_ORDER_FULFILLMENT_VERIFY"),
GAO_ORDER_FULFILLMENT_REJECT(Logger.Module.GAO, "GAO_ORDER_FULFILLMENT_REJECT"),
GAO_ORDER_FULFILLMENT_CANCEL(Logger.Module.GAO, "GAO_ORDER_FULFILLMENT_CANCEL"),
GAO_ORDER_FULFILLMENT_REVOKE(Logger.Module.GAO, "GAO_ORDER_FULFILLMENT_REVOKE"),
GAO_PACKAGE_CONFIG_CREATE(Logger.Module.GAO, "GAO_PACKAGE_CONFIG_CREATE"),
GAO_PACKAGE_CONFIG_UPDATE(Logger.Module.GAO, "GAO_PACKAGE_CONFIG_UPDATE"),
GAO_PACKAGE_CONFIG_DELETE(Logger.Module.GAO, "GAO_PACKAGE_CONFIG_DELETE"),
GAO_PRODUCT_CATEGORY_SORT(Logger.Module.GAO, "GAO_PRODUCT_CATEGORY_SORT"),
GAO_PRODUCT_CATEGORY_CREATE(Logger.Module.GAO, "GAO_PRODUCT_CATEGORY_CREATE"),
GAO_PRODUCT_CATEGORY_UPDATE(Logger.Module.GAO, "GAO_PRODUCT_CATEGORY_UPDATE"),
GAO_PRODUCT_CATEGORY_DISABLE(Logger.Module.GAO, "GAO_PRODUCT_CATEGORY_DISABLE"),
GAO_PRODUCT_CREATE(Logger.Module.GAO, "GAO_PRODUCT_CREATE"),
GAO_PRODUCT_UPDATE(Logger.Module.GAO, "GAO_PRODUCT_UPDATE"),
GAO_PRODUCT_DISABLE(Logger.Module.GAO, "GAO_PRODUCT_DISABLE"),
GAO_PRODUCT_STOCK_INITIAL_IN(Logger.Module.GAO, "GAO_PRODUCT_STOCK_INITIAL_IN"),
GAO_PRODUCT_STOCK_MANUAL_IN(Logger.Module.GAO, "GAO_PRODUCT_STOCK_MANUAL_IN"),
GAO_PRODUCT_STOCK_MANUAL_OUT(Logger.Module.GAO, "GAO_PRODUCT_STOCK_MANUAL_OUT"),
GAO_PRODUCT_STOCK_MANUAL_REVOKE(Logger.Module.GAO, "GAO_PRODUCT_STOCK_MANUAL_REVOKE"),
GAO_PRODUCT_STOCK_STOCKTAKE_GAIN(Logger.Module.GAO, "GAO_PRODUCT_STOCK_STOCKTAKE_GAIN"),
GAO_PRODUCT_STOCK_STOCKTAKE_LOSS(Logger.Module.GAO, "GAO_PRODUCT_STOCK_STOCKTAKE_LOSS"),
GAO_SALES_ORDER_DIRECT_PRODUCT_CREATE(Logger.Module.GAO, "GAO_SALES_ORDER_DIRECT_PRODUCT_CREATE"),
GAO_SALES_ORDER_UPDATE(Logger.Module.GAO, "GAO_SALES_ORDER_UPDATE"),
GAO_SALES_ORDER_CANCEL(Logger.Module.GAO, "GAO_SALES_ORDER_CANCEL");
COMMON_NOTIFY_CREATE(Logger.Module.COMMON),
COMMON_NOTIFY_DELETE(Logger.Module.COMMON),
GAO_CUSTOMER_PACKAGE_PURCHASE(Logger.Module.GAO),
GAO_CUSTOMER_PACKAGE_CANCEL(Logger.Module.GAO),
GAO_SALES_ORDER_PAYMENT_RECEIVE(Logger.Module.GAO),
GAO_SALES_ORDER_PAYMENT_VERIFY(Logger.Module.GAO),
GAO_SALES_ORDER_REFUND(Logger.Module.GAO),
GAO_SALES_ORDER_CONFIRM_NO_REFUND(Logger.Module.GAO),
GAO_SALES_ORDER_FUND_REVOKE(Logger.Module.GAO),
GAO_ORDER_FULFILLMENT_CREATE(Logger.Module.GAO),
GAO_ORDER_FULFILLMENT_PREPARE_STOCK(Logger.Module.GAO),
GAO_ORDER_FULFILLMENT_VERIFY(Logger.Module.GAO),
GAO_ORDER_FULFILLMENT_REJECT(Logger.Module.GAO),
GAO_ORDER_FULFILLMENT_CANCEL(Logger.Module.GAO),
GAO_ORDER_FULFILLMENT_REVOKE(Logger.Module.GAO),
GAO_PACKAGE_CONFIG_CREATE(Logger.Module.GAO),
GAO_PACKAGE_CONFIG_UPDATE(Logger.Module.GAO),
GAO_PACKAGE_CONFIG_DELETE(Logger.Module.GAO),
GAO_PRODUCT_CATEGORY_SORT(Logger.Module.GAO),
GAO_PRODUCT_CATEGORY_CREATE(Logger.Module.GAO),
GAO_PRODUCT_CATEGORY_UPDATE(Logger.Module.GAO),
GAO_PRODUCT_CATEGORY_DISABLE(Logger.Module.GAO),
GAO_PRODUCT_CREATE(Logger.Module.GAO),
GAO_PRODUCT_UPDATE(Logger.Module.GAO),
GAO_PRODUCT_DISABLE(Logger.Module.GAO),
GAO_PRODUCT_STOCK_INITIAL_IN(Logger.Module.GAO),
GAO_PRODUCT_STOCK_MANUAL_IN(Logger.Module.GAO),
GAO_PRODUCT_STOCK_MANUAL_OUT(Logger.Module.GAO),
GAO_PRODUCT_STOCK_MANUAL_REVOKE(Logger.Module.GAO),
GAO_PRODUCT_STOCK_STOCKTAKE_GAIN(Logger.Module.GAO),
GAO_PRODUCT_STOCK_STOCKTAKE_LOSS(Logger.Module.GAO),
GAO_SALES_ORDER_DIRECT_PRODUCT_CREATE(Logger.Module.GAO),
GAO_SALES_ORDER_UPDATE(Logger.Module.GAO),
GAO_SALES_ORDER_CANCEL(Logger.Module.GAO);
private final Logger.Module module;
private final String code;
AuditOperation(Logger.Module module, String code) {
this.module = module;
this.code = code;
}
/// 获取日志模块
///
/// @return 日志模块
public Logger.Module getModule() {
return module;
}
/// 获取操作编码
///
/// @return 操作编码
public String getCode() {
return code;
}
final Logger.Module module;
}
@@ -1,6 +1,7 @@
package com.imyeyu.api.modules.system.audit;
import com.imyeyu.api.modules.system.entity.Logger;
import com.imyeyu.java.TimiJava;
import com.imyeyu.java.bean.timi.TimiException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@@ -30,7 +31,7 @@ public class OperationAuditAspect {
/// 执行并记录操作审计
///
/// @param joinPoint 连接点
/// @param joinPoint 连接点
/// @param operationAudit 审计配置
/// @return 业务返回值
/// @throws Throwable 业务异常
@@ -38,7 +39,7 @@ public class OperationAuditAspect {
public Object around(ProceedingJoinPoint joinPoint, OperationAudit operationAudit) throws Throwable {
AuditOperation operation = operationAudit.value();
Object[] arguments = joinPoint.getArgs();
Logger logger = new Logger(operation.getModule(), operation.getCode());
Logger logger = new Logger(operation.getModule(), operation.name());
logger.setContent(payloadSerializer.serializeArguments(arguments));
long startNanos = System.nanoTime();
try {
@@ -56,9 +57,9 @@ public class OperationAuditAspect {
throw e;
} catch (Throwable e) {
logger.setLevel(Logger.Level.ERROR);
logger.setException(serializeThrowable(e));
logger.setException(TimiJava.serializeThrowable(e));
logger.setDuration(duration(startNanos));
log.error("业务操作失败: {}", operation.getCode(), e);
log.error("业务操作失败: {}", operation.name(), e);
record(logger);
throw e;
}
@@ -79,12 +80,4 @@ public class OperationAuditAspect {
}
return (int) Math.max(0L, millis);
}
private String serializeThrowable(Throwable throwable) {
java.io.StringWriter stringWriter = new java.io.StringWriter();
try (java.io.PrintWriter printWriter = new java.io.PrintWriter(stringWriter)) {
throwable.printStackTrace(printWriter);
}
return stringWriter.toString();
}
}