SpringBoot整合调用微信模板方法实现微信公众号消息通知推送,Java实现微信公众号给关注用户推送自定义消息通知(手把手从0到1)

目录

概述

公众号给关注用户推送自定义消息

一、申请公众号模板消息

二、获取安装“web开发者工具”

三、微信网页授权说明

四、微信网页授权 - 流程时序图

五、HTTPClient 实现微信公众号消息推送与发布(四步走)

六、通过weixin-java-mp SDK实现微信公众号消息推送与发布(七步走)

七、抽取与封装


概述

本篇文章主要基于Java+Spring Boot+Spring Cloud的应用中接入微信公众号,调用微信的JavaSDK > weixin-java-mp进行应用消息推送,实现业务数据推送到指定的微信用户客户端。通过本篇博客,将快速上手,从0到1构建起消息推送与发布。

公众号给关注用户推送自定义消息

一、申请公众号模板消息

1、开通微信公众号平台的“模板消息”栏

提交申请:

添加功能插件>功能详情>申请开通模板接口> 填写业务服务目标所属的行业,申请理由,

如果是新申请的消息模板,需要注意规范,否则会被封号的可能!!!

等待审核通过就可以使用了!

“模板消息”开通审核通过后,在微信公众号平台>左边栏>广告与服务>就可以看到模板消息栏了,

接着,就可以添加用于业务系统推送公众号的模板消息内容了,

如下图: 

 添加完成后,就可以在,模板消息>我的模板,中进行查看了,如下图:

关于推送的模板消息内容,用两种定义方式:
1、用公众号模板库已经存在的,也就是别人之前申请过的,
2、如果在模板消息库中检索不到符合当下业务系统需求的消息模板内容,则可以自定义,在模板库中选择“帮助我们完善模板库”
如下图:

 添加自定义的微信公众号模板的内容的注意事项:
1、添加模版前,需要先仔细阅读《模版消息申请添加前必读指引》。请勿违反运营规则,否则可能被停用模版消息接口甚至封号的可能;
2、贡献新模版需要等待“7-15”天审核期,且内容可能被审核人员修改。每月只可申请新建3个新模版;
3、审核通过后,模版将放入模版库以供他人使用,会被官方共享出去,也就是这里的消息模板,没有私有这一说,之前博主的客户提需求,说必须要私有的,不能共享,因为这不是自己能控制的,遂进行了多轮沟通后最终才说服了客户;

二、获取安装“web开发者工具”

web开发者工具稳定版下载

微信web开发者工具,安装完成后,打开应用程序,选择“公众号网页项目”,
如下图;

为公众号绑定开发者:

如果出现 “ 该微信用户未开启“公众号安全助手”的消息接收功能,请先开启后再绑定 ”

参考:

该微信用户未开启“公众号安全助手”的消息接收功能,请先开启后再绑定

邀请绑定,

设置完成后,再次邀请绑定即可完成绑定了,如下图:

绑定成功后,再打开,微信公众号平台>设置与开发>开发者工具>选择“web开发者工具”>如下图(web开发者工具最多可绑定50人),
如下图:

三、微信网页授权说明

1、微信开发网页授权五步走

第一步:用户同意授权,获取code
在确保微信公众账号拥有授权作用域(scope参数)的权限的前提下(已认证服务号,默认拥有 scope 参数中的snsapi_base和snsapi_userinfo 权限),引导关注者打开如下页面:

https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect

若提示“该链接无法访问”,请检查参数是否填写错误,是否拥有 scope 参数对应的授权作用域权限。

注意:由于授权操作安全等级较高,所以在发起授权请求时,微信会对授权链接做正则强匹配校验,如果链接的参数顺序不对,授权页面将无法正常访问,跳转回调redirect_uri,应当使用 https 链接来确保授权 code 的安全性。

参考链接(请在微信客户端中打开此链接体验):

scope为snsapi_base:

