2.0版本

This commit is contained in:
ageerle
2025-02-07 10:34:31 +08:00
parent 3c3ad701e3
commit c1cbfc2b93
968 changed files with 67565 additions and 1011 deletions

View File

@@ -0,0 +1,53 @@
package org.ruoyi.common.config;
import lombok.Data;
/**
* 支付配置信息
*
* @author Admin
*/
@Data
public class PayConfig {
/**
* 商户ID
*/
private String pid;
/**
* 接口地址
*/
private String payUrl;
/**
* 私钥
*/
private String key ;
/**
* 服务器异步通知地址
*/
private String notify_url;
/**
* 页面跳转通知地址
*/
private String return_url;
/**
* 支付方式
*/
private String type;
/**
* 设备类型
*/
private String device;
/**
* 加密方式默认MD5
*/
private String sign_type;
}

View File

@@ -0,0 +1,51 @@
package org.ruoyi.common.config;
import org.ruoyi.common.core.service.ConfigService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
import org.springframework.scheduling.annotation.Scheduled;
/**
* 支付配置信息
*
* @author Admin
*/
@RequiredArgsConstructor
@Configuration
@Slf4j
public class PayInit {
private final ConfigService configService;
private PayConfig payConfig;
@Bean
@Scope("singleton")
public PayConfig payConfig() {
if (payConfig == null) {
payConfig = new PayConfig();
updatePayConfig();
}
return payConfig;
}
@Scheduled(fixedDelay = 10000) // 每10秒检查一次
public void updatePayConfig() {
payConfig.setType("wxpay");
payConfig.setDevice("pc");
payConfig.setSign_type("MD5");
payConfig.setPid(getKey("pid"));
payConfig.setKey(getKey("key"));
payConfig.setPayUrl(getKey("payUrl"));
payConfig.setNotify_url(getKey("notify_url"));
payConfig.setReturn_url(getKey("return_url"));
}
public String getKey(String key){
return configService.getConfigValue("pay", key);
}
}

View File

@@ -0,0 +1,47 @@
package org.ruoyi.common.config;
import com.github.binarywang.wxpay.config.WxPayConfig;
import com.github.binarywang.wxpay.service.WxPayService;
import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl;
import org.ruoyi.common.core.service.ConfigService;
import jakarta.annotation.PostConstruct;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @author Binary Wang
*/
@Configuration
@RequiredArgsConstructor
public class WxPayConfiguration {
private final ConfigService configService;
private WxPayService wxPayService;
@PostConstruct
public void init() {
WxPayConfig payConfig = new WxPayConfig();
payConfig.setAppId(StringUtils.trimToNull(getKey("appId")));
payConfig.setMchId(StringUtils.trimToNull(getKey("mchId")));
payConfig.setMchKey(StringUtils.trimToNull(getKey("appSecret")));
payConfig.setUseSandboxEnv(false);
wxPayService = new WxPayServiceImpl();
wxPayService.setConfig(payConfig);
}
@Bean
@ConditionalOnMissingBean
public WxPayService wxService() {
return wxPayService;
}
public String getKey(String key) {
return configService.getConfigValue("weixin", key);
}
}

View File

@@ -0,0 +1,37 @@
package org.ruoyi.common.listener;
import com.github.binarywang.wxpay.config.WxPayConfig;
import com.github.binarywang.wxpay.service.WxPayService;
import org.ruoyi.common.core.event.ConfigChangeEvent;
import org.ruoyi.common.core.service.ConfigService;
import org.ruoyi.common.core.utils.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;
/**
* 描述:创建一个监听器,用于处理配置变化事件
*
* @author ageerle@163.com
* date 2024/5/19
*/
@Component
public class ConfigChangeListener implements ApplicationListener<ConfigChangeEvent> {
private final WxPayService wxPayService;
private final ConfigService configService;
public ConfigChangeListener(WxPayService wxPayService, ConfigService configService) {
this.wxPayService = wxPayService;
this.configService = configService;
}
@Override
public void onApplicationEvent(@NotNull ConfigChangeEvent event) {
WxPayConfig newConfig = new WxPayConfig();
newConfig.setAppId(StringUtils.trimToNull(configService.getConfigValue("weixin", "appId")));
newConfig.setMchId(StringUtils.trimToNull(configService.getConfigValue("weixin", "mchId")));
newConfig.setMchKey(StringUtils.trimToNull(configService.getConfigValue("weixin", "mchKey")));
newConfig.setUseSandboxEnv(false);
wxPayService.setConfig(newConfig);
}
}

View File

@@ -0,0 +1,70 @@
package org.ruoyi.common.response;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
/**
* 支付结果响应
*
* @author: wangle
* @date: 2023/7/3
*/
@Data
public class PayResponse {
/**
* 商户ID
*/
private String pid;
/**
* 易支付订单号
*/
@JsonProperty("trade_no")
private String trade_no;
/**
* 商户订单号
*/
@JsonProperty("out_trade_no")
private String out_trade_no;
/**
* 支付方式
*/
private String type;
/**
* 商品名称
*/
private String name;
/**
* 商品金额
*/
private String money;
/**
* 支付状态
*/
@JsonProperty("trade_status")
private String trade_status;
/**
* 业务扩展参数
*/
private String param;
/**
* 签名字符串
*/
private String sign;
/**
* 签名类型
*/
@JsonProperty("sign_type")
private String signType;
}

