From 3b84f7df62ee5c88a517a86615cdbbac5c43fce0 Mon Sep 17 00:00:00 2001 From: xin <1099200748@qq.com> Date: Wed, 28 May 2025 21:56:23 +0800 Subject: [PATCH] 微信和配置 --- oying-system/src/main/java/com/oying/modules/security/config/WeiXinProperties.java | 31 ++++ oying-system/src/main/resources/config/application-dev.yml | 54 +++++++ oying-common/src/main/java/com/oying/utils/HttpRequest.java | 101 ++++++++++++++ oying-system/src/main/resources/config/application-prod.yml | 53 +++++++ pom.xml | 14 ++ oying-common/src/main/java/com/oying/utils/RedisUtils.java | 10 + oying-system/src/main/java/com/oying/modules/security/service/WeiXinService.java | 109 +++++++++++++++ 7 files changed, 372 insertions(+), 0 deletions(-) diff --git a/oying-common/src/main/java/com/oying/utils/HttpRequest.java b/oying-common/src/main/java/com/oying/utils/HttpRequest.java new file mode 100644 index 0000000..d3293c4 --- /dev/null +++ b/oying-common/src/main/java/com/oying/utils/HttpRequest.java @@ -0,0 +1,101 @@ +package com.oying.utils; + +import com.alibaba.fastjson2.JSONObject; +import com.oying.exception.BadRequestException; +import org.apache.http.conn.ssl.NoopHostnameVerifier; +import org.apache.http.conn.ssl.SSLConnectionSocketFactory; +import org.apache.http.conn.ssl.TrustStrategy; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.ssl.SSLContexts; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.MediaType; +import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; +import org.springframework.web.client.RestTemplate; + +import javax.net.ssl.SSLContext; +import javax.servlet.ServletInputStream; +import javax.servlet.http.HttpServletRequest; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.Map; + +/** + * 功能描述: + * + * @author LIX + * @date 创建时间 :2022/6/15 下午4:19 + */ +public class HttpRequest { + + + /** + * 读取请求数据流 + * + * @param request 请求数据 + * @return String + */ + public static String getRequestBody(HttpServletRequest request) { + StringBuilder sb = new StringBuilder(); + try (ServletInputStream inputStream = request.getInputStream(); + BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) { + String line; + while ((line = reader.readLine()) != null) { + sb.append(line); + } + } catch (IOException e) { + throw new BadRequestException("读取数据流异常"); + } + return sb.toString(); + } + + /** + * 忽略ssl证书验证 + * + * @return HttpComponentsClientHttpRequestFactory + */ + public static HttpComponentsClientHttpRequestFactory getFactory() { + HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(); + try { + TrustStrategy acceptingTrustStrategy = (chain, authType) -> true; + SSLContext sslContext = SSLContexts.custom().loadTrustMaterial(null, acceptingTrustStrategy).build(); + SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE); + HttpClientBuilder clientBuilder = HttpClients.custom(); + CloseableHttpClient httpClient = clientBuilder.setSSLSocketFactory(socketFactory).build(); + requestFactory.setHttpClient(httpClient); + } catch (Exception e) { + throw new BadRequestException("忽略ssl证书验证失败!!!"); + } + return requestFactory; + } + + private static HttpHeaders getHeaders() { + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); + return headers; + } + + /** + * http返回String + */ + public static String exchangeString(HttpMethod httpMethod, String url, Map<String, Object> map) { + HttpHeaders headers = getHeaders(); + HttpEntity<Object> httpEntity = new HttpEntity<>(map, headers); + RestTemplate restTemplate = new RestTemplate(); + return restTemplate.exchange(url, httpMethod, httpEntity, String.class).getBody(); + } + + /** + * http返回JSONObject + */ + public static JSONObject exchangeJsonObject(HttpMethod httpMethod, String url, Map<String, Object> map) { + HttpHeaders headers = getHeaders(); + HttpEntity<Object> httpEntity = new HttpEntity<>(map, headers); + RestTemplate restTemplate = new RestTemplate(); + return restTemplate.exchange(url, httpMethod, httpEntity, JSONObject.class).getBody(); + } +} diff --git a/oying-common/src/main/java/com/oying/utils/RedisUtils.java b/oying-common/src/main/java/com/oying/utils/RedisUtils.java index ccd9126..d50d82c 100644 --- a/oying-common/src/main/java/com/oying/utils/RedisUtils.java +++ b/oying-common/src/main/java/com/oying/utils/RedisUtils.java @@ -31,6 +31,16 @@ } /** + * 判断key是否过期 + * + * @param key + * @return + */ + public boolean isExpire(Object key) { + return getExpire(key) > 1 ? false : true; + } + + /** * 指定缓存失效时间 * * @param key 键 diff --git a/oying-system/src/main/java/com/oying/modules/security/config/WeiXinProperties.java b/oying-system/src/main/java/com/oying/modules/security/config/WeiXinProperties.java new file mode 100644 index 0000000..bcaca43 --- /dev/null +++ b/oying-system/src/main/java/com/oying/modules/security/config/WeiXinProperties.java @@ -0,0 +1,31 @@ +package com.oying.modules.security.config; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; + +@Data +@Configuration +@ConfigurationProperties(prefix = "wx") +public class WeiXinProperties { + // APPID + private String appId; + // APP密钥 + private String appSecret; + // 跳转小程序类型 + private String miniProgramState; + /*access_token的KEY*/ + private String tokenKey; + /*access_token的失效时间间隔,微信是2小时,此处隔7200秒就重新获取*/ + private Long tokenTime; + /*POST 获取稳定版接口调用凭据 获取小程序全局唯一后台接口调用凭据,token有效期为7200s,开发者需要进行妥善保存。*/ + private String getStableAccessToken; + /*GET 小程序登录 登录凭证校验。通过 wx.login 接口获得临时登录凭证 code 后传到开发者服务器调用此接口完成登录流程*/ + private String code2Session; + /*POST 获取手机号 该接口用于将code换取用户手机号。 说明,每个code只能使用一次,code的有效期为5min。*/ + private String getPhoneNumber; + /*POST 该接口用于发送订阅消息。*/ + private String sendMessage; + /* 是否生成环境*/ + private boolean enabled; +} diff --git a/oying-system/src/main/java/com/oying/modules/security/service/WeiXinService.java b/oying-system/src/main/java/com/oying/modules/security/service/WeiXinService.java new file mode 100644 index 0000000..2fe0146 --- /dev/null +++ b/oying-system/src/main/java/com/oying/modules/security/service/WeiXinService.java @@ -0,0 +1,109 @@ +package com.oying.modules.security.service; + +import com.alibaba.fastjson2.JSONObject; +import com.oying.modules.security.config.WeiXinProperties; +import com.oying.utils.HttpRequest; +import com.oying.utils.RedisUtils; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.HttpMethod; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.Map; + +@Service +@Slf4j +public class WeiXinService { + + @Resource + private WeiXinProperties weiXinProperties; + @Resource + private RedisUtils redisUtils; + @Value("${wx.enabled}") + private Boolean wxEnabled; + + /** + * POST 获取稳定版接口调用凭据 获取小程序全局唯一后台接口调用凭据,token有效期为7200s,开发者需要进行妥善保存。 + * + * @return accessToken + */ + public String getStableAccessToken() { + String accessToken; + if (redisUtils.isExpire(weiXinProperties.getTokenKey())) { + // 获取接口调用凭据 + String url = weiXinProperties.getGetStableAccessToken(); + Map<String, Object> map = new LinkedHashMap<>(); + map.put("grant_type", "client_credential"); + map.put("appid", weiXinProperties.getAppId()); + map.put("secret", weiXinProperties.getAppSecret()); + map.put("force_refresh", false); + JSONObject jsonObject = HttpRequest.exchangeJsonObject(HttpMethod.POST, url, map); + accessToken = jsonObject.getString("access_token"); + redisUtils.set(weiXinProperties.getTokenKey(), accessToken, weiXinProperties.getTokenTime()); + } else { + // 查询接口调用凭据 + accessToken = (String) redisUtils.get(weiXinProperties.getTokenKey()); + } + return accessToken; + } + + /** + * GET 小程序登录 登录凭证校验。通过 wx.login 接口获得临时登录凭证 code 后传到开发者服务器调用此接口完成登录流程 + * + * @param js_code 登录时获取的 code,可通过wx.login获取 + * @return JSONObject + */ + public JSONObject code2Session(String js_code) { + String url = weiXinProperties.getCode2Session(); + url = url.replace("{appid}", weiXinProperties.getAppId()) + .replace("{secret}", weiXinProperties.getAppSecret()) + .replace("{js_code}", js_code); + return HttpRequest.exchangeJsonObject(HttpMethod.GET, url, null); + } + + /** + * POST 获取手机号 该接口用于将code换取用户手机号。 说明,每个code只能使用一次,code的有效期为5min。 + * + * @param code 手机号获取凭证 + * @return JSONObject + */ + public JSONObject getPhoneNumber(String code) { + String url = weiXinProperties.getGetPhoneNumber(); + url = url.replace("{accessToken}", getStableAccessToken()); + Map<String, Object> map = new LinkedHashMap<>(); + map.put("code", code); + return HttpRequest.exchangeJsonObject(HttpMethod.POST, url, map); + } + + /** + * POST 该接口用于发送订阅消息。 + * + * @param data 请求参数 + * @return JSONObject + */ + public JSONObject sendMessage(Map<String, Object> data, String openId, String templateId, String page) { + if (wxEnabled) { + String url = weiXinProperties.getSendMessage(); + url = url.replace("{accessToken}", getStableAccessToken()); + Map<String, Object> map = getSendMessageDto(data, openId, templateId, page); + return HttpRequest.exchangeJsonObject(HttpMethod.POST, url, map); + } + JSONObject jsonObject = new JSONObject(); + jsonObject.put("message", "测试环境"); + return jsonObject; + } + + private Map<String, Object> getSendMessageDto(Map<String, Object> data, String openId, String templateId, String page) { + Map<String, Object> map = new HashMap<>(); + map.put("touser", openId); + map.put("template_id", templateId); + map.put("page", page); + map.put("miniprogram_state", weiXinProperties.getMiniProgramState()); + map.put("lang", "zh_CN"); + map.put("data", data); + return map; + } +} diff --git a/oying-system/src/main/resources/config/application-dev.yml b/oying-system/src/main/resources/config/application-dev.yml index 1880cf2..ce0a962 100644 --- a/oying-system/src/main/resources/config/application-dev.yml +++ b/oying-system/src/main/resources/config/application-dev.yml @@ -116,3 +116,57 @@ # 文件大小 /M maxSize: 100 avatarMaxSize: 5 + + # 短信验证码key 时间 +sms: + key: lyhd-sms-key- + time: 300 + +#微信配置 +wx: + # 测试环境 + enabled: false + # AppID + app-id: wx2273296a5569cbad + # AppSecret + app-secret: 4526d72d885be322b17d0694cd6d03f1 + # 跳转小程序类型 developer为开发版;trial为体验版;formal为正式版;默认为正式版 + mini-program-state: trial + # access_token的KEY + token-key: wx_access_token + # access_token的失效时间间隔,微信是2小时,此处隔7200秒就重新获取 + token-time: 7200 + # 微信URL调用 + # POST 获取稳定版接口调用凭据 获取小程序全局唯一后台接口调用凭据,token有效期为7200s,开发者需要进行妥善保存。 + get-stable-access-token: https://api.weixin.qq.com/cgi-bin/stable_token + # GET 小程序登录 登录凭证校验。通过 wx.login 接口获得临时登录凭证 code 后传到开发者服务器调用此接口完成登录流程 + code2-session: https://api.weixin.qq.com/sns/jscode2session?appid={appid}&secret={secret}&js_code={js_code}&grant_type=authorization_code + # POST 获取手机号 该接口用于将code换取用户手机号。 说明,每个code只能使用一次,code的有效期为5min。 + get-phone-number: https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token={accessToken} + # POST 该接口用于发送订阅消息。 + send-message: https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token={accessToken} + +# 汇旺财 +swift-pass: + # 密钥1 + key-1: qqqqqqqqqqqqqqqqqqqq + # 私钥 + mch-private-key: qqqqqqqqqqqq + # 公钥 + plat-public-key: qqqqq + # 门店编号1 + mch-id-1: 1111 + # 签名方式 + sign-type: MD5 + # 原生JS + is-raw: 1 + # 是否小程序支付 + is-minipg: 1 + # AppID + app-id: wx2273296a5569cbad + # 请求url + req-url: https://pay.hstypay.com/v2/pay/gateway + # 支付通知地址 + notify-url: https://localhost/lyhd/api/swiftPass/alipayCallback + # 退款通知地址 + refund-url: https://localhost/lyhd/api/swiftPass/returnNotify diff --git a/oying-system/src/main/resources/config/application-prod.yml b/oying-system/src/main/resources/config/application-prod.yml index f3cc9c8..cf83150 100644 --- a/oying-system/src/main/resources/config/application-prod.yml +++ b/oying-system/src/main/resources/config/application-prod.yml @@ -127,3 +127,56 @@ # 文件大小 /M maxSize: 100 avatarMaxSize: 5 + # 短信验证码key 时间 +sms: + key: lyhd-sms-key- + time: 300 + +#微信配置 +wx: + # 测试环境 + enabled: false + # AppID + app-id: wx2273296a5569cbad + # AppSecret + app-secret: 4526d72d885be322b17d0694cd6d03f1 + # 跳转小程序类型 developer为开发版;trial为体验版;formal为正式版;默认为正式版 + mini-program-state: trial + # access_token的KEY + token-key: wx_access_token + # access_token的失效时间间隔,微信是2小时,此处隔7200秒就重新获取 + token-time: 7200 + # 微信URL调用 + # POST 获取稳定版接口调用凭据 获取小程序全局唯一后台接口调用凭据,token有效期为7200s,开发者需要进行妥善保存。 + get-stable-access-token: https://api.weixin.qq.com/cgi-bin/stable_token + # GET 小程序登录 登录凭证校验。通过 wx.login 接口获得临时登录凭证 code 后传到开发者服务器调用此接口完成登录流程 + code2-session: https://api.weixin.qq.com/sns/jscode2session?appid={appid}&secret={secret}&js_code={js_code}&grant_type=authorization_code + # POST 获取手机号 该接口用于将code换取用户手机号。 说明,每个code只能使用一次,code的有效期为5min。 + get-phone-number: https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token={accessToken} + # POST 该接口用于发送订阅消息。 + send-message: https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token={accessToken} + +# 汇旺财 +swift-pass: + # 密钥1 + key-1: qqqqqqqqqqqqqqqqqqqq + # 私钥 + mch-private-key: qqqqqqqqqqqq + # 公钥 + plat-public-key: qqqqq + # 门店编号1 + mch-id-1: 1111 + # 签名方式 + sign-type: MD5 + # 原生JS + is-raw: 1 + # 是否小程序支付 + is-minipg: 1 + # AppID + app-id: wx2273296a5569cbad + # 请求url + req-url: https://pay.hstypay.com/v2/pay/gateway + # 支付通知地址 + notify-url: https://localhost/lyhd/api/swiftPass/alipayCallback + # 退款通知地址 + refund-url: https://localhost/lyhd/api/swiftPass/returnNotify diff --git a/pom.xml b/pom.xml index a2fef79..489ecc4 100644 --- a/pom.xml +++ b/pom.xml @@ -210,6 +210,20 @@ <version>${fastjson2.version}</version> </dependency> + <!-- 请求跳过ssl证书验证 --> + <dependency> + <groupId>org.apache.httpcomponents</groupId> + <artifactId>httpclient</artifactId> + </dependency> + <dependency> + <groupId>org.apache.httpcomponents</groupId> + <artifactId>httpmime</artifactId> + </dependency> + <dependency> + <groupId>org.apache.httpcomponents</groupId> + <artifactId>httpcore</artifactId> + </dependency> + <!-- Java图形验证码 --> <dependency> <groupId>com.github.whvcse</groupId> -- Gitblit v1.9.3