Commit 6b76675f by yuanchao

20240318

parent 925c72e9
......@@ -3,9 +3,12 @@ package com.qianhe.system.controller;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.qianhe.system.config.WechatPayConfig;
import com.qianhe.system.domain.WaterWxpayOrder;
import com.qianhe.system.mapper.WaterWxpayOrderMapper;
import com.qianhe.system.utils.WechatPayValidator;
import com.wechat.pay.contrib.apache.httpclient.auth.Verifier;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
......@@ -13,6 +16,7 @@ import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReentrantLock;
......@@ -35,6 +39,9 @@ public class CallbackController {
@Resource
private Verifier verifier;
@Autowired
private WaterWxpayOrderMapper wxpayOrderMapper;
private final ReentrantLock lock = new ReentrantLock();
......@@ -45,7 +52,7 @@ public class CallbackController {
* @param response
* @return
*/
@PostMapping("/payNotify")
@PostMapping("/payNotify/")
public Map<String, String> payNotify(HttpServletRequest request, HttpServletResponse response) {
log.info("支付回调");
......@@ -61,7 +68,39 @@ public class CallbackController {
// 解密resource中的通知数据
String resource = bodyMap.get("resource").toString();
Map<String, Object> resourceMap = WechatPayValidator.decryptFromResource(resource, wechatPayConfig.getApiV3Key(), 1);
String orderNo = resourceMap.get("out_trade_no").toString();
String outTradeNo = resourceMap.get("out_trade_no").toString();
String appId = resourceMap.get("app_id").toString();
String tradeType = resourceMap.get("trade_type").toString();
String tradeState = resourceMap.get("trade_state").toString();
String desc = resourceMap.get("trade_state_desc").toString();
String successTime = resourceMap.get("success_time").toString();
Object amount = resourceMap.get("amount");
Map<String,Object> amountMap = object2Map(amount);
String payerTotal = amountMap.get("payer_total").toString();
String total = amountMap.get("total").toString();
String currency = amountMap.get("currency").toString();
String payerCurrency = amountMap.get("payer_currency").toString();
Object payer = resourceMap.get("payer");
Map<String,Object> payerMap = object2Map(payer);
String openId = payerMap.get("openid").toString();
String bankType = resourceMap.get("bank_type").toString();
WaterWxpayOrder wxpayOrder = new WaterWxpayOrder();
wxpayOrder.setOutTradeNo(outTradeNo);
wxpayOrder.setTradeState(tradeState);
wxpayOrder.setSuccessTime(successTime);
wxpayOrder.setOpenId(openId);
wxpayOrder.setTradeStateDesc(desc);
wxpayOrder.setAppId(appId);
wxpayOrder.setTradeType(tradeType);
wxpayOrder.setBankType(bankType);
wxpayOrder.setPayerTotal(payerTotal);
wxpayOrder.setTotal(total);
wxpayOrder.setCurrency(currency);
wxpayOrder.setPayerCurrency(payerCurrency);
int pay = wxpayOrderMapper.insertWxpay(wxpayOrder);
// String transactionId = resourceMap.get("transaction_id").toString();
// 更改状态 获取订单号 修改订单状态为已支付
......@@ -77,6 +116,31 @@ public class CallbackController {
return trueMsg(response);
}
/**
* 实体对象转成Map
* @param obj 实体对象
* @return
*/
public static Map<String, Object> object2Map(Object obj) {
Map<String, Object> map = new HashMap<>();
if (obj == null) {
return map;
}
Class clazz = obj.getClass();
Field[] fields = clazz.getDeclaredFields();
try {
for (Field field : fields) {
field.setAccessible(true);
map.put(field.getName(), field.get(obj));
}
} catch (Exception e) {
e.printStackTrace();
}
return map;
}
/**
* 退款回调处理
*
......
package com.qianhe.system.controller;
import cn.hutool.core.codec.Base64Encoder;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.asymmetric.SignAlgorithm;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.qianhe.common.core.domain.AjaxResult;
import com.qianhe.common.utils.DateUtils;
import com.qianhe.common.utils.StringUtils;
import com.qianhe.system.config.WechatPayConfig;
import com.qianhe.system.domain.WaterGoods;
import com.qianhe.system.domain.WaterOrder;
import com.qianhe.system.mapper.WaterOrderMapper;
import com.qianhe.system.service.IWaterOrderService;
import com.qianhe.system.utils.WechatPayRequest;
import io.lettuce.core.dynamic.annotation.Param;
import com.wechat.pay.contrib.apache.httpclient.util.PemUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.io.IOException;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.PrivateKey;
import java.security.Signature;
import java.text.SimpleDateFormat;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
......@@ -30,7 +44,7 @@ import static com.qianhe.common.core.domain.AjaxResult.success;
* @version 1.0
* @className PayController
* @date 2024/3/15 15:03
* @description
* @description 微信支付
*/
@Slf4j
......@@ -43,11 +57,17 @@ public class PayController {
@Resource
private WechatPayRequest wechatPayRequest;
@Autowired
private IWaterOrderService waterOrderService;
@Autowired
private WaterOrderMapper waterOrderMapper;
/**
* 预支付订单生成入口
*/
@GetMapping("/transactions")
public AjaxResult transactions(WaterGoods goods) {
public AjaxResult transactions(WaterGoods goods) throws IOException {
// 统一参数封装
Map<String, Object> params = new HashMap<>(10);
......@@ -56,15 +76,15 @@ public class PayController {
// 2,mch_id:商户号,由微信支付分配。
params.put("mchid", wechatPayConfig.getMchId());
// 3.description body:商品描述。
params.put("description", "奥迪a4l 2023-限量款");
params.put("description", goods.getTitle());
// 4.out_trade_no:商户订单号,由商户自定义。
params.put("out_trade_no", "we56f45waf4w6a5fwa");
params.put("out_trade_no", getOrerNum());
// 5.notify_url:接收微信支付异步通知回调地址。
params.put("notify_url", wechatPayConfig.getNotifyUrl());
// 6.total_fee:订单总金额,单位为分。
Map<String, Object> amountMap = new HashMap<>(4);
// 金额单位为分
amountMap.put("total", 999999);
amountMap.put("total", (int)Math.floor(Double.parseDouble(goods.getTotalPrice())*100));
amountMap.put("currency", "CNY");
params.put("amount", amountMap);
......@@ -91,30 +111,8 @@ public class PayController {
// 得到当前系统时间搓
String timeStamp = String.valueOf(System.currentTimeMillis() / 1000);
// 获取签名
String paySign;
try {
StringBuilder sb = new StringBuilder();
// 应用id
sb.append(wechatPayConfig.getAppId()).append("\n");
// 支付签名时间戳
sb.append(timeStamp).append("\n");
// 随机字符串
sb.append("5w7er7wa4fwa5e").append("\n");
// 预支付交易会话ID 这个要注意 key = "prepay_id=xxxxxx"
sb.append("prepay_id=").append(prepayId).append("\n");
// 签名
Signature sign = Signature.getInstance("SHA256withRSA");
// 获取商户私钥并进行签名
PrivateKey privateKey = wechatPayConfig.getPrivateKey(wechatPayConfig.getKeyPemPath());
sign.initSign(privateKey);
sign.update(sb.toString().getBytes(StandardCharsets.UTF_8));
// 得到签名
paySign = Base64.getEncoder().encodeToString(sign.sign());
} catch (Exception e) {
log.error("支付模块_生成交易签名失败!" + e);
return success(new HashMap<>());
}
String nonceStr = getRandomStringByLength(32);
// 将签名时数据和签名一起返回前端用于前端吊起支付
......@@ -124,18 +122,82 @@ public class PayController {
// 时间戳
map.put("timeStamp", timeStamp);
// 随机字符串
map.put("nonceStr", "56523268632356");
map.put("nonceStr", nonceStr);
// 预支付交易会话ID
map.put("package", "prepay_id=" + prepayId);
// 签名方式
map.put("signType", "RSA");
// 获取签名
String sign = getPaySign(timeStamp,nonceStr,"prepay_id="+prepayId);
// 签名
map.put("paySign", paySign);
map.put("paySign", sign);
System.out.println(map);
return success(map);
}
public String getPaySign(String timeStamp, String nonceStr, String packageStr) throws IOException {
String sourceText = wechatPayConfig.getAppId() + StrUtil.LF + timeStamp + StrUtil.LF + nonceStr + StrUtil.LF + packageStr + StrUtil.LF;
log.info("微信支付签名原文:{}", sourceText);
byte[] sign = SecureUtil.sign(SignAlgorithm.SHA256withRSA)
.setPrivateKey(wechatPayConfig.getPrivateKey(wechatPayConfig.getKeyPemPath()))
.sign(sourceText);
String paySign = Base64Encoder.encode(sign);
log.info("微信支付签名密文:{}", paySign);
return paySign;
}
/**
* 生成订单编号
* @return
*/
public String getOrerNum(){
String orderNum = "";
//获取当前年月日
SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd");
String today = format.format(DateUtils.getNowDate());
Long rqbh = Long.parseLong(today + "0001");
while (true){
WaterOrder waterOrder = new WaterOrder();
waterOrder.setOrderNum(rqbh.toString());
WaterOrder waterOrder1 = waterOrderMapper.selectWaterOrderNumByOrderNum(rqbh.toString());
if (StringUtils.isNotNull(waterOrder1)){
rqbh ++;
}else {
break;
}
}
//生成随机四位英文字母
Random random = new Random();
String randomletters = "";
for (int i = 0; i < 4; i++) {
int index = random.nextInt(26);
char letter = (char) ('A' + index);
randomletters += letter;
}
orderNum = rqbh + randomletters;
return orderNum;
}
/**
* 获取一定长度的随机字符串
*
* @param length 指定字符串长度
* @return 一定长度的字符串
*/
public static String getRandomStringByLength(int length) {
String base = "abcdefghijklmnopqrstuvwxyz0123456789";
Random random = new Random();
StringBuffer sb = new StringBuffer();
for (int i = 0; i < length; i++) {
int number = random.nextInt(base.length());
sb.append(base.charAt(number));
}
return sb.toString();
}
/**
* 申请退款
*/
......
......@@ -66,4 +66,6 @@ public class WaterGoods
private Integer status;
private String openId;
private String totalPrice;
}
package com.qianhe.system.domain;
import lombok.Data;
/**
* @author yc
* @version 1.0
* @className WaterWxpayOrder
* @date 2024/3/18 16:43
* @description 微信支付回调
*/
@Data
public class WaterWxpayOrder {
private String id;
private String outTradeNo;
private String tradeState;
private String successTime;
private String openId;
private String tradeStateDesc;
private String appId;
private String tradeType;
private String bankType;
private String payerTotal;
private String total;
private String currency;
private String payerCurrency;
}
\ No newline at end of file
package com.qianhe.system.mapper;
import com.qianhe.system.domain.WaterWxpayOrder;
/**
* @author yc
* @version 1.0
* @className WaterWxpayOrderMapper
* @date 2024/3/18 16:46
* @description
*/
public interface WaterWxpayOrderMapper {
int insertWxpay(WaterWxpayOrder wxpayOrder);
}
\ No newline at end of file
......@@ -184,7 +184,7 @@ public class WaterOrderServiceImpl implements IWaterOrderService
* 生成订单编号
* @return
*/
private String getOrerNum(){
public String getOrerNum(){
String orderNum = "";
//获取当前年月日
SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd");
......
......@@ -9,6 +9,9 @@ spring:
url: jdbc:mysql://1.116.38.25:3986/slsy?characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&useOldAliasMetadataBehavior=true
username: root
password: qianhe2022
# url: jdbc:mysql://192.168.1.110:3306/slsy?characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&useOldAliasMetadataBehavior=true
# username: root
# password: 123456
# 从库数据源
slave:
# 从数据源开关/默认关闭
......
......@@ -153,9 +153,9 @@ wx:
apiV3Key: 2562AB35D9BFE5CB875FA73954B6F5WW #微信支付v3密钥
#apiKey: asdkjfhakjsdhf12321349898aksjhdj #微信支付v2密钥
#支付通知回调
notifyUrl: http://localhost:5125/callback/payNotify
notifyUrl: https://www.dyzmxx.com/callback/payNotify/
#退款通知回调
refundNotifyUrl: http://localhost:5125/callback/refundNotify
refundNotifyUrl: https://www.dyzmxx.com/callback/refundNotify/
#证书地址
keyPemPath: apiclient_key.pem
......
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.qianhe.system.mapper.WaterWxpayOrderMapper">
<insert id="insertWxpay" parameterType="com.qianhe.system.domain.WaterWxpayOrder" useGeneratedKeys="true" keyProperty="id">
insert into water_wxpay_order
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="outTradeNo != null">out_trade_no,</if>
<if test="tradeState != null">trade_state,</if>
<if test="successTime != null">success_time,</if>
<if test="openId != null">open_id,</if>
<if test="tradeStateDesc != null">trade_state_desc,</if>
<if test="appId != null">app_id,</if>
<if test="tradeType != null">trade_type,</if>
<if test="bankType != null">bank_type,</if>
<if test="payerTotal != null">payer_total,</if>
<if test="total != null">total,</if>
<if test="currency != null">currency,</if>
<if test="payerCurrency != null">payer_currency,</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="outTradeNo != null">#{outTradeNo},</if>
<if test="tradeState != null">#{tradeState},</if>
<if test="successTime != null">#{successTime},</if>
<if test="openId != null">#{openId},</if>
<if test="tradeStateDesc != null">#{tradeStateDesc},</if>
<if test="appId != null">#{appId},</if>
<if test="tradeType != null">#{tradeType},</if>
<if test="bankType != null">#{bankType},</if>
<if test="payerTotal != null">#{payerTotal},</if>
<if test="total != null">#{total},</if>
<if test="currency != null">#{currency},</if>
<if test="payerCurrency != null">#{payerCurrency}</if>
</trim>
</insert>
</mapper>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment