您的位置:首页 > 科技 > IT业 > 北京装修公司电话大全_html5网页设计作业代码_百度一下你就知道官网网页_东莞网站建设推广品众

北京装修公司电话大全_html5网页设计作业代码_百度一下你就知道官网网页_东莞网站建设推广品众

2024/12/23 2:46:29 来源:https://blog.csdn.net/qq_34319145/article/details/144096544  浏览:    关键词:北京装修公司电话大全_html5网页设计作业代码_百度一下你就知道官网网页_东莞网站建设推广品众
北京装修公司电话大全_html5网页设计作业代码_百度一下你就知道官网网页_东莞网站建设推广品众

        之前,我独自一人开发了一个名为“心情追忆”的小程序,旨在帮助用户记录日常的心情变化及重要时刻。我从项目的构思、设计、前端(小程序)开发、后端搭建到最终部署。经过一个月的努力,通过群聊分享等方式,用户量也有了将近200人。虽然取得了初步的成绩,但我希望小程序能够持续发展。

基于上一篇

​​​​​​​心情追忆 - 打造完美支付体验:从零开始的支付功能实现https://blog.csdn.net/qq_34319145/article/details/144003105

是基于产品思维需要开发支付功能, 上篇只写了用户支付, 但实际支付需要有5个基本接口

1.用户支付