https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx520c15f417810387&redirect_uri=https%3A%2F%2Fchong.qq.com%2Fphp%2Findex.php%3Fd%3D%26c%3DwxAdapter%26m%3DmobileDeal%26showwxpaytitle%3D1%26vb2ctag%3D4_2030_5_1194_60&response_type=code&scope=snsapi_base&state=123#wechat_redirect

scope为snsapi_userinfo:

https://open.weixin.qq.com/connect/oauth2/authorize?appid=wxf0e81c3bee622d60&redirect_uri=http%3A%2F%2Fnba.bluewebgame.com%2Foauth_response.php&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect

用户同意授权后

如果用户同意授权,页面将跳转至 redirect_uri/?code=CODE&state=STATE。

code说明:

code作为换取access_token的票据,每次用户授权带上的 code 将不一样,code只能使用一次,5分钟未被使用自动过期

请求参数说明:

回调错误码说明:

第二步:通过 code 换取网页授权access_token

首先请注意,这里通过 code 换取的是一个特殊的网页授权access_token,与基础支持中的access_token(该access_token用于调用其他接口)不同。公众号可通过下述接口来获取网页授权access_token。如果网页授权的作用域为snsapi_base,则本步骤中获取到网页授权access_token的同时,也获取到了openid,snsapi_base式的网页授权流程即到此为止。

注意:由于公众号的 secret 和获取到的access_token安全级别都非常高,必须只保存在服务器,不允许传给客户端。后续刷新access_token、通过access_token获取用户信息等步骤,也必须从服务器发起。

请求方法

获取 code 后,请求以下链接获取access_token:

https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code

请求参数说明:

  

回调参数说明:

回调错误码说明:

 

更多返回码说明请参看:

全局返回码说明

第三步:刷新access_token(可选项)

由于access_token拥有较短的有效期,当access_token超时后,可以使用refresh_token进行刷新,refresh_token有效期为30天,当refresh_token失效之后,需要用户重新授权。

请求方法

获取第二步的refresh_token后,请求以下链接获取access_token:

https://api.weixin.qq.com/sns/oauth2/refresh_token?appid=APPID&grant_type=refresh_token&refresh_token=REFRESH_TOKEN

请求参数说明:

回调参数说明:

回调错误码说明:参看第二步回调错误码说明!

第四步:拉取用户信息(scope 为 snsapi_userinfo)

如果网页授权作用域为snsapi_userinfo,则此时开发者可以通过access_token和 openid 拉取用户信息了。

请求方法

http:GET(请使用 https 协议):

https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN

关于scope授权作用域:

  /**
   * oauth2网页授权的scope.
   */
  public static class OAuth2Scope {
    /**
     * 不弹出授权页面,直接跳转,只能获取用户openid.
     */
    public static final String SNSAPI_BASE = "snsapi_base";

    /**
     * 弹出授权页面,可通过openid拿到昵称、性别、所在地。并且,即使在未关注的情况下,只要用户授权,也能获取其信息.
     */
    public static final String SNSAPI_USERINFO = "snsapi_userinfo";

    /**
     * 手动授权,可获取成员的详细信息,包含手机、邮箱。只适用于企业微信或企业号.
     */
    public static final String SNSAPI_PRIVATEINFO = "snsapi_privateinfo";
  }

请求参数说明:

回调参数说明:

回调错误码说明:参看第二步回调错误码说明!

第五步:检验授权凭证(access_token)是否有效(可选项)

请求方法

http:GET(请使用 https 协议):

https://api.weixin.qq.com/sns/auth?access_token=ACCESS_TOKEN&openid=OPENID

请求参数说明:

回调参数说明:

两个参数(errcode、errmsg)

回调错误码说明:参看第二步回调错误码说明!

2、其它说明

一、关于网页授权回调域名的说明
1、在微信公众号请求用户网页授权之前,开发者需要先到公众平台官网中的“开发 - 接口权限 - 网页服务 - 网页帐号 - 网页授权获取用户基本信息”的配置选项中,修改授权回调域名。请注意,这里填写的是域名(是一个字符串),而不是URL,因此请勿加 http:// 等协议头。


