diff --git a/zc-business/src/main/java/com/zc/business/utils/QYWXUtil.java b/zc-business/src/main/java/com/zc/business/utils/QYWXUtil.java new file mode 100644 index 00000000..879fb0db --- /dev/null +++ b/zc-business/src/main/java/com/zc/business/utils/QYWXUtil.java @@ -0,0 +1,271 @@ +package com.zc.business.utils; + +import com.alibaba.fastjson.JSONObject; +import com.google.gson.Gson; +import com.ruoyi.common.core.domain.entity.SysUser; +import com.ruoyi.common.core.redis.RedisCache; +import com.ruoyi.common.utils.StringUtils; +import com.ruoyi.common.utils.http.HttpUtils; +import com.ruoyi.system.mapper.SysUserMapper; +import com.zc.business.constant.RedisKeyConstants; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +/** + * @Description 企业微信Api工具 + * + * @author liuwenge + * @date 2023/5/18 16:17 + * @return null + */ +@Component +public class QYWXUtil { + @Resource + private RedisCache redisCache; + + /** 企业id*/ + @Value("${qywx.corpId}") + private String corpId; + + /** 企业密钥*/ + @Value("${qywx.corpsecret}") + private String corpsecret; + + /** 应用id*/ + @Value("${qywx.agentId}") + private int agentId; + + @Resource + private SysUserMapper sysUserMapper; + + /** + * @Description 从缓存中获取access_token + * + * @author liuwenge + * @date 2023/5/18 17:37 + * @param + * @return java.lang.String + */ + public String getAccessToken(){ + + // 从redis拿access_token + String accessToken = redisCache.getCacheObject(RedisKeyConstants.QYWX_ACCESS_TOKEN); + if (StringUtils.isEmpty(accessToken)) { + // 如果redis里没有,则重新调http获取,以及存放到redis里 + return getAccessTokenByHttp(); + }else { + // 如果redis里有,则先校验access_token失效有效时间是否快到了 + Long expire = redisCache.getExpire(RedisKeyConstants.QYWX_ACCESS_TOKEN); + System.out.println("access_token剩余时间:"+expire); + // 当前时间+有效时间低于规定时间(秒)默认600秒 + if (expire <= 600) { + // 通过http获取最新access_token,且存到redis + return getAccessTokenByHttp(); + } else { + return accessToken; // 直接返回access_token + } + } + } + + /** + * @Description 重新请求接口获取token,放入缓存 + * + * @author liuwenge + * @date 2023/5/18 17:37 + * @param + * @return java.lang.String + */ + public String getAccessTokenByHttp(){ + // 拼接获取access_token的url + String url = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=" + corpId + "&corpsecret=" + corpsecret; + // 调用get方法获取 + String result = HttpUtils.sendGet(url); + if (!StringUtils.isEmpty(result)) { + // 把响应报文转成json对象 + JSONObject objJsonObject = (JSONObject) JSONObject.parse(result); + if (null != objJsonObject) { + // 出错返回码,为0表示成功,非0表示调用失败 + int iErrorCode = objJsonObject.getIntValue("errcode"); + if (iErrorCode == 0) { + String strAccessToken = objJsonObject.getString("access_token"); + // 设置到redis里,目前的存活时间为120分钟(7200秒) + redisCache.setCacheObject(RedisKeyConstants.QYWX_ACCESS_TOKEN,strAccessToken,7200, TimeUnit.SECONDS); + return strAccessToken; + } + } + } + return null; + } + + /** + * @Description 通过手机号获取企业微信userId + * 注意:请确保手机号的正确性,若出错的次数超出企业规模人数的20%,会导致1天不可调用 + * @author liuwenge + * @date 2023/5/19 9:07 + * @param mobile 手机号 + * @return java.lang.String + */ + public String getUserIdByMobile(String mobile){ + if (StringUtils.isEmpty(mobile)){ + return null; + } + + //拼接请求路径 + String accessToken = this.getAccessToken(); + String url = "https://qyapi.weixin.qq.com/cgi-bin/user/getuserid?access_token=" + accessToken; + //请求参数 + Map params = new HashMap<>(); + params.put("mobile",mobile); + Gson gson = new Gson(); + String jsonMessage = gson.toJson(params); + + //发起post请求 + String result = HttpUtils.sendPost(url,jsonMessage); + if (!StringUtils.isEmpty(result)) { + // 把响应报文转成json对象 + JSONObject objJsonObject = (JSONObject) JSONObject.parse(result); + if (null != objJsonObject) { + // 出错返回码,为0表示成功,非0表示调用失败 + int iErrorCode = objJsonObject.getIntValue("errcode"); + if (iErrorCode == 0) { + //返回用户id + return objJsonObject.getString("userid"); + } else if (iErrorCode == 42001){ + //access_token过期,重新获取 + getAccessTokenByHttp(); + //重新获取userId + getUserIdByMobile(mobile); + } + System.out.println("通过手机号获取userId失败! 错误码:" + iErrorCode + ", 错误信息:" + objJsonObject.getString("errmsg")); + } + } + return null; + } + + /** + * @Description 给企业微信用户发送文本消息 + * + * @author liuwenge + * @date 2023/5/19 9:43 + * @param userId 消息接收人id(企业微信的userid) + * @param content 消息内容 + * @return java.util.Map + */ + public Map sendMessageByWxUserId(List userId,String content){ + Map result = new HashMap<>(); + + if (userId.size() < 1 || userId.size() >= 1001){ + result.put("msg","接收人不能为空,并且最多支持1000个"); + result.put("code","0"); + return result; + } else if (StringUtils.isEmpty(content)){ + result.put("msg","消息内容不能为空"); + result.put("code","0"); + return result; + } + + //请求路径 + String accessToken = this.getAccessToken(); + String url = "https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token=" + accessToken; + + //请求参数 + Map params = new HashMap<>(); + //指定接收消息的成员,成员ID列表(多个接收者用‘|’分隔,最多支持1000个) + String toUser = String.join("|",userId); + params.put("touser",toUser); + //消息类型,此时固定为:text + params.put("msgtype","text"); + //企业应用的id + params.put("agentid",agentId); + //消息内容,最长不超过2048个字节,超过将截断(支持id转译) + Map text = new HashMap<>(); + text.put("content",content); + params.put("text",text); + + Gson gson = new Gson(); + String jsonMessage = gson.toJson(params); + //发起post请求 + String httpResult = HttpUtils.sendPost(url,jsonMessage); + + if (!StringUtils.isEmpty(httpResult)) { + // 把响应报文转成json对象 + JSONObject objJsonObject = (JSONObject) JSONObject.parse(httpResult); + if (null != objJsonObject) { + // 出错返回码,为0表示成功,非0表示调用失败 + int iErrorCode = objJsonObject.getIntValue("errcode"); + + System.out.println("发送企业微信消息,状态码: " + iErrorCode + ", 提示信息:" + objJsonObject.getString("errmsg")); + + if (iErrorCode == 0) { + //返回消息id + String msgId = objJsonObject.getString("msgid"); + result.put("code","1"); + result.put("msg","发送企业微信消息成功!"); + result.put("data",msgId); + } else if (iErrorCode == 42001){ + //access_token过期,重新获取 + getAccessTokenByHttp(); + //重新发送文本消息 + sendMessageByWxUserId(userId,content); + } else { + result.put("code","0"); + result.put("msg","发送企业微信消息失败!错误码:" + iErrorCode + ", 错误信息:" + objJsonObject.getString("errmsg")); + } + } + } + return result; + + } + + /** + * @Description 给企业微信用户发送文本消息 + * 注意:如不能保证手机号的正确性,此方法不建议使用,因企业微信有严格的错误频率限制,若出错的次数超出企业规模人数的20%,会导致1天不可调用 + * @author liuwenge + * @date 2023/5/19 9:43 + * @param sysUser 消息接收人(此系统中的用户) + * @param content 消息内容 + * @return java.util.Map + */ + public Map sendMessageBySysUser(List sysUser, String content){ + Map result = new HashMap<>(); + + if (sysUser.size() < 1 || sysUser.size() >= 1001){ + result.put("msg","接收人不能为空,并且最多支持1000个"); + result.put("code","0"); + return result; + } else if (StringUtils.isEmpty(content)){ + result.put("msg","消息内容不能为空"); + result.put("code","0"); + return result; + } + + //循环查出企业微信中的用户id + List userList = new ArrayList<>(); + String userId; + for (SysUser user : sysUser) { + userId = getUserIdByMobile(user.getPhonenumber()); + if (!StringUtils.isEmpty(userId)){ + userList.add(userId); + System.out.println("已通过手机号:" + user.getPhonenumber() + "查询到企业微信用户:userId"); + } + } + + if (userList.size() < 1){ + result.put("msg","未查到企业微信用户"); + result.put("code","0"); + return result; + } + + result = sendMessageByWxUserId(userList,content); + return result; + } + + +}