文章目录

  • 1. 公众号申请和配置
    • 首先!!记得设置白名单
  • 2. 依赖
    • 2.1 父子工程聚合
    • 2.2 独立的单独工程
  • 3. 工具类
    • 3.1 HttpUtil http请求工具类
    • 3.2 RestTemplateConfig 配置类
    • 3.3 WeChatTemplate 短信模板实体类
    • 3.4 WxConstant 微信相关参数封装类
    • 3.5 WxGetTokenUtil 生成 access_token
    • 3.7 WxMpConfiguration 微信server的配置类,不写这个server就没法用
    • 3.8 WxResult 微信返回错误码封装类
    • 3.9 WxSendUtill 发送消息工具类
  • 4. 调用(controller)

1. 公众号申请和配置

首先!!记得设置白名单

2. 依赖

2.1 父子工程聚合

<!--父工程版本控制-->   <properties><weixin-java-mp.version>3.0.0</weixin-java-mp.version></properties><dependencyManagement><dependencies><!--微信公众号--><dependency><groupId>com.github.binarywang</groupId><artifactId>weixin-java-mp</artifactId><version>${weixin-java-mp.version}</version></dependency><!--json转化的工具依赖--><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>${fastjson.version}</version></dependency></dependencies></dependencyManagement><!--子工程中引用--><!--微信公众号--><dependency><groupId>com.github.binarywang</groupId><artifactId>weixin-java-mp</artifactId></dependency><!--json转化的工具依赖--><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId></dependency>

2.2 独立的单独工程

         <!--微信公众号--><dependency><groupId>com.github.binarywang</groupId><artifactId>weixin-java-mp</artifactId><version>3.0.0</version></dependency><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.47</version></dependency>

3. 工具类

目录结构:

  • util.wx文件夹

    • HttpUtil.java 类
    • RestTemplateConfig.java 类
    • WeChatTemplate 类
    • WxConstant.java 类
    • WxGetTokenUtil.java 类
    • WxResult.java 类
    • WxSendUtil.java 类

