刘光辉
9 小时以前 06f314545ac3514d7ce28939920866ae8188d31c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
package jnpf.message.service;
 
import jnpf.base.UserInfo;
import jnpf.exception.DataException;
import jnpf.message.entity.MessageReceiveEntity;
import jnpf.message.entity.MessageTemplateConfigEntity;
import jnpf.message.mapper.DmsUpgradeMessageMapper;
import jnpf.message.model.DmsUpgradeMessage;
import jnpf.message.util.PushMessageUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.web.util.HtmlUtils;
import java.util.*;
 
/** DMS专属可靠站内信分支;不改变其他消息的发送行为。 */
@Slf4j
@Service
@RequiredArgsConstructor
public class DmsUpgradeMessageService {
    private final DmsUpgradeMessageMapper mapper;
 
    @Transactional(rollbackFor = Exception.class)
    public boolean send(DmsUpgradeMessage request) {
        if (request == null || blank(request.getTenantId()) || blank(request.getTaskId())
                || request.getToUserIds() == null || request.getToUserIds().isEmpty()
                || request.getToUserIds().stream().anyMatch(DmsUpgradeMessageService::blank))
            throw new DataException("升版通知缺少事件或接收人");
        List<MessageTemplateConfigEntity> templates = mapper.templates(request.getTenantId());
        if (templates.size() != 1) throw new DataException("请配置唯一且启用的站内信模板 dmsTemplateUpgrade");
        MessageTemplateConfigEntity template = templates.get(0);
        if (blank(template.getTitle()) || blank(template.getContent())) throw new DataException("升版消息模板标题或正文为空");
        String title = render(template.getTitle(), request.getParameters(), false);
        String content = render(template.getContent(), request.getParameters(), true);
        Map<String,MessageReceiveEntity> inserted = new LinkedHashMap<>();
        for (String user : new LinkedHashSet<>(request.getToUserIds())) {
            if (mapper.claimDelivery(request.getTenantId(), request.getTaskId(), user) == 0) continue;
            MessageReceiveEntity message = new MessageReceiveEntity();
            message.setId(UUID.randomUUID().toString().replace("-", "")); message.setUserId(user);
            message.setTitle(title); message.setBodyText(content); message.setType(3); message.setIsRead(0);
            message.setCreatorUserId(request.getActorId()); message.setCreatorTime(new Date());
            if (mapper.insertMessage(message, request.getTenantId()) != 1) throw new DataException("站内信保存失败");
            inserted.put(user, message);
        }
        UserInfo actor = new UserInfo(); actor.setTenantId(request.getTenantId()); actor.setUserId(request.getActorId());
        // 事务提交即为可靠送达;WebSocket仅刷新在线界面,不把离线或推送失败误判为丢消息。
        if (!inserted.isEmpty()) TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
            @Override public void afterCommit() {
                try { PushMessageUtil.pushMessage(inserted, actor, 3); }
                catch (RuntimeException error) { log.warn("升版站内信已保存,在线推送刷新失败", error); }
            }
        });
        return true;
    }
 
    static String render(String template, Map<String,String> values, boolean html) {
        java.util.regex.Matcher matcher = java.util.regex.Pattern.compile("\\{@([A-Za-z][A-Za-z0-9]*)}").matcher(template);
        StringBuffer result = new StringBuffer();
        while (matcher.find()) {
            String value = values == null ? null : values.get(matcher.group(1));
            if (value == null) throw new DataException("升版消息模板包含未知参数:" + matcher.group(1));
            matcher.appendReplacement(result, java.util.regex.Matcher.quoteReplacement(html ? HtmlUtils.htmlEscape(value) : value));
        }
        matcher.appendTail(result); return result.toString();
    }
    private static boolean blank(String value) { return value == null || value.isBlank(); }
}