微信小程序支付
1.文档
文档内详细代码移步:https://github.com/ys-1998/WxPay/tree/main
微信官方文档:https://developers.weixin.qq.com/doc/
微信支付文档:https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pages/index.shtml
小程序接入前准备:https://pay.weixin.qq.com/wiki/doc/apiv3/open/pay/chapter2_8_0.shtml
小程序接口文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_5_1.shtml
SDK使用文档:https://github.com/wechatpay-apiv3/wechatpay-java【wechatpay-java(推荐)】
SDK例子快速查看:https://github.com/wechatpay-apiv3/wechatpay-java/blob/main/service/src/example/java/com/wechat/pay/java/service/payments/jsapi/JsapiServiceExample.java 【下单 关单 订单查询 】
2.流程
文档说明:https://pay.weixin.qq.com/wiki/doc/apiv3/open/pay/chapter2_8_1.shtml
1.申请小程序 获取小程序的[appid,secret]
2.申请商户号 获取[1. mchid(商户号) 2. apiV3key(apiv3密钥) 3.merchantSerialNumber(证书序列号) 4.申请证书]
3.绑定小程序和商户号
3.开发
Maven依赖
<dependency>
<groupId>com.github.wechatpay-apiv3</groupId>
<artifactId>wechatpay-java</artifactId>
<version>0.2.7</version>
</dependency>
配置类
1.配置类填入我们需要的参数方便后续使用
yourServiceName:
wx:
appid: wx33ca5310e9xxx 小程序appid
secret: 10c61a693ced428b6e583xxxxxx 小程序密钥
token-grant-type: client_credential 小程序接口调用凭证请求参数固定值
token-url: https://api.weixin.qq.com/cgi-bin/token 小程序接口调用凭证请求地址
pay:
mchid: xxxx 商户号
apiV3key: xxxx apiV3密钥
merchantSerialNumber: 商户证书序列号
privateKeyPath: xxxx 存放证书密钥apiclient_key.pem的路径:文档结尾有推荐写法
notifyUrl: xxxx 支付回调接口
工具类
注:详细内容请见上传的文件
WxUtil:获取(接口调用凭证token)用于获取用户的信息,获取用户手机号,获取openid用于支付
获取接口调用凭证token:https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/mp-access-token/getAccessToken.html
@Data
@Component
@ConfigurationProperties(prefix = "cateen.wx")
@Slf4j
public class WxUtil {
private String appid;
private String secret;
private String tokenGrantType;
private String tokenUrl;
private String token;
private final RestTemplate restTemplate;
/**
* 注意需要定时任务刷新token
*wx获取接口调用凭证 返回数据示例
* {
* "access_token":"ACCESS_TOKEN",
* "expires_in":7200
* }
* @return
*/
public String getToken() {
//xxxx
}
/**
* wx获取手机号返回数据示例
* {
* "errcode":0,
* "errmsg":"ok",
* "phone_info": {
* "phoneNumber":"xxxxxx",
* "purePhoneNumber": "xxxxxx",
* "countryCode": 86,
* "watermark": {
* "timestamp": 1637744274,
* "appid": "xxxx"
* }
* }
* }
*/
public String getUserPhoneNumber(String code) {
//xxx
}
/**
* wx获取用户openid
* {
* "errcode": 0,
* "errmsg": "ok",
* "openpid": "GACo74wkDIkDzEhkwRwgjGt1pqlk",
* }
* @param code
* @return
*/
public String wxLoginOpenid(String code) {
//xxxx
}
}
SpringUtil:用于获取spring容器中的bean
@Component
public class SpringUtil implements ApplicationContextAware {
private static ApplicationContext applicationContext = null;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
SpringUtil.applicationContext = applicationContext;
}
public static <T> T getBean(Class<T> cla) {
return applicationContext.getBean(cla);
}
public static <T> T getBean(String name, Class<T> cal) {
return applicationContext.getBean(name, cal);
}
public static Object getBean(String name) {
return applicationContext.getBean(name);
}
public static String getProperty(String key) {
return applicationContext.getBean(Environment.class).getProperty(key);
}
public static <T> T getProperty(String key, Class<T> targetType) {
return applicationContext.getBean(Environment.class).getProperty(key, targetType);
}
}
定时任务
用于刷新接口调用凭据token:注意,token有效期为7200s
说明文档:https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/mp-access-token/getAccessToken.html
@Component
public class Jobs {
private final WxUtil wxUtil;
public Jobs(WxUtil wxUtil) {
this.wxUtil = wxUtil;
}
@Scheduled(fixedRate = 60 * 60 * 1000)
public void refreshToken() {
wxUtil.getToken();
}
}
Service
import com.wechat.pay.java.service.payments.jsapi.model.PrepayWithRequestPaymentResponse;
import com.wechat.pay.java.service.payments.model.Transaction;
import work.yspan.jadeplaces.yspan.work.models.response.BaseResult;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.math.BigDecimal;
public interface WeChatPayService {
//支付
PrepayWithRequestPaymentResponse pay(BigDecimal bigDecimal,String orderNumber,String description,String notifyUrl,String attach,String code);
//回调
Transaction callback(HttpServletRequest request, HttpServletResponse response) throws IOException;
//微信订单号查询订单
Transaction findOrderDetails(String wxOrderNo);
//商户号查询订单
Transaction findOrderDetailsByOrderNumber(String orderNumber);
//关单
BaseResult<?> closeOrder(String canteenOrderNo);
}
ServiceImpl
详情请见上传的文件
import com.alibaba.fastjson2.JSON;
import com.wechat.pay.java.core.Config;
import com.wechat.pay.java.core.exception.ServiceException;
import com.wechat.pay.java.core.notification.NotificationConfig;
import com.wechat.pay.java.core.notification.NotificationParser;
import com.wechat.pay.java.core.notification.RequestParam;
import com.wechat.pay.java.service.payments.jsapi.JsapiServiceExtension;
import com.wechat.pay.java.service.payments.jsapi.model.*;
import com.wechat.pay.java.service.payments.model.Transaction;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import work.yspan.jadeplaces.yspan.work.mapper.CateenOrderMapper;//自定义的订单类用于查询订单,删除订单
import work.yspan.jadeplaces.yspan.work.models.response.BaseResult;//自定义的返回类
import work.yspan.jadeplaces.yspan.work.service.WeChatPayService;
import work.yspan.jadeplaces.yspan.work.util.components.SpringUtil;
import work.yspan.jadeplaces.yspan.work.util.components.WxUtil;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.math.BigDecimal;
@Slf4j
@Service
public class WeChatPayServiceImpl implements WeChatPayService {
@Resource
private WxUtil wxUtil;
/**
* 商户号
*/
@Value("${cateen.wx.pay.mchid}")
public String merchantId;
/**
* 小程序 appid
*/
@Value("${cateen.wx.appid}")
public String appid;
@Resource
private CateenOrderMapper cateenOrderMapper;
@Override
public PrepayWithRequestPaymentResponse pay(BigDecimal bigDecimal, String orderNumber,String description,String notifyUrl,String attach,String code) {
}
@Override
public Transaction callback(HttpServletRequest request, HttpServletResponse response) throws IOException {
//xxxx
}
@Override
public Transaction findOrderDetails(String wxOrderNo) {
//xxxxx
}
public Transaction findOrderDetailsByOrderNumber(String orderNumber) {
//xxxx
}
@Override
public BaseResult<?> closeOrder(String canteenOrderNo) {
//xxxx
}
}
4.打包发布
推荐:证书密钥放在与src同级目录下新建的目录key
地址填写:./key/apiclient_key.pem
上传服务器:记得也将证书密钥文件apiclient_key.pem上传至与jar包相同的位置
findOrderDetailsByOrderNumber(String orderNumber) {
//xxxx
}
@Override
public BaseResult<?> closeOrder(String canteenOrderNo) {
//xxxx
}
}
4.打包发布
推荐:证书密钥放在与src同级目录下新建的目录key
地址填写:./key/apiclient_key.pem
上传服务器:记得也将证书密钥文件apiclient_key.pem上传至与jar包相同的位置