3.1 HttpUtil http请求工具类

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;import javax.net.ssl.*;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Map;@Slf4j
public class HttpUtil {protected static final String POST_METHOD = "POST";private static final String GET_METHOD = "GET";static {TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager() {@Overridepublic void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {log.debug("ClientTrusted");}@Overridepublic void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {log.debug("ServerTrusted");}@Overridepublic X509Certificate[] getAcceptedIssuers() {return new X509Certificate[]{};}}};HostnameVerifier doNotVerify = (s, sslSession) -> true;try {SSLContext sc = SSLContext.getInstance("SSL", "SunJSSE");sc.init(null, trustAllCerts, new SecureRandom());HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());HttpsURLConnection.setDefaultHostnameVerifier(doNotVerify);} catch (Exception e) {log.error("Initialization https impl occur exception : {}", e);}}/*** 默认的http请求执行方法** @param url  url 路径* @param method 请求的方法 POST/GET* @param map  请求参数集合* @param data  输入的数据 允许为空* @return result*/private static String HttpDefaultExecute(String url, String method, Map<String, String> map, String data) {String result = "";try {url = setParmas(url, map, null);result = defaultConnection(url, method, data);} catch (Exception e) {log.error("出错参数 {}", map);}return result;}public static String httpGet(String url, Map<String, String> map) {return HttpDefaultExecute(url, GET_METHOD, map, null);}public static String httpPost(String url, Map<String, String> map, String data) {return HttpDefaultExecute(url, POST_METHOD, map, data);}/*** 默认的https执行方法,返回** @param url  url 路径* @param method 请求的方法 POST/GET* @param map  请求参数集合* @param data  输入的数据 允许为空* @return result*/private static String HttpsDefaultExecute(String url, String method, Map<String, String> map, String data) {try {url = setParmas(url, map, null);log.info(data);return defaultConnection(url, method, data);} catch (Exception e) {log.error("出错参数 {}", map);}return "";}public static String doGet(String url, Map<String, String> map) {return HttpsDefaultExecute(url, GET_METHOD, map, null);}public static String doPost(String url, Map<String, String> map, String data) {return HttpsDefaultExecute(url, POST_METHOD, map, data);}/*** @param path  请求路径* @param method 方法* @param data  输入的数据 允许为空* @return* @throws Exception*/private static String defaultConnection(String path, String method, String data) throws Exception {if (StringUtils.isBlank(path)) {throw new IOException("url can not be null");}String result = null;URL url = new URL(path);HttpURLConnection conn = getConnection(url, method);if (StringUtils.isNotEmpty(data)) {OutputStream output = conn.getOutputStream();output.write(data.getBytes(StandardCharsets.UTF_8));output.flush();output.close();}if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) {InputStream input = conn.getInputStream();result = IOUtils.toString(input, StandardCharsets.UTF_8);input.close();conn.disconnect();}return result;}/*** 根据url的协议选择对应的请求方式* @param url  请求路径* @param method 方法* @return conn* @throws IOException 异常*///待改进protected static HttpURLConnection getConnection(URL url, String method) throws IOException {HttpURLConnection conn;if (StringUtils.equals("https", url.getProtocol())) {conn = (HttpsURLConnection) url.openConnection();} else {conn = (HttpURLConnection) url.openConnection();}if (conn == null) {throw new IOException("connection can not be null");}conn.setRequestProperty("Pragma", "no-cache");// 设置不适用缓存conn.setRequestProperty("Cache-Control", "no-cache");conn.setRequestProperty("Connection", "Close");// 不支持Keep-Aliveconn.setUseCaches(false);conn.setDoOutput(true);conn.setDoInput(true);conn.setInstanceFollowRedirects(true);conn.setRequestMethod(method);conn.setConnectTimeout(8000);conn.setReadTimeout(8000);return conn;}/*** 根据url* @param url 请求路径* @return isFile* @throws IOException 异常*///待改进protected static HttpURLConnection getConnection(URL url, boolean isFile) throws IOException {HttpURLConnection conn = (HttpURLConnection) url.openConnection();if (conn == null) {throw new IOException("connection can not be null");}//设置从httpUrlConnection读入conn.setDoInput(true);conn.setDoOutput(true);conn.setUseCaches(false);//如果是上传文件,则设为POSTif (isFile) {conn.setRequestMethod(POST_METHOD); //GET和 POST都可以 文件略大改成POST}// 设置请求头信息conn.setRequestProperty("Connection", "Keep-Alive");conn.setRequestProperty("Charset", String.valueOf(StandardCharsets.UTF_8));conn.setConnectTimeout(8000);conn.setReadTimeout(8000);return conn;}/*** 拼接参数* @param url   需要拼接参数的url* @param map   参数* @param charset 编码格式* @return 拼接完成后的url*/public static String setParmas(String url, Map<String, String> map, String charset) throws Exception {String result = StringUtils.EMPTY;boolean hasParams = false;if (StringUtils.isNotEmpty(url) && map != null && !map.isEmpty()) {StringBuilder builder = new StringBuilder();for (Map.Entry<String, String> entry : map.entrySet()) {String key = entry.getKey().trim();String value = entry.getValue().trim();if (hasParams) {builder.append("&");} else {hasParams = true;}if (StringUtils.isNotEmpty(charset)) {builder.append(key).append("=").append(URLEncoder.encode(value, charset));} else {builder.append(key).append("=").append(value);}}result = builder.toString();}URL u = new URL(url);if (StringUtils.isEmpty(u.getQuery())) {if (url.endsWith("?")) {url += result;} else {url = url + "?" + result;}} else {if (url.endsWith("&")) {url += result;} else {url = url + "&" + result;}}log.debug("request url is {}", url);return url;}
}

3.2 RestTemplateConfig 配置类

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;@Configuration
public class RestTemplateConfig {@Beanpublic RestTemplate restTemplate(ClientHttpRequestFactory factory) {return new RestTemplate(factory);}@Beanpublic ClientHttpRequestFactory simpleClientHttpRequestFactory() {SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();factory.setConnectTimeout(15*1000);factory.setReadTimeout(60*60*1000);return factory;}
}

3.3 WeChatTemplate 短信模板实体类

import lombok.Data;
import java.util.TreeMap;
@Data
public class WeChatTemplate {private String touser; //接收者openidprivate String template_id; //模板IDprivate String url; //URL置空,则在发送后,点击模板消息会进入一个空白页面(ios),或无法点击(android)private TreeMap<String, TreeMap<String, String>> data; //data数据public static TreeMap<String, String> item(String value, String color) {TreeMap<String, String> params = new TreeMap<String, String>();params.put("value", value);params.put("color", color);return params;}@Overridepublic String toString() {return "WechatTemplate" +"{" +"openId='" + touser + "'," +"template_id='" + template_id + "'," +"url='" + url + "'," +"data=" + data +'}';}
}

3.4 WxConstant 微信相关参数封装类

public class WxConstant {/*** 开发者appId*/public static final String appId="xxxxxxxxxxxxxxxxx";/*** 开发者密码 appSecret*/public static final String appSecret="xxxxxxxxxxxxxxxxxxxxxxxx";/*** templateId:微信公众号模板id*/public static final String templateId="xxxxxxxxxxxxxxxxxxxx";
}