2、授权回调域名配置规范为全域名,比如需要网页授权的域名为:www.qq.com,配置以后此域名下面的页面http://www.qq.com/music.html 、 http://www.qq.com/login.html 都可以进行OAuth2.0鉴权。但http://pay.qq.com 、 http://music.qq.com 、 http://qq.com 无法进行OAuth2.0鉴权。
3、如果公众号登录授权给了第三方开发者来进行管理,则不必做任何设置,由第三方代替公众号实现网页授权即可。

二、关于网页授权的两种 scope 的区别说明
1、以snsapi_base为 scope 发起的网页授权,是用来获取进入页面的用户的 openid 的,并且是静默授权并自动跳转到回调页的。用户感知的就是直接进入了回调页(往往是业务页面)。


2、以snsapi_userinfo为 scope 发起的网页授权,是用来获取用户的基本信息的。但这种授权需要用户手动同意,并且由于用户同意过,所以无须关注,就可在授权后获取该用户的基本信息。


3、用户管理类接口中的“获取用户基本信息接口”,是在用户和公众号产生消息交互或关注后事件推送后,才能根据用户 OpenID 来获取用户基本信息。这个接口,包括其他微信接口,都是需要该用户(即openid)关注了公众号后,才能调用成功的。

三、关于网页授权access_token和普通access_token的区别
1、微信网页授权是通过OAuth2.0机制实现的,在用户授权给公众号后,公众号可以获取到一个网页授权特有的接口调用凭证(网页授权access_token),通过网页授权access_token可以进行授权后接口调用,如获取用户基本信息。


2、其他微信接口,需要通过基础支持中的“获取access_token”接口来获取到的普通access_token调用。

四、微信网页授权 - 流程时序图

五、HTTPClient 实现微信公众号消息推送与发布(四步走)

第一步:获取微信公众号CODE

    /**
     * Description:[获取公众号CODE]
     *
     * @date 2019-05-19
     * @author huazai
     */
    @GetMapping("/getWeChatCode")
    @ApiOperation(value = "/getWeChatCode", notes = "获取公众号CODE")
    public void getWeChatCode(HttpServletResponse response) {
        try {
            // 构建公众号消息体
            String weChatGetCodeUrl = String.format(this.WE_CHAT_CODE_URL, this.WE_CHAT_APP_ID, this.WE_CHAT_CALL_BACK_DOMAIN_URL, WxConsts.OAuth2Scope.SNSAPI_BASE);
            log.info("we_chat_get_code_url:" + weChatGetCodeUrl);
            response.sendRedirect(weChatGetCodeUrl);

        } catch (Exception e) {
            log.info("异常信息:{}", e);
        }
    }

 请求回调获取的用户授权CODE,如下图:

第二部:根据Code获取用户OpenId

    /**
     * Description:[根据Code获取用户OpenId]
     *
     * @return JSONResult
     * @date 2019-05-19
     * @author huazai
     */
    @GetMapping("/getWeChatOpenId")
    @ApiOperation(value = "/getWeChatOpenId", notes = "根据Code获取用户OpenId")
    public JSONResult getWeChatOpenId(@RequestParam String code, @RequestParam String state) {
        try {
            log.info("we_chat_code: " + code);
            String weChatDomain = String.format(this.WE_CHAT_AUTHORIZATION_URL, this.WE_CHAT_APP_ID, this.WE_CHAT_SECRET, code);

            RestTemplate restTemplate = new RestTemplate();
            ResponseEntity<String> responseEntity = restTemplate.getForEntity(weChatDomain, String.class);
            String openid = JSONObject.parseObject(responseEntity.getBody()).getString("openid");
            String access_token = JSONObject.parseObject(responseEntity.getBody()).getString("access_token");

            // 用户的OpenId,用户的微信授权Access_Token
            log.info("we_chat_open_id: " + openid);
            log.info("we_chat_access_token: " + access_token);

            return JSONResult.success(openid);
        } catch (Exception e) {
            log.info("异常信息:{}", e);
        }
        return null;
    }

 获取的openid如下图:

