java整合微信支付功能详细示例
微信服务商户号和普通商户号的区别
1. 适用范围不同:
微信服务商户号适用于代理商、第三方服务商等,也就是说,只有中间商才可以成功创建微信服务商户号。而普通商户号适用于普通商家。
2. 支付方式不同:
微信服务商户号支持多个子商户从属于一个服务商,实现统一线上收款和资金结算,同时支持分账等多种支付方式,方便代理商为子商户提供中间担保结算、派单抽成、资金归集、单一入口、风控应用等服务。
普通商户号只能被单独占有,支持一种支付方式,即从客户直接收款,对于多个门店的商家,需要分别开通每个门店的商户号,管理起来比较繁琐。
3. 申请及审核方式不同:
申请微信服务商户号需要提供相关商业资质证明,如公司注册证明、公司经营资质证明等,审核通过后方可获得认证。
普通商户号的申请相对较为简单,只需要提供公司营业执照、结算银行账号等资料,审核通过后即可开通商户号。
总之,微信服务商户号适合代理商、第三方服务商等机构场景,可以实现代理收款、分账结算等多种支付服务,方便代理商为子商户提供完整的商业解决方案;而普通商户号适合单个商家接受在线收款,管理更为简单。
使用
这里我们就先配置服务商号
微信商户号中配置信息
- 需要提供企业相关的资料进行等待审核大概在一周左右
- 开通商户号
- 创建子商户号
- 生成API3私钥和密钥
- 授权支付回调目录
- 在微信开发者平台中小程序关联服务商户号
代码
Jar依赖
<dependency> <groupId>com.fasterxml.jackson.dataformat</groupId> <artifactId>jackson-dataformat-csv</artifactId> <version>2.11.2</version> </dependency> <dependency> <groupId>com.github.wechatpay-apiv3</groupId> <artifactId>wechatpay-apache-httpclient</artifactId> <version>0.2.2</version> </dependency>
配置微信API
#微信配置 wx-applet: url: https://api.mch.weixin.qq.com/papay/querycontract payUrl: https://api.mch.weixin.qq.com/pay/pappayapply notifyUrl: https://chillman.com.cn/applet/applyPayNotify qureyOrderUrl: https://chillman.com.cn/pay/paporderquery appId: 小程序应用ID appSecret: 小程序密钥 mchId: 子商户id #微信支付配置 wechat-pay: url: https://api.mch.weixin.qq.com appId: 小程序Id mchId: 商户号 mchSerialNo: apiV3Key: 私钥key # 商户key mchPrivateKey: 私钥 notifyUrl: 回调地址 apiClientKey: 私钥 certificatesUrl: https://api.mch.weixin.qq.com/v3/certificates
微信API工具类
package com.snow.param; import lombok.Data; /** * @Author: zhaohaoxin * @Date: 2023-06-02-16:10 */ @Data public class PlaceAnOrderParam2 { private String sp_appid; private String sp_mchid; private String sub_appid; private String sub_mchid; private String description; private String out_trade_no; private String notify_url; private AmountParam amount; private PayerParam payer; public PlaceAnOrderParam2(String sp_appid, String sp_mchid, String sub_appid, String sub_mchid, String description, String out_trade_no, String notify_url, AmountParam amount, PayerParam payer) { this.sp_appid = sp_appid; this.sp_mchid = sp_mchid; this.sub_appid = sub_appid; this.sub_mchid = sub_mchid; this.description = description; this.out_trade_no = out_trade_no; this.notify_url = notify_url; this.amount = amount; this.payer = payer; } }
package com.snow.service.imple; import com.fasterxml.jackson.databind.ObjectMapper; import com.snow.api.WXPayRequest; import com.snow.constant.PathConstant; import com.snow.dto.WXPayDto; import com.snow.param.OrderStatusParam; import com.snow.param.PlaceAnOrderParam; import com.snow.param.PlaceAnOrderParam2; import com.snow.param.SingParam; import com.snow.service.WXPayService; import com.snow.sgin.NewPaySignUtil; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.RandomStringUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @Service @Slf4j public class WXPayServiceImpl implements WXPayService { @Autowired private WXPayRequest wxPayRequest; @Autowired private NewPaySignUtil newPaySignUtil; public static final String SING_TYPE = "RSA_1_256"; public static final String PATH_JSAPI = "/v3/pay/partner/transactions/jsapi"; @Override public String WXPayUnifyOrder(PlaceAnOrderParam placeAnOrderParam) { try { String reqBody = ""; if (placeAnOrderParam != null) { ObjectMapper objectMapper = new ObjectMapper(); reqBody = objectMapper.writeValueAsString(placeAnOrderParam); } return wxPayRequest.requestOnce(PATH_JSAPI, reqBody); }catch (Exception e){ log.error("调用微信支付统一下单失败",e); return StringUtils.EMPTY; } } @Override public String WXPayUnifyOrder(PlaceAnOrderParam2 placeAnOrderParam) { try { String reqBody = ""; if (placeAnOrderParam != null) { ObjectMapper objectMapper = new ObjectMapper(); reqBody = objectMapper.writeValueAsString(placeAnOrderParam); } return wxPayRequest.requestOnce(PathConstant.PATH_JSAPI, reqBody); }catch (Exception e){ log.error("调用微信支付统一下单失败",e); return StringUtils.EMPTY; } } @Override public String getOrderStatus(OrderStatusParam orderStatusParam) { try { String reqBody = ""; String url = PathConstant.PATH_GET_ORDER + orderStatusParam.getOutTradeNo() + "?mchid="+orderStatusParam.getMchid(); return wxPayRequest.requestOnce(url,reqBody); }catch (Exception e){ log.error("调用查询订单状态接口失败",e); return StringUtils.EMPTY; } } @Override public WXPayDto getWXPaySing(SingParam singParam) { String appid = singParam.getAppid(); long timeStamp = System.currentTimeMillis() / 1000; String nonceStr = RandomStringUtils.randomAlphanumeric(32); String prepayId = "prepay_id=" + singParam.getPrepayId(); String preStr = appid+"\n" +timeStamp+"\n" +nonceStr+"\n" +prepayId+"\n"; String paySign = newPaySignUtil.getSign(SING_TYPE, preStr); WXPayDto wxPayDto = new WXPayDto(timeStamp,prepayId,nonceStr,paySign); return wxPayDto; } }
发起支付后获取微信小程序根据prepayId参数调用支付方法弹出支付会话框
微信回调
package com.snow.controller; import com.alibaba.fastjson.JSON; import com.snow.annotation.SystemLog; import com.snow.business.domain.XqSnowOrder; import com.snow.business.domain.XqSnowOrderExample; import com.snow.business.service.XqSnowOrderService; import com.snow.common.exception.RequestWechatException; import com.snow.common.utils.DateUtils; import com.snow.enumz.OrderStateEnum; import com.snow.pem.PayResponseUtils; import com.snow.pem.StaticParameter; import com.wechat.pay.contrib.apache.httpclient.util.AesUtil; import lombok.extern.slf4j.Slf4j; import net.sf.json.JSONArray; import net.sf.json.JSONObject; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Controller; import org.springframework.util.Base64Utils; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.math.BigDecimal; import java.security.GeneralSecurityException; import java.security.Signature; import java.security.cert.X509Certificate; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.HashMap; import java.util.Map; import java.util.stream.Collectors; import java.util.stream.Stream; @Controller @RestController @RequestMapping("/wxPay/callBack") @Slf4j public class WXPayCallBackController { @Value("${wechat-pay.apiV3Key}") private String apiV3Key; @Autowired private XqSnowOrderService orderService; @SystemLog(menu = "微信支付支付结果通知回调") @PostMapping("wxPayRequest") public String wxPayRequest(HttpServletRequest request, HttpServletResponse response){ log.info("==微信回调开始=="); Map<String, String> map = new HashMap<>(); try { InputStream in = request.getInputStream(); BufferedReader br = new BufferedReader(new InputStreamReader(in, "UTF-8")); StringBuffer param = new StringBuffer(); String line; while ((line = br.readLine()) != null) { param.append(line); } String callBackParam = param.toString(); JSONObject object = JSONObject.fromObject(callBackParam); log.info("微信回调参数={}" + callBackParam); //回调摘要 String summary = object.getString("summary"); //如果验证签名序列号通过 if (verifiedSign(request,callBackParam)){ JSONObject resource = object.getJSONObject("resource"); String associatedData = resource.getString("associated_data"); String nonce = resource.getString("nonce"); String ciphertext = resource.getString("ciphertext"); AesUtil aesUtil = new AesUtil(apiV3Key.getBytes()); String res = aesUtil.decryptToString(associatedData.getBytes(), nonce.getBytes(), ciphertext); JSONObject resObj = JSONObject.fromObject(res); log.info("微信通知支付成功通知参数={}",resObj); //交易状态 String tradeState = resObj.getString("trade_state"); //订单号 String outTradeNo = resObj.getString("out_trade_no"); //支付完成时间 String time_end = resObj.getString("success_time"); //微信交易订单号 String transactionId = resObj.getString("transaction_id"); //订单金额 com.alibaba.fastjson.JSONObject amount = JSON.parseObject(resObj.getString("amount")); //总金额 String total = amount.getString("total"); //用户支付金额 String payerTotal = amount.getString("payer_total"); OrderStateEnum orderStateEnum = OrderStateEnum.OK; if (tradeState.equals("SUCCESS")){ //查询订单状态 XqSnowOrderExample snowOrderExample = new XqSnowOrderExample(); snowOrderExample.createCriteria().andorderNoEqualTo(outTradeNo); XqSnowOrder snowOrder = orderService.selectFirstByExample(snowOrderExample); //订单已经处理 if(snowOrder.getPayStatus().equals(orderStateEnum.getState()) ){ log.info("扣款失败订单已经处理,订单号:"+outTradeNo+",订单状态:"+snowOrder.getPayStatus()); map.put("code", "SUCCESS"); map.put("message", "成功"); return JSON.toJSONString(map); } Date timeEnd = null; try { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX"); timeEnd = sdf.parse(time_end); } catch (ParseException e) { e.printStackTrace(); } BigDecimal cashFee = new BigDecimal(payerTotal).divide(new BigDecimal(100)).setScale(2, BigDecimal.ROUND_HALF_DOWN); XqSnowOrder snowOrderEdition = new XqSnowOrder(); //微信支付交易号 snowOrderEdition.setWxOrderNo(transactionId); //修改订单状态为已支付 snowOrderEdition.setPayStatus(orderStateEnum.getState()); snowOrderEdition.setPayTime(timeEnd); if (Integer.valueOf(total)-Integer.valueOf(payerTotal)>0){ //有优惠 //代金券或立减优惠金额 //优惠功能 if(resObj.containsKey("promotion_detail")){ JSONArray promotionDetails = JSONArray.fromObject(resObj.getString("promotion_detail")); if(promotionDetails != null){ JSONObject promotionDetail = promotionDetails.getJSONObject(0); String coupon_fee = promotionDetail.getString("amount"); if (!StringUtils.isEmpty(coupon_fee)){ BigDecimal couponFee = new BigDecimal(coupon_fee).divide(new BigDecimal(100)).setScale(2, BigDecimal.ROUND_HALF_DOWN); //tMoheOrder.setWxCouponFee(couponFee); log.info("订单号:{},有优惠-->couponFee:,{}",outTradeNo,coupon_fee); } //代金券或立减优惠ID String coupon_id_$n = promotionDetail.getString("coupon_id"); if (!StringUtils.isEmpty(coupon_id_$n)){ //tMoheOrder.setWxCouponId(coupon_id_$n); log.info("订单号:{},,代金券或立减优惠ID:{}",outTradeNo,coupon_id_$n); } } } log.info("此订单有优惠,订单号:"+outTradeNo); } //没有优惠 XqSnowOrderExample snowOrderExampleEdit = new XqSnowOrderExample(); snowOrderExampleEdit.createCriteria().andorderNoEqualTo(outTradeNo); orderService.updateByExampleSelective(snowOrderEdition,snowOrderExampleEdit); log.info("扣款订单微信支付处理成功,此订单已经支付,订单号码:"+outTradeNo); }else{ log.info("微信返回支付错误摘要:"+summary); } map.put("code", "SUCCESS"); map.put("message", "成功"); }else{ log.info("扣款回调签名验证失败"); } } catch (IOException e) { log.error("微信支付支付结果通知回调接口异常:",e); } catch (ParseException e) { log.error("微信支付支付结果通知回调接口异常:",e); } catch (RequestWechatException e) { log.error("微信支付支付结果通知回调接口异常:",e); } catch (GeneralSecurityException e) { log.error("微信支付支付结果通知回调接口异常:",e); } return JSON.toJSONString(map); } /** * 验证微信签名 * @param request * @param body * @return * @throws GeneralSecurityException * @throws IOException * @throws InstantiationException * @throws IllegalAccessException * @throws ParseException */ private boolean verifiedSign(HttpServletRequest request,String body) throws GeneralSecurityException, ParseException, RequestWechatException { //微信返回的证书序列号 String serialNo = request.getHeader("Wechatpay-Serial"); //微信返回的随机字符串 String nonceStr = request.getHeader("Wechatpay-Nonce"); //微信返回的时间戳 String timestamp = request.getHeader("Wechatpay-Timestamp"); //微信返回的签名 String wechatSign = request.getHeader("Wechatpay-Signature"); //组装签名字符串 String signStr = Stream.of(timestamp, nonceStr, body) .collect(Collectors.joining("\n", "", "\n")); //当证书容器为空 或者 响应提供的证书序列号不在容器中时 就应该刷新了 if (StaticParameter.certificateMap.isEmpty() || !StaticParameter.certificateMap.containsKey(serialNo)) { PayResponseUtils.refreshCertificate(); } //根据序列号获取平台证书 X509Certificate certificate = StaticParameter.certificateMap.get(serialNo); //获取失败 验证失败 if (certificate == null){ return false; } //SHA256withRSA签名 Signature signature = Signature.getInstance("SHA256withRSA"); signature.initVerify(certificate); signature.update(signStr.getBytes()); //返回验签结果 return signature.verify(Base64Utils.decodeFromString(wechatSign)); } }
效果
以上就是小程序支付的整个流程
总结
到此这篇关于java整合微信支付功能的文章就介绍到这了,更多相关java整合微信支付内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
相关文章
Kotlin常用函数let,with,run,apply用法与区别案例详解
这篇文章主要介绍了Kotlin常用函数let,with,run,apply用法与区别案例详解,本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下2021-09-09java源码解析之String类的compareTo(String otherString)方法
这篇文章主要给大家介绍了关于java源码解析之String类的compareTo(String otherString)方法的相关资料,文中通过示例代码介绍的非常详细,需要的朋友可以参考借鉴,下面随着小编来一起学习学习吧2018-09-09Java中使用JavaMail多发邮件及邮件的验证和附件实现
这篇文章主要介绍了Java中使用Java Mail多发邮件及邮件的验证和附件实现,包括在邮件中加入图片等功能的实现讲解,需要的朋友可以参考下2016-02-02Spring boot 整合 Redisson实现分布式锁并验证功能
这篇文章主要介绍了Spring boot 整合 Redisson实现分布式锁并验证,redisson是官方推荐的分布式锁实现方案,采用redis自身的原子命令和lua脚本来实现,需要的朋友可以参考下2022-05-05spring cloud alibaba Nacos 注册中心搭建过程详解
这篇文章主要介绍了spring cloud alibaba Nacos 注册中心搭建过程详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下2019-10-10
最新评论