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);
BizAssertions.assertNotNull(button, "找不到对应的预设按钮, request={}", JSON.toJSONString(request));
ArrayList<Card> updates = new ArrayList<>(cards.size());
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);
CardLogger updateCardLogger = cardLoggers.createLogger(CardRequestContext.create(request));
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);
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);
cardLogger.reloadAndLogCards("presetButtonPressed:mq:success");
updateCardLogger.reloadAndLogCards("presetButtonPressed:mq:success");
}
}

View File

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

View File

@ -1,5 +1,10 @@
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
*/
@ -9,6 +14,13 @@ public interface CardLogger {
reloadAndLogCards(operationContext, null);
}
default void addCards(Collection<Card> cards) {
if (CollectionUtils.isNotEmpty(cards))
cards.forEach(this::addCard);
}
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 java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
@ -24,35 +25,51 @@ public class CardLoggers {
private final CardLogDao cardLogDao;
private final CardProps cardProps;
public CardLogger createLogger(CardRequestContext<?> requestContext, List<Card> cards) {
return (operationContext, exception) -> {
if (!cardProps.isEnableCardLog()) return;
ArrayList<CardLog> logs = new ArrayList<>(cards.size());
for (Card card : cardDao.reloadCards(cards)) {
CardLog log = new CardLog();
logs.add(log);
log.setSenderPersonId(card.getSenderPersonId());
log.setSenderOuId(card.getSenderOuId());
log.setSenderWorkspaceId(card.getSenderWorkspaceId());
log.setReceiverPersonId(card.getReceiverPersonId());
log.setReceiverOuId(card.getReceiverOuId());
log.setReceiverWorkspaceId(card.getReceiverWorkspaceId());
log.setReceiverAppType(card.getReceiverAppType());
log.setBizState(card.getBizState());
log.setCardState(card.getCardState());
log.setIdentityCode(card.getIdentityCode());
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());
public CardLogger createLogger(CardRequestContext<?> requestContext) {
return createLogger(requestContext, Collections.emptyList());
}
public CardLogger createLogger(CardRequestContext<?> requestContext, List<Card> initCards) {
return new CardLogger() {
private final List<Card> cards = new ArrayList<>(initCards);
@Override
public void reloadAndLogCards(String operationContext, Exception exception) {
if (!cardProps.isEnableCardLog()) return;
ArrayList<CardLog> logs = new ArrayList<>();
for (Card card : cardDao.reloadCards(cards)) {
CardLog log = new CardLog();
logs.add(log);
log.setSenderPersonId(card.getSenderPersonId());
log.setSenderOuId(card.getSenderOuId());
log.setSenderWorkspaceId(card.getSenderWorkspaceId());
log.setReceiverPersonId(card.getReceiverPersonId());
log.setReceiverOuId(card.getReceiverOuId());
log.setReceiverWorkspaceId(card.getReceiverWorkspaceId());
log.setReceiverAppType(card.getReceiverAppType());
log.setBizState(card.getBizState());
log.setCardState(card.getCardState());
log.setIdentityCode(card.getIdentityCode());
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 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()));

View File

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

View File

@ -78,19 +78,31 @@ public class CardDao extends ServiceImpl<CardMapper, Card> {
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) {
if (CollectionUtils.isEmpty(cards))
return Collections.emptyList();
return DeleteAwareInterceptor.execute(()-> listByIds(collectCardIds(cards)));
return DeleteAwareInterceptor.execute(()-> listByIds(collectCardIdsSorted(cards)));
}
public void deleteCards(List<Card> cards) {
if (CollectionUtils.isEmpty(cards))
return;
removeByIds(collectCardIds(cards));
removeByIds(collectCardIdsSorted(cards));
}
private static List<Long> collectCardIds(List<Card> cards) {
return cards.stream().map(BaseEntityExt::getId).collect(toList());
private static List<Long> collectCardIdsSorted(List<Card> cards) {
return cards.stream()
.map(BaseEntityExt::getId)
.sorted()
.collect(toList());
}
}