第三步:根据Code获取用户Access_Token(可选)

    /**
     * Description:[根据Code获取用户Access_Token]
     *
     * @return JSONResult
     * @date 2019-05-19
     * @author huazai
     */
    @GetMapping("/getUserAccessToken")
    @ApiOperation(value = "/getUserAccessToken", notes = "根据Code获取用户Access_Token")
    public JSONResult getUserAccessToken(@RequestParam String code, @RequestParam String state) {
        try {
            String weChatDomain = String.format(this.WE_CHAT_AUTHORIZATION_URL, this.WE_CHAT_APP_ID, this.WE_CHAT_SECRET, code);
            log.info("we_chat_authorization_url:{}" + weChatDomain);

            RestTemplate restTemplate = new RestTemplate();
            ResponseEntity<String> responseEntity = restTemplate.getForEntity(weChatDomain, String.class);

            String accessToken = JSONObject.parseObject(responseEntity.getBody()).getString("access_token");
            log.info("we_chat_access_token: " + accessToken);

            return JSONResult.success(accessToken);
        } catch (Exception e) {
            log.info("异常信息:{}", e);
        }
        return null;
    }

第四步:获取微信公众号的Access_Token

    /**
     * Description:[获取微信公众号的Access_Token]
     *
     * @return JSONResult
     * @date 2019-05-19
     * @author huazai
     */
    @GetMapping("/getWeChatAccessToken")
    @ApiOperation(value = "/getWeChatAccessToken", notes = "微信公众号的Access_Token")
    public JSONResult getWeChatAccessToken() {
        try {
            // 微信公众号官方获取AccessToken
            RestTemplate restTemplate = new RestTemplate();
            String requestParams = String.format(this.WE_CHAT_ACCESS_TOKEN_URL, this.WE_CHAT_APP_ID, this.WE_CHAT_SECRET);
            ResponseEntity<String> responseEntity = restTemplate.getForEntity(requestParams, String.class);

            String accessToken = JSONObject.parseObject(responseEntity.getBody()).getString("access_token");
            log.info("we_chat_access_token: " + accessToken);

            return JSONResult.success(accessToken);
        } catch (Exception e) {
            log.info("异常信息:{}", e);
        }
        return null;
    }

第五步:微信公众号指定用户消息推送与发布

    /**
     * Description:[公众号指定用户消息推送]
     *
     * @return JSONResult
     * @date 2019-05-19
     * @author huazai
     */
    @GetMapping("/sendWeChatRecharge")
    @ApiOperation(value = "/sendWeChatRecharge", notes = "公众号指定用户消息推送")
    public JSONResult sendWeChatRecharge() {

        // 1、构建公众号消息体
        WeChatRechargeTemplateParamsDTO weChatRechargeTemplateParamsDTO = WeChatRechargeTemplateParamsDTO.builder()
                .first("尊敬用户您好,你的缴费结果如下:")
                .keyword1("HuaZai")
                .keyword2("10010110010001")
                .keyword3(BigDecimal.valueOf(2000))
                .keyword4(BigDecimal.valueOf(10000182.92))
                .keyword5(DateUtil.getDateTime())
                .remark("缴费成功,祝您生活愉快!")
                .touser("**********")
                .customerNumber("549527")
                .build();

        // 2、组装消息数据
        Map<String, WeChatMsgDTO> weChatMsgMap = new HashMap<>();
        weChatMsgMap.put("first", new WeChatMsgDTO(weChatRechargeTemplateParamsDTO.getFirst()));
        weChatMsgMap.put("keyword1", new WeChatMsgDTO(weChatRechargeTemplateParamsDTO.getKeyword1()));
        weChatMsgMap.put("keyword2", new WeChatMsgDTO(weChatRechargeTemplateParamsDTO.getKeyword2()));
        weChatMsgMap.put("keyword3", new WeChatMsgDTO(weChatRechargeTemplateParamsDTO.getKeyword3().toString()));
        weChatMsgMap.put("keyword4", new WeChatMsgDTO(weChatRechargeTemplateParamsDTO.getKeyword4().toString()));
        weChatMsgMap.put("keyword5", new WeChatMsgDTO(weChatRechargeTemplateParamsDTO.getKeyword5()));
        weChatMsgMap.put("remark", new WeChatMsgDTO(weChatRechargeTemplateParamsDTO.getRemark()));
        String customerCallUrl = String.format(this.WE_CHAT_CUSTOMER_CALL_URL, weChatRechargeTemplateParamsDTO.getCustomerNumber());

        //3、构建模板消息体
        WeChatTemplateParamsDTO weChatTemplateParamsDTO = WeChatTemplateParamsDTO.builder()
                .touser(weChatRechargeTemplateParamsDTO.getTouser())
                .template_id(this.WE_CHAT_TEMPLATE_ID)
                .url(customerCallUrl)
                .topcolor(this.WE_CHAT_TOP_COLOR)
                .data(weChatMsgMap)
                .build();

        // 4、微信公众号消息推送与发布
        RestTemplate restTemplate = new RestTemplate();
        String resultUrl = String.format(this.WE_CHAT_REQUEST_URL, this.WE_CHAT_ACCESS_TOKEN);
        ResponseEntity<String> responseEntity = restTemplate.postForEntity(resultUrl, weChatTemplateParamsDTO, String.class);

        if (!OK.equals(responseEntity.getStatusCode())) {
            log.error("公众号消息推送失败!", responseEntity.getBody());
        }

        return JSONResult.success();
    }

