PRIMETON TECHNOLOGIES, LTD. 普元信息技术股份有限公司

消息中心使用说明

No part of this document may be reproduced, stored in any electronic retrieval system, or transmitted in any form or by any means, mechanical, photocopying, recording, otherwise, without the written permission of the copyright owner.

[TOC]

# 消息发送方式

# 流程触发事件调用发送消息

消息中心提供对外发送消息接口,通过配置触发事件来实现发送消息功能

# 消息发送接口详情

接口path:/api/bfp/messagecenter/send-message

请求方式:post

参数:

参数属性名 参数类型 参数说明
messageContent String 发送消息内容,json格式数据
{”content“:”消息体“,"subTitle":"消息标题"}
sendTarget String 发送目标,json格式数据{type:data},
type为组织、角色、用户(org,role,emp)。data为对应类型id,同一类型多个值时逗号分隔
{"org":"orgId1,orgId2","role":"roleId1,roleId2","emp":"empId1,empId2"}
messageChannel String 消息发送渠道
邮件:com.primeton.gocom.bfp.message.sender.service.impl.EmailChannelSendServiceImpl
企业微信:com.primeton.gocom.bfp.message.sender.service.impl.WecomChannelSendServiceImpl
钉钉:com.primeton.gocom.bfp.message.sender.service.impl.DingChannelSendServiceImpl
isChildOrg boolean 是否给子机构发送 默认false

# 流程消息配置自动发送消息

# 配置员工相关信息

流程发送消息时通过获取员工信息中个人信息-电话来发送钉钉、企业微信,通过个人信息-邮件来发送邮件消息。流程环节若配置任务通知,但环节参与者对应员工信息未填写电话或邮件时,消息发送失败。

image-20230117162408048

# 配置消息模板

流程消息配置方式需要先配置流程对应消息模板,流程消息模板再与流程环节进行关联。

编辑模板时绑定流程即可配置对应流程相关表单属性变量,消息中心发送内容时会进行变量值替换

image-20230117163853860

image-20230117164019036

# 流程环节配置任务通知

AFCenter业务配置中可将已创建消息模板与流程活动相关联,流程引擎在启动当前环节任务后会自动触发任务通知,消息中心针对流程环节已开启的消息渠道发送对应模板消息。

渠道只能选择对应类型消息模板,渠道支持多选(企业微信和钉钉只支持二选一)

image-20230106151517655

# ide开发中心配置人工活动任务通知

ide中人工活动配置任务通知和在afcenter中业务配置添加活动任务通知数据相通,即都是为该环节配置消息通知。

image-20230117163603879

# 流程人工环节配置参与者

配置了任务通知的人工环节需要配置对应参与者,该参与者对应员工信息中需要有消息渠道所需信息(手机号、邮箱)

image-20230117164210160

# 人工活动环节启动自动发送消息

当流程启动到配置了任务通知的环节时会触发调用消息中心对参与者发送消息。

image-20230117164844931

# 消息渠道

产品约定企业微信和钉钉配置文件中只能开启一个,不能同时配置并enabled=true

# 邮件

消息中心发送邮件消息时,需要在主配置文件application.properties文件中配置邮件相关属性

bfp.email.enabled=true
#配置smtp服务器地址
bfp.email.account.host=smtp.qq.com
#配置smtp服务端口号
bfp.email.account.port=465
#设置需要用户名密码验证
bfp.email.account.auth=true
#设置邮箱地址
bfp.email.account.from=
#设置邮箱用户名,一般为域名前的部分
bfp.email.account.user=
#设置用户登陆密码,使用qq邮箱时填写qq邮箱单独生成的授权码
bfp.email.account.pass=
#是否使用 STARTTLS安全连接
bfp.email.account.starttls-enable=true
#是否使用 SSL安全连接
bfp.email.account.ssl-enable=true
#指定实现javax.net.SocketFactory接口的类的名称
bfp.email.account.socket-factory-class=javax.net.ssl.SSLSocketFactory
#如果设置为true,未能创建一个套接字使用指定的套接字工厂类将导致使用java.net.Socket创建的套接字类
bfp.email.account.socket-factory-fallback=true
#指定的端口连接到在使用指定的套接字工厂
bfp.email.account.socket-factory-port=465
#设置SMTP超时时长,单位毫秒,缺省值不超时
bfp.email.account.timeout=0
#设置Socket连接超时值,单位毫秒,缺省值不超时
bfp.email.account.connection-timeout=0
#消息中心邮件发送失败重试次数 默认0
message.push.sender.channel.email.fail-retry-times=0
#消息中心邮件发送最大线程数 默认10
message.push.sender.channel.email.thread-pool.max-pool-size=10

