REQ-3201: 预设按钮幂等控制

This commit is contained in:
yanglin 2024-12-19 12:27:11 +08:00
parent 75f97b9c10
commit 0b31cc123f
7 changed files with 110 additions and 49 deletions

View File

@ -174,27 +174,31 @@ public class CardManager {
} }
MessageTemplateButtonV3 button = templateModel.findPresetButton(request.getPresetButtonType()).orElse(null); MessageTemplateButtonV3 button = templateModel.findPresetButton(request.getPresetButtonType()).orElse(null);
BizAssertions.assertNotNull(button, "找不到对应的预设按钮, request={}", JSON.toJSONString(request)); BizAssertions.assertNotNull(button, "找不到对应的预设按钮, request={}", JSON.toJSONString(request));
ArrayList<Card> updates = new ArrayList<>(cards.size()); CardLogger updateCardLogger = cardLoggers.createLogger(CardRequestContext.create(request));
for (Card card : cards) {
CardButtonStates buttonStates = CardButtonStates.create(card.getButtonStates());
//noinspection DataFlowIssue
buttonStates.setActionPerformed(button.getCode());
Card update = new Card();
update.setId(card.getId());
update.setButtonStates(buttonStates.getStates());
update.setBizState(CardBizState.COMPLETED);
update.setCardState(CardState.COMPLETED);
updates.add(update);
}
CardLogger cardLogger = cardLoggers.createLogger(CardRequestContext.create(request), cards);
execTransactional(() -> { execTransactional(() -> {
ArrayList<Card> updates = new ArrayList<>(cards.size());
for (Card card : cardDao.getCardsForUpdate(cards)) {
if (card.getCardState() == CardState.COMPLETED)
continue;
updateCardLogger.addCard(card);
CardButtonStates buttonStates = CardButtonStates.create(card.getButtonStates());
//noinspection DataFlowIssue
buttonStates.setActionPerformed(button.getCode());
Card update = new Card();
update.setId(card.getId());
update.setButtonStates(buttonStates.getStates());
update.setBizState(CardBizState.fromPresetButton(request.getPresetButtonType()));
update.setCardState(CardState.COMPLETED);
updates.add(update);
}
BizAssertions.assertNotEmpty(updates, "卡片已是终态, 无法'{}'", request.getPresetButtonType().getDesc());
cardDao.updateBatchById(updates); cardDao.updateBatchById(updates);
rebuildCardContent(templateModel, cards); rebuildCardContent(templateModel, cards);
cardLogger.reloadAndLogCards("presetButtonPressed:enqueue"); updateCardLogger.reloadAndLogCards("presetButtonPressed:enqueue");
}); });
if (updateMessages("presetButtonPressed", cardLogger, cards)) { if (updateMessages("presetButtonPressed", updateCardLogger, cards)) {
cardBroadcaster.firePresetButtonPressed(cards, request); cardBroadcaster.firePresetButtonPressed(cards, request);
cardLogger.reloadAndLogCards("presetButtonPressed:mq:success"); updateCardLogger.reloadAndLogCards("presetButtonPressed:mq:success");
} }
} }

View File

@ -57,7 +57,7 @@ class CardParser {
bizBody.setUpdateTime(System.currentTimeMillis()); bizBody.setUpdateTime(System.currentTimeMillis());
CardStateInfo stateInfo = card.getStateInfo(); CardStateInfo stateInfo = card.getStateInfo();
bizBody.setStateImage(CardStateImageConfigs bizBody.setStateImage(CardStateImageConfigs
.create(template.getStateImageConfigs()) .create(template.determineStateImageConfigs())
.determineStateImage(stateInfo.getBizState())); .determineStateImage(stateInfo.getBizState()));
if (StringUtils.isNotBlank(card.getSubtitle())) { if (StringUtils.isNotBlank(card.getSubtitle())) {
GeneralMessagePushVO.Subtitle subtitle = new GeneralMessagePushVO.Subtitle(); GeneralMessagePushVO.Subtitle subtitle = new GeneralMessagePushVO.Subtitle();

View File

@ -1,5 +1,10 @@
package cn.axzo.msg.center.message.service.card.log; package cn.axzo.msg.center.message.service.card.log;
import cn.axzo.msg.center.domain.entity.Card;
import org.apache.commons.collections4.CollectionUtils;
import java.util.Collection;
/** /**
* @author yanglin * @author yanglin
*/ */
@ -9,6 +14,13 @@ public interface CardLogger {
reloadAndLogCards(operationContext, null); reloadAndLogCards(operationContext, null);
} }
default void addCards(Collection<Card> cards) {
if (CollectionUtils.isNotEmpty(cards))
cards.forEach(this::addCard);
}
void reloadAndLogCards(String operationContext, Exception e); void reloadAndLogCards(String operationContext, Exception e);
void addCard(Card card);
} }

View File

