如果服务器对进出的ip有限制,则需要将相应的ip添加到白名单中。调用公众号或小程序(对应域名是api.weixin.qq.com)、微信支付(对应域名是api.mch.weixin.qq.com)、企业微信(对应域名是qyapi.weixin.qq.com)的api时就需要检测ip可能发生变动之后发送通知。
本示例是发送通知到企业微信群聊天机器人。当然也可以使用发送公众号模板消息、短信等。
pom文件
<!-- https://mvnrepository.com/artifact/com.github.binarywang/wx-java -->
<dependency>
<groupId>com.github.binarywang</groupId>
<artifactId>weixin-java-mp</artifactId>
<version>4.5.0</version>
</dependency>
<dependency>
<groupId>com.github.binarywang</groupId>
<artifactId>weixin-java-cp</artifactId>
<version>4.5.0</version>
</dependency>
<dependency>
<groupId>com.github.binarywang</groupId>
<artifactId>weixin-java-miniapp</artifactId>
<version>4.5.0</version>
</dependency>
<!--https://github.com/redisson/redisson-->
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson-spring-boot-starter</artifactId>
<version>3.14.0</version>
</dependency>
定义微信和企业微信bean
@Bean("wxService")
@ConditionalOnClass(RedissonClient.class)
public WxMaService newWxService(RedissonClient redissonClient) {
String keyPrefix = ""; // 缓存的前缀
String appid = ""; // 微信app id
String appSecret = ""; // 微信app secret
WxMaDefaultConfigImpl wxMaDefaultConfig = new WxMaRedissonConfigImpl(redissonClient, keyPrefix);
wxMaDefaultConfig.setAppid(appid);
wxMaDefaultConfig.setSecret(appSecret);
WxMaService wxMaService = new WxMaServiceImpl();
wxMaService.setWxMaConfig(wxMaDefaultConfig);
return wxMaService;
}
@Bean("wxCpService")
@ConditionalOnClass(RedissonClient.class)
public WxCpService newWxCpService(RedissonClient redissonClient) {
String keyPrefix = ""; // 缓存的前缀
String corpId = ""; // 企业微信id
Integer agentId = 0; // 企业微信应用id
String agentSecret = ""; // 企业微信应用密钥
WxCpDefaultConfigImpl wxCpDefaultConfig = new WxCpRedissonConfigImpl(redissonClient, keyPrefix);
wxCpDefaultConfig.setCorpId(corpId);
wxCpDefaultConfig.setAgentId(agentId);
wxCpDefaultConfig.setCorpSecret(agentSecret);
WxCpService wxCpService = new WxCpServiceImpl();
wxCpService.setWxCpConfigStorage(wxCpDefaultConfig);
return wxCpService;
}
定时任务
import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaSubscribeMessage;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.cp.api.WxCpService;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
import java.util.*;
import java.util.stream.Collectors;
@Component
public class WechatTask {
protected static Logger logger = LoggerFactory.getLogger(WechatTask.class);
@Qualifier("wxService")
@Autowired
private WxMaService wxMaService;
@Qualifier("wxCpService")
@Autowired
private WxCpService wxCpService;
@Autowired
private RedisTemplate<String, String> redisTemplate;
@Autowired
private RestTemplate restTemplate;
/**
* 定时检查微信服务器的ip是否有变动,有变动则发送通知
*/
@Scheduled(cron = "0 0 18 * * ?")
public void getWechatIp() throws WxErrorException {
// 获取微信API接口 IP地址
// 参考:https://developers.weixin.qq.com/doc/offiaccount/Basic_Information/Get_the_WeChat_server_IP_address.html
String s = wxMaService.get("https://api.weixin.qq.com/cgi-bin/get_api_domain_ip", "");
Map map = JSONObject.parseObject(s, Map.class);
JSONArray ipListArr = (JSONArray) map.get("ip_list");
List<String> ipList = ipListArr.toJavaList(String.class)
.stream().sorted().collect(Collectors.toList());
String ipStr = String.join(",", ipList);
// 读取保存的ip地址
String redisKey = "wechat_api_ip_list";
String ipStrInDB = redisTemplate.opsForValue().get(redisKey);
if (!ipStr.equals(ipStrInDB)) {
// 企业微信群聊发送消息
sendCpMsg("微信接口的ip地址有变动:\n" + ipStr);
// 保存ip地址
redisTemplate.opsForValue().set(redisKey, ipStr);
}
// 获取微信callback IP地址
// 参考:https://developers.weixin.qq.com/doc/offiaccount/Basic_Information/Get_the_WeChat_server_IP_address.html
s = wxMaService.get("https://api.weixin.qq.com/cgi-bin/getcallbackip", "");
map = JSONObject.parseObject(s, Map.class);
ipListArr = (JSONArray) map.get("ip_list");
ipList = ipListArr.toJavaList(String.class)
.stream().sorted().collect(Collectors.toList());
ipStr = String.join(",", ipList);
// 读取保存的ip地址
redisKey = "wechat_api_callback_ip_list";
ipStrInDB = redisTemplate.opsForValue().get(redisKey);
if (!ipStr.equals(ipStrInDB)) {
// 企业微信群聊发送消息
sendCpMsg("微信接口的回调ip地址有变动:\n" + ipStr);
// 保存ip地址
redisTemplate.opsForValue().set(redisKey, ipStr);
}
// 获取企业微信接口IP段
// 参考:https://developer.work.weixin.qq.com/document/path/92520
s = wxCpService.get("https://qyapi.weixin.qq.com/cgi-bin/get_api_domain_ip", "");
map = JSONObject.parseObject(s, Map.class);
ipListArr = (JSONArray) map.get("ip_list");
ipList = ipListArr.toJavaList(String.class)
.stream().sorted().collect(Collectors.toList());
ipStr = String.join(",", ipList);
// 读取保存的ip地址
redisKey = "wechat_qyapi_ip_list";
ipStrInDB = redisTemplate.opsForValue().get(redisKey);
if (!ipStr.equals(ipStrInDB)) {
// 企业微信群聊发送消息
sendCpMsg("企业微信接口的ip地址有变动:\n" + ipStr);
// 保存ip地址
redisTemplate.opsForValue().set(redisKey, ipStr);
}
// 获取企业微信回调接口IP段
// 参考:https://developer.work.weixin.qq.com/document/path/92521
final String[] callbackIp = wxCpService.getCallbackIp();
Arrays.sort(callbackIp);
ipStr = String.join(",", callbackIp);
// 读取保存的ip地址
redisKey = "wechat_qyapi_callback_ip_list";
ipStrInDB = redisTemplate.opsForValue().get(redisKey);
if (!ipStr.equals(ipStrInDB)) {
// 企业微信群聊发送消息
sendCpMsg("企业微信接口的回调ip地址有变动:\n" + ipStr);
// 保存ip地址
redisTemplate.opsForValue().set(redisKey, ipStr);
}
// 微信支付服务器ip没有接口可以查询,只能通过微信支付公告查看
}
/**
* 发送微信群聊天机器人消息
*
* @param msg 消息
*/
private void sendCpMsg(String msg) {
// 群聊机器人webhook
// 需要注意:是由内部群聊才能设置群聊机器人
// 参考:http://open-work-weixin-qq-com-443.webvpn.sxu.edu.cn/help2/pc/14931?person_id=1
String webhook = "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=0fa57ab3-f3f4-404d-8206-c2b03337469e";
Map<String, Object> params = new HashMap<>();
params.put("msgtype", "text");
Map<String, Object> text = new HashMap<>();
text.put("content", msg);
text.put("mentioned_list", new String[]{"@all"}); // 提醒所有人
params.put("text", text);
final Map sendMsgResult = restTemplate.postForObject(webhook, params, Map.class);
final Object errcode = sendMsgResult.get("errcode");
if (errcode != null && Integer.parseInt(errcode.toString()) == 0) {
logger.info("企业微信群聊发送消息成功");
} else {
logger.error("企业微信群聊发送消息失败,errcode:{}", errcode);
}
}
}