使用Java实现公众号功能的接入,配合业务实现:

  用户关注、取消关注、推送数据服务、用户在公众号信息转发人工服务等功能

  本文章说明公众号代码配置实现,公众号申请,注册方式,自行查看官网说明

引入依赖

<!--微信公众号(包括订阅号和服务号)-->
<dependency>
    <groupId>com.github.binarywang</groupId>
    <artifactId>weixin-java-mp</artifactId>
    <version>4.5.0</version>
</dependency>

注册公众号配置

@Slf4j
@Configuration
@RequiredArgsConstructor
@ConditionalOnClass(WxMpService.class)
@EnableConfigurationProperties()
public class WxMpConfiguration {
    private final MpConfigMapper mpConfigMapper;
    private final LogHandler logHandler;
    private final SubscribeHandler subscribeHandler;
    private final UnsubscribeHandler unsubscribeHandler;
    private final TextMsgHandler textMsgHandler;

    /**
     * 用户配置(获取用户客户代码)
     */
    private static Map<String, Integer> MP_USER_CONF = new HashMap<>();

    public static Long getCustomId(String appid) {
        return Long.valueOf(MP_USER_CONF.getOrDefault(appid, 0));
    }

    /**
     * 加载公众号配置,注册Bean对象
     */
	@Bean
    public WxMpService wxMpService() {
    	//这个是数据库公众号信息配置表
        List<MpConfig> mpConfigs = mpConfigMapper.selectList(Wrappers.emptyWrapper());
        if (CollectionUtil.isEmpty(mpConfigs)) {
            log.error("读取配置为空,公众号配置类加载失败!");
            return new WxMpServiceImpl();
        }
        log.info("公众号的配置:{}", JSON.toJSONString(mpConfigs));
        Map<String, WxMpConfigStorage> multiConfigStorages = new HashMap<>(16);
        for (MpConfig mpConfig : mpConfigs) {
            WxMpDefaultConfigImpl configStorage = new WxMpDefaultConfigImpl();
            configStorage.setAppId(mpConfig.getAppid());
            configStorage.setSecret(mpConfig.getSecret());
            configStorage.setToken(mpConfig.getToken());
            configStorage.setAesKey(mpConfig.getAeskey());
            multiConfigStorages.put(mpConfig.getCustomerCode(), configStorage);
            MP_USER_CONF.put(mpConfig.getAppid(), mpConfig.getCustomerId());
        }
        WxMpService mpService = new WxMpServiceImpl();
        mpService.setMultiConfigStorages(multiConfigStorages);
        return mpService;
    }
    
     /**
     * 配置公众号个事件路由,分类处理:关注、取消关注、用户发送消息
     */
    @Bean
    public WxMpMessageRouter messageRouter(WxMpService wxMpService) {
        final WxMpMessageRouter newRouter = new WxMpMessageRouter(wxMpService);
        // 记录所有事件的日志 (异步执行)
        newRouter.rule().handler(this.logHandler).next();
        // 关注事件
        newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT).
                event(WxConsts.EventType.SUBSCRIBE).handler(this.subscribeHandler).end();
        //取消关注事件
        newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT).
 event(WxConsts.EventType.UNSUBSCRIBE).handler(this.unsubscribeHandler).end();
 		//用户往公众号发送消息事件处理
        newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.TEXT).
                handler(this.textMsgHandler).end();
        return newRouter;
    }
 }

公众号各事件处理

实现公众号事件处理类

/**
 * 微信公众号AbstractHandler
 */
public abstract class AbstractHandler implements WxMpMessageHandler {
    protected Logger logger = LoggerFactory.getLogger(getClass());
}

实现公众号日志记录处理器

/**
 * 微信公众号日志记录处理器
 */
@Component
public class LogHandler extends AbstractHandler {
    @Override
    public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
                                    Map<String, Object> context, WxMpService wxMpService,
                                    WxSessionManager sessionManager) {
        this.logger.info("【公众号】-记录请求日志,内容:{}", JSON.toJSONString(wxMessage));
        return null;
    }
}