View File

@@ -0,0 +1,23 @@
package org.ruoyi.common.service;
/**
* 支付服务
*
* @author: wangle
* @date: 2023/7/3
*/
public interface PayService {
/**
* 获取支付地址
*
* @Date 2023/7/3
* @param orderNo
* @param name
* @param money
* @param clientIp
* @return String
**/
String getPayUrl(String orderNo, String name, double money, String clientIp);
}

View File

@@ -0,0 +1,53 @@
package org.ruoyi.common.service.impl;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONObject;
import org.ruoyi.common.config.PayConfig;
import org.ruoyi.common.service.PayService;
import org.ruoyi.common.utils.MD5Util;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.Map;
/**
* 支付服务
* @author Admin
*/
@Service
@RequiredArgsConstructor
@Slf4j
public class PayServiceImpl implements PayService {
private final PayConfig payConfig;
@Override
public String getPayUrl(String orderNo, String name, double money, String clientIp) {
String out_trade_no = orderNo, sign = "";
//封装请求参数
String mdString = "clientip=" + clientIp + "&device=" + payConfig.getDevice() + "&money=" + money + "&name=" + name + "&" +
"notify_url=" + payConfig.getNotify_url() + "&out_trade_no=" + out_trade_no + "&pid=" + payConfig.getPid() + "&return_url=" + payConfig.getReturn_url() +
"&type=" + payConfig.getType() + payConfig.getKey();
sign = MD5Util.GetMD5Code(mdString);
Map<String, Object> map = new HashMap<>(10);
map.put("clientip", clientIp);
map.put("device", payConfig.getDevice());
map.put("money", money);
map.put("name", name);
map.put("notify_url", payConfig.getNotify_url());
map.put("out_trade_no", out_trade_no);
map.put("pid", payConfig.getPid());
map.put("return_url", payConfig.getReturn_url());
map.put("sign_type", payConfig.getSign_type());
map.put("type", payConfig.getType());
map.put("sign", sign);
String body = HttpUtil.post(payConfig.getPayUrl(), map);
log.info("支付返回信息:{},配置信息: {}",body,payConfig);
JSONObject jsonObject = new JSONObject(body);
return (String) jsonObject.get("qrcode");
}
}

View File

@@ -0,0 +1,106 @@
package org.ruoyi.common.utils;
import cn.hutool.core.util.StrUtil;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Map;
import java.util.TreeMap;
/**
* MD5 算法
*
* @author Admin
*/
public class MD5Util {
/**
* 全局数组
*/
public final static String[] strDigits = { "0", "1", "2", "3", "4", "5",
"6", "7", "8", "9", "a", "b", "c", "d", "e", "f" };
public MD5Util() {
}
/**
* 返回形式为数字跟字符串
*
* @Date 2023/7/3
* @param bByte
* @return String
**/
public static String byteToArrayString(byte bByte) {
int iRet = bByte;
if (iRet < 0) {
iRet += 256;
}
int iD1 = iRet / 16;
int iD2 = iRet % 16;
return strDigits[iD1] + strDigits[iD2];
}
/**
* 转换字节数组为16进制字串
*
* @Date 2023/7/3
* @param bByte
* @return String
**/
public static String byteToString(byte[] bByte) {
StringBuffer sBuffer = new StringBuffer();
for (int i = 0; i < bByte.length; i++) {
sBuffer.append(byteToArrayString(bByte[i]));
}
return sBuffer.toString();
}
/**
* 生成md5代码
*
* @Date 2023/7/3
* @param strObj
* @return String
**/
public static String GetMD5Code(String strObj) {
String resultString = null;
try {
resultString = new String(strObj);
MessageDigest md = MessageDigest.getInstance("MD5");
resultString = byteToString(md.digest(strObj.getBytes()));
} catch (NoSuchAlgorithmException ex) {
ex.printStackTrace();
}
return resultString;
}
/**
* 组装签名的字段
*
* @param params 参数
* @param urlEncoder 是否urlEncoder
* @return {String}
*/
public static String packageSign(Map<String, Object> params, boolean urlEncoder) {
// 先将参数以其参数名的字典序升序进行排序
TreeMap<String, Object> sortedParams = new TreeMap<String, Object>(params);
// 遍历排序后的字典,将所有参数按"key=value"格式拼接在一起
StringBuilder sb = new StringBuilder();
boolean first = true;
for (Map.Entry<String, Object> param : sortedParams.entrySet()) {
String value = String.valueOf(param.getValue());
if (StrUtil.isBlank(value)) {
continue;
}
if (first) {
first = false;
} else {
sb.append("&");
}
sb.append(param.getKey()).append("=");
sb.append(value);
}
return sb.toString();
}
}