From 62cf8661119d91fc2e8e8c7a895023b85e8d12c9 Mon Sep 17 00:00:00 2001 From: xiang2lin <251481237@qq.com> Date: Tue, 24 Sep 2024 11:36:23 +0800 Subject: [PATCH] =?UTF-8?q?=E5=88=A0=E9=99=A4fw-weixin=E5=9C=A8master?= =?UTF-8?q?=E4=B8=8A=E7=9A=84=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- fw-weixin/pom.xml | 48 ---- .../src/main/java/com/hzya/frame/Main.java | 5 - .../frame/wecom/service/IWeComService.java | 54 ---- .../wecom/service/impl/WeComServiceImpl.java | 252 ------------------ .../frame/wecom/util/WeComAccessToken.java | 67 ----- .../target/classes/com/hzya/frame/Main.class | Bin 576 -> 0 bytes .../classes/com/hzya/frame/wecom/Test.class | Bin 279 -> 0 bytes .../frame/wecom/service/IWeComService.class | Bin 428 -> 0 bytes .../wecom/service/impl/WeComServiceImpl.class | Bin 5880 -> 0 bytes .../frame/wecom/util/WeComAccessToken.class | Bin 2807 -> 0 bytes 10 files changed, 426 deletions(-) delete mode 100644 fw-weixin/pom.xml delete mode 100644 fw-weixin/src/main/java/com/hzya/frame/Main.java delete mode 100644 fw-weixin/src/main/java/com/hzya/frame/wecom/service/IWeComService.java delete mode 100644 fw-weixin/src/main/java/com/hzya/frame/wecom/service/impl/WeComServiceImpl.java delete mode 100644 fw-weixin/src/main/java/com/hzya/frame/wecom/util/WeComAccessToken.java delete mode 100644 fw-weixin/target/classes/com/hzya/frame/Main.class delete mode 100644 fw-weixin/target/classes/com/hzya/frame/wecom/Test.class delete mode 100644 fw-weixin/target/classes/com/hzya/frame/wecom/service/IWeComService.class delete mode 100644 fw-weixin/target/classes/com/hzya/frame/wecom/service/impl/WeComServiceImpl.class delete mode 100644 fw-weixin/target/classes/com/hzya/frame/wecom/util/WeComAccessToken.class diff --git a/fw-weixin/pom.xml b/fw-weixin/pom.xml deleted file mode 100644 index 51dce4e6..00000000 --- a/fw-weixin/pom.xml +++ /dev/null @@ -1,48 +0,0 @@ - - - - com.hzya.frame - kangarooDataCenterV3 - ${revision} - - - 4.0.0 - fw-weixin - jar - ${revision} - - - - com.hzya.frame - base-service - ${revision} - - - - 8 - 8 - UTF-8 - - - - - org.springframework.boot - spring-boot-maven-plugin - - none - execute - true - - - - - repackage - - - - - - - \ No newline at end of file diff --git a/fw-weixin/src/main/java/com/hzya/frame/Main.java b/fw-weixin/src/main/java/com/hzya/frame/Main.java deleted file mode 100644 index 1817eb3e..00000000 --- a/fw-weixin/src/main/java/com/hzya/frame/Main.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.hzya.frame;public class Main { - public static void main(String[] args) { - System.out.println("Hello world!"); - } -} \ No newline at end of file diff --git a/fw-weixin/src/main/java/com/hzya/frame/wecom/service/IWeComService.java b/fw-weixin/src/main/java/com/hzya/frame/wecom/service/IWeComService.java deleted file mode 100644 index aec0dd6d..00000000 --- a/fw-weixin/src/main/java/com/hzya/frame/wecom/service/IWeComService.java +++ /dev/null @@ -1,54 +0,0 @@ -package com.hzya.frame.wecom.service; - -import com.alibaba.fastjson.JSONObject; -import com.hzya.frame.sysnew.application.entity.SysExtensionApiEntity; -import com.hzya.frame.web.entity.JsonResultEntity; - -/** - * @Description 企业微信service - * @Author xiangerlin - * @Date 2024/9/23 14:23 - **/ -public interface IWeComService { - /** - * 获取accessToken - * 该方法会缓存accessToken - * https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=ID&corpsecret=SECRET - * @param jsonObject - * @return - */ - JSONObject accessToken(JSONObject jsonObject); - - /** - * 发送消息 - * https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token=ACCESS_TOKEN - * @param jsonObject - * @return - */ - JSONObject messageSend(JSONObject jsonObject); - - /** - * 根据授权码获取用户信息 - * 单点登录的时候用 - * https://qyapi.weixin.qq.com/cgi-bin/auth/getuserinfo?access_token=ACCESS_TOKEN&code=CODE - * @param jsonObject - * @return - */ - JSONObject getUserInfoByAuthCode(JSONObject jsonObject); - - /** - * 根据userid读取成员信息 - * https://qyapi.weixin.qq.com/cgi-bin/user/get?access_token=ACCESS_TOKEN&userid=USERID - * @param jsonObject - * @return - */ - JSONObject getUserInfoByUserId(JSONObject jsonObject); - - /** - * 根据手机号获取userid - * https://qyapi.weixin.qq.com/cgi-bin/user/getuserid?access_token=ACCESS_TOKEN - * @param jsonObject - * @return - */ - JSONObject getUserIdByMobile(JSONObject jsonObject); -} diff --git a/fw-weixin/src/main/java/com/hzya/frame/wecom/service/impl/WeComServiceImpl.java b/fw-weixin/src/main/java/com/hzya/frame/wecom/service/impl/WeComServiceImpl.java deleted file mode 100644 index 70f26871..00000000 --- a/fw-weixin/src/main/java/com/hzya/frame/wecom/service/impl/WeComServiceImpl.java +++ /dev/null @@ -1,252 +0,0 @@ -package com.hzya.frame.wecom.service.impl; - -import cn.hutool.core.util.StrUtil; -import cn.hutool.http.HttpRequest; -import com.alibaba.fastjson.JSONObject; -import com.hzya.frame.sysnew.application.entity.SysExtensionApiEntity; -import com.hzya.frame.web.entity.BaseResult; -import com.hzya.frame.web.entity.JsonResultEntity; -import com.hzya.frame.wecom.service.IWeComService; -import com.hzya.frame.wecom.util.WeComAccessToken; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.stereotype.Service; - -/** - * @Description 企业微信service - * @Author xiangerlin - * @Date 2024/9/23 14:24 - **/ -@Service(value = "weComServiceImpl") -public class WeComServiceImpl implements IWeComService { - static Logger logger = LoggerFactory.getLogger(WeComServiceImpl.class); - /** - * 获取accessToken - * https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=ID&corpsecret=SECRET - * @param json - * @return - */ - @Override - public JSONObject accessToken(JSONObject json) { - JSONObject jsonObject = json.getJSONObject("jsonStr"); - if (null == jsonObject){ - return this.error("参数不能为空"); - } - String corpid = jsonObject.getString("corpid"); - String corpsecret = jsonObject.getString("corpsecret"); - if (StrUtil.isEmpty(corpid)) { - return this.error("corpid不能为空"); - } - if (StrUtil.isEmpty(corpsecret)) { - return this.error("corpsecret不能为空"); - } - try { - String accessToken = WeComAccessToken.getAccessToken(corpid, corpsecret); - return this.ok(accessToken); - }catch(Exception e){ - logger.error("获取accessToken出错",e); - } - return this.error("系统异常"); - } - - /** - * 发送消息 - * https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token=ACCESS_TOKEN - * @param json - * @return - */ - @Override - public JSONObject messageSend(JSONObject json) { - JSONObject jsonObject = json.getJSONObject("jsonStr"); - if (null == jsonObject){ - return this.error("参数不能为空"); - } - String agentid = jsonObject.getString("agentid"); - String text = jsonObject.getString("text"); - String access_token = jsonObject.getString("access_token"); - if (StrUtil.isEmpty(agentid)){ - return this.error("agentid不能为空"); - } - if (StrUtil.isEmpty(text)){ - return this.error("消息内容不能为空"); - } - if (StrUtil.isEmpty(access_token)){ - return this.error("access_token不能为空"); - } - String url = "https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token="+access_token; - jsonObject.remove("access_token"); - String param = jsonObject.toString(); - String res = HttpRequest.post(url).body(param).timeout(30000).execute().body(); - if (StrUtil.isNotEmpty(res)){ - JSONObject msgResponse = JSONObject.parseObject(res); - String errcode = msgResponse.getString("errcode"); - String errmsg = msgResponse.getString("errmsg"); - if ("0".equals(errcode)){ - return ok(); - }else { - return error(errmsg); - } - } - return this.error("操作失败"); - } - - /** - * 根据授权码获取用户信息 - * 单点登录的时候用 - * https://qyapi.weixin.qq.com/cgi-bin/auth/getuserinfo?access_token=ACCESS_TOKEN&code=CODE - * - * @param json - * @return - */ - @Override - public JSONObject getUserInfoByAuthCode(JSONObject json) { - JSONObject jsonObject = json.getJSONObject("jsonStr"); - if (null == jsonObject){ - return this.error("参数不能为空"); - } - String access_token = jsonObject.getString("access_token"); - String code = jsonObject.getString("code"); - if (StrUtil.isEmpty(access_token)){ - //如果token为空,手动获取一次 - String corpid = jsonObject.getString("corpid"); - String corpsecret = jsonObject.getString("corpsecret"); - if (StrUtil.isEmpty(corpid)){ - this.error("corpid不能为空"); - } - if (StrUtil.isEmpty(corpsecret)){ - this.error("corpsecret不能为空"); - } - access_token = WeComAccessToken.getAccessToken(corpid, corpsecret); - } - if (StrUtil.isEmpty(code)){ - return error("code不能为空"); - } - String url = "https://qyapi.weixin.qq.com/cgi-bin/auth/getuserinfo?access_token="+access_token+"&code="+code; - String res = HttpRequest.get(url).timeout(30000).execute().body(); - if (StrUtil.isNotEmpty(res)){ - JSONObject msgResponse = JSONObject.parseObject(res); - String errcode = msgResponse.getString("errcode"); - String errmsg = msgResponse.getString("errmsg"); - String userid = msgResponse.getString("userid"); - if ("0".equals(errcode)){ - return ok(userid); - }else { - return error(errmsg); - } - } - return null; - } - - /** - * 根据userid读取成员信息 - * https://qyapi.weixin.qq.com/cgi-bin/user/get?access_token=ACCESS_TOKEN&userid=USERID - * - * @param json - * @return - */ - @Override - public JSONObject getUserInfoByUserId(JSONObject json) { - JSONObject jsonObject = json.getJSONObject("jsonStr"); - if (null == jsonObject){ - return this.error("参数不能为空"); - } - String access_token = jsonObject.getString("access_token"); - String userid = jsonObject.getString("userid"); - if (StrUtil.isEmpty(access_token)){ - return error("access_token不能为空"); - } - if (StrUtil.isEmpty(userid)){ - return error("userid不能为空"); - } - String url = "https://qyapi.weixin.qq.com/cgi-bin/user/get?access_token="+access_token+"&userid="+userid; - String res = HttpRequest.get(url).timeout(30000).execute().body(); - if (StrUtil.isNotEmpty(res)){ - JSONObject msgResponse = JSONObject.parseObject(res); - String errcode = msgResponse.getString("errcode"); - String errmsg = msgResponse.getString("errmsg"); - if ("0".equals(errcode)){ - return ok(res); - }else { - return error(errmsg); - } - } - return null; - } - - /** - * 根据手机号获取userid - * https://qyapi.weixin.qq.com/cgi-bin/user/getuserid?access_token=ACCESS_TOKEN - * - * @param json - * @return - */ - @Override - public JSONObject getUserIdByMobile(JSONObject json) { - JSONObject jsonObject = json.getJSONObject("jsonStr"); - if (null == jsonObject){ - return this.error("参数不能为空"); - } - String access_token = jsonObject.getString("access_token"); - String mobile = jsonObject.getString("mobile"); - if (StrUtil.isEmpty(access_token)){ - return error("access_token不能为空"); - } - if (StrUtil.isEmpty(mobile)){ - return error("mobile不能为空"); - } - String url = "https://qyapi.weixin.qq.com/cgi-bin/user/getuserid?access_token="+access_token; - jsonObject.remove("access_token"); - String param = jsonObject.toString(); - String res = HttpRequest.post(url).body(param).timeout(30000).execute().body(); - if (StrUtil.isNotEmpty(res)){ - JSONObject msgResponse = JSONObject.parseObject(res); - String errcode = msgResponse.getString("errcode"); - String errmsg = msgResponse.getString("errmsg"); - String userid = msgResponse.getString("userid"); - if ("0".equals(errcode)){ - return ok(userid); - }else { - return error(errmsg); - } - } - return null; - } - - /** - * 成功 - * @return - */ - private static JSONObject ok(){ - JSONObject jsonObject = new JSONObject(); - jsonObject.put("code","200"); - jsonObject.put("msg","成功"); - jsonObject.put("data",""); - return jsonObject; - } - - /** - * 成功 - * @param data 返回数据 - * @return - */ - private static JSONObject ok(String data){ - JSONObject jsonObject = new JSONObject(); - jsonObject.put("code","200"); - jsonObject.put("msg","成功"); - jsonObject.put("data",data); - return jsonObject; - } - - /** - * 失败 - * @param msg 失败原因 - * @return - */ - private static JSONObject error(String msg){ - JSONObject jsonObject = new JSONObject(); - jsonObject.put("code","500"); - jsonObject.put("msg",msg); - jsonObject.put("data",""); - return jsonObject; - } -} diff --git a/fw-weixin/src/main/java/com/hzya/frame/wecom/util/WeComAccessToken.java b/fw-weixin/src/main/java/com/hzya/frame/wecom/util/WeComAccessToken.java deleted file mode 100644 index 78b6dc19..00000000 --- a/fw-weixin/src/main/java/com/hzya/frame/wecom/util/WeComAccessToken.java +++ /dev/null @@ -1,67 +0,0 @@ -package com.hzya.frame.wecom.util; - -import cn.hutool.core.util.StrUtil; -import cn.hutool.http.HttpRequest; -import com.alibaba.fastjson.JSONObject; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import java.time.Instant; - -/** - * @Description 获取企业微信accesToken - * @Author xiangerlin - * @Date 2024/9/23 14:08 - **/ -public class WeComAccessToken { - - static Logger logger = LoggerFactory.getLogger(WeComAccessToken.class); - //token - private static String accessToken; - //过期时间 - private static Instant expireTime; - private static final Long CACHE_EXPIRY_TIME = 7000L; // 缓存有效时间(秒) - - - /** - * 获取accessToken - * - * @param corpid 企业ID - * @param corpsecret 应用的凭证密钥 - * @return - */ - public static String getAccessToken(String corpid,String corpsecret) { - //判断是否过期 如果没过期直接返回 - if (null != accessToken && expireTime != null && Instant.now().isBefore(expireTime)) { - return accessToken; - } - //获取新的accessToken - accessToken = fetchNewAccessToken(corpid,corpsecret); - //过期时间设置成当前事件+7000s,预留200s的时间 - expireTime = Instant.now().plusSeconds(CACHE_EXPIRY_TIME); - return accessToken; - } - - /** - * 获取信的token - * @param corpid - * @param corpsecret - * @return - */ - private static String fetchNewAccessToken(String corpid, String corpsecret) { - String url = " https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid="+corpid+"&corpsecret="+corpsecret; - String response = HttpRequest.get(url).timeout(30000).execute().body(); - if (StrUtil.isNotEmpty(response)){ - JSONObject json = JSONObject.parseObject(response); - String accessToken = json.getString("access_token"); - return accessToken; - } - return null; - } - - public static void main(String[] args) { - for (int i=0; i<2; i++){ - String accessToken1 = WeComAccessToken.getAccessToken("wwb46c3f5e6ffe3e2b", "oON2ELxNVyl7wc37LeA9bNOsv_jyuFXdrvD9e0yogbQ"); - System.out.println(accessToken1); - } - } -} diff --git a/fw-weixin/target/classes/com/hzya/frame/Main.class b/fw-weixin/target/classes/com/hzya/frame/Main.class deleted file mode 100644 index fcf604dc32d90998f8f726d809a0b84c22d4e9c1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 576 zcmZuuyH3ME5S+`)u`whB!ut`R2^6?Nq5#n#A&T&jg3?f3k|Q}}`;g;+;IE(niGmN{ zqYz_*6p&)cyWZKonH}Hf*ZT*6J#0BBplV|d^F=H;Sj3WrWeY0;g+m?c_(&jI-);%y zj!jnylo~oz=fj|_qAS_FT9bh410 zi0mf3E-Vx+th!jkx`2DCeBaa_OyqYrEYw_VV3R6icBIN^v5WSt>csz`=Hnn%0soB| zvQhnUp^bM*3o(r-8PMiT%JCl-uQYZI^#6}s@#4CLBG|xmw Ij2X;+1H{>R5C8xG diff --git a/fw-weixin/target/classes/com/hzya/frame/wecom/Test.class b/fw-weixin/target/classes/com/hzya/frame/wecom/Test.class deleted file mode 100644 index 32e87025ee472c7091e1e997a4904190ce3d2942..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 279 zcmZ{ey>7xl5QJxqe}XZ=qC=_ZAVsc87nBBx%7Oxm{(Ky8$Ul-XLFBDcMWWyV@=#Is z5N&p)(axvc(f<5it^i&UhiIW2;4wgt;7?3xns-8LG+q(hX|>jbUSdi;KNgv;Q<>#V z`bni^zLK@E{tn${XAXp?L{){@eV(P*)Uwdxq%BDGp?M>O%j#GwJu^0@ZQ;vae#i(e zJi_4LQ$lR_L@vv%SY&&x8Vup^^R|ea16X}_;^qPG`5W}bz(K(3GX@^Gf#^1SXd`4t J=&(A7{s5q@I*0%O diff --git a/fw-weixin/target/classes/com/hzya/frame/wecom/service/IWeComService.class b/fw-weixin/target/classes/com/hzya/frame/wecom/service/IWeComService.class deleted file mode 100644 index 4914de8e1c430e2b1ec33525303f9954a4e994d7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 428 zcmaiwy-veG5QOJK5`)7(;vIm3Yv`y*BBUTfkPMNz zGt&0@{9lK_;goD*qDNJ!f-F_FfbVkF5nNhurHUz_G7>nA$v)RqP0G0$Ha82Kj7&rV zCmVd_VE554jfTzCglW!BKQN0*)9p$ePhMzbih!zRs_8OQOC@mO&Pv`JzRB$*-^c+j zbso7f!RxyjnX59E>y7&Y0v&!F(CZ3pq074Glt3R~e| diff --git a/fw-weixin/target/classes/com/hzya/frame/wecom/service/impl/WeComServiceImpl.class b/fw-weixin/target/classes/com/hzya/frame/wecom/service/impl/WeComServiceImpl.class deleted file mode 100644 index cab0982e9d8e6924e4e2052c54105b875784532b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5880 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