消息推送,返回code为0,即表示消息已成功推送(否则失败,需要code码和上面的错误信息说明进行对比,针对性问题处理),如下图:

再打开微信公众号,就可以看到推送的消息了,如下图:

 

常量说明:

    // 微信公众号的 app_id
    String WE_CHAT_APP_ID = "**********";
    // 微信公众号的 secret
    String WE_CHAT_SECRET = "**********";
    // 微信公众号的 access_token
    String WE_CHAT_ACCESS_TOKEN = "**********";
    // 微信公众号code获取地址
    String WE_CHAT_CODE_URL = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=%s&redirect_uri=%s&response_type=code&scope=%s&state=STATE#wechat_redirect";
    // 回调地址,获取open_id
    String WE_CHAT_CALL_BACK_DOMAIN_URL = "https://***.***.***.***/***/***/getWeChatOpenId";
    // 微信公众号的token获取地址
    String WE_CHAT_ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s";
    // 微信公众号消息推送地址
    String WE_CHAT_REQUEST_URL = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=%s";
    // 微信公众号推送消息模板id
    String WE_CHAT_TEMPLATE_ID = "**********";
    // 微信公众号的消息回调地址(这儿可根据业务需求自定义动作,可选)
    String WE_CHAT_CUSTOMER_CALL_URL = "https://***.***.***.***/***/***/accountInfo?keyword=%s";
    // 微信公众号的主题颜色
    String WE_CHAT_TOP_COLOR = "#A349A4";
    // 微信公众号微信用户授权地址
    String WE_CHAT_AUTHORIZATION_URL = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code";

六、通过weixin-java-mp SDK实现微信公众号消息推送与发布(七步走)

第一步:pom.xml新增依赖

        <dependency>
            <groupId>com.github.binarywang</groupId>
            <artifactId>weixin-java-mp</artifactId>
            <version>4.3.0</version>
        </dependency>

第二步:配置WxMpService

配置me.chanjar.weixin.mp.api.WxMpService,可以通过@Component组件注入交由Spring进行管理,或者直接在启动类@SpringBootApplication中@Bean注入,