# 企业微信

消息中心发送企业微信消息时,需要在主配置文件application.properties文件中配置企业微信相关属性

#三方消息企业微信发送开关
afc.third-party.wechat.enable=true
#企业微信平台-我的企业-企业信息页面底部【企业ID】
afc.third-party.wechat.crop-id=
#企业微信平台-应用管理-创建的应用中AgentID
afc.third-party.wechat.agent-id=
#企业微信平台-应用管理-创建的应用中Secret
afc.third-party.wechat.secret=

#消息中心企业微信发送失败重试次数 默认0
message.push.sender.channel.wecom.fail-retry-times=0
#消息中心企业微信发送最大线程数 默认10
message.push.sender.channel.wecom.thread-pool.max-pool-size=10

# 钉钉

消息中心发送钉钉消息时,需要在主配置文件application.properties文件中配置钉钉相关属性

#三方消息钉钉发送开关
afc.third-party.ding.enable=true
#钉钉开放平台中创建的应用-基础信息-应用凭证AppKey
afc.third-party.ding.app-key=
#钉钉开放平台中创建的应用-基础信息-应用凭证AppSeccret
afc.third-party.ding.secret=
#钉钉开放平台中创建的应用-基础信息-应用凭证AgentId
afc.third-party.ding.agent-id=
#消息中心钉钉发送失败重试次数 默认0
message.push.sender.channel.ding.fail-retry-times=0
#消息中心钉钉发送最大线程数 默认10
message.push.sender.channel.ding.thread-pool.max-pool-size=10

钉钉发送消息时同一天时间内不允许给同一个用户多次发送相同内容,如业务需要多次发送时,可在模板配置时添加${dateTime}变量,通过时间来约束内容唯一。

# 消息渠道扩展实现

消息中心渠道目前支持邮件、钉钉、企业微信三种,如需其他发送渠道可自行通过扩展方式实现。

# 添加相关依赖

添加消息中心starter对应发布版本

 <dependency>
      <groupId>com.primeton.gocom.bfp</groupId>
      <artifactId>com.primeton.gocom.bfp.message.starter</artifactId>
 </dependency>

# 实现相关类

  • 实现com.primeton.gocom.bfp.message.configuration.IChannelConfiguration接口

描述:消息渠道相关配置类,自定义配置消息发送失败重试次数、当前消息渠道发送最大线程数。具体实现方案可参照已实现渠道。

示例:

@Configuration
public class DingChannelConfiguration implements IChannelConfiguration{

    @Value("${message.push.sender.channel.ding.fail-retry-times:0}")
    private int failRetryTimes;

    @Value("${message.push.sender.channel.ding.thread-pool.max-pool-size:10}")
    private int maxThreadPoolSize;

    @Override
    public String getChannelType() {
        return "ding";
    }

    @Override
    public int getFailRetryTimes() {
        return failRetryTimes;
    }

    @Override
    public int getMaxThreadPoolSize() {
        return maxThreadPoolSize;
    }
}
  • 实现com.primeton.gocom.bfp.message.ext.api.IChannelSend接口

描述:消息渠道发送消息实现类,通过实现该接口中sendMessage方法来实现消息统一推送。

示例:

@Component
public class DingChannelSendServiceImpl implements IChannelSend {

    private static final Logger log = LoggerFactory.getLogger(DingChannelSendServiceImpl.class);
    @Autowired
    private DingChannelConfiguration dingChannelConfiguration;

    @Override
    public String getChannelType() {
        return dingChannelConfiguration.getChannelType();
    }