实现公众号用户关注处理器

/**
 * 微信公众号用户关注
 */
@Component
@RequiredArgsConstructor
public class SubscribeHandler extends AbstractHandler {
	//公众号用户表
    private final MpUserParentMapper mpUserParentMapper;
    //小程序用户表(一般公众号和小程序配套使用)
    private final MiniappUserParentMapper miniappUserParentMapper;
    //公众号配置表
    private final MpConfigMapper mpConfigMapper;

	@Override
    public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
                                    Map<String, Object> context, WxMpService wxMpService,
                                    WxSessionManager sessionManager) throws WxErrorException {

        this.logger.info("【公众号-关注功能】-新关注用户 OPENID: " + wxMessage.getFromUser());

        // 获取微信用户基本信息
        try {
            WxMpUser userWxInfo = wxMpService.getUserService()
                    .userInfo(wxMessage.getFromUser(), null);
            String appId = wxMpService.getWxMpConfigStorage().getAppId();
            Long customerId = WxMpConfiguration.getCustomId(appId);
            logger.info("userWxInfo:{}", userWxInfo);
            if (userWxInfo != null) {
            	//查询数据库,公众号用户表,是否有这个用户
                MpUserParent existMpUser = mpUserParentMapper.selectOneByOpenId(userWxInfo.getOpenId());
                //不存在则新增一条公众号用户记录
                if (existMpUser == null) {
                    MpUserParent mpUser = new MpUserParent();
                    mpUser.setOpenId(userWxInfo.getOpenId());
                    mpUser.setUnionId(userWxInfo.getUnionId());
                    mpUser.setAvatarUrl(userWxInfo.getHeadImgUrl());
                    mpUser.setNickName(userWxInfo.getNickname());
                    mpUser.setCustomerId(customerId);
                    mpUserParentMapper.insert(mpUser);
                    //检测是否有跟小程序账号关联
                    MiniappUserParent maUserParent = miniappUserParentMapper.selectOneByUnionId(mpUser.getUnionId(),
                     customerId);
                    if (maUserParent != null && StringUtil.isBlank(maUserParent.getMpOpenId())) {
                        maUserParent.setMpOpenId(mpUser.getOpenId());
                        maUserParent.setUpdateTime(new Date());
                        miniappUserParentMapper.updateById(maUserParent);
                        this.logger.info("【公众号-关注功能】-公众号账号和小程序绑定成功!unionId:{},mpOpenId:{} ",
                         mpUser.getUnionId(), mpUser.getOpenId());
                    }
                } else {
                    //之前有关注过的,无需重复写入,更改关注状态即可
                    MpUserParent updateUser = new MpUserParent();
                    updateUser.setMpId(existMpUser.getMpId());
                    updateUser.setFollowStatus(1);
                    updateUser.setUpdateTime(new Date());
                    updateUser.setCustomerId(customerId);
                    updateUser.setUnionId(userWxInfo.getUnionId());
                    mpUserParentMapper.updateById(updateUser);
                }
			}
        } catch (WxErrorException e) {
            if (e.getError().getErrorCode() == 48001) {
                this.logger.error("【公众号-关注功能】-该公众号没有获取用户信息权限!");
            }
            logger.error("【公众号-关注功能异常】-异常信息:{}", e);
        }
		WxMpXmlOutMessage responseResult = null;
        try {
            responseResult = this.handleSpecial(wxMessage);
        } catch (Exception e) {
            this.logger.error(e.getMessage(), e);
        }
        if (responseResult != null) {
            return responseResult;
        }
        String appId = wxMpService.getWxMpConfigStorage().getAppId();
        try {
            logger.info("获取公众号appid:{}", appId);
            MpConfig miniappConfig = mpConfigMapper.selectByAppid(appId);
            //关注公众号,发送消息给用户
            return new TextBuilder().build("感谢关注,将持续为您推送信息", wxMessage, wxMpService);
        } catch (Exception e) {
            this.logger.error(e.getMessage(), e);
        }
		return null;
    }
    
    /**
     * 处理特殊请求,比如如果是扫码进来的,可以做相应处理
     */
    private WxMpXmlOutMessage handleSpecial(WxMpXmlMessage wxMessage) throws Exception {
        //TODO
        return null;
    }
}

