一、支付宝支付
1、官方文档是最好的教程:
①电脑网站支付文档:https://docs.open.alipay.com/270/105899/
②支付宝沙箱使用教程:https://docs.open.alipay.com/200/105311/
③调用支付宝相关接口的应用创建:https://open.alipay.com/developmentAccess/developmentAccess.htm
2、支付宝支付示例:
在使用支付宝支付时,先要在蚂蚁金服开放平台中下载alipay-sdk-java-3.4.49.ALL.jar。
在调用支付接口乃至很多第三方接口时,很多都有一个发起调用的方法和一个调用成功后的回调方法。在支付宝支付中也是一样,先看看发起支付的方法:
/*** 发起支付* @param httpRequest* @param httpResponse* @param out_trade_no 订单号* @param total_amount 订单金额* @param subject 订单名称* @param body 商品描述* @throws ServletException* @throws IOException*/@RequestMapping("aliPay")public void aliPay(HttpServletRequest httpRequest, HttpServletResponse httpResponse,String out_trade_no,String total_amount, String subject,String body) throws ServletException, IOException{doPost(httpRequest, httpResponse, out_trade_no, total_amount, subject, body);}/*** @param httpRequest* @param httpResponse* @param out_trade_no 订单号* @param total_amount 订单金额* @param subject 订单名称* @param body 商品描述* @throws ServletException* @throws IOException*/public void doPost(HttpServletRequest httpRequest, HttpServletResponse httpResponse,String out_trade_no,String total_amount, String subject,String body)throws ServletException, IOException {AlipayClient alipayClient = new DefaultAlipayClient(AlipayConfig.GATEWAYURL, AlipayConfig.APP_ID,AlipayConfig.APP_PRIVATE_KEY, AlipayConfig.FORMAT, AlipayConfig.CHARSET, AlipayConfig.ALIPAY_PUBLIC_KEY, AlipayConfig.SIGN_TYPE); // 获得初始化的AlipayClient// 创建API对应的requestAlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest();alipayRequest.setReturnUrl(AlipayConfig.RETURN_URL);alipayRequest.setNotifyUrl(AlipayConfig.NOTIFY_URL);alipayRequest.setBizContent("{\"out_trade_no\":\""+ out_trade_no +"\"," + "\"total_amount\":\""+ total_amount +"\"," + "\"subject\":\""+ subject +"\"," + "\"body\":\""+ body +"\"," + "\"product_code\":\"FAST_INSTANT_TRADE_PAY\"}");String form = "";try {// 调用SDK生成表单form = alipayClient.pageExecute(alipayRequest).getBody(); } catch (AlipayApiException e) {e.printStackTrace();}httpResponse.setContentType("text/html;charset=" + AlipayConfig.CHARSET);// 直接将完整的表单html输出到页面httpResponse.getWriter().write(form);httpResponse.getWriter().flush();httpResponse.getWriter().close();}
支付宝支付成功后的回调方法:
/*** 支付宝支付回调* @param request* @return* @throws UnsupportedEncodingException* @throws AlipayApiException*/@RequestMapping("aliPaySuccess")public String aliPaySuccess(HttpServletRequest request) throws UnsupportedEncodingException, AlipayApiException {System.out.println("------------------------------------>回调成功!");Map<String,String> params = new HashMap<String,String>();Map<String,String[]> requestParams = request.getParameterMap();for (Iterator<String> iter = requestParams.keySet().iterator(); iter.hasNext();) {String name = (String) iter.next();String[] values = (String[]) requestParams.get(name);String valueStr = "";for (int i = 0; i < values.length; i++) {valueStr = (i == values.length - 1) ? valueStr + values[i]: valueStr + values[i] + ",";}//乱码解决,这段代码在出现乱码时使用valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");params.put(name, valueStr);}boolean signVerified = AlipaySignature.rsaCheckV1(params, AlipayConfig.ALIPAY_PUBLIC_KEY, AlipayConfig.CHARSET, AlipayConfig.SIGN_TYPE); //调用SDK验证签名//——请在这里编写您的程序(以下代码仅作参考)——/* 实际验证过程建议商户务必添加以下校验:1、需要验证该通知数据中的out_trade_no是否为商户系统中创建的订单号,2、判断total_amount是否确实为该订单的实际金额(即商户订单创建时的金额),3、校验通知中的seller_id(或者seller_email) 是否为out_trade_no这笔单据的对应的操作方(有的时候,一个商户可能有多个seller_id/seller_email)4、验证app_id是否为该商户本身。*/if(signVerified) {//验证成功//商户订单号String out_trade_no = new String(request.getParameter("out_trade_no").getBytes("ISO-8859-1"),"UTF-8");//支付宝交易号String trade_no = new String(request.getParameter("trade_no").getBytes("ISO-8859-1"),"UTF-8");System.out.println("trade_no"+out_trade_no);System.out.println("trade_no"+trade_no);System.out.println("支付成功");}else {//验证失败System.out.println("支付失败");}return "testPay/aliPayPage";}
AlipayConfig.java常量类:
package com.mfc.util;/*** @author 74790* 支付宝支付相关参数*/
public class AlipayConfig {// 支付宝网关public static String GATEWAYURL = "https://openapi.alipaydev.com/gateway.do";// 应用ID,您的APPID,收款账号既是您的APPID对应支付宝账号public static final String APP_ID = "";// 商户私钥,您的PKCS8格式RSA2私钥public static final String APP_PRIVATE_KEY = "";public static final String FORMAT = "json";// 字符编码格式public static final String CHARSET = "utf-8";// 支付宝公钥,查看地址:https://openhome.alipay.com/platform/keyManage.htm 对应APPID下的支付宝公钥。public static final String ALIPAY_PUBLIC_KEY = "";// 签名方式public static final String SIGN_TYPE = "RSA2";//页面跳转同步通知页面路径 需http://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问public static final String RETURN_URL="";// 服务器异步通知页面路径 需http://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问public static final String NOTIFY_URL="";
}
3、支付宝支付订单实现思路:
①.点击支付调用TestPayCtrl中的aliPay方法发起支付,此时会跳往支付宝支付界面
②.在发起支付的aliPay方法中(本示例中其实是在doPost方法中),调用service方法将支付相关信息(如订单号、订单金额、商品信息等)存进自己系统的业务表中(这里只演示支付过程,所以没有将支付相关信息存进自己系统的业务表中)。
③.支付宝支付成功后会回调本系统的一个方法,我这里回调的是TestPayCtrl中的aliPaySuccess方法,支付宝会反馈给回调方法一些参数: 如out_trade_no(商户的订单号)、trade_no(支付宝交易号)等。<br/>
④.在回调方法中就可以通过out_trade_no(商户的订单号)取支付相关信息(支付相关信息在步骤2中已经存进了自己的业务表)。取出这些支付相关信息就可以写自己网站的逻辑了。<br/>
二、微信支付
1、同样官方文档是最好的教程:
官方支付相关文档:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=4_2
微信支付(扫码支付)教程:https://www.cnblogs.com/gdufs/p/7230950.html
2、微信支付示例:
这里使用Maven依赖:
<!-- 微信支付 --><dependency><groupId>com.github.wxpay</groupId><artifactId>wxpay-sdk</artifactId><version>0.0.3</version></dependency><!-- google二维码工具 --><dependency><groupId>com.google.zxing</groupId><artifactId>javase</artifactId><version>3.1.0</version></dependency>
微信支付发起支付:
private WxPayConfig config = new WxPayConfig();private WXPay wxPay = new WXPay(config);@RequestMapping("wxpay/pay")public void pay(HttpServletResponse response){//这里执行商户系统创建新的订单操作,写商户自己的逻辑//设置微信支付请求参数Map<String, String> data = new HashMap<String, String>();//商品简单描述,该字段请按照规范传递,具体请见参数规定,必填data.put("body", "微信支付测试");//商户订单号 ,必填data.put("out_trade_no", "20190106");//设备号,非必填//data.put("device_info", "");//标价币种,默认人民币(CNY),非必填data.put("fee_type", "CNY");//标价金额,必填data.put("total_fee", "1");//支持IPV4和IPV6两种格式的IP地址。调用微信支付API的机器IP,必填data.put("spbill_create_ip", "192.168.0.11");//异步接收微信支付结果通知的回调地址,通知url必须为外网可访问的url,不能携带参数。data.put("notify_url", "");//交易类型,必填data.put("trade_type", "NATIVE"); // 此处指定为扫码支付//商品ID,非必填data.put("product_id", "12");try {//发起支付Map<String, String> resp = wxPay.unifiedOrder(data);//获取二维码URLString code_url = resp.get("code_url");//根据URL生成二维码MultiFormatWriter multiFormatWriter = new MultiFormatWriter();//设置二维码参数Map<EncodeHintType, Object> hints = new HashMap<EncodeHintType, Object>();hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");BitMatrix bitMatrix = multiFormatWriter.encode(code_url, BarcodeFormat.QR_CODE, 300, 300, hints);//返回二维码MatrixToImageWriter.writeToStream(bitMatrix, "jpg", response.getOutputStream());} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}}
支付成功回调:
/*** 支付结果回调* @return* @throws Exception */@RequestMapping("/wxpay/notify_url")public void notifyUrl(HttpServletRequest request, HttpServletResponse response) throws Exception {// 读取回调内容InputStream inputStream;StringBuffer sb = new StringBuffer();inputStream = request.getInputStream();String s;BufferedReader in = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));while ((s = in.readLine()) != null) {sb.append(s);}in.close();inputStream.close();// 支付结果通知的xml格式数据String notifyData = sb.toString(); // 转换成mapMap<String, String> notifyMap = WXPayUtil.xmlToMap(notifyData);//支付确认内容String resXml = "";//验证签名if (wxPay.isPayResultNotifySignatureValid(notifyMap)) { // 签名正确System.out.println("返回的商户订单号:"+notifyMap.get("out_trade_no"));System.out.println("这里需要根据商户的订单号在自己系统中查询,判断这个订单号是不是本系统的订单号");if(notifyMap.get("out_trade_no") != null) {if("SUCCESS".equals(notifyMap.get("result_code"))) { //交易成功// TODO:更新订单System.out.println("订单" + notifyMap.get("out_trade_no") + "微信支付成功");} else { //交易失败System.out.println("订单" + notifyMap.get("out_trade_no") + "微信支付失败");}}// 注意特殊情况:订单已经退款,但收到了支付结果成功的通知,不应把商户侧订单状态从退款改成支付成功//设置成功确认内容resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>" + "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";}else { // 签名错误,如果数据里没有sign字段,也认为是签名错误//设置失败确认内容resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>" + "<return_msg></return_msg>" + "</xml> ";System.out.println("订单" + notifyMap.get("out_trade_no") + "微信支付失败");}//发送通知response.getWriter().println(resXml);}
实现的微信支付相关配置的参数类:
package com.mfc.util;import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;import com.github.wxpay.sdk.WXPayConfig;public class WxPayConfig implements WXPayConfig{private byte[] certData;//初始化退款、撤销时的商户证书public WxPayConfig() {try {String certPath = "D://第三方开放平台/wx_apiclient_cert.p12";File file = new File(certPath);InputStream certStream = new FileInputStream(file);this.certData = new byte[(int) file.length()];certStream.read(this.certData);certStream.close();} catch (FileNotFoundException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}/*** 微信支付分配的公众账号ID(企业号corpid即为此appId)* */public String getAppID() {return "";}/*** 微信支付分配的商户号* */public String getMchID() {return "";}public String getKey() {return "";}public int getHttpConnectTimeoutMs() {return 8000;}public int getHttpReadTimeoutMs() {return 10000;}public InputStream getCertStream() {ByteArrayInputStream certBis;certBis = new ByteArrayInputStream(this.certData);return certBis;}
}
3、微信支付实现思路:
①.点击支付调用TestPayCtrl中的pay方法发起支付,此时弹出微信支付二维码
②.在发起支付的pay方法中,调用service方法将支付相关信息(如订单号、订单金额、商品信息等)存进自己系统的业务表中。
③.微信支付成功后会回调本系统的一个方法,我这里回调的是TestPayCtrl中的notifyUrl方法,微信会反馈给回调方法一些参数:如out_trade_no(商户的订单号)等。
④.在回调方法中就可以通过out_trade_no(商户的订单号)取支付相关信息(支付相关信息在步骤2中已经存进了自己的业务表)。取出这些支付相关信息就可以写自己网站的逻辑了。