10分钟完成微信JSAPI支付对接过程-JAVA后端接口
- 引入架包
<dependency><groupId>com.github.javen205</groupId><artifactId>IJPay-WxPay</artifactId><version>${ijapy.version}</version></dependency>


配置类
package com.joolun.web.config;import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;/*** <p>微信配置 Bean</p>** @author yuhaiguang*/
@Component
@PropertySource("classpath:/wxpay.properties")
@ConfigurationProperties(prefix = "wxpay")
public class WxPayBean {private String appId;private String appSecret;private String mchId;private String partnerKey;private String certPath;private String domain;public String getAppId() {return appId;}public void setAppId(String appId) {this.appId = appId;}public String getAppSecret() {return appSecret;}public void setAppSecret(String appSecret) {this.appSecret = appSecret;}public String getMchId() {return mchId;}public void setMchId(String mchId) {this.mchId = mchId;}public String getPartnerKey() {return partnerKey;}public void setPartnerKey(String partnerKey) {this.partnerKey = partnerKey;}public String getCertPath() {return certPath;}public void setCertPath(String certPath) {this.certPath = certPath;}public String getDomain() {return domain;}public void setDomain(String domain) {this.domain = domain;}@Overridepublic String toString() {return "WxPayBean [appId=" + appId + ", appSecret=" + appSecret + ", mchId=" + mchId + ", partnerKey="+ partnerKey + ", certPath=" + certPath + ", domain=" + domain + "]";}
}
controller
AbstractWxPayApiController
package com.joolun.web.controller.weixin;import com.ijpay.wxpay.WxPayApiConfig;public abstract class AbstractWxPayApiController {public abstract WxPayApiConfig getApiConfig();
}
接口:
package com.joolun.web.controller.weixin;import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.extension.api.R;
import com.ijpay.core.enums.SignType;
import com.ijpay.core.enums.TradeType;
import com.ijpay.core.kit.IpKit;
import com.ijpay.core.kit.WxPayKit;
import com.ijpay.wxpay.WxPayApi;
import com.ijpay.wxpay.WxPayApiConfig;
import com.ijpay.wxpay.WxPayApiConfigKit;
import com.ijpay.wxpay.model.UnifiedOrderModel;
import com.joolun.common.core.domain.AjaxResult;
import com.joolun.web.config.WxPayBean;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;import javax.servlet.http.HttpServletRequest;
import java.util.Map;@RestController
@RequestMapping("/wxPay")
public class WxPayController extends AbstractWxPayApiController{private final Logger log = LoggerFactory.getLogger(this.getClass());@Autowiredprivate WxPayBean wxPayBean;private String notifyUrl;private String refundNotifyUrl;@Overridepublic WxPayApiConfig getApiConfig() {WxPayApiConfig apiConfig;try {apiConfig = WxPayApiConfigKit.getApiConfig(wxPayBean.getAppId());} catch (Exception e) {apiConfig = WxPayApiConfig.builder().appId(wxPayBean.getAppId()).mchId(wxPayBean.getMchId()).partnerKey(wxPayBean.getPartnerKey()).certPath(wxPayBean.getCertPath()).domain(wxPayBean.getDomain()).build();}notifyUrl = apiConfig.getDomain().concat("/wxPay/payNotify");refundNotifyUrl = apiConfig.getDomain().concat("/wxPay/refundNotify");return apiConfig;}@RequestMapping(value = "/webPay", method = {RequestMethod.POST, RequestMethod.GET})@ResponseBodypublic R webPay(HttpServletRequest request) {// openId,采用 网页授权获取 access_token API:SnsAccessTokenApi获取String openId = (String) request.getSession().getAttribute("openId");if (openId == null) {openId = "oQe4A6_acTpnPFTuAaxKq0Ss-yMo";}if (StrUtil.isEmpty(openId)) {return R.failed("openId is null");}String ip = IpKit.getRealIp(request);if (StrUtil.isEmpty(ip)) {ip = "127.0.0.1";}WxPayApiConfig wxPayApiConfig = WxPayApiConfigKit.getWxPayApiConfig();Map<String, String> params = UnifiedOrderModel.builder().appid(wxPayApiConfig.getAppId()).mch_id(wxPayApiConfig.getMchId()).nonce_str(WxPayKit.generateStr()).body("微信网页内测试").attach("产品说名").out_trade_no(WxPayKit.generateStr()).total_fee("1").spbill_create_ip(ip).notify_url(notifyUrl).trade_type(TradeType.JSAPI.getTradeType()).openid(openId).build().createSign(wxPayApiConfig.getPartnerKey(), SignType.HMACSHA256);String xmlResult = WxPayApi.pushOrder(false, params);log.info(xmlResult);Map<String, String> resultMap = WxPayKit.xmlToMap(xmlResult);String returnCode = resultMap.get("return_code");String returnMsg = resultMap.get("return_msg");if (!WxPayKit.codeIsOk(returnCode)) {return R.failed(returnMsg);}String resultCode = resultMap.get("result_code");if (!WxPayKit.codeIsOk(resultCode)) {return R.failed(returnMsg);}// 以下字段在 return_code 和 result_code 都为 SUCCESS 的时候有返回String prepayId = resultMap.get("prepay_id");Map<String, String> packageParams = WxPayKit.prepayIdCreateSign(prepayId, wxPayApiConfig.getAppId(),wxPayApiConfig.getPartnerKey(), SignType.HMACSHA256);String jsonStr = JSON.toJSONString(packageParams);return R.failed(jsonStr);}}
配置初始化拦截器
package com.joolun.web.config;import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.support.config.FastJsonConfig;
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;import com.joolun.web.interceptor.WxPayInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;@Configuration
public class IJPayConfigurer extends WebMvcConfigurationSupport {@Overridepublic void addInterceptors(InterceptorRegistry registry) {//registry.addInterceptor(new AliPayInterceptor()).addPathPatterns("/aliPay/**");registry.addInterceptor(new WxPayInterceptor()).addPathPatterns("/wxPay/**");super.addInterceptors(registry);}@Overridepublic void addResourceHandlers(ResourceHandlerRegistry registry) {// 将所有/static/** 访问都映射到classpath:/static/ 目录下registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");}@Overridepublic void configureMessageConverters(List<HttpMessageConverter<?>> converters) {super.configureMessageConverters(converters);FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter();FastJsonConfig config = new FastJsonConfig();config.setSerializerFeatures(SerializerFeature.WriteMapNullValue, // 保留map空的字段SerializerFeature.WriteNullStringAsEmpty, // 将String类型的null转成""SerializerFeature.WriteNullNumberAsZero, // 将Number类型的null转成0SerializerFeature.WriteNullListAsEmpty, // 将List类型的null转成[]SerializerFeature.WriteNullBooleanAsFalse, // 将Boolean类型的null转成falseSerializerFeature.DisableCircularReferenceDetect);// 避免循环引用converter.setFastJsonConfig(config);converter.setDefaultCharset(Charset.forName("UTF-8"));List<MediaType> mediaTypeList = new ArrayList<>();// 解决中文乱码问题,相当于在Controller上的@RequestMapping中加了个属性produces = "application/json"mediaTypeList.add(MediaType.APPLICATION_JSON);converter.setSupportedMediaTypes(mediaTypeList);converters.add(converter);converters.add(responseBodyConverter());}@Beanpublic HttpMessageConverter<String> responseBodyConverter() {return new StringHttpMessageConverter(Charset.forName("UTF-8"));}
}
package com.joolun.web.interceptor;import com.ijpay.wxpay.WxPayApiConfigKit;
import com.joolun.web.controller.weixin.AbstractWxPayApiController;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;/*** <p>微信支付拦截器</p>** @author yuhaiguang*/
public class WxPayInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object handler) {if (HandlerMethod.class.equals(handler.getClass())) {HandlerMethod method = (HandlerMethod) handler;Object controller = method.getBean();if (!(controller instanceof AbstractWxPayApiController)) {throw new RuntimeException("控制器需要继承 AbstractWxPayApiController");}WxPayApiConfigKit.setThreadLocalWxPayApiConfig(((AbstractWxPayApiController) controller).getApiConfig());return true;}return false;}
}

源码:
https://gitee.com/champion-myth/wx-shop/tree/dev-wx-pay/
相关文章:
10分钟完成微信JSAPI支付对接过程-JAVA后端接口
引入架包 <dependency><groupId>com.github.javen205</groupId><artifactId>IJPay-WxPay</artifactId><version>${ijapy.version}</version></dependency>配置类 package com.joolun.web.config;import org.springframework.b…...
如何寻找一个领域的顶级会议,并且判断这个会议的影响力?
如何寻找一个领域的顶级会议,并且判断这个会议的影响力? 会议之眼 快讯 很多同学都在问:学术会议不是期刊,即使被SCI检索,也无法查询影响因子。那么如何知道各个领域的顶级会议,并对各个会议有初步了解呢…...
真的假不了,假的真不了
大家好,我是瑶琴呀,拥有一头黑长直秀发的女程序员。 最近,17岁的中专生姜萍参加阿里巴巴 2024 年的全球数学竞赛,取得了 12 名的好成绩,一时间在网上沸腾不止。 从最开始的“数学天才”,到被质疑ÿ…...
看完这篇文章你就知道什么是未来软件开发的方向了!即生成式AI在软件开发领域的革新=CodeFlying
从最早的UGC(用户生成内容)到PGC(专业生成内容)再到AIGC(人工智能生成内容)体现了web1.0→web2.0→web3.0的发展历程。 毫无疑问UGC已经成为了当前拥有群体数量最大的内容生产方式。 同时随着人工智能技术…...
HTML5五十六个民族网站模板源码
文章目录 1.设计来源高山族1.1 登录界面演示1.2 注册界面演示1.3 首页界面演示1.4 中国民族界面演示1.5 关于高山族界面演示1.6 联系我们界面演示 2.效果和源码2.1 动态效果2.2 源代码2.3 源码目录 源码下载 作者:xcLeigh 文章地址:https://blog.csdn.ne…...
Linux_fileio实现copy文件
参考韦东山老师教程:https://www.bilibili.com/video/BV1kk4y117Tu?p12 目录 1. 通过read方式copy文件2. 通过mmap映射方式copy文件 1. 通过read方式copy文件 copy文件代码: #include <sys/types.h> #include <sys/stat.h> #include <…...
【JavaEE精炼宝库】多线程进阶(2)synchronized原理、JUC类——深度理解多线程编程
一、synchronized 原理 1.1 基本特点: 结合上面的锁策略,我们就可以总结出,synchronized 具有以下特性(只考虑 JDK 1.8): 开始时是乐观锁,如果锁冲突频繁,就转换为悲观锁。 开始是轻量级锁实现ÿ…...
【Linux进程通信】使用匿名管道制作一个简单的进程池
进程池是什么呢?我们可以类比内存池的概念来理解进程池。 内存池 内存池是在真正使用内存之前,先申请分配一定数量的、大小相等(一般情况下)的内存块留作备用。当有新的内存需求时,就从内存池中分出一部分内存块,若内存块不够再继…...
Django 多对多关系
多对多关系作用 Django 中,多对多关系模型的作用主要是为了表示两个模型之间的多对多关系。具体来说,多对多关系允许一个模型的实例与另一个模型的多个实例相关联,反之亦然。这在很多实际应用场景中非常有用,比如: 博…...
构建 Audio Unit 应用程序
构建 Audio Unit 应用程序 构建 Audio Unit 应用程序从选择设计模式开始I/O Pass ThroughI/O Without a Render Callback FunctionI/O with a Render Callback FunctionOutput-Only with a Render Callback Function其他设计模式 构建应用程序配置 audio session指定 audio uni…...
JavaScript 实用技巧
1. 使用 const 和 let 替代 var 在 ES6 之前,我们通常使用 var 声明变量。但如今,推荐使用 const 和 let,因为它们具有块级作用域,可以避免很多潜在的问题。 const PI 3.14; // 常量,无法重新赋值 let age 25; // …...
Python协作运动机器人刚体力学解耦模型
🎯要点 🎯腿式或固定式机器人模型 | 🎯网格、点云和体素网格碰撞检测 | 🎯正反向运动学和动力学 | 🎯机器人刚体力学计算 | 🎯编辑参考系姿势和路径 | 🎯软件接口实体机器人模拟 | Ἲ…...
可重入锁思想,设计MQ迁移方案
如果你的MQ消息要从Kafka切换到RocketMQ且不停机,怎么做?在让这个MQ消息调用第三方发奖接口,但无幂等字段又怎么处理?今天小傅哥就给大家分享一个关于MQ消息在这样的场景中的处理手段。 这是一种比较特例的场景,需要保…...
Redis安装与使用
目录 1、介绍 1、redis的特点: 2、缓存 2、安装Redis 1、安装单机版redis 2、redis-cli命令参数 3、清空数据库的两种方式和作用域: 4、redis的增删查改命令 5、redis的查看所有分类命令 6、redis过期时间与控制键的行为 7、redis的相关工具 1、介绍 r…...
base64字符串空格问题
客户端使用的Content-Type为application/x-www-form-urlencoded时,字符串中出现了空格,base64解码时出错了,因为原来的字符有号, Spring Boot 对于Content-Type为application/x-www-form-urlencoded的HTTP请求,默认情…...
【BES2500x系列 -- RTX5操作系统】深入探索CMSIS-RTOS RTX -- 同步与通信篇 -- 消息队列和邮箱处理 --(四)
💌 所属专栏:【BES2500x系列】 😀 作 者:我是夜阑的狗🐶 🚀 个人简介:一个正在努力学技术的CV工程师,专注基础和实战分享 ,欢迎咨询! Ὁ…...
电信NR零流量小区处理
【摘要】随着目前网络建设逐步完善,5G用户的不断发展,针对零流量小区的分析及处理存在着必要性,零流量小区的出现既是用户分布及行为的直观体现,也是发展用户的一个指引,同时也能发现设备的一些故障。一个站点的能够带…...
ArcTs布局入门03——层叠布局(Stack)
如果你也对鸿蒙开发感兴趣,加入“Harmony自习室”吧! 扫描下面的二维码关注公众号。 1、概述 叠布局(StackLayout)用于在屏幕上预留一块区域来显示组件中的元素,提供元素可以重叠的布局。层叠布局通过Stack容器组件实…...
C语言之线程的学习
线程属于某一个进程 共同点:都能并发 线程共享变量,进程不共享。 多线程任务中,其中某一个线程调用了exit了,其他线程会跟着一起退出 如果是特定的线程就调用pthread_exit 失败返回的是错误号 下面也是...
HT8691 内置升压模块的D类音频功率放大器芯片IC
一般描述 HT8691是一款内置升压模块的D类音频功率放大器。内置的升压模块可通过外置电阻调节升压值,即使是锂电池供电,在升压至6.5V时,10%THDN,4Ω负载条件下能连续输出5.5W功率;升压至7V,3Ω负载条件下则能连续输出7.0W功率。其支持外部设置…...
【JavaEE】-- HTTP
1. HTTP是什么? HTTP(全称为"超文本传输协议")是一种应用非常广泛的应用层协议,HTTP是基于TCP协议的一种应用层协议。 应用层协议:是计算机网络协议栈中最高层的协议,它定义了运行在不同主机上…...
聊聊 Pulsar:Producer 源码解析
一、前言 Apache Pulsar 是一个企业级的开源分布式消息传递平台,以其高性能、可扩展性和存储计算分离架构在消息队列和流处理领域独树一帜。在 Pulsar 的核心架构中,Producer(生产者) 是连接客户端应用与消息队列的第一步。生产者…...
苍穹外卖--缓存菜品
1.问题说明 用户端小程序展示的菜品数据都是通过查询数据库获得,如果用户端访问量比较大,数据库访问压力随之增大 2.实现思路 通过Redis来缓存菜品数据,减少数据库查询操作。 缓存逻辑分析: ①每个分类下的菜品保持一份缓存数据…...
(转)什么是DockerCompose?它有什么作用?
一、什么是DockerCompose? DockerCompose可以基于Compose文件帮我们快速的部署分布式应用,而无需手动一个个创建和运行容器。 Compose文件是一个文本文件,通过指令定义集群中的每个容器如何运行。 DockerCompose就是把DockerFile转换成指令去运行。 …...
Android第十三次面试总结(四大 组件基础)
Activity生命周期和四大启动模式详解 一、Activity 生命周期 Activity 的生命周期由一系列回调方法组成,用于管理其创建、可见性、焦点和销毁过程。以下是核心方法及其调用时机: onCreate() 调用时机:Activity 首次创建时调用。…...
JAVA后端开发——多租户
数据隔离是多租户系统中的核心概念,确保一个租户(在这个系统中可能是一个公司或一个独立的客户)的数据对其他租户是不可见的。在 RuoYi 框架(您当前项目所使用的基础框架)中,这通常是通过在数据表中增加一个…...
【生成模型】视频生成论文调研
工作清单 上游应用方向:控制、速度、时长、高动态、多主体驱动 类型工作基础模型WAN / WAN-VACE / HunyuanVideo控制条件轨迹控制ATI~镜头控制ReCamMaster~多主体驱动Phantom~音频驱动Let Them Talk: Audio-Driven Multi-Person Conversational Video Generation速…...
Go语言多线程问题
打印零与奇偶数(leetcode 1116) 方法1:使用互斥锁和条件变量 package mainimport ("fmt""sync" )type ZeroEvenOdd struct {n intzeroMutex sync.MutexevenMutex sync.MutexoddMutex sync.Mutexcurrent int…...
LabVIEW双光子成像系统技术
双光子成像技术的核心特性 双光子成像通过双低能量光子协同激发机制,展现出显著的技术优势: 深层组织穿透能力:适用于活体组织深度成像 高分辨率观测性能:满足微观结构的精细研究需求 低光毒性特点:减少对样本的损伤…...
微服务通信安全:深入解析mTLS的原理与实践
🔥「炎码工坊」技术弹药已装填! 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 一、引言:微服务时代的通信安全挑战 随着云原生和微服务架构的普及,服务间的通信安全成为系统设计的核心议题。传统的单体架构中&…...