实现公众号用户取消关注处理器

/**
 * 微信公众号用户取消关注
 */
@Component
@RequiredArgsConstructor
public class UnsubscribeHandler extends AbstractHandler {
    private final MpUserParentMapper mpUserParentMapper;
    private final MpConfigMapper mpConfigMapper;
	@Override
    public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
                                    Map<String, Object> context, WxMpService wxMpService,
                                    WxSessionManager sessionManager) {
        String openId = wxMessage.getFromUser();
        this.logger.info("取消关注用户 OPENID: " + openId);
        //更新关注状态为取消关注状态
        UpdateWrapper<MpUserParent> updateWrapper = new UpdateWrapper();
        updateWrapper.eq("openId", openId);
        updateWrapper.eq("followStatus", 1);
        MpUserParent updateMpUser = new MpUserParent();
        updateMpUser.setFollowStatus(2);
        //不删除公众号用户信息,修改关注状态值即可
        mpUserParentMapper.update(updateMpUser, updateWrapper);
        String appId = wxMpService.getWxMpConfigStorage().getAppId();
        logger.info("获取公众号appid:{}",appId);
        MpConfig miniappConfig = mpConfigMapper.selectByAppid(appId);
        //取消关注,发送信息给用户
        return new TextBuilder().build("已退订", wxMessage, wxMpService);
    }
}

实现公众号用户发送消息处理器

@Slf4j
@Component
@RequiredArgsConstructor
public class TextMsgHandler extends AbstractHandler {

    private final static Integer TEXT_TYPE = 1;
    @Override
    public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, Map<String, Object> context, WxMpService wxMpService,
     WxSessionManager sessionManager) throws WxErrorException {
        String content = wxMessage.getContent();
        log.info("【公众号-消息】-用户:{} , 发送消息:{}, ", wxMessage.getFromUser(), content);
        // 获取微信用户基本信息
        try {
            String appId = wxMpService.getWxMpConfigStorage().getAppId();
            Long customerId = WxMpConfiguration.getCustomId(appId);
            //自动回复匹配的关键字
            MpAutoReplyDTO autoReply = InitConfDataUtil.getAutoReply(customerId, content);
            if (autoReply != null) {
                Integer replyType = autoReply.getReplyType();
                String reply = autoReply.getReply();
                if (TEXT_TYPE.equals(replyType)) {
                	//文字处理
                    return new TextBuilder().build(reply, wxMessage, wxMpService);
                } else {
                	//图片处理
                    return new ImageBuilder().build(reply, wxMessage, wxMpService);
                }
            } else {
                //自动回复没有匹配的就转到人工
                WxMpXmlOutMessage build = new TextBuilder().build(wxMessage.getContent(), wxMessage, wxMpService);
                //msgType设置固定值就转到人工:transfer_customer_service
                build.setMsgType("transfer_customer_service");
                return build;
            }
        } catch (Exception e) {
            log.info("回复失败e:{}", e);
        }
        return null;
    }
}

用户消息事件分类处理Builder

定义处理抽象类

//该类定义处理标准,后续根据业务自行扩展
public abstract class AbstractBuilder {
    protected final Logger logger = LoggerFactory.getLogger(getClass());
    public abstract WxMpXmlOutMessage build(String content,
                                            WxMpXmlMessage wxMessage, WxMpService service);
}

实现处理抽象类–子类–文本消息

public class TextBuilder extends AbstractBuilder {
    @Override
    public WxMpXmlOutMessage build(String content, WxMpXmlMessage wxMessage,
                                   WxMpService service) {
        return WxMpXmlOutMessage.TEXT().content(content)
                .fromUser(wxMessage.getToUser()).toUser(wxMessage.getFromUser())
                .build();
    }
}

