This commit is contained in:
Lx 2025-04-17 20:45:38 +08:00
parent 8743504224
commit 15d3215d74

View File

@ -0,0 +1,242 @@
package cn.iocoder.yudao.module.jx.controller.app;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
import cn.iocoder.yudao.module.course.entity.SchoolCourseOrder;
import cn.iocoder.yudao.module.course.service.SchoolCourseOrderService;
import cn.iocoder.yudao.module.course.vo.SchoolCourseOrderVO;
import cn.iocoder.yudao.module.jx.mapper.DriveSchoolCourseMapper;
import cn.iocoder.yudao.module.jx.payment.mapper.DrivePayMapper;
import cn.iocoder.yudao.module.jx.payment.utils.WechatPayRequests;
import cn.iocoder.yudao.module.jx.service.DrivePayService;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
import cn.iocoder.yudao.util.WechatPayConfig;
import cn.iocoder.yudao.util.WechatPayUrlEnum;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.alibaba.fastjson2.TypeReference;
import com.wechat.pay.contrib.apache.httpclient.util.PemUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.io.IOException;
import java.security.*;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
@Slf4j
@RestController
@RequestMapping("/small/jxInfo")
public class NewSmallProgramJxOrderController {
@Resource
private DrivePayService drivePayService;
@Resource
private WechatPayConfig wechatPayConfigs;
@Resource
private WechatPayRequests wechatPayRequests;
@Resource
private DrivePayMapper drivePayMapper;
@Resource
private DriveSchoolCourseMapper driveSchoolCourseMapper;
@Resource
private AdminUserApi userApi;
@Resource
private SchoolCourseOrderService schoolCourseOrderService;
@PostMapping("/offLinePay")
@TenantIgnore
public CommonResult offLinePay(@RequestBody SchoolCourseOrder schoolCourseOrder) {
SchoolCourseOrderVO schoolCourseOrderVO = BeanUtils.toBean(schoolCourseOrder, SchoolCourseOrderVO.class);
schoolCourseOrderVO.setPaymentStatus("0");
boolean exists = false;
String orderNo;
int retryCount = 0;
int maxRetry = 5;
do {
// 生成 14 位订单号
Random random = new Random();
StringBuilder number = new StringBuilder();
for (int i = 0; i < 14; i++) {
int randomDigit = random.nextInt(10);
number.append(randomDigit);
}
orderNo = number.toString();
// 检查订单号是否已存在
exists = schoolCourseOrderService.lambdaQuery()
.eq(SchoolCourseOrder::getOrderNo, orderNo)
.exists();
retryCount++;
} while (exists);
schoolCourseOrderVO.setOrderNo(orderNo);
schoolCourseOrderService.createSchoolCourseOrder(schoolCourseOrderVO);
return CommonResult.success("ok");
}
@PostMapping("/onLinePay")
@TenantIgnore
public Map<String,String> userPayOnLine(@RequestBody SchoolCourseOrder schoolCourseOrder) {
SchoolCourseOrderVO schoolCourseOrderVO = BeanUtils.toBean(schoolCourseOrder, SchoolCourseOrderVO.class);
schoolCourseOrderVO.setPaymentStatus("0");
// 生成 14 位订单号
Random random = new Random();
StringBuilder number = new StringBuilder();
for (int i = 0; i < 14; i++) {
int randomDigit = random.nextInt(10);
number.append(randomDigit);
}
String randomNumber = number.toString();
schoolCourseOrderVO.setOrderNo(randomNumber);
log.info("随机数为 ====================>>> {}", randomNumber);
Long userId = SecurityFrameworkUtils.getLoginUserId();
log.info("当前用户id ============>,{}", userId);
schoolCourseOrderVO.setUserId(Math.toIntExact(userId));
String orderId = schoolCourseOrderService.createSchoolCourseOrder(schoolCourseOrderVO);
SchoolCourseOrder dbSchoolCourseOrder = schoolCourseOrderService.getSchoolCourseOrder(orderId);
String orderNo = dbSchoolCourseOrder.getOrderNo();
Map<String,String> resMap = new HashMap<>();
resMap.put("orderNo",orderNo);
resMap.put("orderId",orderId);
return resMap;
}
@GetMapping("/prepayment")
@TenantIgnore
public Map<String,Object> transactions(String type, String orderId, String orderNo, String payType) throws SignatureException, NoSuchAlgorithmException, InvalidKeyException, IOException {
Long userId = SecurityFrameworkUtils.getLoginUserId();
AdminUserRespDTO user = userApi.getUser(userId);
SchoolCourseOrder dbSchoolCourseOrder = schoolCourseOrderService.getSchoolCourseOrder(orderId);
// 统一参数封装
Map<String, Object> params = new HashMap<>(8);
params.put("appid", wechatPayConfigs.getJxAppId());
params.put("mchid", wechatPayConfigs.getMchId());
params.put("description", dbSchoolCourseOrder.getCourseName());
params.put("out_trade_no", orderNo);
params.put("notify_url", wechatPayConfigs.getNotifyUrl());
Map<String, Object> amountMap = new HashMap<>(4);
Double amount = 0.0;
// 金额单位为分
amount = dbSchoolCourseOrder.getReserveMoney().doubleValue()*100;
if (payType.equals("2")){
amount = dbSchoolCourseOrder.getReserveMoney().doubleValue()*100;
}
amountMap.put("total", amount.intValue());
//人民币
amountMap.put("currency", "CNY");
params.put("amount", amountMap);
// 场景信息
Map<String, Object> sceneInfoMap = new HashMap<>(4);
// 客户端IP
sceneInfoMap.put("payer_client_ip", "127.0.0.1");
// 商户端设备号门店号或收银设备ID
sceneInfoMap.put("device_id", "127.0.0.1");
// 除H5与JSAPI有特殊参数外其他的支付方式都一样
if (type.equals(WechatPayUrlEnum.H5.getType())) {
Map<String, Object> h5InfoMap = new HashMap<>(4);
// 场景类型:iOS, Android, Wap
h5InfoMap.put("type", "IOS");
sceneInfoMap.put("h5_info", h5InfoMap);
} else if (type.equals(WechatPayUrlEnum.JSAPI.getType()) || type.equals(WechatPayUrlEnum.SUB_JSAPI.getType())) {
Map<String, Object> payerMap = new HashMap<>(4);
payerMap.put("openid", user.getDriverOpenId());
params.put("payer", payerMap);
}
params.put("scene_info", sceneInfoMap);
String paramsStr = JSON.toJSONString(params);
log.info("请求参数 ===> {}" + paramsStr);
String resStr = wechatPayRequests.wechatHttpPost("https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi",paramsStr);
Map<String, Object> resMap = JSONObject.parseObject(resStr, new TypeReference<Map<String, Object>>(){});
Map<String, Object> signMap = paySignMsg(resMap.get("prepay_id").toString(), wechatPayConfigs.getJxAppId(),null);
return signMap;
}
String buildMessage(String appId, String timestamp,String nonceStr,String prepay_id) {
return appId + "\n"
+ timestamp + "\n"
+ nonceStr + "\n"
+ prepay_id + "\n";
}
String sign(byte[] message,String privateKeyStr) throws NoSuchAlgorithmException, SignatureException, IOException, InvalidKeyException {
//签名方式
Signature sign = Signature.getInstance("SHA256withRSA");
//私钥通过MyPrivateKey来获取这是个静态类可以接调用方法 需要的是_key.pem文件的绝对路径配上文件名
PrivateKey privateKey =null;
if (StringUtils.isNotEmpty(privateKeyStr)){
privateKey = PemUtil.loadPrivateKey(privateKeyStr);
}else {
privateKey = wechatPayConfigs.getPrivateKey(wechatPayConfigs.getKeyPemPath());
}
sign.initSign(privateKey);
sign.update(message);
return Base64.getEncoder().encodeToString(sign.sign());
}
private Map<String, Object> paySignMsg(String prepayId,String appId,String privateKeyStr) throws IOException, NoSuchAlgorithmException, InvalidKeyException, SignatureException {
long timeMillis = System.currentTimeMillis();
String timeStamp = timeMillis/1000+"";
String nonceStr = timeMillis+"";
String packageStr = "prepay_id="+prepayId;
// 公共参数
Map<String, Object> resMap = new HashMap<>();
resMap.put("nonceStr",nonceStr);
resMap.put("timeStamp",timeStamp);
resMap.put("appId",appId);
resMap.put("package", packageStr);
// 使用字段appIdtimeStampnonceStrpackage进行签名
//从下往上依次生成
String message = buildMessage(appId, timeStamp, nonceStr, packageStr);
//签名
String paySign = sign(message.getBytes("utf-8"), privateKeyStr);
resMap.put("paySign", paySign);
resMap.put("signType", "RSA");
return resMap;
}
/**
* 生成新的订单号
*/
@GetMapping("/generateOrderNo")
@TenantIgnore
public String generateOrderNo() {
// 格式化当前时间取前11位 yyMMddHHmmss
String timeStr = new java.text.SimpleDateFormat("yyMMddHHmm")
.format(new java.util.Date());
// 补上1位秒数只取秒的十位
String seconds = new java.text.SimpleDateFormat("ss").format(new java.util.Date());
timeStr += seconds.charAt(0);
// 生成一位随机数
int randomDigit = (int) (Math.random() * 10);
// 拼接前缀+时间+随机数
return "jx" + timeStr + randomDigit;
}
}