public static PrepayWithRequestPaymentResponse prepay(Integer total, String productTitle, String outTradeNo, String userOpenId) {// 使用单例模式获取配置Config config = getConfigInstance();// 构建serviceJsapiServiceExtension service = new JsapiServiceExtension.Builder().config(config).build();// request.setXxx(val)设置所需参数,具体参数可见Request定义PrepayRequest request = new PrepayRequest();Amount amount = new Amount();// 金额(单位分)amount.setTotal(total);request.setAmount(amount);request.setAppid(appId);request.setMchid(merchantId);// 支付项目名称request.setDescription(productTitle);// 回调地址request.setNotifyUrl(prePayNotifyUrl);// 交易编号request.setOutTradeNo(outTradeNo);Payer payer = new Payer();// 用户openidpayer.setOpenid(userOpenId);request.setPayer(payer);// 调用下单方法,这个是要给前端唤醒支付组件PrepayWithRequestPaymentResponse prepayWithRequestPaymentResponse = service.prepayWithRequestPayment(request);return prepayWithRequestPaymentResponse;}

2.支付回调

public void payNotify(@RequestHeader("Wechatpay-Signature") String wechatSignature,@RequestHeader("Wechatpay-Serial") String wechatPaySerial,@RequestHeader("Wechatpay-Nonce") String wechatpayNonce,@RequestHeader("Wechatpay-Timestamp") String wechatTimestamp,@RequestHeader("Wechatpay-Signature-Type") String signatureType,@RequestBody String requestBody) {// 打印上面的所有参数, 方便调试log.info("wechatSignature: {}, wechatPaySerial: {}, wechatpayNonce: {}, wechatTimestamp: {}, signatureType: {}, requestBody: {}",wechatSignature, wechatPaySerial, wechatpayNonce, wechatTimestamp, signatureType, requestBody);// 构建RequestParam, 这是下面的回调通知解析器需要用到的参数com.wechat.pay.java.core.notification.RequestParam requestParam = new com.wechat.pay.java.core.notification.RequestParam.Builder().serialNumber(wechatPaySerial).nonce(wechatpayNonce).signature(wechatSignature).timestamp(wechatTimestamp).body(requestBody).build();// 初始化 回调通知解析器, 传参和支付的配置一样NotificationParser parser = new NotificationParser(WxPayment.getConfigInstance());// sdk自动 验签、解密并转换成 Transaction(交易信息)Transaction transaction = parser.parse(requestParam, Transaction.class);// 更新支付记录表WechatPaymentRecords wechatPaymentRecord = wechatPaymentRecordsService.findByOutTradeNo(transaction.getOutTradeNo());wechatPaymentRecord.setStatus(transaction.getTradeState().name());wechatPaymentRecord.setTransactionId(transaction.getTransactionId());wechatPaymentRecordsService.updateById(wechatPaymentRecord);// 上面都成功后, 处理业务: 增加用户可使用次数UserFunctionRecord userFunctionRecord = userFunctionRecordService.getUserFunctionRecord(wechatPaymentRecord.getUserId());userFunctionRecord.setTotalUsageLimit(userFunctionRecord.getTotalUsageLimit() + 1);userFunctionRecordService.updateById(userFunctionRecord);// 自己好玩, 发个钉钉消息dingTalkMsg.sendMsgToDingTalk(JSONUtil.toJsonPrettyStr(transaction));}

3.支付列表查询

        这个就是查自己记录的表了

    public BaseResult<List<WechatPaymentRecords>> listPayments(@CurrentUser UserPrincipal userPrincipal) {// 基于springSecurity管理的CurrentUser拿到用户ID, 去查询支付记录List<WechatPaymentRecords> byUserId = wechatPaymentRecordsService.findByUserId(userPrincipal.getUserId());return BaseResult.success(byUserId);}

4.用户退款

和支付差不多, 不过比支付简单的是不用返回唤起支付组件的参数, 随便返回业务需要的参数就好

/*** 退款* @param outTradeNo 内部支付单号* @param outRefundNo 内部退款单号, 自己生成* @param reason 退款原因, 不必填, 业务必须填, 用于用户画像* @param total 订单金额* @param refund 退款金额* @return*/public static Refund createRefund(String outTradeNo,String outRefundNo, String reason, Long total, Long refund) {// 使用单例模式获取配置Config config = getConfigInstance();// 构建serviceRefundService service = new RefundService.Builder().config(config).build();CreateRequest request = new CreateRequest();request.setOutTradeNo(outTradeNo);request.setOutRefundNo(outRefundNo);request.setReason(reason);request.setNotifyUrl(refundNotifyUrl);AmountReq amount = new AmountReq();amount.setTotal(total);amount.setRefund(refund);amount.setCurrency("CNY");request.setAmount(amount);Refund refundResponse = service.create(request);return refundResponse;}

5.退款回调

和支付回调差不多, 只不过解析出来的是RefundNotification退款信息, 支付回调可以和退款回调写相同的一个, 也可以写不同. 我觉得写不同代码看的会少很多分支会简洁一点. 

public void refundNotify(@RequestHeader("Wechatpay-Signature") String wechatSignature,@RequestHeader("Wechatpay-Serial") String wechatPaySerial,@RequestHeader("Wechatpay-Nonce") String wechatpayNonce,@RequestHeader("Wechatpay-Timestamp") String wechatTimestamp,@RequestHeader("Wechatpay-Signature-Type") String signatureType,@RequestBody String requestBody) {// 打印上面的所有参数log.info("wechatSignature: {}, wechatPaySerial: {}, wechatpayNonce: {}, wechatTimestamp: {}, signatureType: {}, requestBody: {}",wechatSignature, wechatPaySerial, wechatpayNonce, wechatTimestamp, signatureType, requestBody);// 构建RequestParamcom.wechat.pay.java.core.notification.RequestParam requestParam = new com.wechat.pay.java.core.notification.RequestParam.Builder().serialNumber(wechatPaySerial).nonce(wechatpayNonce).signature(wechatSignature).timestamp(wechatTimestamp).body(requestBody).build();// 初始化 NotificationParserNotificationParser parser = new NotificationParser(WxPayment.getConfigInstance());// sdk自动 验签、解密并转换成 RefundNotification(退款信息)RefundNotification transaction = parser.parse(requestParam, RefundNotification.class);WechatPaymentRecords wechatPaymentRecord = wechatPaymentRecordsService.findByOutTradeNo(transaction.getOutTradeNo());wechatPaymentRecord.setRefundStatus(transaction.getRefundStatus().name());wechatPaymentRecord.setRefundAmount(transaction.getAmount().getRefund());wechatPaymentRecord.setRefundTime(LocalDateTime.now());wechatPaymentRecord.setOutRefundNo(transaction.getOutRefundNo());wechatPaymentRecord.setRefundId(transaction.getRefundId());wechatPaymentRecordsService.updateById(wechatPaymentRecord);dingTalkMsg.sendMsgToDingTalk(JSONUtil.toJsonPrettyStr(transaction));}

然后就是通用的配置

标准的单例双重验证, 不知道的可以去了解一下单例双重验证

// 提供一个静态方法来获取 Config 实例public static RSAAutoCertificateConfig getConfigInstance() {if (configInstance == null) {synchronized (lock) {if (configInstance == null) {configInstance = new RSAAutoCertificateConfig.Builder().merchantId(merchantId).privateKeyFromPath(privateKeyPath).merchantSerialNumber(merchantSerialNumber).apiV3Key(apiV3key).build();}}}return configInstance;}

因为支付是购买产品, 所以需要一个产品表product, (有的大公司还有sku的概念, 但我这里不需要, 一切从简)

所以支付表可以这么设计:

关键是, 微信交易(transaction_id)的唯一Id和自己交易编号(out_trade_no)的唯一Id, 和状态, 退款也有一套. 是为了在微信支付平台查询实际交易信息用.

其中要关联业务数据userId和product_id.

CREATE TABLE `wechat_payment_records` (`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键,自增ID',`transaction_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '微信支付交易号,用于唯一标识一次支付交易',`out_trade_no` varchar(64) COLLATE utf8mb4_general_ci NOT NULL COMMENT '商户订单号,由商户生成,用于唯一标识一次支付请求',`user_id` bigint NOT NULL COMMENT '用户ID,关联用户表',`product_id` bigint NOT NULL COMMENT '产品Id',`amount` bigint NOT NULL COMMENT '支付金额,单位为元',`currency` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '货币种类,如CNY',`payment_time` datetime DEFAULT NULL COMMENT '支付时间,记录实际支付成功的时间',`status` varchar(20) COLLATE utf8mb4_general_ci NOT NULL COMMENT '支付状态,如SUCCESS、FAIL、REFUND等',`payment_method` varchar(50) COLLATE utf8mb4_general_ci NOT NULL COMMENT '支付方式,如JSAPI、APP、H5等',`description` text COLLATE utf8mb4_general_ci COMMENT '订单描述,用于记录支付的具体内容',`notify_url` varchar(255) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '回调通知URL,微信支付回调的地址',`created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '记录创建时间,即发起支付请求的时间',`updated_at` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '记录更新时间,每次更新记录时自动更新',`ip_address` varchar(45) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '用户发起支付请求时的IP地址',`device_info` varchar(255) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '设备信息,如设备型号、操作系统等',`refund_status` varchar(20) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '退款状态,如NOT_REFUND、PARTIAL_REFUND、FULL_REFUND等',`refund_amount` bigint DEFAULT NULL COMMENT '退款金额,单位为元',`refund_time` datetime DEFAULT NULL COMMENT '退款时间,记录实际退款成功的时间',`out_refund_no` varchar(64) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '退款编号',`refund_id` varchar(64) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '微信支付退款单号',`refund_reason` varchar(255) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '退款原因',PRIMARY KEY (`id`),UNIQUE KEY `out_trade_no` (`out_trade_no`),UNIQUE KEY `transaction_id` (`transaction_id`),KEY `idx_user_id` (`user_id`) COMMENT '用户ID索引,用于快速查询某个用户的支付记录',KEY `idx_status` (`status`) COMMENT '支付状态索引,用于快速查询特定状态的支付记录',KEY `idx_created_at` (`created_at`) COMMENT '创建时间索引,用于按时间范围查询支付记录'
) ENGINE=InnoDB AUTO_INCREMENT=20 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='微信支付记录表';

总结

        和之前一篇一样: 

Java项目部署的三个阶段https://blog.csdn.net/qq_34319145/article/details/143963071目前我只有一个产品就是支付获得分析次数, 所以支付相关的表可以不太多. 如果后续业务变多变复杂, 就再继续去设计, 去完善. 不能一开始就上最完美的方案, 一定是要从最小MVP产品去一步一步迭代才行.

PS:

        上线审核时, 发现IOS打开小程序不允许出现虚拟产品的交易, 所以要关掉iOS的支付功能

// 检查是否为iOS系统const systemInfo = Taro.getSystemInfoSync();if (systemInfo.platform === 'ios') {Taro.showToast({title: 'iOS用户暂不支持支付功能',icon: 'none',duration: 2000});return;}

 

 

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com