瓜果蔬菜做的好的电商网站,小程序如何开发,四川建设网项目招标公告,wordpress如何评论微信支付 付款码支付 付款码支付是指用户展示微信钱包内的“付款码”给商户系统扫描后直接完成支付#xff0c;适用于线下场所面对面收银的场景#xff0c;例如商超、便利店、餐饮、医院、学校、电影院和旅游景区等具有明确经营地址的实体场所JSAPI支付 JSAPI支付是指商户通过…微信支付 付款码支付 付款码支付是指用户展示微信钱包内的“付款码”给商户系统扫描后直接完成支付适用于线下场所面对面收银的场景例如商超、便利店、餐饮、医院、学校、电影院和旅游景区等具有明确经营地址的实体场所JSAPI支付 JSAPI支付是指商户通过调用微信支付提供的JSAPI接口在支付场景中调起微信支付模块完成收款。
应用场景有
线下场所调用接口生成二维码用户扫描二维码后在微信浏览器中打开页面后完成支付
公众号场景用户在微信公众账号内进入商家公众号打开某个主页面完成支付
PC网站场景在网站中展示二维码用户扫描二维码后在微信浏览器中打开页面后完成支付
小程序支付 小程序支付是指商户通过调用微信支付小程序支付接口在微信小程序平台内实现支付功能用户打开商家助手小程序下单输入支付密码并完成支付后返回商家小程序。Native支付 Native支付是指商户系统按微信支付协议生成支付二维码用户再用微信“扫一扫”完成支付的模式。该模式适用于PC网站、实体店单品或订单、媒体广告支付等场景。APP支付 APP支付是指商户通过在移动端应用APP中集成开放SDK调起微信支付模块来完成支付。适用于在移动端APP中集成微信支付功能的场景。刷脸支付 刷脸支付是指用户在刷脸设备前通过摄像头刷脸、识别身份后进行的一种支付方式安全便捷。适用于线下实体场所的收银场景如商超、餐饮、便利店、医院、学校等。
支付流程
三个关键步骤是需要后台人员去实现的
核心依赖
dependencygroupIdcom.github.wechatpay-apiv3/groupIdartifactIdwechatpay-apache-httpclient/artifactIdversion0.4.9/version
/dependency主要是用来向微信服务器发送http请求的客户端
API证书
拿营业执照申请API证书
下单请求
根据接口文档通过httpClient发送请求
请求体
{mchid: 1900006XXX,out_trade_no: native12177525012014070332333,appid: wxdace645e0bc2cXXX,description: Image形象店-深圳腾大-QQ公仔,notify_url: https://weixin.qq.com/,amount: {total: 1,currency: CNY}
}响应体
{code_url: weixin://wxpay/bizpayurl?prp4lpSuKzz
}请求体参数可以封装成对应的对象
/**
* 订单请求体
* */
Data
Builder
public class NativePayParams {/*** 应用id* */private String appid;/*** 商户id* */private String mchid;/*** 商品描述* */private String description;/*** 订单号* */private String out_trade_no;/*** 回调通知地址* */private String notify_url;/*** 订单金额* */private Amount amount;}/**
* 金额对象
* */
Data
Builder
public class Amount {/*** 总金额* */private Integer total;/*** 货币单位* */private String currency;}public class PayService {private CloseableHttpClient httpClient;/*** 必备的校验参数需要拿营业执照向腾讯申请* *//*** 商户API私钥* */private String privateKey;private String mchId;/*** 证书序列号* */private String mchSerialNo;/*** API v3密钥* */private String apiV3Key;public static void main(String[] args) {try {PayService payService new PayService();payService.setup();payService.CreateOrder();payService.after();} catch (Exception e) {throw new RuntimeException(e);}}/*** 初始化* */public void setup() throws IOException {// 加载商户私钥privateKey私钥字符串PrivateKey merchantPrivateKey PemUtil.loadPrivateKey(new ByteArrayInputStream(privateKey.getBytes(utf-8)));// 加载平台证书mchId商户号,mchSerialNo商户证书序列号,apiV3KeyV3密钥AutoUpdateCertificatesVerifier verifier new AutoUpdateCertificatesVerifier(new WechatPay2Credentials(mchId, new PrivateKeySigner(mchSerialNo, merchantPrivateKey)),apiV3Key.getBytes(utf-8));// 初始化httpClienthttpClient WechatPayHttpClientBuilder.create().withMerchant(mchId, mchSerialNo, merchantPrivateKey).withValidator(new WechatPay2Validator(verifier)).build();}/*** 创建并发送订单* */public void CreateOrder() throws Exception{HttpPost httpPost new HttpPost(https://api.mch.weixin.qq.com/v3/pay/transactions/native);// 封装请求体String reqdata json字符串;StringEntity entity new StringEntity(reqdata,utf-8);entity.setContentType(application/json);httpPost.setEntity(entity);httpPost.setHeader(Accept, application/json);//发送http请求CloseableHttpResponse response httpClient.execute(httpPost);try {int statusCode response.getStatusLine().getStatusCode();if (statusCode 200) { //处理成功System.out.println(success,return body EntityUtils.toString(response.getEntity()));} else if (statusCode 204) { //处理成功无返回BodySystem.out.println(success);} else {System.out.println(failed,resp code statusCode ,return body EntityUtils.toString(response.getEntity()));throw new IOException(request failed);}} finally {response.close();}}/*** 关闭连接* */public void after() throws IOException {httpClient.close();}}支付结果
微信官方会异步通知商户支付结果商户也可以自行查询支付结果
异步通知
在发送下单请求时需要指定notify_url这是一个接口地址微信会访问这个接口并通过http传递支付结果 写一个接口来接收通知就行了 接口要接收的请求体
{id: EV-2018022511223320873,create_time: 2015-05-20T13:29:3508:00,resource_type: encrypt-resource,event_type: TRANSACTION.SUCCESS,summary: 支付成功,resource: {original_type: transaction,algorithm: AEAD_AES_256_GCM,ciphertext: ,associated_data: ,nonce: }
}/**
* 回调通知
* */
Data
public class NotifyDTO {/*** 通知的唯一ID* */private String id;/*** 通知创建的时间* */private String create_time;/*** 通知的类型* */private String event_type;/*** 通知的资源数据类型* */private String resource_type;/*** 回调摘要* */private String summary;/*** 通知资源数据* */private ResourceDTO resourceDTO;
}/**
* 资源
* */
Data
public class ResourceDTO {/*** 对开启结果数据进行加密的加密算法* */private String algorithm;/*** Base64编码后的开启/停用结果数据密文* */private String ciphertext;/*** 附加数据* */private String associated_data;/*** 原始回调类型为transaction* */private String original_type;/*** 加密使用的随机串* */private String nonce;
}接口返回结果
/**
* 接收失败时需要返回一个对象给微信
* */
Data
public class ErrorDTO {/*** 错误码SUCCESS为清算机构接收成功其他错误码为失败* */private String code;/*** 返回信息如非空为错误原因* */private String message;}接口设计
/*** 与微信的交互*/
RestController
RequestMapping(/pay)
public class PayController {ResourceNativePayService nativePayService;PostMapping(/notify)public ErrorDTO getNotify(RequestBody NotifyDTO notifyDTO) {nativePayService.payNotify(notifyDTO);return new ErrorDTO();}} 解密Resource
解密微信发来的Resource部分可以拿到订单对应的编号从而根据该编号完成支付流程 AES-256-GCM是一种对称密钥加密也就是说加密解密只考虑apiV3Key密钥即可
/**
* 处理支付业务
* */
Service
public class NativeServiceImpl implements NativePayService{/*** 对称密钥* */private static final String apiV3Key;/*** 订单号* */public static String tradeNo;Overridepublic ErrorDTO payNotify(NotifyDTO notifyDTO) {try {AesUtil aesUtil new AesUtil(apiV3Key.getBytes());ResourceDTO resourceDTO notifyDTO.getResourceDTO();String json aesUtil.decryptToString(resourceDTO.getAssociated_data().getBytes(),resourceDTO.getNonce().getBytes(),resourceDTO.getCiphertext());Map map JSONUtil.parseObj(json);tradeNo map.get(out_trade_no).toString();} catch (GeneralSecurityException e) {throw new RuntimeException(e);}return null;}
}主动查询订单
后台需要不断轮询向微信查询订单支付的结果直到获得成功的结果 使用定时任务即可 请求体 响应体
{appid : wxd678efh567hg6787,mchid : 1230000109,out_trade_no : 1217752501201407033233368018,transaction_id : 1217752501201407033233368018,trade_type : MICROPAY,trade_state : SUCCESS,trade_state_desc : 支付失败请重新下单支付,bank_type : CMC,attach : 自定义数据,success_time : 2018-06-08T10:34:5608:00,payer : {openid : oUpF8uMuAJO_M2pxb1Q9zNjWeS6o\t},amount : {total : 100,payer_total : 100,currency : CNY,payer_currency : CNY},scene_info : {device_id : 013467007045764},promotion_detail : [{coupon_id : 109519,name : 单品惠-6,scope : GLOBAL,type : CASH,amount : 100,stock_id : 931386,wechatpay_contribute : 0,merchant_contribute : 0,other_contribute : 0,currency : CNY,goods_detail : [{goods_id : M1006,quantity : 1,unit_price : 100,discount_amount : 1,goods_remark : 商品备注信息}]}]
}
支付宝 沙箱环境
访问支付宝接口需要的验证信息在这里获取 如果是生产环境则需要拿营业执照向官方申请密钥和证书
加密原理
非对称加密
通信双方分别创建公钥和私钥并且保证公钥所加密的信息只有配对的私钥可以解密接下来双方公开交换公钥通信时使用对方的公钥进行加密如此就能确保对方能够通过自己的私钥解密 显然这种做法并不安全第三方可以直接拦截一方发送的公钥将其调包成自己的公钥这样一来另一方使用该公钥加密的所有信息都能被第三方轻易解密
二维码信息载体
一维码只有宽度表示信息二维码长度和宽度都能储存信息 二维码生成过程
数据经过编码之后得到一个二进制串数据串将和纠错码交织在一起依据相应版本二维码的规范利用不同尺寸的方块填充得到二维码
对接支付宝
依赖
!-- https://mvnrepository.com/artifact/com.alipay.sdk/alipay-easysdk --
dependencygroupIdcom.alipay.sdk/groupIdartifactIdalipay-easysdk/artifactIdversion2.2.3/version
/dependency
配置文件
server:port: 15100
pay:alipay:protocol: httpsgatewayHost: openapi-sandbox.dl.alipaydev.comsignType: RSA2appId: #应用IdmerchantPrivateKey: #应用私钥alipayPublicKey: #支付宝公钥notifyUrl: #支付宝发送通知地址这里的notifyUrl指的是公网的url如果想要本机接收需要先进行内网穿透 内网穿透 教程参考内网穿透教程 工具cpolar 命令: cpolar authtoken 令牌 #将authtoken保存到本机 cpolar http 要暴露的端口号 #在这个端口上开一个通道连接到cpolar
RestController
RequestMapping(/alipay)
Slf4j
public class AliPayController {ResourceConfig config;ResourceAliPayConfig aliPayConfig;GetMapping(/code)public String pay() throws Exception {try {//1.添加配置项Factory.setOptions(config);//2.调用接口发送请求AlipayTradePrecreateResponse response Factory.Payment.FaceToFace().preCreate(aliPayConfig.getSubject(),123456,10);//3.解析响应结果String httpBody response.getHttpBody();JSONObject jsonObject JSONUtil.parseObj(httpBody);//3.2获取订单号String qrCode jsonObject.getJSONObject(alipay_trade_precreate_response).get(qr_code).toString();log.info(返回二维码{}, qrCode);QrCodeUtil.generate(qrCode,500,500,new File(D:/test2.jpg));return qrCode;} catch (Exception e) {log.error(发生错误{}, e.getClass().getName() e.getMessage());e.printStackTrace();return 获取二维码失败请稍后再试;}}PostMapping(/notify)public String notify(HttpServletRequest request) {String outTradeNo request.getParameter(out_trade_no);log.info(订单{}支付成功, outTradeNo);return success;}GetMapping(/query)public String queryOrder() {try {Factory.setOptions(config);AlipayTradeQueryResponse response Factory.Payment.Common().query(123456);log.info(支付结果{}, response);return response.getHttpBody();} catch (Exception e) {throw new RuntimeException(e);}}}