From 55c5cd7335665ca9f38b9c4bdf4163f4e124950f Mon Sep 17 00:00:00 2001 From: quyixiao <2621048238@qq.com> Date: Wed, 12 Nov 2025 12:32:31 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8F=90=E4=BA=A4=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/heyu/api/data/utils/WeChatUtils.java | 177 ++++++++++++++++++ .../com/heyu/api/data/utils/WechatUtils.java | 56 ------ .../alibaba/request/vv/AppLinkRequest.java | 11 ++ .../alibaba/request/vv/AppQrCodeRequest.java | 10 + .../alibaba/request/vv/AppSchemeRequest.java | 11 ++ .../api/controller/vv/AppLinkController.java | 55 ++++++ .../controller/vv/AppQrCodeController.java | 52 ++--- .../controller/vv/AppUserLoginController.java | 7 +- pom.xml | 9 + 9 files changed, 292 insertions(+), 96 deletions(-) create mode 100644 api-mapper/src/main/java/com/heyu/api/data/utils/WeChatUtils.java delete mode 100644 api-mapper/src/main/java/com/heyu/api/data/utils/WechatUtils.java create mode 100644 api-third/src/main/java/com/heyu/api/alibaba/request/vv/AppLinkRequest.java create mode 100644 api-third/src/main/java/com/heyu/api/alibaba/request/vv/AppQrCodeRequest.java create mode 100644 api-third/src/main/java/com/heyu/api/alibaba/request/vv/AppSchemeRequest.java create mode 100644 api-web/api-interface/src/main/java/com/heyu/api/controller/vv/AppLinkController.java diff --git a/api-mapper/src/main/java/com/heyu/api/data/utils/WeChatUtils.java b/api-mapper/src/main/java/com/heyu/api/data/utils/WeChatUtils.java new file mode 100644 index 0000000..9af0eee --- /dev/null +++ b/api-mapper/src/main/java/com/heyu/api/data/utils/WeChatUtils.java @@ -0,0 +1,177 @@ +package com.heyu.api.data.utils; + +import cn.hutool.http.HttpUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.heyu.api.data.dto.AccessTokenDTO; +import com.heyu.api.data.dto.WeiChatLoginDTO; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +import java.util.HashMap; + +@Slf4j +@Component +public class WeChatUtils { + + + /** + * 微信 auth.code2Session 接口 + */ + public final static String WECHAT_LOGIN_URL = "https://api.weixin.qq.com/sns/jscode2session"; + public final static String WECHAT_APPID = "wx75fa59c097bd3dfd"; + public final static String WECHAT_SECRET = "1837c382de696013a2dfc64591e6b854"; + + + public static final String wechatAccessTokenUrl = "https://api.weixin.qq.com/cgi-bin/token?appid=%s&secret=%s&grant_type=client_credential"; + + + private static final String linkUrl = "https://api.weixin.qq.com/wxa/generate_urllink?access_token="; + + private static final String schemeUrl = "https://api.weixin.qq.com/wxa/generatescheme?access_token="; + + + @Autowired + private RedisUtils redisUtils; + + + @Value("${eb.config.weixin.pay.appid}") + private String appid; + + @Value("${eb.config.weixin.pay.appSecret}") + private String appSecret; + + + public static final String jsapi_acessToken = "jsapi_acessToken"; + + public static void main(String[] args) { + // 获取 openid + // WeiChatLoginDTO weiChatLoginDTO = getOpenId("0b1tMGll2jJdBg4sfwml2pnGk32tMGlg",WECHAT_APPID,WECHAT_SECRET); +// System.out.println(weiChatLoginDTO.getOpenid()); +// System.out.println("o6t1512tT-JuBeT6rIu6RhFGf3BQ".length()); +// System.out.println("FMOMCp63WoRFUJtL4tvjcQ==".length()); + + } + + /** + * 通过微信登录code获取openId + * + * @param code 微信登录code + * @return openId + */ + // ============json============{"session_key":"FMOMCp63WoRFUJtL4tvjcQ==","openid":"o6t1512tT-JuBeT6rIu6RhFGf3BQ"} + public WeiChatLoginDTO getOpenId(String code) { + try { + // 添加参数 + HashMap map = new HashMap<>(); + map.put("appid", appid); + map.put("secret", appSecret); + map.put("js_code", code); + map.put("grant_type", "authorization_code"); + // 使用封装好的HttpClientUtil工具类发送请求 + String result = HttpUtils.doGet(WECHAT_LOGIN_URL, map); + log.info("getOpenId params:{}, result:{}", JSON.toJSONString(map), result); + // 将JSON字符串转换为JSONObject对象 + WeiChatLoginDTO weiChatLoginDTO = JSON.parseObject(result, WeiChatLoginDTO.class); + // 从JSONObject中获取openid并返回 + return weiChatLoginDTO; + } catch (Exception e) { + log.error("getOpenId error", e); + } + return null; + } + + public AccessTokenDTO getAccessTokenDTO() { + AccessTokenDTO accessTokenDTO = null; + String acessTokenJson = redisUtils.get(jsapi_acessToken); + if (StringUtils.isNotEmpty(acessTokenJson)) { + accessTokenDTO = JSONObject.parseObject(acessTokenJson, AccessTokenDTO.class); + } else { + accessTokenDTO = getAccessToken(appid, appSecret); + redisUtils.set(jsapi_acessToken, JSON.toJSONString(accessTokenDTO), RedisUtils.one_hours); + } + return accessTokenDTO; + } + + + // 获取access_token + private AccessTokenDTO getAccessToken(String appid, String appSecret) { + String url = String.format(wechatAccessTokenUrl, appid, appSecret); + String responseBody = HttpUtils.doGet(url); + log.info("getAccessToken responseBody:{}", responseBody); + AccessTokenDTO accessTokenDTO = JSONObject.parseObject(responseBody, AccessTokenDTO.class); + return accessTokenDTO; + } + + + /** + * 生成小程序跳转短链 code + * https://blog.csdn.net/weixin_44548582/article/details/131868367 + *

+ * https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/qrcode-link/url-link/generateUrlLink.html + * + * @param path 小程序页面路径 null为首页 + * @param query 与前端商量,携带的参数 + * @return + */ + public String jumpAppletShortUrl(String path, String query, Integer days) { + String accessToken = getAccessTokenDTO().getAccessToken(); + + String url = linkUrl + accessToken; + cn.hutool.json.JSONObject body = cn.hutool.json.JSONUtil.createObj(); + body.putOpt("path", path); + + body.putOpt("query", query); + + //链接过期类型:0时间戳 1间隔天数 + body.putOpt("expire_type", 1); + + //指定失效天数,最多30 + days = (days == null || days > 30) ? 30 : days; + + body.putOpt("expire_interval", days); + + //小程序版本,正式版为 "release",体验版为"trial",开发版为"develop" + body.putOpt("env_version", "trial"); + String result = HttpUtil.post(url, body.toJSONString(2)); + log.info("jumpAppletShortUrl params:{}, result:{}", JSON.toJSONString(body), result); + return result; + } + + + /** + * scheme 跳转微信小程序,需中转H5 + * + * @param path + * @param query + * @param days https://blog.csdn.net/weixin_44548582/article/details/131868367 + * + * https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/qrcode-link/url-scheme/generateScheme.html + * @return + */ + public String jumpAppletSchemeUrl(String path, String query, Integer days) { + String url = schemeUrl + getAccessTokenDTO().getAccessToken(); + cn.hutool.json.JSONObject body = cn.hutool.json.JSONUtil.createObj(); + cn.hutool.json.JSONObject jumpWxa = cn.hutool.json.JSONUtil.createObj(); + jumpWxa.putOpt("path", path); + jumpWxa.putOpt("query", query); + jumpWxa.putOpt("env_version", "release"); + body.putOpt("jump_wxa", jumpWxa); + //链接过期类型:0时间戳 1间隔天数 + body.putOpt("expire_type", 1); + body.putOpt("is_expire", true); + //指定失效天数,最多30 + days = (days == null || days > 30) ? 30 : days; + body.putOpt("expire_interval", days); + String post = HttpUtil.post(url, body.toJSONString(2)); + + log.info("jumpAppletSchemeUrl params:{}, result:{}", JSON.toJSONString(body), post); + cn.hutool.json.JSONObject result = cn.hutool.json.JSONUtil.parseObj(post); + + return result.toJSONString(2); + } + + +} diff --git a/api-mapper/src/main/java/com/heyu/api/data/utils/WechatUtils.java b/api-mapper/src/main/java/com/heyu/api/data/utils/WechatUtils.java deleted file mode 100644 index 4123d1e..0000000 --- a/api-mapper/src/main/java/com/heyu/api/data/utils/WechatUtils.java +++ /dev/null @@ -1,56 +0,0 @@ -package com.heyu.api.data.utils; - -import com.alibaba.fastjson.JSON; -import com.heyu.api.data.dto.WeiChatLoginDTO; -import lombok.extern.slf4j.Slf4j; - -import java.util.HashMap; - -@Slf4j -public class WechatUtils { - - /** - * 微信 auth.code2Session 接口 - */ - public final static String WECHAT_LOGIN_URL = "https://api.weixin.qq.com/sns/jscode2session"; - public final static String WECHAT_APPID = "wx75fa59c097bd3dfd"; - public final static String WECHAT_SECRET = "1837c382de696013a2dfc64591e6b854"; - - public static void main(String[] args) { - // 获取 openid - WeiChatLoginDTO weiChatLoginDTO = getOpenId("0b1tMGll2jJdBg4sfwml2pnGk32tMGlg"); - System.out.println(weiChatLoginDTO.getOpenid()); - System.out.println("o6t1512tT-JuBeT6rIu6RhFGf3BQ".length()); - System.out.println("FMOMCp63WoRFUJtL4tvjcQ==".length()); - - } - - /** - * 通过微信登录code获取openId - * - * @param code 微信登录code - * @return openId - */ - // ============json============{"session_key":"FMOMCp63WoRFUJtL4tvjcQ==","openid":"o6t1512tT-JuBeT6rIu6RhFGf3BQ"} - public static WeiChatLoginDTO getOpenId(String code) { - try { - // 添加参数 - HashMap map = new HashMap<>(); - map.put("appid", WECHAT_APPID); - map.put("secret", WECHAT_SECRET); - map.put("js_code", code); - map.put("grant_type", "authorization_code"); - // 使用封装好的HttpClientUtil工具类发送请求 - String json = HttpUtils.doGet(WECHAT_LOGIN_URL, map); - System.out.println("============json============" + json); - // 将JSON字符串转换为JSONObject对象 - WeiChatLoginDTO weiChatLoginDTO = JSON.parseObject(json, WeiChatLoginDTO.class); - // 从JSONObject中获取openid并返回 - return weiChatLoginDTO; - } catch (Exception e) { - log.error("getOpenId error", e); - } - return null; - } - -} diff --git a/api-third/src/main/java/com/heyu/api/alibaba/request/vv/AppLinkRequest.java b/api-third/src/main/java/com/heyu/api/alibaba/request/vv/AppLinkRequest.java new file mode 100644 index 0000000..1ba6269 --- /dev/null +++ b/api-third/src/main/java/com/heyu/api/alibaba/request/vv/AppLinkRequest.java @@ -0,0 +1,11 @@ +package com.heyu.api.alibaba.request.vv; + + +import lombok.Data; + +@Data +public class AppLinkRequest extends AppBaseRequest { + + + +} diff --git a/api-third/src/main/java/com/heyu/api/alibaba/request/vv/AppQrCodeRequest.java b/api-third/src/main/java/com/heyu/api/alibaba/request/vv/AppQrCodeRequest.java new file mode 100644 index 0000000..38396ea --- /dev/null +++ b/api-third/src/main/java/com/heyu/api/alibaba/request/vv/AppQrCodeRequest.java @@ -0,0 +1,10 @@ +package com.heyu.api.alibaba.request.vv; + + +import lombok.Data; + +@Data +public class AppQrCodeRequest extends AppBaseRequest { + + +} diff --git a/api-third/src/main/java/com/heyu/api/alibaba/request/vv/AppSchemeRequest.java b/api-third/src/main/java/com/heyu/api/alibaba/request/vv/AppSchemeRequest.java new file mode 100644 index 0000000..802aa4b --- /dev/null +++ b/api-third/src/main/java/com/heyu/api/alibaba/request/vv/AppSchemeRequest.java @@ -0,0 +1,11 @@ +package com.heyu.api.alibaba.request.vv; + + +import lombok.Data; + +@Data +public class AppSchemeRequest extends AppBaseRequest { + + + +} diff --git a/api-web/api-interface/src/main/java/com/heyu/api/controller/vv/AppLinkController.java b/api-web/api-interface/src/main/java/com/heyu/api/controller/vv/AppLinkController.java new file mode 100644 index 0000000..017e518 --- /dev/null +++ b/api-web/api-interface/src/main/java/com/heyu/api/controller/vv/AppLinkController.java @@ -0,0 +1,55 @@ +package com.heyu.api.controller.vv; + + +import com.heyu.api.alibaba.request.vv.AppLinkRequest; +import com.heyu.api.alibaba.request.vv.AppSchemeRequest; +import com.heyu.api.common.annotation.Describe; +import com.heyu.api.data.utils.R; +import com.heyu.api.data.utils.WeChatUtils; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@Slf4j +@RestController +@RequestMapping("/app/create") +public class AppLinkController { + + + // 自行配置:正式版为 "release",体验版为 "trial",开发版为 "develop"。默认是正式版。 + private String envVersion = "trial"; + + @Autowired + private WeChatUtils weChatUtils; + + /*** + * 链接 + * http://localhost:8888/app/create/link + * + */ + @Describe("生成link") + @RequestMapping("/link") + public R link(@RequestBody AppLinkRequest request) { + String url = weChatUtils.jumpAppletShortUrl("abc", "89ew8392", 30); + + return R.ok(); + } + + + /*** + * 链接 + * http://localhost:8888/app/create/scheme + */ + @Describe("生成") + @RequestMapping("/scheme") + public R scheme(@RequestBody AppSchemeRequest request) { + String url = weChatUtils.jumpAppletSchemeUrl("abc", "89ew8392", 30); + return R.ok(); + } + +} + + + diff --git a/api-web/api-interface/src/main/java/com/heyu/api/controller/vv/AppQrCodeController.java b/api-web/api-interface/src/main/java/com/heyu/api/controller/vv/AppQrCodeController.java index a4d7e34..a7493b0 100644 --- a/api-web/api-interface/src/main/java/com/heyu/api/controller/vv/AppQrCodeController.java +++ b/api-web/api-interface/src/main/java/com/heyu/api/controller/vv/AppQrCodeController.java @@ -1,15 +1,12 @@ package com.heyu.api.controller.vv; -import com.alibaba.fastjson.JSON; -import com.alibaba.fastjson.JSONObject; -import com.heyu.api.alibaba.request.vv.AppPromoterRequest; +import com.heyu.api.alibaba.request.vv.AppQrCodeRequest; import com.heyu.api.common.annotation.Describe; import com.heyu.api.data.dto.AccessTokenDTO; import com.heyu.api.data.utils.HttpUtils; import com.heyu.api.data.utils.R; -import com.heyu.api.data.utils.RedisUtils; -import com.heyu.api.data.utils.StringUtils; +import com.heyu.api.data.utils.WeChatUtils; import com.heyu.api.oss.OssFileUploadService; import com.heyu.api.oss.OssUploadResult; import lombok.extern.slf4j.Slf4j; @@ -26,30 +23,21 @@ import java.util.Map; @RestController @RequestMapping("/app/qrcode") public class AppQrCodeController { - - public static final String wechatQrcodeUrl = "https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token="; - public static final String wechatAccessTokenUrl = "https://api.weixin.qq.com/cgi-bin/token?appid=%s&secret=%s&grant_type=client_credential"; - @Value("${eb.config.weixin.pay.appid}") - private String appid; - - @Value("${eb.config.weixin.pay.appSecret}") - private String appSecret; // 自行配置:正式版为 "release",体验版为 "trial",开发版为 "develop"。默认是正式版。 private String envVersion = "trial"; - @Autowired - private RedisUtils redisUtils; - - public static final String jsapi_acessToken = "jsapi_acessToken"; @Autowired private OssFileUploadService ossFileUploadService; + @Autowired + private WeChatUtils weChatUtils; + /*** * 列表 * http://localhost:8888/app/qrcode/create @@ -59,20 +47,14 @@ public class AppQrCodeController { */ @Describe("生成二维码") @RequestMapping("/create") - public R create(@RequestBody AppPromoterRequest request) { + public R create(@RequestBody AppQrCodeRequest request) { + + AccessTokenDTO accessTokenDTO = weChatUtils.getAccessTokenDTO(); // 当前登录账号 String accountId = "123456"; - AccessTokenDTO accessTokenDTO = null; - String acessTokenJson = redisUtils.get(jsapi_acessToken); - if (StringUtils.isNotEmpty(acessTokenJson)) { - accessTokenDTO = JSONObject.parseObject(acessTokenJson, AccessTokenDTO.class); - } else { - accessTokenDTO = getAccessToken(appid, appSecret); - redisUtils.set(jsapi_acessToken, JSON.toJSONString(accessTokenDTO), RedisUtils.one_hours); - } - String accessToken = accessTokenDTO.getAccessToken(); - String url = wechatQrcodeUrl + accessToken; + String url = wechatQrcodeUrl + accessTokenDTO.getAccessToken(); + Map body = new HashMap<>(); @@ -82,7 +64,6 @@ public class AppQrCodeController { body.put("env_version", envVersion); // body.put("page", envVersion); 默认是主页,页面 page,例如 pages/index/index,根路径前不要填加 /,不能携带参数(参数请放在scene字段里),如果不填写这个字段,默认跳主页面。scancode_time为系统保留参数,不允许配置 - // 透明 body.put("is_hyaline", true); // 默认是false,是否需要透明底色,为 true 时,生成透明底色的小程序 @@ -91,23 +72,16 @@ public class AppQrCodeController { if (bytes == null) { return R.error("bytes is null"); } + String error = new String(bytes); + if (error.contains("errcode")) { return R.error(error); } OssUploadResult ossUploadResult = ossFileUploadService.uploadImageByBytes(bytes); + return R.ok().setData(ossUploadResult); } - // 获取access_token - public AccessTokenDTO getAccessToken(String appid, String appSecret) { - String url = String.format(wechatAccessTokenUrl, appid, appSecret); - String responseBody = HttpUtils.doGet(url); - log.info("getAccessToken responseBody:{}", responseBody); - AccessTokenDTO accessTokenDTO = JSONObject.parseObject(responseBody, AccessTokenDTO.class); - return accessTokenDTO; - } - - } diff --git a/api-web/api-interface/src/main/java/com/heyu/api/controller/vv/AppUserLoginController.java b/api-web/api-interface/src/main/java/com/heyu/api/controller/vv/AppUserLoginController.java index ff29565..50bdf2f 100644 --- a/api-web/api-interface/src/main/java/com/heyu/api/controller/vv/AppUserLoginController.java +++ b/api-web/api-interface/src/main/java/com/heyu/api/controller/vv/AppUserLoginController.java @@ -34,11 +34,16 @@ public class AppUserLoginController { private RedisUtils redisUtils; + @Autowired + private WeChatUtils weChatUtils; + + + // http://localhost:8888/app/user/login @RequestMapping("/login") @Describe("微信用户登录") public R login(@RequestBody AppUserLoginRequest request) { - WeiChatLoginDTO weiChatLoginDTO = WechatUtils.getOpenId(request.getCode()); + WeiChatLoginDTO weiChatLoginDTO = weChatUtils.getOpenId(request.getCode()); if (weiChatLoginDTO == null) { return R.error("code 失效"); } diff --git a/pom.xml b/pom.xml index d689690..368d94d 100644 --- a/pom.xml +++ b/pom.xml @@ -91,6 +91,15 @@ + + + + cn.hutool + hutool-all + 5.8.25 + + + org.springframework.boot