@ -11,6 +11,7 @@ import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
/** /**
@ -24,35 +25,51 @@ public class CardLoggers {
private final CardLogDao cardLogDao; private final CardLogDao cardLogDao;
private final CardProps cardProps; private final CardProps cardProps;
public CardLogger createLogger(CardRequestContext<?> requestContext, List<Card> cards) { public CardLogger createLogger(CardRequestContext<?> requestContext) {
return (operationContext, exception) -> { return createLogger(requestContext, Collections.emptyList());
if (!cardProps.isEnableCardLog()) return; }
ArrayList<CardLog> logs = new ArrayList<>(cards.size());
for (Card card : cardDao.reloadCards(cards)) { public CardLogger createLogger(CardRequestContext<?> requestContext, List<Card> initCards) {
CardLog log = new CardLog(); return new CardLogger() {
logs.add(log);
log.setSenderPersonId(card.getSenderPersonId()); private final List<Card> cards = new ArrayList<>(initCards);
log.setSenderOuId(card.getSenderOuId());
log.setSenderWorkspaceId(card.getSenderWorkspaceId()); @Override
log.setReceiverPersonId(card.getReceiverPersonId()); public void reloadAndLogCards(String operationContext, Exception exception) {
log.setReceiverOuId(card.getReceiverOuId()); if (!cardProps.isEnableCardLog()) return;
log.setReceiverWorkspaceId(card.getReceiverWorkspaceId()); ArrayList<CardLog> logs = new ArrayList<>();
log.setReceiverAppType(card.getReceiverAppType()); for (Card card : cardDao.reloadCards(cards)) {
log.setBizState(card.getBizState()); CardLog log = new CardLog();
log.setCardState(card.getCardState()); logs.add(log);
log.setIdentityCode(card.getIdentityCode()); log.setSenderPersonId(card.getSenderPersonId());
log.setTemplateCode(card.getTemplateCode()); log.setSenderOuId(card.getSenderOuId());
log.setBizMessageId(card.getBizMessageId()); log.setSenderWorkspaceId(card.getSenderWorkspaceId());
log.setBizCode(card.getBizCode()); log.setReceiverPersonId(card.getReceiverPersonId());
log.setSubBizCode(card.getSubBizCode()); log.setReceiverOuId(card.getReceiverOuId());
log.setContext(operationContext); log.setReceiverWorkspaceId(card.getReceiverWorkspaceId());
log.setBatchNo(requestContext.getBatchNo()); log.setReceiverAppType(card.getReceiverAppType());
log.setCardContent(card.getCardContent()); log.setBizState(card.getBizState());
log.setError(exception == null ? "" : Throwables.getStackTraceAsString(exception)); log.setCardState(card.getCardState());
log.addLogContent("request", requestContext.getRequest()); log.setIdentityCode(card.getIdentityCode());
log.addLogContent("isCardDelete", card.getIsDelete()); log.setTemplateCode(card.getTemplateCode());
log.setBizMessageId(card.getBizMessageId());
log.setBizCode(card.getBizCode());
log.setSubBizCode(card.getSubBizCode());
log.setContext(operationContext);
log.setBatchNo(requestContext.getBatchNo());
log.setCardContent(card.getCardContent());
log.setError(exception == null ? "" : Throwables.getStackTraceAsString(exception));
log.addLogContent("request", requestContext.getRequest());
log.addLogContent("isCardDelete", card.getIsDelete());
}
cardLogDao.saveBatch(logs);
} }
cardLogDao.saveBatch(logs);
@Override
public void addCard(Card card) {
cards.add(card);
}
}; };
} }

View File

@ -34,6 +34,18 @@ public enum CardBizState implements CodeDefinition<String> {
private final boolean imageConfigurable; private final boolean imageConfigurable;
private final String defaultImageUrl; private final String defaultImageUrl;
public static CardBizState fromPresetButton(PresetButtonType presetButtonType) {
switch (presetButtonType) {
case AGREE:
return AGREED;
case REJECT:
return REJECTED;
case REVOKE:
return REVOKED;
default:
throw new IllegalArgumentException("不支持的预设按钮类型: " + presetButtonType);
}
}
private static Map<String, CardBizState> codeMap = Arrays.stream(values()).collect(Collectors.toMap(CardBizState::name, Function.identity())); private static Map<String, CardBizState> codeMap = Arrays.stream(values()).collect(Collectors.toMap(CardBizState::name, Function.identity()));

View File

@ -137,6 +137,10 @@ public class ParsedTemplateV3 {
*/ */
private List<MessageChannel> channels; private List<MessageChannel> channels;
public List<StateImageConfig> determineStateImageConfigs() {
return stateImageConfigs == null ? Collections.emptyList() : stateImageConfigs;
}
public List<AppTypeEnum> parseImAppTypes() { public List<AppTypeEnum> parseImAppTypes() {
if (CollectionUtils.isEmpty(appVersionConfigs)) if (CollectionUtils.isEmpty(appVersionConfigs))
return Collections.emptyList(); return Collections.emptyList();

View File

@ -78,19 +78,31 @@ public class CardDao extends ServiceImpl<CardMapper, Card> {
updateBatchById(updates); updateBatchById(updates);
} }
public List<Card> getCardsForUpdate(List<Card> cards) {
if (CollectionUtils.isEmpty(cards))
return Collections.emptyList();
return lambdaQuery()
.in(Card::getId, collectCardIdsSorted(cards))
.last("FOR UPDATE")
.list();
}
public List<Card> reloadCards(List<Card> cards) { public List<Card> reloadCards(List<Card> cards) {
if (CollectionUtils.isEmpty(cards)) if (CollectionUtils.isEmpty(cards))
return Collections.emptyList(); return Collections.emptyList();
return DeleteAwareInterceptor.execute(()-> listByIds(collectCardIds(cards))); return DeleteAwareInterceptor.execute(()-> listByIds(collectCardIdsSorted(cards)));
} }
public void deleteCards(List<Card> cards) { public void deleteCards(List<Card> cards) {
if (CollectionUtils.isEmpty(cards)) if (CollectionUtils.isEmpty(cards))
return; return;
removeByIds(collectCardIds(cards)); removeByIds(collectCardIdsSorted(cards));
} }
private static List<Long> collectCardIds(List<Card> cards) { private static List<Long> collectCardIdsSorted(List<Card> cards) {
return cards.stream().map(BaseEntityExt::getId).collect(toList()); return cards.stream()
.map(BaseEntityExt::getId)
.sorted()
.collect(toList());
} }
} }