SpringBoot(JAVA)整合微信公众号消息推送

您所在的位置:网站首页 微信公众号专栏添加了看不到 SpringBoot(JAVA)整合微信公众号消息推送

SpringBoot(JAVA)整合微信公众号消息推送

2024-07-15 00:33| 来源: 网络整理| 查看: 265

网上那些都是零零碎碎的,不完整,重新整理下,代码可直接使用。 微信公众号消息推送大致分为两类,一是文本推送,二是带图片/视频推送。 文本推送很好理解,可以用模板消息以及自定义消息推送。 图文/视频推送就稍微麻烦些步骤分为 上传素材到临时/永久库->上传图文消息->消息推送。 贴几个官方文档,有总比没有好。 群发推送官网文档:https://developers.weixin.qq.com/doc/offiaccount/Message_Management/Batch_Sends_and_Originality_Checks.html 上传素材官方文档:https://developers.weixin.qq.com/doc/offiaccount/Asset_Management/New_temporary_materials.html 官方素材上传调试平台:https://mp.weixin.qq.com/debug/cgi-bin/apiinfo?t=index&type=%E5%9F%BA%E7%A1%80%E6%94%AF%E6%8C%81&form=%E5%A4%9A%E5%AA%92%E4%BD%93%E6%96%87%E4%BB%B6%E4%B8%8A%E4%BC%A0%E6%8E%A5%E5%8F%A3%20/media/upload

一、文本推送

这里文本推送,可以采取模板和自定义推送内容。以下是模板方式推送,在图片/视频推送中会使用自定义内容推送演示。

首先需要在微信公众号上把测试的环境弄好。 点击开发者工具->公众平台测试账号。进去创建好对应的消息模板以及关注该测试的公众号。里面会有appID/appsecret,用户,模板以及能体验接口的信息,没有认证的微信号,有些接口是没有权限的,而且部分接口在没有认证的情况下每天都会有调用次数限制。 在这里插入图片描述 在这里插入图片描述在这里插入图片描述 添加依赖,因为项目里面用了自己的http封装类,需替换下

com.squareup.okhttp3 okhttp 5.0.0-alpha.14 com.squareup.okio okio 3.6.0

WxToken 用于生成请求接口token

