赞
踩
前提:对小程序开发有一定的基础;小程序已发布使用,已开通微信支付,关联商户号。
微信小程序平台:小程序平台
微信开发者文档:开发者文档
微信小程序支付API 地址:微信支付文档地址
微信支付平台:微信支付平台地址
开通微信支付和商户号,关联商户号【需公司信息、银行账户等,按提示逐步完成即可】:
登录微信支付商户平台- 账户中心 - 账户设置 -API安全-申请证书、设置秘钥【按提示逐步完成即可,秘钥必须32位】,使用超级管理员账号进行设置;下载API证书apiclient_cert.p12的文件
Java后端使用的是jeecgboot框架
1)pom.xml 引入依赖
<!--微信小程序-->
<dependency>
<groupId>com.github.binarywang</groupId>
<artifactId>weixin-java-miniapp</artifactId>
<version>4.2.0</version>
</dependency>
<!--微信小程序 支付-->
<dependency>
<groupId>com.github.binarywang</groupId>
<artifactId>weixin-java-pay</artifactId>
<version>4.2.0</version>
</dependency>
2)application.yml配置
#小程序
wechat:
appid:
secret:
mchId: #微信支付商户号
mchKey: #微信支付商户密钥
keyPath: classpath:apiclient_cert.p12 # p12证书的位置,可以指定绝对路径,也可以指定类路径(以classpath:开头)
tradeType: JSAPI #JSAPI--公众号支付 NATIVE--原生扫码支付 APP--app支付
notifyUrl: https://www.XXXX.com/wx/wxOrder/notify: #微信支付异步回掉地址,通知url必须为直接可访问的url,不能携带参数.
keyPath对应的apiclient_cert.p12文件就是在微信商户平台下载的API证书文件
3)微信小程序配置文件
(1)微信小程序配置文件:
@AllArgsConstructor
@Configuration
@ConditionalOnClass({WxMaService.class, WxPayService.class})
@EnableConfigurationProperties(WxProperties.class)
public class WxConfig {
private final WxProperties wxProperties;
/**
* 小程序配置
* @return
*/
@Bean
@ConditionalOnMissingBean
public WxMaConfig wxMaConfig() {
WxMaDefaultConfigImpl config = new WxMaDefaultConfigImpl();
config.setAppid(this.wxProperties.getAppId());
config.setSecret(this.wxProperties.getSecret());
return config;
}
@Bean
public WxMaService wxMaService(WxMaConfig maConfig) {
WxMaService service = new WxMaServiceImpl();
service.setWxMaConfig(maConfig);
return service;
}
/**
* 支付配置
*
* @return
*/
@Bean
@ConditionalOnMissingBean
public WxPayService wxService() {
WxPayConfig payConfig = new WxPayConfig();
payConfig.setAppId(StringUtils.trimToNull(this.wxProperties.getAppId()));
payConfig.setMchId(StringUtils.trimToNull(this.wxProperties.getMchId()));
payConfig.setMchKey(StringUtils.trimToNull(this.wxProperties.getMchKey()));
payConfig.setKeyPath(StringUtils.trimToNull(this.wxProperties.getKeyPath()));
payConfig.setTradeType(StringUtils.trimToNull(this.wxProperties.getTradeType()));
payConfig.setNotifyUrl(StringUtils.trimToNull(this.wxProperties.getNotifyUrl()));
// 可以指定是否使用沙箱环境
payConfig.setUseSandboxEnv(false);
WxPayService wxPayService = new WxPayServiceImpl();
wxPayService.setConfig(payConfig);
return wxPayService;
}
}
(2)微信小程序属性
@Data
@Component
@ConfigurationProperties(prefix = "wechat")
public class WxProperties {
private String appId;
private String secret;
//微信支付商户号
private String mchId;
//微信支付商户密钥
private String mchKey;
// p12证书的位置,可以指定绝对路径,也可以指定类路径(以classpath;开头)
private String keyPath;
private String tradeType;
private String notifyUrl;
}
参数、结果接收按照自己的代码实际情况设置:
// 登录动作
doLogin: function () {
let that = this;
wx.login({
success: function (loginRes) {
if (loginRes.code) {
wx.getUserInfo({
withCredentials: true, // 非必填, 默认为true
success: function (infoRes) {
//获取openid
wx.request({
url: loginUrl,
data: {
code: loginRes.code, // 临时登录凭证
rawData: infoRes.rawData, // 用户非敏感信息
signature: infoRes.signature, // 签名
encryptedData: infoRes.encryptedData, // 用户敏感信息
ivStr: infoRes.iv // 解密算法的向量
},
success: function (res) {
res = res.data;
if (res.code == 1) {
that.globalData.userInfo = JSON.parse(infoRes.rawData);
wx.setStorageSync('openid', res.data.openId);
wx.setStorageSync('loginFlag', res.data.sessionKey);
} else {
that.showInfo(res.info);
}
},
fail: function (error) {
//调用接口失败
}
});
},
fail: function (error) {
// 获取 userInfo 失败,去检查是否未开启权限
}
});
} else {
// 获取 code 失败
}
},
fail: function (error) {
// 调用 wx.login 接口失败
}
});
},
访问后端的url: loginUrl对应的登录获取openid方法:
controller层:
/**
* 执行微信端登录
*
* @param code : 微信登录code
* @param encryptedData : 包括敏感数据在内的完整用户信息的加密数据
* @param ivStr : 加密算法的初始向量
* @return : org.dpkj.bean.Result
*/
@RequestMapping("login")
public Result login(String code, String encryptedData, String ivStr) {
Result result = new Result();
try {
WxUserBean result1 = userService.doLogin(code, encryptedData, ivStr);
result.setCode(ResultState.OK);
result.setInfo("oponId获取成功");
result.setData(result1);
} catch (Exception ex) {
ex.printStackTrace();
logger.info(ex.getMessage());
result.setInfo("接口异常,请联系管理员!");
result.setCode(ResultState.NO);
}
return result;
}
serviceImpl层:
@Autowired
private WxMaService wxMaService;
@Override
public WxUserBean doLogin(String code, String encryptedData, String ivStr) throws Exception {
WxMaJscode2SessionResult sessionInfo = wxMaService.getUserService().getSessionInfo(code);
WxMaUserInfo userInfo = wxMaService.getUserService().getUserInfo(sessionInfo.getSessionKey(), encryptedData, ivStr);
//数据库操作
bean.setSessionKey(sessionInfo.getSessionKey());
return bean;
}
微信支付API接口:支付API接口
参数、结果接收按照自己的代码实际情况设置:
startTestPay: function (e) {
let data = {
pickPhone: wx.getStorageSync("phoneNumber"),
openId: wx.getStorageSync("openid"),
testid: id,
title: title,
}
if (data.pickTest && data.pickPhone && data.openId) {
//正则判断手机号
if (/^[1][3,4,5,7,8,9][0-9]{9}$/.test(data.pickPhone)) {
data.amount = price * 100; //把价格换成分
if (app.globalData.userInfo) {
//插入订单
if(price > 0){
wx.request({
url: _createOrder,
data: data,
method: 'post',
success: function (res) {
if (res.data.success) {
let resData = res.data.result;
//吊起微信支付
wx.requestPayment({
nonceStr: resData.nonceStr,
package: resData.packageValue,
paySign: resData.paySign,
timeStamp: resData.timeStamp,
signType: resData.signType,
success() {
console.log("支付成功");
wx.navigateTo({
url: url
})
},
fail() {
//微信支付出现问题,请稍后再试
}
})
} else {
}
},
fail: function (res) {
//检查用户出现问题,请稍后再试
},
});
}else{
//价格为0,直接进入目标页面
wx.navigateTo({
url: url
})
}
} else {
wx.showToast({
title: '微信环境异常,请重新进入小程序后尝试',
icon: 'none'
})
}
} else {
wx.showToast({
title: '请填写正确的手机号码',
icon: 'none'
})
}
} else {
wx.showToast({
title: '请完善用户信息',
icon: 'none'
})
}
},
controller层
/**
* @param data 所有请求参数
* @Description: 统一下单接口
* @Return: org.jeecg.common.api.vo.Result
*/
@RequestMapping("createOrder")
public Result createOrder(@RequestBody Map<String, Object> data) {
try {
return Result.ok(wxOrderService.createOrder(data));
} catch (Exception ex) {
ex.printStackTrace();
return Result.error(ex.getMessage());
}
}
serviceImpl层
@Autowired
private WxPayService wxPayService;
@Override
@Transactional(rollbackFor = Exception.class)
public Map<String, Object> createOrder(Map<String, Object> map) throws Exception {
String type = "paytest";//类型
String eventId = map.get("testid").toString();//测评id
String remark = map.get("title").toString();//测评标题
String customerId = map.get("openId") == null ? "" : map.get("openId").toString();//测评人id
String openId = map.get("openId").toString(); //用户微信标识
String description = map.get("title").toString();//商品描述
String amount = map.get("amount").toString();//付款金额
//保存微信订单
PayOrder wxOrder = new PayOrder();
wxOrder.setOpenId(openId);
wxOrder.setDescription(description);
wxOrder.setRemark(remark);
wxOrder.setEventId(eventId);
wxOrder.setEventModule("paytest");
wxOrder.setPayerTotal(Double.parseDouble(amount) / 100);
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
StringBuffer sb = new StringBuffer();
sb.append(dateTimeFormatter.format(LocalDateTime.now()));
sb.append(new Random().nextInt(9999));
wxOrder.setOutTradeNo(sb.toString()); //时间戳+四位随机数
wxOrder.setCreateTime(new Date());
wxOrder.setTradeState(PayStatusConst.APPLY);
payOrderService.save(wxOrder);
//向微信服务器提交申请
return this.createWxOrderToWxService(openId, wxOrder.getOutTradeNo(), Integer.valueOf(amount), wxOrder.getDescription(), type);
}
/**
* @param openId 微信用户openId
* @param outTradeNo 我们的系统订单编号
* @param amount 付款金额
* @param description 商品描述
* @param type 付款类型 详见PayTypeEnumConst
* @Description: 向微信服务器发起预付款订单
* @Return: java.util.Map<java.lang.String, java.lang.Object>
*/
public Map<String, Object> createWxOrderToWxService(String openId, String outTradeNo, Integer amount, String description, String type) throws Exception {
final WxPayUnifiedOrderRequest wxPayUnifiedOrderRequest = WxPayUnifiedOrderRequest.newBuilder()
//调起支付的人的 openId
.openid(openId)
//订单编号
.outTradeNo(outTradeNo)
//订单金额
.totalFee(amount)
//商品描述
.body(description)
//获取本地IP
.spbillCreateIp(InetAddress.getLoopbackAddress().getHostAddress())
.attach(type)
//回调的 URL 地址 已经在WxConfig文件中进行设置
.build();
WxPayMpOrderResult result = this.wxPayService.createOrder(wxPayUnifiedOrderRequest);
Map<String, Object> returnMap = new HashMap<>();
returnMap.put("appId", result.getAppId());
returnMap.put("nonceStr", result.getNonceStr());
returnMap.put("packageValue", result.getPackageValue());
returnMap.put("paySign", result.getPaySign());
returnMap.put("signType", result.getSignType());
returnMap.put("timeStamp", result.getTimeStamp());
returnMap.put("orderId", outTradeNo);
return returnMap;
}
调用方法时的打印数据参考:
我这样写是因为在yml文件中设置了notifyUrl,然后在WxConfig文件中的wxService方法中进行支付配置了,如果不用配置也可以直接在使用wxPayService.createOrder()方法中对WxPayUnifiedOrderRequest参数设置.notifyUrl(回调地址),多种方式,实现即可。
异步回调方法为:
controller层:
@ApiOperation(value = "支付回调通知处理")
@RequestMapping("/notify")
public String parseOrderNotifyResult(@RequestBody String xmlData) throws WxPayException {
try {
this.wxOrderService.parseOrderNotifyResult(xmlData);
return WxPayNotifyResponse.success("成功");
} catch (Exception ex) {
ex.printStackTrace();
return WxPayNotifyResponse.failResp("失败");
}
}
serviceImpl层:
@Override
public void parseOrderNotifyResult(String xmlData) throws Exception {
final WxPayOrderNotifyResult notifyResult = this.wxPayService.parseOrderNotifyResult(xmlData);
if (null != notifyResult && StringUtils.isNotBlank(notifyResult.getTransactionId())) {
//更新用户订单状态
PayOrder wxOrder = payOrderService.getOne(new LambdaQueryWrapper<PayOrder>().eq(PayOrder::getOutTradeNo, notifyResult.getOutTradeNo()));
wxOrder.setBankType(notifyResult.getBankType());
wxOrder.setTradeState(PayStatusConst.SUCCESS);
wxOrder.setSuccessTime(new Date());
wxOrder.setTransactionId(notifyResult.getTransactionId());
payOrderService.updateById(wxOrder);
System.out.println("==============>atach" + notifyResult.getAttach());
if (StringUtils.isNotEmpty(notifyResult.getAttach())) {
}
}
}
注意:
除了这个方法,还有其他方式可用,实现即可,若是记录中有错误或遗漏的地方,欢迎评论指出。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。