注入的内容如下:

    @Bean
    public WxMpService wxMpService() {
        WxMpMapConfigImpl wxMpMapConfig = new WxMpMapConfigImpl();
        wxMpMapConfig.setAppId(Constant.WE_CHAT_APP_ID);
        wxMpMapConfig.setSecret(Constant.WE_CHAT_SECRET);
        val wxMpService = new WxMpServiceImpl();
        wxMpService.setWxMpConfigStorage(wxMpMapConfig);

        return wxMpService;
    }

 第三步:获取微信公众号CODE


    @Autowired
    private WxMpService wxMpService;


    /**
     * Description:[获取公众号CODE]
     *
     * @date 2019-05-19
     * @author huazai
     */
    @GetMapping("/getWeChatCode")
    @ApiOperation(value = "/getWeChatCode", notes = "获取公众号CODE")
    public RedirectView getWeChatCode() {
        try {
            // 构造网页授权url
            String authorizationUrl = wxMpService.getOAuth2Service().buildAuthorizationUrl(this.WE_CHAT_CALL_BACK_DOMAIN_URL, WxConsts.OAuth2Scope.SNSAPI_BASE, null);
            log.info("we_chat_get_code_url:" + authorizationUrl);

            return new RedirectView(authorizationUrl);
        } catch (Exception e) {
            log.info("异常信息:{}", e);
        }
        return null;
    }

第四步:根据Code获取用户OpenId

    /**
     * Description:[根据Code获取用户OpenId]
     *
     * @return JSONResult
     * @date 2019-05-19
     * @author huazai
     */
    @GetMapping("/getWeChatOpenId")
    @ApiOperation(value = "/getWeChatOpenId", notes = "根据Code获取用户OpenId")
    public JSONResult getWeChatOpenId(@RequestParam String code, @RequestParam String state) {
        try {
            log.info("we_chat_code: " + code);
            // 通过微信回调过来的code获得access token,其中也包含用户的openid等信息
            WxOAuth2AccessToken wxOAuth2AccessToken = wxMpService.getOAuth2Service().getAccessToken(code);

            String openid = wxOAuth2AccessToken.getOpenId();
            String access_token = wxOAuth2AccessToken.getAccessToken();
            // 用户的OpenId,用户的微信授权Access_Token
            log.info("we_chat_open_id: " + openid);
            log.info("we_chat_access_token: " + access_token);

            return JSONResult.success(openid);
        } catch (Exception e) {
            log.info("异常信息:{}", e);
        }
        return null;
    }

第五步:根据Code获取用户Access_Token(可选)

    /**
     * Description:[根据Code获取用户Access_Token]
     *
     * @return JSONResult
     * @date 2019-05-19
     * @author huazai
     */
    @GetMapping("/getUserAccessToken")
    @ApiOperation(value = "/getUserAccessToken", notes = "根据Code获取用户Access_Token")
    public JSONResult getUserAccessToken(@RequestParam String code, @RequestParam String state) {
        try {
            // 根据Code获取用户Access_Token
            WxOAuth2AccessToken wxOAuth2AccessToken = wxMpService.getOAuth2Service().getAccessToken(code);

            String accessToken = wxOAuth2AccessToken.getAccessToken();
            log.info("we_chat_user_access_token: " + accessToken);

            return JSONResult.success(accessToken);
        } catch (Exception e) {
            log.info("异常信息:{}", e);
        }
        return null;
    }

第六步:获取微信公众号的Access_Token
 

    /**
     * Description:[获取微信公众号的Access_Token]
     *
     * @return JSONResult
     * @date 2019-05-19
     * @author huazai
     */
    @GetMapping("/getWeChatAccessToken")
    @ApiOperation(value = "/getWeChatAccessToken", notes = "微信公众号的Access_Token")
    public JSONResult getWeChatAccessToken() {
        try {
            // 微信公众号官方获取AccessToken
            String accessToken = wxMpService.getAccessToken();
            log.info("we_chat_access_token: " + accessToken);

            return JSONResult.success(accessToken);
        } catch (Exception e) {
            log.info("异常信息:{}", e);
        }
        return null;
    }