/** * 存储微信公众号Token的POJO类 * * @author zjw * @description */ public class WxToken { // 存储token信息 private String accessToken; // 10:00:00 // 12:00:00 // 存储当前的token有效期到什么时间点 private Long expire; public String getAccessToken() { // 获取token之前,需要先判断生存时间到了没 return expire == null || expire 上传图文消息->消息推送。 之前看社区说永久的素材库不能使用,下面的示例采用的是临时库。

注:上传素材的时候会返回media_id这个ID在上传图文消息的时候需要用到,上传图文消息的时候也会返回media_id,这个ID在消息推送的时候也会用到。 在这里插入图片描述

WxMagPushAllReq

@Data @Schema(description = "微信消息推送全部用户实体") @JsonInclude(JsonInclude.Include.NON_NULL) public class WxMagPushAllReq { @Schema(description = "1-文本,2图文,当发送图文消息时,mediaId不能为空") private String type; // @NotBlank(message = "消息内容不能为空") @Schema(description = "图文mediaId") private String mediaId; // @NotBlank(message = "消息内容不能为空") @Schema(description = "消息内容") private String content; }

WxTuwen

@Data public class WxTuwen { //图片media_id @Schema(description = "图片media_id") private String thumb_media_id; @Schema(description = "图文消息的作者") //图文消息的作者 private String author; @Schema(description = "标题") //标题 private String title; @Schema(description = "在图文消息页面点击“阅读原文”后的页面,受安全限制,如需跳转Appstore,可以使用itun.es或appsto.re的短链服务,并在短链后增加 #wechat_redirect 后缀") //在图文消息页面点击“阅读原文”后的页面,受安全限制,如需跳转Appstore,可以使用itun.es或appsto.re的短链服务,并在短链后增加 #wechat_redirect 后缀。 private String content_source_url; @Schema(description = "图文消息页面的内容") //图文消息页面的内容,支持HTML标签。 private String content; @Schema(description = "图文消息的描述") //图文消息的描述,如本字段为空 private String digest; @Schema(description = "是否显示封面,1为显示,0为不显示") //是否显示封面,1为显示,0为不显示 private Integer show_cover_pic; }

controller

@Operation(summary = "微信公众号消息推送--推送全部用户") @PostMapping("/wxMsgPushAll") public Result wxMsgPushAll(@RequestBody @Valid WxMagPushAllReq wxMagPushAllReq) { return messageService.wxMsgPushAll(wxMagPushAllReq); } @Operation(summary = "微信公众号消息推送--上传临时素材") @PostMapping("/addMaterial") public Result addMaterial(@RequestParam("media") MultipartFile media, @RequestParam("type") String type) { return messageService.addMaterial(media,type); } @Operation(summary = "微信公众号消息推送--上传图文消息素材") @PostMapping("/uploadnews") public Result uploadnews(@RequestBody @Valid WxTuwen wxTuwen) { return messageService.uploadnews(wxTuwen); }

serveice

Result wxMsgPushAll(WxMagPushAllReq wxMagPushAllReq); Result addMaterial(MultipartFile media, String type); Result uploadnews(WxTuwen wxTuwen);

serviceImpl

@Value("${weixin.msg.secret}") private String secret; @Value("${weixin.msg.appid}") private String appid; private static WxToken wxToken = new WxToken(); @Override public Result wxMsgPushAll(WxMagPushAllReq wxMagPushAllReq) { String list = getWxUserOpenid(getTokenString(), "", ""); if (StringUtils.isEmpty(list)) { return Result.ok(); } String url = "https://api.weixin.qq.com/cgi-bin/message/mass/send?access_token=" + getTokenString(); //预览接口,可以看推送的效果 // String url = " https://api.weixin.qq.com/cgi-bin/message/mass/preview?access_token=" + getTokenString(); String params = ""; if ("1".equals(wxMagPushAllReq.getType())) { //自定义推送内容 params = "{\n" + " \"touser\":[" + list.substring(0, list.length() - 1) + "],\n" + " \"msgtype\": \"text\",\n" + " \"text\": { \"content\": \"" + wxMagPushAllReq.getContent() + "\"}" + " }"; } else { //带图文推送消息 params = "{\n" + " \"touser\":[" + list.substring(0, list.length() - 1) + "],\n" + " \"mpnews\":{\n" + " \"media_id\":\"" + wxMagPushAllReq.getMediaId() + "\"\n" + " },\n" + " \"msgtype\":\"mpnews\",\n" + " \"send_ignore_reprint\":0\n" + "}"; } HttpRequest request = HttpUtil.createPost(url); request.body(params); String str = request.execute().body(); System.out.println(str); return Result.ok(str); } @Override public Result addMaterial(MultipartFile media, String type) { try { String mediaId = uploadFile(transferToFile(media), getTokenString(), type); return Result.ok(mediaId); } catch (Exception e) { throw new RuntimeException(e); } } @Override public Result uploadnews(WxTuwen wxTuwen) { //如需处理多个图文,修改为循环处理 String url = "https://api.weixin.qq.com/cgi-bin/media/uploadnews?access_token=" + getTokenString(); String str = JSONObject.toJSONString(wxTuwen); str = "{" + "\"articles\":[" + str + "]" + "}"; HttpRequest request = HttpUtil.createPost(url); request.body(str); String body = request.execute().body(); JSONObject jsonObject = JSONObject.parseObject(body); return Result.ok(jsonObject.getString("media_id")); } //将类型MultipartFile转为file类型 public File transferToFile(MultipartFile file) { try { File convFile = new File(file.getOriginalFilename()); convFile.createNewFile(); InputStream in = file.getInputStream(); OutputStream out = new FileOutputStream(convFile); byte[] bytes = new byte[1024]; int read; while ((read = in.read(bytes)) != -1) { out.write(bytes, 0, read); } return convFile; } catch (Exception e) { throw new RuntimeException(); } } //上传到临时库,返回一个ID public String uploadFile(File file, String accessToken, String type) throws Exception { //临时素材地址 String url1 = "https://api.weixin.qq.com/cgi-bin/media/upload?access_token=" + accessToken + "&type=" + type; //永久素材的地址 // String url1 = "https://api.weixin.qq.com/cgi-bin/material/add_material?access_token=" + accessToken + "&type=" + type; if (!file.exists() || !file.isFile()) { throw new IOException("文件不存在!"); } URL urlObj = new URL(url1); //连接 HttpURLConnection conn = (HttpURLConnection) urlObj.openConnection(); conn.setRequestMethod("POST"); conn.setDoInput(true); conn.setDoOutput(true); conn.setUseCaches(false); //请求头 conn.setRequestProperty("Connection", "Keep-Alive"); conn.setRequestProperty("Charset", "UTF-8"); //conn.setRequestProperty("Content-Type","multipart/form-data;"); //设置边界 String BOUNDARY = "----------" + System.currentTimeMillis(); conn.setRequestProperty("Content-Type", "multipart/form-data;boundary=" + BOUNDARY); StringBuilder sb = new StringBuilder(); sb.append("--"); sb.append(BOUNDARY); sb.append("\r\n"); sb.append("Content-Disposition:form-data;name=\"file\";filename=\"" + file.getName() + "\"\r\n"); sb.append("Content-Type:application/octet-stream\r\n\r\n"); System.out.println(sb); byte[] head = sb.toString().getBytes("UTF-8"); //输出流 OutputStream out = new DataOutputStream(conn.getOutputStream()); out.write(head); //文件正文部分 DataInputStream in = new DataInputStream(new FileInputStream(file)); int bytes = 0; byte[] bufferOut = new byte[1024]; while ((bytes = in.read(bufferOut)) != -1) { out.write(bufferOut, 0, bytes); } in.close(); //结尾 byte[] foot = ("\r\n--" + BOUNDARY + "--\r\n").getBytes("utf-8"); out.write(foot); out.flush(); out.close(); //获取响应 StringBuffer buffer = new StringBuffer(); BufferedReader reader = null; String result = null; reader = new BufferedReader(new InputStreamReader(conn.getInputStream())); String line = null; while ((line = reader.readLine()) != null) { buffer.append(line); } if (result == null) { result = buffer.toString(); } reader.close(); //需要添加json-lib jar包 JSONObject json = JSONObject.parseObject(result); System.out.println(json); String mediaId = json.getString("thumb_media_id"); return result; } //根据appid和secretaccess_token private String getToken() { String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + appid + "&secret=" + secret; //2、基于doGet方法,调用地址获取Token HttpRequest request = HttpUtil.createGet(url); String resultJSON = request.execute().body(); JSONObject jsonObject = JSONObject.parseObject(resultJSON); String accessToken = jsonObject.getString("access_token"); Long expiresIn = jsonObject.getLong("expires_in"); //3、存储到WxToken对象里 wxToken.setAccessToken(accessToken); wxToken.setExpire(expiresIn); //4、返回Token return wxToken.getAccessToken(); } public String getTokenString() { // 从对象中获取accessToken String accessToken = wxToken.getAccessToken(); // 获取的accessToken为null,可能之前没获取,可能过期了 if (accessToken == null) { // 加锁 synchronized (wxToken) { // 再次判断 if (wxToken.getAccessToken() == null) { getToken(); } } } return wxToken.getAccessToken(); }


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3