package cn.iocoder.yudao.module.mp.service.message; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.util.json.JsonUtils; import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; import cn.iocoder.yudao.module.mp.controller.admin.message.vo.template.MpMessageTemplateListReqVO; import cn.iocoder.yudao.module.mp.controller.admin.message.vo.template.MpMessageTemplateSendReqVO; import cn.iocoder.yudao.module.mp.dal.dataobject.account.MpAccountDO; import cn.iocoder.yudao.module.mp.dal.dataobject.message.MpMessageTemplateDO; import cn.iocoder.yudao.module.mp.dal.dataobject.user.MpUserDO; import cn.iocoder.yudao.module.mp.dal.mysql.message.MpMessageTemplateMapper; import cn.iocoder.yudao.module.mp.framework.mp.core.MpServiceFactory; import cn.iocoder.yudao.module.mp.service.account.MpAccountService; import cn.iocoder.yudao.module.mp.service.user.MpUserService; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.mp.bean.template.WxMpTemplate; import me.chanjar.weixin.mp.bean.template.WxMpTemplateData; import me.chanjar.weixin.mp.bean.template.WxMpTemplateMessage; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import java.util.ArrayList; import java.util.List; import java.util.Map; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; import static cn.iocoder.yudao.module.mp.enums.ErrorCodeConstants.*; /** * 公众号模版消息 Service 实现类 * * @author dengsl */ @Service @Validated @Slf4j public class MpMessageTemplateServiceImpl implements MpMessageTemplateService { @Resource @Lazy // 延迟加载,为了解决延迟加载 private MpServiceFactory mpServiceFactory; @Resource private MpMessageTemplateMapper messageTemplateMapper; @Resource private MpAccountService mpAccountService; @Resource private MpUserService mpUserService; @Override public void deleteMessageTemplate(Long id) { // 校验存在 MpMessageTemplateDO template = validateMsgTemplateExists(id); // 第一步,删除模板到公众号平台 try { mpServiceFactory.getRequiredMpService(template.getAppId()) .getTemplateMsgService().delPrivateTemplate(template.getTemplateId()); } catch (WxErrorException e) { throw exception(MESSAGE_TEMPLATE_DELETE_FAIL, e.getError().getErrorMsg()); } // 第二步,删除模板到数据库 messageTemplateMapper.deleteById(id); } private MpMessageTemplateDO validateMsgTemplateExists(Long id) { MpMessageTemplateDO template = messageTemplateMapper.selectById(id); if (template == null) { throw exception(MESSAGE_TEMPLATE_NOT_EXISTS); } return template; } @Override public MpMessageTemplateDO getMessageTemplate(Long id) { return messageTemplateMapper.selectById(id); } @Override public List getMessageTemplateList(MpMessageTemplateListReqVO listReqVO) { return messageTemplateMapper.selectList(listReqVO); } @Override @Transactional(rollbackFor = Exception.class) public void syncMessageTemplate(Long accountId) { MpAccountDO account = mpAccountService.getRequiredAccount(accountId); // 第一步,从公众号平台获取最新的模板列表 List wxTemplates; try { wxTemplates = mpServiceFactory.getRequiredMpService(accountId) .getTemplateMsgService().getAllPrivateTemplate(); } catch (WxErrorException e) { throw exception(MESSAGE_TEMPLATE_SYNC_FAIL, e.getError().getErrorMsg()); } // 第二步,合并更新回自己的数据库 Map templateMap = convertMap( messageTemplateMapper.selectList(new LambdaQueryWrapperX() .eq(MpMessageTemplateDO::getAppId, account.getAppId())), MpMessageTemplateDO::getTemplateId); wxTemplates.forEach(wxTemplate -> { MpMessageTemplateDO template = templateMap.remove(wxTemplate.getTemplateId()); // 情况一,不存在,新增 if (template == null) { template = new MpMessageTemplateDO().setAccountId(account.getId()).setAppId(account.getAppId()) .setTemplateId(wxTemplate.getTemplateId()).setTitle(wxTemplate.getTitle()) .setContent(wxTemplate.getContent()).setExample(wxTemplate.getExample()) .setPrimaryIndustry(wxTemplate.getPrimaryIndustry()).setDeputyIndustry(wxTemplate.getDeputyIndustry()); messageTemplateMapper.insert(template); return; } // 情况二,存在,则更新 messageTemplateMapper.updateById(new MpMessageTemplateDO().setId(template.getId()) .setTitle(wxTemplate.getTitle()).setContent(wxTemplate.getContent()).setExample(wxTemplate.getExample()) .setPrimaryIndustry(wxTemplate.getPrimaryIndustry()).setDeputyIndustry(wxTemplate.getDeputyIndustry())); }); // 情况三,部分模板已经不存在了,删除 if (CollUtil.isNotEmpty(templateMap)) { messageTemplateMapper.deleteByIds(convertList(templateMap.values(), MpMessageTemplateDO::getId)); } } @Override public void sendMessageTempalte(MpMessageTemplateSendReqVO sendReqVO) { // 获得关联信息 MpUserDO user = mpUserService.getRequiredUser(sendReqVO.getUserId()); MpMessageTemplateDO template = validateMsgTemplateExists(sendReqVO.getId()); // 发送模版消息 WxMpTemplateMessage templateMessage = buildTemplateMessage(template, user, sendReqVO); try { mpServiceFactory.getRequiredMpService(template.getAppId()) .getTemplateMsgService().sendTemplateMsg(templateMessage); } catch (WxErrorException e) { throw exception(MESSAGE_TEMPLATE_SEND_FAIL, e.getError().getErrorMsg()); } // 不用记录 MpMessageDO 记录,因为,微信会主动推送,可见文档 https://developers.weixin.qq.com/doc/service/guide/product/template_message/Template_Message_Interface.html } private WxMpTemplateMessage buildTemplateMessage(MpMessageTemplateDO msgTemplateDO, MpUserDO user, MpMessageTemplateSendReqVO sendReqVO) { List data = new ArrayList<>(); WxMpTemplateMessage.WxMpTemplateMessageBuilder builder = WxMpTemplateMessage.builder() .templateId(msgTemplateDO.getTemplateId()) .data(data) .toUser(user.getOpenid()); // 设置跳转链接 if (StrUtil.isNotBlank(sendReqVO.getUrl())) { builder.url(sendReqVO.getUrl()); } // 设置小程序跳转 if (StrUtil.isNotBlank(sendReqVO.getMiniprogram())) { // https://developers.weixin.qq.com/doc/service/api/notify/template/api_sendtemplatemessage.html#Body__miniprogram builder.miniProgram(JsonUtils.parseObject(sendReqVO.getMiniprogram(), WxMpTemplateMessage.MiniProgram.class)); } // 设置模板数据 if (sendReqVO.getData() != null) { sendReqVO.getData().forEach((key, value) -> data.add(new WxMpTemplateData(key, value))); } return builder.build(); } }