    @Override
    public SendResult sendMessage(BaseMessageModel baseMessageModel) {
        IAFCClient afcClient = AFCClientFactory.getInstance().createAFCClient();
        Set<String> employeePhoneNumList = new HashSet<>();
        SendResult sendResult = new SendResult();
        String sendTarget = baseMessageModel.getSendTarget();
        JSONObject userBodyJson = getUserBodyJson(sendTarget);
        String userBody = userBodyJson.getString(MESSAGE_USER_KEY);
        if(StringUtil.isNotNullAndBlank(userBody)){
            //根据账号查询员工信息
            List<String> users = Arrays.asList(userBody.split(","));
            for(String empId : users){
                Employee employee = afcClient.getEmployeeAPI().queryEmployeeById(empId);
                if(Objects.nonNull(employee)){
                    employeePhoneNumList.add(employee.getPhoneNumber());
                }
            }
        }
        String roleBody = userBodyJson.getString(MESSAGE_ROLE_KEY);
        if(StringUtil.isNotNullAndBlank(roleBody)){
            //根据角色查询员工信息
            List<String> roles = Arrays.asList(roleBody.split(","));
            for (String roleId : roles){
                List<Employee> employees = afcClient.getEmployeeAPI().queryEmployeeByRoleId(roleId);
                if(CollectionUtil.isNotEmpty(employees)){
                    employeePhoneNumList.addAll(employees.stream().map(e->e.getPhoneNumber()).collect(Collectors.toList()));
                }
            }
        }
        String orgBody = userBodyJson.getString(MESSAGE_ORG_KEY);
        if(StringUtil.isNotNullAndBlank(orgBody)){
            List<String> orgs = Arrays.asList(orgBody.split(","));
            //判断是否需要查询子机构
            if(baseMessageModel.isChildOrg()){
                for (String orgId : orgs){
                    List<Employee> thisOrgAndAllSubOrgEmployees = afcClient.getEmployeeAPI().getThisOrgAndAllSubOrgEmployees(orgId);
                    if(CollectionUtil.isNotEmpty(thisOrgAndAllSubOrgEmployees)){
                        employeePhoneNumList.addAll(thisOrgAndAllSubOrgEmployees.stream().map(e->e.getPhoneNumber()).collect(Collectors.toList()));
                    }
                }
            }else{
                for (String orgId : orgs){
                    List<Employee> employeeList = afcClient.getEmployeeAPI().queryEmployeeByOrgId(orgId);
                    if(CollectionUtil.isNotEmpty(employeeList)){
                        employeePhoneNumList.addAll(employeeList.stream().map(e->e.getPhoneNumber()).collect(Collectors.toList()));
                    }
                }
            }
        }
        JSONObject messageBodyJson = getMessageBodyJson(baseMessageModel);
        //正文
        String content = messageBodyJson.getString(MESSAGE_BODY_KEY_CONTENT);
        try {
            boolean result = afcClient.getThirdMessageAPI().sendMessage(new ArrayList<>(employeePhoneNumList),
                    content);
            if(result){
                sendResult.Ok();
            }else {
                sendResult.fail("发送三方消息失败");
            }
        }catch (Exception e){
            log.error("钉钉消息发送失败-异常信息:{}",e.getMessage());
            sendResult.fail(e.getMessage());
            throw new RuntimeException(e.getMessage());
        }
        return sendResult;
    }

    @Override
    public int getFailRetryTimes() {
        return dingChannelConfiguration.getFailRetryTimes();
    }

    @Override
    public int getOrder() {
        return 0;
    }
}
  • 集成com.primeton.gocom.bfp.message.ext.api.PushChannelType类

描述:消息渠道类型枚举类,该类定义枚举用于前端页面显示、后端消息推送具体渠道推送消息实现类获取。

示例:

@Component
public class DingPushChannelType extends PushChannelType {
    @Override
    public String getChannelClassRefence() {
        return DingChannelSendServiceImpl.class.getName();
    }

    @Override
    public String getChannelDisplayName() {
        return "钉钉";
    }

    @Override
    public String getChannelType() {
        return BeanFactory.newInstance().getBean(DingChannelConfiguration.class).getChannelType();
    }
}

# 特殊注意事项:

业务应用在使用时需要在application.properties中配置消息中心应用名称属性

示例:message.application.name=AFCENTER

上次更新: 2023/3/23下午4:28:40