3.5 WxGetTokenUtil 生成 access_token

import com.alibaba.fastjson.JSONObject;
import java.util.HashMap;
import java.util.Map;
public class WxGetTokenUtil {public static String getAccessToken() {String appSecret = WxConstant.appSecret;String appId = WxConstant.appId;String tokenUrl = "https://api.weixin.qq.com/cgi-bin/token";Map<String, String> params = new HashMap<>();params.put("appid", appId);params.put("secret", appSecret);params.put("grant_type", "client_credential");String response = HttpUtil.doGet(tokenUrl, params);System.out.println("WxGetTokenUtil.getAccessToken()返回值:" + response);//此处可注释,调试时解开,防止code出报错找不到原因JSONObject accessTokenObject = JSONObject.parseObject(response);return accessTokenObject.getString("access_token");}
}

3.7 WxMpConfiguration 微信server的配置类,不写这个server就没法用

import me.chanjar.weixin.mp.api.WxMpConfigStorage;
import me.chanjar.weixin.mp.api.WxMpInMemoryConfigStorage;
import me.chanjar.weixin.mp.api.WxMpService;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/*** wechat mp configuration*/
@Configuration
@ConditionalOnClass(WxMpService.class)
public class WxMpConfiguration {@Bean@ConditionalOnMissingBeanpublic WxMpConfigStorage configStorage() {WxMpInMemoryConfigStorage configStorage = new WxMpInMemoryConfigStorage();configStorage.setAppId(WxConstant.appId);configStorage.setSecret(WxConstant.appSecret);
//    configStorage.setToken(WxConstant.token);
//    configStorage.setAesKey(WxConstant.key);return configStorage;}@Bean@ConditionalOnMissingBeanpublic WxMpService wxMpService(WxMpConfigStorage configStorage) {WxMpService wxMpService = new me.chanjar.weixin.mp.api.impl.WxMpServiceImpl();wxMpService.setWxMpConfigStorage(configStorage);return wxMpService;}
}

3.8 WxResult 微信返回错误码封装类

import lombok.Data;
@Data
public class WxResult {private String errcode;private String errmsg;private String msgid;@Overridepublic String toString() {return "WxError{errcode='" + errcode + "',errmsg='" + errmsg + "',msgid='" + msgid + "'}";}
}

3.9 WxSendUtill 发送消息工具类

注意,参数是根据你自己的模板进行组装的,我的模板有以下参数

{first,keyword1,keyword2,keyword3,keyword4,keyword5,remark}

import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.exception.WxErrorException;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.template.WxMpTemplateData;
import me.chanjar.weixin.mp.bean.template.WxMpTemplateMessage;
import net.sf.json.JSONObject;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TreeMap;
/*** 推送公众号消息*/
@Slf4j
@Component //使用方式2,需要用到这个注解,并且需要用到WxMapConfiguration。
public class WxSendUtil {/*** 发送消息,方式1* @param openId 用户openId* @param data   数据* @param title  标题*/public static WxResult send(String openId, String data, String title) {String url = "https://www.baidu.com";String templateUrl = "https://api.weixin.qq.com/cgi-bin/message/template/send";String time = parseDate3String(new Date());String accessToken = WxGetTokenUtil.getAccessToken();log.info("获取access_token,微信平台接口返回{}", accessToken);TreeMap<String, TreeMap<String, String>> params = new TreeMap<String, TreeMap<String, String>>();//根据具体模板参数的  添加数据params.put("first", WeChatTemplate.item(title, "#000000"));//一般是标题params.put("keyword1", WeChatTemplate.item("项目名称", "#ff0000"));//项目名称,字体颜色params.put("keyword2", WeChatTemplate.item(time, "#000000"));params.put("keyword3", WeChatTemplate.item(time, "#000000"));params.put("keyword4", WeChatTemplate.item(time, "#000000"));params.put("keyword5", WeChatTemplate.item(time, "#000000"));params.put("remark", WeChatTemplate.item(data, "#000000"));WeChatTemplate wechatTemplate = new WeChatTemplate();wechatTemplate.setTemplate_id(WxConstant.templateId);//模板idwechatTemplate.setTouser(openId);// 接收者openidwechatTemplate.setUrl(url); // 模板跳转链接wechatTemplate.setData(params);JSONObject json = JSONObject.fromObject(wechatTemplate);//将java对象转换为json对象String sendData = json.toString();//将json对象转换为字符串log.info("板参数组装{}", sendData);TreeMap<String, String> treeMap = new TreeMap<String, String>();treeMap.put("access_token", accessToken);String retInfo = HttpUtil.doPost(templateUrl, treeMap, sendData);if (!StringUtils.isBlank(retInfo)) {return JSON.parseObject(retInfo, WxResult.class);}log.info("消息模板返回{}", retInfo);return null;}@Autowiredprivate WxMpService wxService;/*** 发送消息,方式2* 发送微信模板信息* @param openId openId* @param url    跳转地址* @param title  标题*/public Boolean sendWxMsg(String openId, String url, String title) {String time = parseDate3String(new Date());// 发送模板消息接口WxMpTemplateMessage templateMessage = WxMpTemplateMessage.builder()// 接收者openid.toUser(openId)// 模板id.templateId(WxConstant.templateId)// 模板跳转链接.url(url).build();// 添加模板数据templateMessage.addData(new WxMpTemplateData("first", title, "#FF00FF")).addData(new WxMpTemplateData("keyword1", "紧急", "#A9A9A9")).addData(new WxMpTemplateData("keyword2", time, "#A9A9A9")).addData(new WxMpTemplateData("remark", url, "#FF00FF"));String msgId = null;try {// 发送模板消息msgId = this.wxService.getTemplateMsgService().sendTemplateMsg(templateMessage);} catch (WxErrorException e) {e.printStackTrace();}log.warn("·==++--·推送微信模板信息:{}·--++==·", msgId != null ? "成功" : "失败");return msgId != null;}//时间转化成字符串,格式  yyyy-MM-dd HH:mm:ssprivate static String parseDate3String(Date date) {SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");return sdf.format(date);}}

4. 调用(controller)

发消息得有发送对象—用户,,要获取到用户的openId,然后才能进行发送

import com.alibaba.fastjson.JSONObject;
import com.sq.statistics.utils.wx.WxGetTokenUtil;
import com.sq.statistics.utils.wx.WxSendUtil;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;import java.util.HashMap;
import java.util.List;
import java.util.Map;@RestController
@RequestMapping("/wx")
public class WXController {@Autowiredprivate RestTemplate restTemplate;/*** 获取关注者的openid*/@GetMapping("/open-id/list")public Map<String, Object> getOpenIdList(@RequestParam(required = false) String next_openid) {String url = "https://api.weixin.qq.com/cgi-bin/user/get?access_token={access_token}";Map<String, Object> param = new HashMap<>();param.put("next_openid", next_openid);param.put("access_token", WxGetTokenUtil.getAccessToken());HttpHeaders headers = new HttpHeaders();ResponseEntity<String> entity =restTemplate.exchange(url,HttpMethod.GET,new HttpEntity<String>(headers),String.class,param);String result = entity.getBody();System.out.println("WXController.getOpenIdList()返回值:" + result);//此处可注释,调试时解开,防止code出报错if (result != null && result.contains("count")) {//返回值可能有两种,一种是报错的,一种是正常返回Map<String, Object> resultData = JSONObject.parseObject(result, Map.class);
//            return resultData;//可以直接返回,也可以自己抽取,,我只需要openId和next_openIdString next_openId = resultData.get("next_openid").toString(); //这个是下一组数据需要的传参Map<String, Object> data = JSONObject.parseObject(resultData.get("data").toString(), Map.class);List<String> openidList = JSONObject.parseArray(data.get("openid").toString(), String.class);Map<String, Object> map = new HashMap<>();map.put("next_openId", next_openId);map.put("openidList", openidList);return map;}return null;//返回的是tokenList,如果想要下一组数据,最后传的/*** 正确返回* {"total":2,"count":2,"data":{"openid":["111111","222222"]},"next_openid":"222222"}** 错误返回,下边这个是白名单没开* {"errcode":40164,"errmsg":"invalid ip 180.0.0.0 ipv6 ::ffff:180.0.0.0, not in whitelist rid: 6268e703-5bc5bc49-4d17363f"}*/}/*** 发送消息*/@PostMapping("/send/message")public void sendMessage(String message, String title, String openId) {WxSendUtil.send(openId, message, title);}
}

springboot推送微信公众号消息,java推送微信公众号消息相关推荐