第七步:微信公众号指定用户消息推送与发布

    /**
     * Description:[公众号指定用户消息推送]
     *
     * @return JSONResult
     * @date 2019-05-19
     * @author huazai
     */
    @GetMapping("/sendWeChatRecharge")
    @ApiOperation(value = "/sendWeChatRecharge", notes = "公众号指定用户消息推送")
    public JSONResult sendWeChatRecharge() {
        try {
            // 1、构建公众号消息体
            WeChatRechargeTemplateParamsDTO weChatRechargeTemplateParamsDTO = WeChatRechargeTemplateParamsDTO.builder()
                    .first("尊敬用户您好,你的缴费结果如下:")
                    .keyword1("HuaZai")
                    .keyword2("10010110010001")
                    .keyword3(BigDecimal.valueOf(2000))
                    .keyword4(BigDecimal.valueOf(10000182.92))
                    .keyword5(DateUtil.getDateTime())
                    .remark("缴费成功,祝您生活愉快!")
                    .touser("**********")
                    .customerNumber("549527")
                    .build();

            // 2、组装消息数据
            List<WxMpTemplateData> wxMpTemplateDataList = new ArrayList<>();
            wxMpTemplateDataList.add(new WxMpTemplateData("first", weChatRechargeTemplateParamsDTO.getFirst(), this.WE_CHAT_TOP_COLOR));
            wxMpTemplateDataList.add(new WxMpTemplateData("keyword1", weChatRechargeTemplateParamsDTO.getKeyword1(), this.WE_CHAT_TOP_COLOR));
            wxMpTemplateDataList.add(new WxMpTemplateData("keyword2", weChatRechargeTemplateParamsDTO.getKeyword2(), this.WE_CHAT_TOP_COLOR));
            wxMpTemplateDataList.add(new WxMpTemplateData("keyword3", weChatRechargeTemplateParamsDTO.getKeyword3().toString(), this.WE_CHAT_TOP_COLOR));
            wxMpTemplateDataList.add(new WxMpTemplateData("keyword4", weChatRechargeTemplateParamsDTO.getKeyword4().toString(), this.WE_CHAT_TOP_COLOR));
            wxMpTemplateDataList.add(new WxMpTemplateData("keyword5", weChatRechargeTemplateParamsDTO.getKeyword5(), this.WE_CHAT_TOP_COLOR));
            wxMpTemplateDataList.add(new WxMpTemplateData("remark", weChatRechargeTemplateParamsDTO.getRemark(), this.WE_CHAT_TOP_COLOR));
            String customerCallUrl = String.format(this.WE_CHAT_CUSTOMER_CALL_URL, weChatRechargeTemplateParamsDTO.getCustomerNumber());

            //3、构建模板消息体
            WxMpTemplateMessage wxMpTemplateMessage = WxMpTemplateMessage.builder()
                    .toUser(weChatRechargeTemplateParamsDTO.getTouser())
                    .templateId(this.WE_CHAT_TEMPLATE_ID)
                    .url(customerCallUrl)
                    .data(wxMpTemplateDataList)
                    .build();

            // 4、微信公众号消息推送与发布
            String msgId = wxMpService.getTemplateMsgService().sendTemplateMsg(wxMpTemplateMessage);
            log.error("公众号模板消息推送与发布结果:{}", msgId);
        } catch (Exception e) {
            log.info("异常信息:{}", e);
        }

        return JSONResult.success();
    }

七、抽取与封装

这儿的封装需要更具自身业务的不同,封装的深度也不同,需要自由抽取封装,但万变不离其宗,

1、简单工厂-普通模式

建立一个工厂类,对实现了同一接口的一些类进行实例的创建。

如下图:

2、简单工厂-多方法模式

对普通工厂方法模式的改进,在普通工厂方法模式中,如果传递的字符串出错,则不能正确创建对象,而多个工厂方法模式是提供多个工厂方法,分别创建对象。

如下图:

3、简单工厂-多静态方法模式

将多工厂方法模式里的方法置为静态的,不需要创建实例,直接调用即可。

4、工厂方法模式

简单工厂模式有一个问题就是,类的创建依赖工厂类,也就是说,如果想要拓展程序,必须对工厂类进行修改,这违背了闭包原则,所以,从设计角度考虑,有一定的问题,如何解决?

解决这个问题就用到工厂方法模式,创建一个工厂接口和创建多个工厂实现类,这样一旦需要增加新的功能,直接增加新的工厂类就可以了,不需要修改之前的代码。

5、抽象工厂模式