实现处理抽象类–子类–图片消息

public class ImageBuilder extends AbstractBuilder {
    @Override
    public WxMpXmlOutMessage build(String content, WxMpXmlMessage wxMessage,
                                   WxMpService service) {
        return WxMpXmlOutMessage.IMAGE().mediaId(content)
                .fromUser(wxMessage.getToUser()).toUser(wxMessage.getFromUser())
                .build();
    }
}

公众号模板消息推送

以上实现了Java整合公众号,后续业务扩展,需要往关注公众号的用户进行相关的消息推送,消息推送前,

需要在微信公众号申请推送模板,拿到对应的模板ID,这个有用,生成推送消息时,需要往模板填充信息,

如何申请公众号模板,自行参考下官网说明

/**
 * 微信公众号信息推送
 */
@Slf4j
@RequiredArgsConstructor
@Component
public class MpMsgPush {
	//微信的公众号推送处理类
    private final WxMpService wxMpAgentService;
    //数据库公众号模板消息表
    private final MpTemplateManage mpTemplateManage;

 	/**
     * 发送微信模板信息
     *
     * @param mpPushDTO 推送信息实体类
     * @return 是否推送成功
     */
    @Async
    public Boolean sendTemplateMsg(MpPushDTO mpPushDTO) {
        log.info("【公众号告警模板信息推送】-推送信息:{}", JSONObject.toJSONString(mpPushDTO));
        Long customerId = mpPushDTO.getCustomerId();
        String name = mpPushDTO.getMpName();
        //选择往哪个公众号发送模板消息,这个上面注册公众号的Bean的时候已经注入
        WxMpService wxMpService = wxMpAgentService.switchoverTo(mpPushDTO.getCustomerCode());
        //自己搞的一个枚举,根据当前的消息实体类信息,来判断使用哪个模板ID
        String templateId = TemplateConfConstant.getWXTemplateConf(customerId, mpPushTypeEnum.getValue());
        // 获取模板消息接口
        WxMpTemplateMessage templateMessage = mpTemplateManage.getWarnTemplate(mpPushDTO, templateId, name);
        if (templateMessage != null) {
            log.info("发送消息:{}", JSONObject.toJSONString(templateMessage));
        } else {
            log.error("获取消息模板为空!");
            return false;
        }
        String msgId = null;
        try {
            Long parentId = mpPushDTO.getParentId();
            String imeiNo = mpPushDTO.getImeiNo();
            // 发送模板消息
            msgId = wxMpService.getTemplateMsgService().sendTemplateMsg(templateMessage);
        } catch (Exception e) {
            log.error("【公众号模板信息推送】-推送失败,异常信息:", e);
        }
        log.warn("·==++--·推送公众号模板信息:{}·--++==·", msgId != null ? "成功" : "失败");
        return msgId != null;
    }
    
	/**
     * 获取提醒模板
     *
     * @param mpPushDTO
     * @return
     */
    public WxMpTemplateMessage getWarnTemplate(MpPushDTO mpPushDTO, String templateId, String name) {
        // 发送模板消息接口
        WxMpTemplateMessage templateMessage = WxMpTemplateMessage.builder()
                // 接收者openid
                .toUser(mpPushDTO.getOpenId())
                // 模板id
                .templateId(templateId)
                .build();
        StringBuilder keyword1 = new StringBuilder();
        keyword1.append(mpPushDTO.getStudentName()).
                append("(").append(mpPushDTO.getImeiNo()).append(")");
        // 添加模板数据
        templateMessage.addData(new WxMpTemplateData("first", "您好,你有一条新的提醒"))
                .addData(new WxMpTemplateData("keyword1", keyword1.toString()))
                .addData(new WxMpTemplateData("keyword2", mpPushDTO.getTemplateType()))
                .addData(new WxMpTemplateData("remark", name + "智能推送系统"));
        return templateMessage;
    }


}


转自:https://blog.csdn.net/weixin_41451078/article/details/129818448