  1. java 微信 百度地图_[Java教程]H5微信通过百度地图API实现导航方式二

    [Java教程]H5微信通过百度地图API实现导航方式二 0 2017-08-01 23:53:20 要有服务器才行哦 body, html {width: 100%;height: 100%;mar ...

  2. 微信公众号开发java流程_微信公众号开发教程java 编程语言的特点及选择

    微信公众号开发教程java 编程语言的特点及选择 微信公众号为用户提供了相关的工具,来对微信公众号进行一个简单的开发.但是如果想实现一些复杂的功能,其实还是要借助于一些编程语言的使用.所以要了解,在微 ...

  3. 微信公众平台开发JAVA(四)公众号进行视频发送

    备注:测试基于微信公众平台测试号编写,真实开发环境基本适用 微信公众号在进行视频群发的时候有一个坑,大家可以先看一下文档描述: 意思就是说要先把视频素材的media_id通过这个接口post一下,于是 ...

  4. 微信第三方扫描登录 java源代码_微信开放平台基于网站应用授权登录源码(java)...

    1. 第三方发起微信授权登录请求,微信用户允许授权第三方应用后,微信会拉起应用或重定向到第三方网站,并且带上授权临时票据code参数: 2. 通过code参数加上AppID和AppSecret等,通过 ...

  5. java服务器如何群发消息,java TCP编程简单实现一个消息群发功能

    client: package com.lzs.net; import java.io.*; import java.net.Socket; /** * Created by zaish on 201 ...

  6. java调用个人微信api接口实现收发消息发朋友圈

    个人微信api接口,java调用个人微信api接口实现收发消息发朋友圈 1.微信好友收发消息         /**      * 给微信好友发消息      * @author wechatno:t ...

  7. 送100本书!涵盖Java 、大数据、推荐系统、机器学习、黑客、数据库、手游、少儿编程等!免费包邮!...

    「清华大学出版社」联系了包括架构师小秘圈在内的 10 家技术公众号,送出 100本技术书.内容涉及Java. 大数据.推荐系统.机器学习.黑客.数据库.手游.少儿编程等! 01 书怎么送 在下面的公众 ...

  8. java微信签名什么意思,java,_求java实现微信签名,java - phpStudy

    求java实现微信签名 1.求java怎么实现微信签名 package sign; import java.security.MessageDigest; public class MD5Util { ...

  9. 《啊哈!算法》第二章 - 第一节 - 解密QQ号(Java实现)

    <啊哈!算法>第二章 - 第一节- 解密QQ号(Java实现) 解密QQ号--队列 解密QQ号--队列 新学期开始了,小哈是小哼的新同桌(小哈是个小美女哦~),小哼向小哈询问 QQ号, 小 ...

  10. 微信公众号 - Java推送公众号模板消息给用户

    不啰嗦,我们直接开始! 由于没有公众帐号,本文使用微信公众平台接口测试帐号进行调试. 一.申请测试帐号 1.使用微信扫码登录下面网址 微信公众平台 (qq.com) 2.找到appID和appsecr ...

最新文章

  1. mysql主从切换(正常切换)
  2. 北京瑜舍酒店成京城“精品”酒店代表(图)_新浪尚品_新浪网
  3. C++ 基本数据类型
  4. windows 安装 openssl
  5. CLR线程概览(一)
  6. Hive笔记之JOIN的左外链接和右外链接
  7. Linux | Ubuntu:十年,十个关键时刻
  8. 群体智能优化算法之蟑螂算法((Cockroach Swarm Optimization,CSO)
  9. leancloud 怎么绑定域名_云引擎支持绑定加速域名 | LeanCloud 八月变化
  10. PDF转WORD乱码怎么办
  11. mssql数据库置疑修复
  12. 智能客服、聊天机器人的应用和架构、算法分享和介绍
  13. pdg文件格式 到 pdf文件格式 的转换
  14. 云计算:几种aaS(as a Server)
  15. UITT 自动跟单系统
  16. 《老炮儿》的江湖道义就是互联网创业的规矩?
  17. IDEA代码抽取为方法快捷键
  18. 6月26日科技资讯|华为获首张 5G 终端进网许可证;Linux 之父来华;Eclipse 4.12 发布
  19. “香港街马”3名跑手晕倒送院 医生:应量力而为
  20. 研一学机器学习和深度学习,为什么感觉越学越不会,怎么解决呢?

热门文章

  1. 6 种常用的项目管理模式
  2. Java开发社招面试经验:2021最新Java面试笔试
  3. 阿里云DataV基础平面地图使用笔记(2)
  4. 为什么计算机和网络设备都需要接地,一个实例全面讲解机房如何做防雷接地?...
  5. 游戏加加导致cpu降频
  6. JavaScript基础复习下(51st)
  7. 如何建立工程测量平面控制网?
  8. EasyUI中combogrid设置onSelect后 获取不到getSelecte问题解决
  9. 计算机投影仪的作用是什么,投影电脑
  10. excel工作表合并