工厂方法模式:

  1. 一个抽象产品类,可以派生出多个具体产品类;
  2. 一个抽象工厂类,可以派生出多个具体工厂类; 
  3. 每个具体工厂类只能创建一个具体产品类的实例;

抽象工厂模式:

  1. 多个抽象产品类,每个抽象产品类可以派生出多个具体产品类;
  2. 一个抽象工厂类,可以派生出多个具体工厂类;
  3. 每个具体工厂类可以创建多个具体产品类的实例,也就是创建的是一个产品线下的多个产品;

区别:

  1. 工厂方法模式只有一个抽象产品类,而抽象工厂模式有多个;
  2. 工厂方法模式的具体工厂类只能创建一个具体产品类的实例,而抽象工厂模式可以创建多个;
  3. 工厂方法创建 "一种" 产品,他的着重点在于"怎么创建",也就是说如果你开发,你的大量代码很可能围绕着这种产品的构造,初始化这些细节上面。也因为如此,类似的产品之间有很多可以复用的特征,所以会和模版方法相随;
  4. 抽象工厂需要创建一些列产品,着重点在于"创建哪些"产品上,也就是说,如果你开发,你的主要任务是划分不同差异的产品线,并且尽量保持每条产品线接口一致,从而可以从同一个抽象工厂继承;

对于Java应用程序来说,能见到的大部分抽象工厂模式都是这样的:里面是一堆工厂方法,每个工厂方法返回某种类型的对象。
例如:工厂可以生产鼠标和键盘。那么抽象工厂的实现类(它的某个具体子类)的对象都可以生产鼠标和键盘,但可能工厂 A 生产的是先科的键盘和鼠标,工厂 B 是Microsoft的。这样 A 和 B 就是工厂,对应于抽象工厂;每个工厂生产的鼠标和键盘就是产品,对应于工厂方法;用了工厂方法模式,你替换生成键盘的工厂方法,就可以把键盘从先科如丝滑般的切换到Microsoft。但是用了抽象工厂模式,要想切换工厂 C 的雷蛇,就可以同时替换鼠标和键盘一套。如果产品有几十个,当然用抽象工厂模式一次替换全部最方便快捷(工厂会替换相应的工厂方法)

所以抽象工厂就像工厂,而工厂方法则像是工厂的一种产品生产线!!!

微信公众号开发注意两点:
1、公众号开发获取调用auoth2授权接口获取,Token_assecc授权时,需要授权IP,
参考:
errcode“:40164,“errmsg“:“invalid ip ...微信公众号开发调用失败的解决办法
2、在发布时,由于是基于Web页面开发的,需要授权域名的绑定验证,
参考:
微信公众号开发redirect_uri 参数错误 的解决办法,Oauth2授权重定向域名参数错误解决办法

3、SpringBoot整合调用微信模板方法实现微信公众号消息通知推送

《 HTTPClient 实现微信公众号消息推送与发布(四步走)

4、SpringBoot整合调用微信模板方法实现微信公众号消息通知推送

《 通过weixin-java-mp SDK实现微信公众号消息推送与发布(七步走)

参考:

公众号模板消息接口文档

微信网页开发-Web开发者工具下载

微信开发包】更多内容查看WIKI,MP_OAuth2网页授权

模板消息接口文档

MP_OAuth2网页授权


 好了,关于 SpringBoot整合调用微信模板方法实现微信公众号消息通知推送,Java实现微信公众号给关注用户推送自定义消息通知(从0到1)  就写到这儿了,如果还有什么疑问或遇到什么问题欢迎扫码提问,也可以给我留言哦,我会一一详细的解答的。 
歇后语:“ 共同学习,共同进步 ”,也希望大家多多关注CSND的IT社区。


作       者: 华    仔
联系作者: [email protected]
来        源: CSDN (Chinese Software Developer Network)
原        文: https://blog.csdn.net/Hello_World_QWP/article/details/125871196
版权声明: 本文为博主原创文章,请在转载时务必注明博文出处!

猜你喜欢

转载自blog.csdn.net/Hello_World_QWP/article/details/125871196