From 15d3215d746a74b252f6fb0ac77d0002b449a531 Mon Sep 17 00:00:00 2001 From: Lx <935448346@qq.com> Date: Thu, 17 Apr 2025 20:45:38 +0800 Subject: [PATCH] 0417-4 --- .../app/NewSmallProgramJxOrderController.java | 242 ++++++++++++++++++ 1 file changed, 242 insertions(+) create mode 100644 dl-module-jx/src/main/java/cn/iocoder/yudao/module/jx/controller/app/NewSmallProgramJxOrderController.java diff --git a/dl-module-jx/src/main/java/cn/iocoder/yudao/module/jx/controller/app/NewSmallProgramJxOrderController.java b/dl-module-jx/src/main/java/cn/iocoder/yudao/module/jx/controller/app/NewSmallProgramJxOrderController.java new file mode 100644 index 00000000..ffe35877 --- /dev/null +++ b/dl-module-jx/src/main/java/cn/iocoder/yudao/module/jx/controller/app/NewSmallProgramJxOrderController.java @@ -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 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 resMap = new HashMap<>(); + resMap.put("orderNo",orderNo); + resMap.put("orderId",orderId); + + return resMap; + } + + @GetMapping("/prepayment") + @TenantIgnore + public Map 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 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 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 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 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 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 resMap = JSONObject.parseObject(resStr, new TypeReference>(){}); + Map 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 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 resMap = new HashMap<>(); + resMap.put("nonceStr",nonceStr); + resMap.put("timeStamp",timeStamp); + resMap.put("appId",appId); + resMap.put("package", packageStr); + // 使用字段appId、timeStamp、nonceStr、package进行签名 + //从下往上依次生成 + 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; + } + +}