最近在做一些企业微信应用推送消息的一些东西,总结一下。
插件:基于OkHttp发送请求。
package io.yunke.common.utils;
import com.alibaba.fastjson.JSON;
import okhttp3.*;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicReference;
public class HTTP {
private static final MediaType JSONTYPE
= MediaType.get("application/json; charset=utf-8");
public static <T> T post(String url, Object obj, Class<T> clazz) {
RequestBody body = RequestBody.create(JSONTYPE, JSON.toJSONString(obj));
Request request = new Request.Builder()
.url(url)
.post(body)
.build();
try (Response response = new OkHttpClient().newCall(request).execute()) {
return JSON.parseObject(Objects.requireNonNull(response.body()).string(), clazz);
} catch (Exception e) {
return null;
}
}
public static <T> T get(String url, Map<String, String> param, Class<T> clazz) {
// 处理问号传值
AtomicReference<String> _url = new AtomicReference<>("");
if (param.keySet().size() != 0) {
_url.set(url + "?");
param.forEach((k, v) -> {
String u = _url.get();
u += (k + "=" + v + "&");
_url.set(u);
});
} else {
_url.set(url);
}
Request request = new Request.Builder()
.url(_url.get())
.get()
.build();
try (Response response = new OkHttpClient().newCall(request).execute()) {
return JSON.parseObject(Objects.requireNonNull(response.body()).string(), clazz);
} catch (Exception e) {
return null;
}
}
}
// 企业微信标准发送格式
{
"touser" : "UserID1|UserID2|UserID3",
"toparty" : "PartyID1 | PartyID2",
"totag" : "TagID1 | TagID2",
"msgtype" : "news",
"agentid" : 1,
"news" : {
"articles" : [
{
"title" : "中秋节礼品领取",
"description" : "今年中秋节公司有豪礼相送",
"url" : "URL",
"picurl" : "http://res.mail.qq.com/node/ww/wwopenmng/images/independent/doc/test_pic_msg1.png",
"appid": "wx123123123123123",
"pagepath": "pages/index?userid=zhangsan&orderid=123123123",
}
]
},
"enable_id_trans": 0,
"enable_duplicate_check": 0,
"duplicate_check_interval": 1800
}
构造实体类(示例):
package io.yunke.modules.wechat.entity;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.annotations.ApiModelProperty;
import io.yunke.modules.wechat.vo.PictureNewsVo;
import lombok.Data;
import java.io.Serializable;
@Data
@TableName("picture_news_push")
public class PictureNewsPushEntity implements Serializable {
@TableId
private Long id;
/**
* 格式:"UserID1"或"UserID1|UserID2|UserID3"
*/
@ApiModelProperty(value = "推送给谁")
private String touser;
/**
* 格式:"PartyID1"或"PartyID1 | PartyID2"
*/
@ApiModelProperty(value = "部门")
private String toparty;
/**
* 标签ID列表
*/
@ApiModelProperty(value = "标签")
private String totag;
/**
* 消息类型
*/
@ApiModelProperty(value = "消息类型")
private String msgtype;
/**
* 企业应用的id,整型。
*/
@ApiModelProperty(value = "企业应用的id,整型。")
private String agentid;
/**
* 表示是否开启id转译,0表示否,1表示是,默认0
*/
@ApiModelProperty(value = "表示是否开启id转译,0表示否,1表示是,默认0")
private Integer enable_id_trans;
/**
* 表示是否开启重复消息检查,0表示否,1表示是,默认0
*/
@ApiModelProperty(value = "表示是否开启重复消息检查,0表示否,1表示是,默认0")
private Integer enable_duplicate_check;
@TableField(exist = false)
private PictureNewsVo news;
}
内容实体类(示例):
@Data
@TableName("picture_content")
public class PictureWordContentEntity {
/*
{
"title": "Title",
"thumb_media_id": "MEDIA_ID",
"author": "Author",
"content_source_url": "URL",
"content": "Content",
"digest": "Digest description"
}
*/
@ApiModelProperty(value = "标题")
private String title;
@ApiModelProperty(value = "上传临时文件返回的media_id")
private String thumb_media_id;
@ApiModelProperty(value = "作者")
private String author;
@ApiModelProperty(value = "跳转的url")
private String content_source_url;
@ApiModelProperty(value = "内容")
private String content;
@ApiModelProperty(value = "企业应用的id")
private String digest;
}
中间表实体类(示例):
@Data
public class PictureNewsVo implements Serializable {
private List<PictureNewsContentEntity> articles;
}
构造返回数据结果(示例):
/**
* @notes: 企业微信返回数据
*/
@Data
public class WeChatResultVo {
/**
* {
* "errcode" : 0,
* "errmsg" : "ok",
* "invaliduser" : "userid1|userid2",
* "invalidparty" : "partyid1|partyid2",
* "invalidtag": "tagid1|tagid2",
* "msgid": "xxxx",
* "response_code": "xyzxyz"
* }
*/
private Integer errcode;
private String errmsg;
private String invaliduser;
private String invalidparty;
private String invalidtag;
private String msgid;
private String response_code;
}
token存在redis中缓存,启动获取token(示例):
import io.yunke.common.constant.WeChatConstant;
import io.yunke.common.utils.HTTP;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
/**
* @notes: 企业微信调用接口
*/
@Slf4j
@Component
public class Oauth {
@Autowired
StringRedisTemplate redisTemplate;
@Value("${tencent.weixin.qiye.corpid}")
private String corpid;
@Value("${tencent.weixin.qiye.corpsecret}")
private String corpsecret;
private static String sCorpid;
private static String sCorpsecret;
public static String accessToken;
private Map generateAccessToken() {
Map parMap = new HashMap<>();
parMap.put("corpid", sCorpid);
parMap.put("corpsecret", sCorpsecret);
Map map = HTTP.get(WeChatConstant.GETTOKEN_URL, parMap, Map.class);
return map;
}
@PostConstruct
public void getCorpidAndCorpsecret() {
sCorpid = this.corpid;
sCorpsecret = this.corpsecret;
}
/**
* 每1个小时58分钟获取一次tokne
* @return
*/
@PostConstruct
@Scheduled(cron = "0 0/58 0/1 * * ? ")
public String getToken() {
log.info("开始查询token");
String token = redisTemplate.opsForValue().get("TOKEN");
if (StringUtils.isNotEmpty(token)) return token;
log.info("远程查询token");
Map map = generateAccessToken();
int error = (int) map.get(WeChatConstant.ERRORCODE);
if (error == 0) {
accessToken = map.get(WeChatConstant.ACCESS_TOKEN).toString();
log.info("正则表达式:{}", accessToken);
redisTemplate.opsForValue().set("TOKEN", accessToken, 2, TimeUnit.HOURS);
return accessToken;
} else {
log.error("获取验证码错误!");
return null;
}
}
}
该处使用的url网络请求的数据。
post请求。
@Override
public void pushPicture(PictureNewsPushEntity pictureNewsPush) {
String token = oauth.getToken();
// 企业微信推送
String itemUrl = new StringBuffer(WeChatConstant.MESSAGE_SEND).append("?").append(WeChatConstant.ACCESS_TOKEN).append("=").append(token).toString();
log.info("wx send: {} ", JSON.toJSONString(pictureNewsPush));
WeChatResultVo res = HTTP.post(itemUrl, pictureNewsPush, WeChatResultVo.class);
log.info("wx send resp: {}", JSON.toJSONString(res));
}
测试代码
import com.alibaba.fastjson.JSON;
import io.yunke.common.constant.WeChatConstant;
import io.yunke.common.utils.HTTP;
import io.yunke.common.utils.RedisUtils;
import io.yunke.modules.sys.entity.SysUserEntity;
import io.yunke.modules.wechat.Utils.MessageTemplate;
import io.yunke.modules.wechat.entity.*;
import io.yunke.modules.wechat.oauth.Oauth;
import io.yunke.modules.wechat.vo.PictureMpnewsVo;
import io.yunke.modules.wechat.vo.PictureNewsVo;
import io.yunke.modules.wechat.vo.WeChatResultVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.core.io.FileSystemResource;
import org.springframework.http.ContentDisposition;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder;
import java.io.IOException;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@Slf4j
@RunWith(SpringRunner.class)
@SpringBootTest
public class RedisTest {
@Autowired
private RedisUtils redisUtils;
@Autowired
Oauth oauth;
@Value("${tencent.weixin.qiye.agentid}")
private String agentid;
@Test
public void contextLoads() {
SysUserEntity user = new SysUserEntity();
user.setEmail("[email protected]");
redisUtils.set("user", user);
System.out.println(ToStringBuilder.reflectionToString(redisUtils.get("user", SysUserEntity.class)));
}
/**
* 文本消息推送
*/
@Test
public void text() {
String token = oauth.getToken();
TextEntity textEntity = new TextEntity();
textEntity.setTouser("yfl");
textEntity.setMsgtype("text");
textEntity.setAgentid(agentid);
TextTextEntity textTextEntity = new TextTextEntity();
MessageTemplate messageTemplate = new MessageTemplate();
String text = messageTemplate.text("http://work.weixin.qq.com");
textTextEntity.setContent(text);
textEntity.setText(textTextEntity);
Object json = JSON.toJSON(textEntity);
String itemUrl = new StringBuffer(WeChatConstant.MESSAGE_SEND).append("?").append(WeChatConstant.ACCESS_TOKEN).append("=").append(token).toString();
log.info("wx send: {} ", JSON.toJSONString(textEntity));
WeChatResultVo resMap = HTTP.post(itemUrl, textEntity, WeChatResultVo.class);
log.info("wx send resp: {}", JSON.toJSONString(resMap));
}
/**
* 图文消息推送
*/
@Test
public void pictureWordPushWehChcat() {
String token = oauth.getToken();
PictureMpnPushEntity picture = new PictureMpnPushEntity();
picture.setTouser("yfl");
picture.setMsgtype("mpnews");
picture.setAgentid(agentid);
PictureWordContentEntity picContent = new PictureWordContentEntity();
picContent.setAuthor("yfl");
picContent.setContent("新年快乐!");
picContent.setContent_source_url("https://cdn.com/report/#/annualSummary?userId=yfl");
// 下面有获取值得方法
picContent.setThumb_media_id("3uBAmXHrMhhIb7_TJwJkMCSFW8f3sCnQHzafRyI_Pt_gkebZhENXvfI0XJOG0xj");
picContent.setTitle("2022新年快乐!");
List<PictureWordContentEntity> picContents = new ArrayList<>();
picContents.add(picContent);
PictureMpnewsVo pictureMpnewsVo = new PictureMpnewsVo();
pictureMpnewsVo.setArticles(picContents);
picture.setMpnews(pictureMpnewsVo);
String itemUrl = new StringBuffer(WeChatConstant.MESSAGE_SEND).append("?").append(WeChatConstant.ACCESS_TOKEN).append("=").append(token).toString();
log.info("wx send: {} ", JSON.toJSONString(picture));
Map resMap = HTTP.post(itemUrl, picture, Map.class);
log.info("wx send resp: {}", JSON.toJSONString(resMap));
}
/**
* 图片消息推送
*/
@Test
public void picturePushWehChcat() {
String token = oauth.getToken();
PictureNewsPushEntity picture = new PictureNewsPushEntity();
picture.setTouser("yfl");
picture.setMsgtype("news");// 消息类型
picture.setAgentid(agentid);
PictureNewsContentEntity picContent = new PictureNewsContentEntity();
picContent.setUrl("https://cdn.com/report/#/annuSummary?userId=yfl");
picContent.setPicurl("https://project-stage.obs.cn-east-2.myhuaweicloud.com/workCamp/2022/01/26/14861633939047362_yunke.png");
picContent.setTitle("2022新年快乐!");
List<PictureNewsContentEntity> picContents = new ArrayList<>();
picContents.add(picContent);
PictureNewsVo pictureMpnewsVo = new PictureNewsVo();
pictureMpnewsVo.setArticles(picContents);
picture.setNews(pictureMpnewsVo);
String itemUrl = new StringBuffer(WeChatConstant.MESSAGE_SEND).append("?").append(WeChatConstant.ACCESS_TOKEN).append("=").append(token).toString();
log.info("wx send: {} ", JSON.toJSONString(picture));
Map resMap = HTTP.post(itemUrl, picture, Map.class);
log.info("wx send resp: {}", JSON.toJSONString(resMap));
}
/**
* @return 企业微信上传临时文件
* @throws IOException
* 主要是获取 media_id
*/
@Test
public void uploadimg() throws IOException {
String token = oauth.getToken();
RestTemplate restTemplate = new RestTemplate();
URI uri = UriComponentsBuilder.fromHttpUrl("https://qyapi.weixin.qq.com/cgi-bin/media/upload")
.queryParam("access_token", token)
.queryParam("type", "image")
.build().toUri();
FileSystemResource fileSystemResource = new FileSystemResource("C:\\Users\\86188\\Pictures\\yunke\\yunke.png");
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
/*Content-Disposition: form-data; name="media";filename="wework.txt"; filelength=6*/
ContentDisposition build = ContentDisposition.builder("form-data").filename(fileSystemResource.getFilename()).build();
headers.setContentDisposition(build);
MultiValueMap<String, Object> params = new LinkedMultiValueMap<>();
params.add("media", fileSystemResource);
HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(params, headers);
String s = restTemplate.postForObject(uri, requestEntity, String.class);
log.info("上传文件返回值:{}", s);
}
}
提示:post发送请求jsonObject:
实体类直接转为jsonObject
JSON.toJSONString(obj)