xin
2025-05-28 3b84f7df62ee5c88a517a86615cdbbac5c43fce0
微信和配置
3 files added
4 files modified
372 ■■■■■ changed files
oying-common/src/main/java/com/oying/utils/HttpRequest.java 101 ●●●●● patch | view | raw | blame | history
oying-common/src/main/java/com/oying/utils/RedisUtils.java 10 ●●●●● patch | view | raw | blame | history
oying-system/src/main/java/com/oying/modules/security/config/WeiXinProperties.java 31 ●●●●● patch | view | raw | blame | history
oying-system/src/main/java/com/oying/modules/security/service/WeiXinService.java 109 ●●●●● patch | view | raw | blame | history
oying-system/src/main/resources/config/application-dev.yml 54 ●●●●● patch | view | raw | blame | history
oying-system/src/main/resources/config/application-prod.yml 53 ●●●●● patch | view | raw | blame | history
pom.xml 14 ●●●●● patch | view | raw | blame | history
oying-common/src/main/java/com/oying/utils/HttpRequest.java
New file
@@ -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();
    }
}
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  键
oying-system/src/main/java/com/oying/modules/security/config/WeiXinProperties.java
New file
@@ -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;
}
oying-system/src/main/java/com/oying/modules/security/service/WeiXinService.java
New file
@@ -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;
    }
}
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
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
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>