江南大学做网站做汽车价格的网站
web/
2025/9/26 2:21:36/
文章来源:
江南大学做网站,做汽车价格的网站,高端访问,最近最火的关键词支付宝简介
使用流程
支付宝开放平台 (alipay.com)
1、登录支付宝开放平台-创建应用 得到app_id 2、绑定应用#xff1a;在产品绑定中#xff0c;绑定支付宝的相关功能3、配置应用#xff1a; 配置各种加密方式 4、提交审核#xff1a;5、把支付宝整个功能整合项目
沙箱…支付宝简介
使用流程
支付宝开放平台 (alipay.com)
1、登录支付宝开放平台-创建应用 得到app_id 2、绑定应用在产品绑定中绑定支付宝的相关功能3、配置应用 配置各种加密方式 4、提交审核5、把支付宝整个功能整合项目
沙箱
支付宝提前为我们创建好一个账号用这个账号可以体验支付宝的所有功能应用开发期间用沙箱账号上线以后替换成线上账号即可。
产品介绍 - 支付宝文档中心 (alipay.com)电脑网站支付的所有文档
沙箱
下载密钥生成工具密钥工具下载 - 支付宝文档中心 (alipay.com)
按照官方教程去生成自己的私钥。
支付宝整体应用流程
配置properties方便配置支付宝appid私钥密钥等
Data
ConfigurationProperties(prefix app.pay.alipay)
public class AlipayProperties {// 应用ID,您的APPID收款账号既是您的APPID对应支付宝账号private String app_id ;// 商户私钥您的PKCS8格式RSA2私钥private String merchant_private_key;// 支付宝公钥,查看地址https://openhome.alipay.com/platform/keyManage.htm 对应APPID下的支付宝公钥。private String alipay_public_key;// 服务器异步通知页面路径 需http://格式的完整路径不能加?id123这类自定义参数必须外网可以正常访问private String notify_url ;// 页面跳转同步通知页面路径 需http://格式的完整路径不能加?id123这类自定义参数必须外网可以正常访问private String return_url;// 签名方式private String sign_type;// 字符编码格式private String charset;// 支付宝网关private String gatewayUrl;
}
在config类中放一个AlipayClient。避免每次调用都需要专门new一个。
EnableConfigurationProperties(AlipayProperties.class)
Configuration
public class AlipayConfig {BeanAlipayClient alipayClient(AlipayProperties alipayProperties){return new DefaultAlipayClient( alipayProperties.getGatewayUrl(),alipayProperties.getApp_id(),alipayProperties.getMerchant_private_key(),json,alipayProperties.getCharset(),alipayProperties.getAlipay_public_key(),alipayProperties.getSign_type());}}
在payService实现生成支付页的方法 Overridepublic String generatePayPage(Long orderId, Long userId) throws AlipayApiException {//创建一个AlipayClient//创建一个支付请求AlipayTradePagePayRequest alipayRequest new AlipayTradePagePayRequest();alipayRequest.setReturnUrl(alipayProperties.getReturn_url());//同步回调 支付成功后浏览器跳转到的地址alipayRequest.setNotifyUrl(alipayProperties.getNotify_url());//通知回调 支付成功后通知的地址//准备待支付的订单数据//远程调用订单服务获取其基本信息 基于此数据生成订单页OrderInfo orderInfo orderFeignClient.getOrderInfoById(orderId).getData();//商户订单号商户网站订单系统中唯一订单号必填String outTradeNo orderInfo.getOutTradeNo();//付款金额必填BigDecimal totalAmount orderInfo.getTotalAmount();//订单名称必填String orderName 尚品汇-订单-outTradeNo;//商品描述可空String tradeBody orderInfo.getTradeBody();MapString,Object bizContent new HashMap();bizContent.put(out_trade_no,outTradeNo);bizContent.put(total_amount,totalAmount);bizContent.put(subject,orderName);bizContent.put(body,tradeBody);bizContent.put(product_code,FAST_INSTANT_TRADE_PAY);alipayRequest.setBizContent(JSON.toJSONString(bizContent));//请求String page alipayClient.pageExecute(alipayRequest).getBody();return page;}需要一个方法去接受支付宝支付成功的回调。此处将其放入mq消息队列中。等待消费。修改订单状态 /*** 支付成功后支付宝会给这里发送支付结果通知 异步* param params* return*/PostMapping(/notify/success)public String paySuccessNotify(RequestParam MapString,String params) throws AlipayApiException {log.info(收到支付宝支付消息通知{}, JSON.toJSONString(params));//验证签名boolean signVerified AlipaySignature.rsaCheckV1(params,alipayProperties.getAlipay_public_key(),alipayProperties.getCharset(),alipayProperties.getSign_type());//调用SDK验证签名if(signVerified){log.info(验签通过准备修改订单状态);String trade_status params.get(trade_status);if(TRADE_SUCCESS.equals(trade_status)){//修改订单状态 通过消息传递机制mqService.send(params, MqConst.ORDER_EVENT_EXCHANGE,MqConst.ORDER_PAYED_RK);}}//什么时候给支付宝返回successreturn success;}修改订单状态 如果用户在临关单前的极限时间支付后为了避免用户订单被强制改为关单。我们需要设置较高的优先级。 Overridepublic void payedOrder(String outTradeNo, Long userId) {//关单消息和支付消息同时抵达的话以支付为准将其改为已支付//订单是未支付或是已关闭都可以改为已支付ProcessStatus payed ProcessStatus.PAID;//修改订单状态为已支付boolean update orderInfoService.lambdaUpdate().set(OrderInfo::getOrderStatus, payed.getOrderStatus().name()).set(OrderInfo::getProcessStatus, payed.name()).eq(OrderInfo::getUserId, userId).eq(OrderInfo::getOutTradeNo, outTradeNo).in(OrderInfo::getOrderStatus, OrderStatus.UNPAID.name(), OrderStatus.CLOSED.name()).in(OrderInfo::getProcessStatus, ProcessStatus.UNPAID.name(), ProcessStatus.CLOSED.name()).update();log.info(修改订单{} 状态为已支付成功{},outTradeNo,update);}修改状态后将payment_info也存入数据 /*** 监听所有成功单队列*/RabbitListener(queues MqConst.ORDER_PAYED_QUEUE)public void listen(Message message, Channel channel) throws IOException {long tag message.getMessageProperties().getDeliveryTag();String json new String(message.getBody());try {MapString, String content JSON.parseObject(json, new TypeReferenceMapString, String() {});log.info(修改订单状态为已支付);//订单的唯一对外交易号String out_trade_no content.get(out_trade_no);//知道用户idString[] split out_trade_no.split(-);Long userId Long.parseLong(split[split.length - 1]);//根据唯一对外交易号和用户id修改orderBizService.payedOrder(out_trade_no,userId);PaymentInfo info preparePaymentInfo(json, content, out_trade_no, userId);paymentInfoService.save(info);channel.basicAck(tag,false);} catch (NumberFormatException | IOException e) {mqService.retry(channel,tag,json,5);}}private PaymentInfo preparePaymentInfo(String json, MapString, String content, String out_trade_no, Long userId) {//保存此次支付的回调信息到payment_info里PaymentInfo info new PaymentInfo();//查询orderInfoOrderInfo orderInfo orderInfoService.lambdaQuery().eq(OrderInfo::getOutTradeNo, out_trade_no).eq(OrderInfo::getUserId, userId).one();info.setOutTradeNo(out_trade_no);info.setUserId(userId);info.setOrderId(orderInfo.getId());info.setPaymentType(orderInfo.getPaymentWay());//支付宝给的流水号String trade_no content.get(trade_no);info.setTradeNo(trade_no);String total_amount content.get(total_amount);info.setTotalAmount(new BigDecimal(total_amount));info.setSubject(content.get(subject));info.setPaymentStatus(content.get(trade_status));info.setCreateTime(new Date());info.setCallbackTime(new Date());info.setCallbackContent(json);return info;}微信支付
微信支付V2
准备环境
C扫B需求要求可以手机网页交互微信JSAPI/NATIVE支付符合需求。
总结步骤
微信支付商户平台申请支付商户填写企业资质认证后可以在用户信息中获取 商户号以企业身份注册微信公众号 https://mp.weixin.qq.com/登录公众号点击左侧菜单 “微信支付” 开通微信支付需要提供营业执照、身份证等信息。缴纳认证费用等待1-3工作日审核。审核通过后在支付设置中获取 APPID审核通过后需要在 微信支付商户平台 中绑定APPID绑定成功后需要申请 支付相关API秘钥
快速入门
参考文档https://pay.weixin.qq.com/wiki/doc/api/index.html
支付产品: https://pay.weixin.qq.com/static/product/product_index.shtml
退款https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter9_4
微信支付目前有两个大版本是公司使用的分别是V2 和 V3 版本旧项目-V2 新项目-V3
V3新版本https://pay.weixin.qq.com/wiki/doc/apiv3/wechatpay/wechatpay-1.shtml
官方SDK与DEMO代码https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter11_1
开发流程 注意demo用的是微信V2版本实际项目用的是微信V3版本
NATIVE代码实现
1添加依赖
dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactId
/dependency
dependencygroupIdcom.github.tedzhdz/groupIdartifactIdwxpay-sdk/artifactIdversion3.0.10/version
/dependency2编写配置类
package com.itheima.pay.config;
import com.github.wxpay.sdk.IWXPayDomain;
import com.github.wxpay.sdk.WXPayConfig;
import com.github.wxpay.sdk.WXPayConstants;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
public class WXPayConfigCustom extends WXPayConfig {/*** 开发者ID(AppID)* return*/Overrideprotected String getAppID() {return wx0ca99a203b1e9943;}/*** 商户号* return*/Overrideprotected String getMchID() {return 1561414331;}/*** appkey API密钥* return*/Overrideprotected String getKey() {return CZBK51236435wxpay435434323FFDuis;}// 退款必须强制使用API证书Overrideprotected InputStream getCertStream() {try {String path ClassLoader.getSystemResource().getPath();return new FileInputStream(new File(pathapiclient_cert.p12));} catch (FileNotFoundException e) {e.printStackTrace();}return null;}Overrideprotected IWXPayDomain getWXPayDomain() {return new IWXPayDomain() {Overridepublic void report(String s, long l, Exception e) {}Overridepublic DomainInfo getDomain(WXPayConfig wxPayConfig) {return new DomainInfo(WXPayConstants.DOMAIN_API, true);}};}
}注意
退款操作需要API证书将资料中的证书apiclient_cert.p12放到resources路径下
3编写下单测试方法
package com.itheima.pay.controller;
import com.github.binarywang.wxpay.bean.notify.WxPayNotifyResponse;
import com.github.wxpay.sdk.WXPay;
import com.github.wxpay.sdk.WXPayUtil;
import com.itheima.pay.config.WXPayConfigCustom;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
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.util.HashMap;
import java.util.Map;
/*** Description:* Version: V1.0*/
Slf4j
RestController
RequestMapping(wxpay)
public class WxpayController {/*** 支付回调通知* param request* param response* return*/RequestMapping(notify)public String payNotify(HttpServletRequest request, HttpServletResponse response) {try {String xmlResult IOUtils.toString(request.getInputStream(), request.getCharacterEncoding());MapString, String map WXPayUtil.xmlToMap(xmlResult);// 加入自己处理订单的业务逻辑需要判断订单是否已经支付过否则可能会重复调用String orderId map.get(out_trade_no);String tradeNo map.get(transaction_id);String totalFee map.get(total_fee);String returnCode map.get(return_code);String resultCode map.get(result_code);return WxPayNotifyResponse.success(处理成功!);} catch (Exception e) {log.error(微信回调结果异常,异常原因{}, e.getMessage());return WxPayNotifyResponse.fail(e.getMessage());}}/*** 下单操作* param code* return* throws Exception*/GetMapping(unifiedOrder/{code})public String unifiedOrder(PathVariable String code) throws Exception {WXPayConfigCustom config new WXPayConfigCustom();WXPay wxpay new WXPay(config);MapString, String data new HashMapString, String();data.put(body, 餐掌柜-餐饮消费);
// data.put(out_trade_no, 2138091910595900001012);data.put(out_trade_no, code);data.put(device_info, );data.put(fee_type, CNY);data.put(total_fee, 1);data.put(spbill_create_ip, 123.12.12.123);data.put(notify_url, http://itheima.ngrok2.xiaomiqiu.cn/wxpay/notify);data.put(trade_type, NATIVE); // NATIVE 指定为扫码支付 JSAPI 网站支付
// data.put(openid, 12);try {MapString, String resp wxpay.unifiedOrder(data);System.out.println(支付结果resp);return resp.get(code_url);} catch (Exception e) {e.printStackTrace();}return OK;}/*** 退款* param code 订单号* param refund_no 退款号* return* throws Exception*/GetMapping(refunds/{code}/{refund_no})public MapString, String refunds(PathVariable String code, PathVariable String refund_no) throws Exception {WXPayConfigCustom config new WXPayConfigCustom();WXPay wxpay new WXPay(config);MapString, String data new HashMapString, String();data.put(out_trade_no, code);data.put(out_refund_no, refund_no);data.put(notify_url, http://484cd438.cpolar.io/wxpay/notify);data.put(refund_desc, 已经售罄);data.put(refund_fee, 1);data.put(total_fee, 1);data.put(refund_fee_type, CNY);System.out.println(请求参数 data);MapString, String map wxpay.refund(data);return map;}
}微信支付V3
V3版本。文档地址https://pay.weixin.qq.com/wiki/doc/apiv3_partner/index.shtml
微信官方并没有提供类似支付宝的EasySDK只提供了基于HttpClient封装的SDK包在项目中我们对于此SDK做了二次封装。微信接口都是基于RESTful进行提供的。 /*** 微信支付远程调用对象*/
Data
Builder
NoArgsConstructor
AllArgsConstructor
public class WechatPayHttpClient {private String mchId; //商户号private String appId; //应用号private String privateKey; //私钥字符串private String mchSerialNo; //商户证书序列号private String apiV3Key; //V3密钥private String domain; //请求域名private String notifyUrl; //请求地址public static WechatPayHttpClient get(Long enterpriseId) {// 查询配置PayChannelService payChannelService SpringUtil.getBean(PayChannelService.class);PayChannelEntity payChannel payChannelService.findByEnterpriseId(enterpriseId, TradingConstant.TRADING_CHANNEL_WECHAT_PAY);if (ObjectUtil.isEmpty(payChannel)) {throw new SLException(TradingEnum.CONFIG_EMPTY);}//通过渠道对象转化成微信支付的client对象JSONObject otherConfig JSONUtil.parseObj(payChannel.getOtherConfig());return WechatPayHttpClient.builder().appId(payChannel.getAppId()).domain(payChannel.getDomain()).privateKey(payChannel.getMerchantPrivateKey()).mchId(otherConfig.getStr(mchId)).mchSerialNo(otherConfig.getStr(mchSerialNo)).apiV3Key(otherConfig.getStr(apiV3Key)).notifyUrl(payChannel.getNotifyUrl()).build();}/**** 构建CloseableHttpClient远程请求对象* return org.apache.http.impl.client.CloseableHttpClient*/public CloseableHttpClient createHttpClient() throws Exception {// 加载商户私钥privateKey私钥字符串PrivateKey merchantPrivateKey PemUtil.loadPrivateKey(new ByteArrayInputStream(privateKey.getBytes(StandardCharsets.UTF_8)));// 加载平台证书mchId商户号,mchSerialNo商户证书序列号,apiV3KeyV3密钥PrivateKeySigner privateKeySigner new PrivateKeySigner(mchSerialNo, merchantPrivateKey);WechatPay2Credentials wechatPay2Credentials new WechatPay2Credentials(mchId, privateKeySigner);// 向证书管理器增加需要自动更新平台证书的商户信息CertificatesManager certificatesManager CertificatesManager.getInstance();certificatesManager.putMerchant(mchId, wechatPay2Credentials, apiV3Key.getBytes(StandardCharsets.UTF_8));// 初始化httpClientreturn com.wechat.pay.contrib.apache.httpclient.WechatPayHttpClientBuilder.create().withMerchant(mchId, mchSerialNo, merchantPrivateKey).withValidator(new WechatPay2Validator(certificatesManager.getVerifier(mchId))).build();}/**** 支持post请求的远程调用** param apiPath api地址* param params 携带请求参数* return 返回字符串*/public WeChatResponse doPost(String apiPath, MapString, Object params) throws Exception {String url StrUtil.format(https://{}{}, this.domain, apiPath);HttpPost httpPost new HttpPost(url);httpPost.addHeader(Accept, application/json);httpPost.addHeader(Content-type, application/json; charsetutf-8);String body JSONUtil.toJsonStr(params);httpPost.setEntity(new StringEntity(body, CharsetUtil.UTF_8));CloseableHttpResponse response this.createHttpClient().execute(httpPost);return new WeChatResponse(response);}/**** 支持get请求的远程调用* param apiPath api地址* param params 在路径中请求的参数* return 返回字符串*/public WeChatResponse doGet(String apiPath, MapString, Object params) throws Exception {URI uri UrlBuilder.create().setHost(this.domain).setScheme(https).setPath(UrlPath.of(apiPath, CharsetUtil.CHARSET_UTF_8)).setQuery(UrlQuery.of(params)).setCharset(CharsetUtil.CHARSET_UTF_8).toURI();return this.doGet(uri);}/**** 支持get请求的远程调用* param apiPath api地址* return 返回字符串*/public WeChatResponse doGet(String apiPath) throws Exception {URI uri UrlBuilder.create().setHost(this.domain).setScheme(https).setPath(UrlPath.of(apiPath, CharsetUtil.CHARSET_UTF_8)).setCharset(CharsetUtil.CHARSET_UTF_8).toURI();return this.doGet(uri);}private WeChatResponse doGet(URI uri) throws Exception {HttpGet httpGet new HttpGet(uri);httpGet.addHeader(Accept, application/json);CloseableHttpResponse response this.createHttpClient().execute(httpGet);return new WeChatResponse(response);}
}代码说明
通过get(Long enterpriseId)方法查询商户对应的配置信息最后封装到WechatPayHttpClient对象中。通过createHttpClient()方法封装了请求微信接口必要的参数最后返回CloseableHttpClient对象。封装了doGet()、doPost()方便对微信接口进行调用。 try {WeChatResponse response client.doPost(apiPath, params);if(!response.isOk()){throw new SLException(TradingEnum.NATIVE_PAY_FAIL);}tradingEntity.setPlaceOrderCode(Convert.toStr(response.getStatus())); //返回的编码tradingEntity.setPlaceOrderMsg(JSONUtil.parseObj(response.getBody()).getStr(code_url)); //二维码需要展现的信息tradingEntity.setPlaceOrderJson(JSONUtil.toJsonStr(response));tradingEntity.setTradingState(TradingStateEnum.FKZ);} catch (Exception e) {throw new SLException(TradingEnum.NATIVE_PAY_FAIL);}PS接收回调地址的话需要用到内网穿透工具如果没开内网穿透则无法接收到。推荐用cpolar或者natapp
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/81944.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!