支付接口调用(支付宝、微信)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/fancheng614/article/details/85917539

一、支付宝支付

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对应的request
		AlipayTradePagePayRequest 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);
			//获取二维码URL
			String 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 block
			e.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(); 

        // 转换成map
        Map<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 block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.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中已经存进了自己的业务表)。取出这些支付相关信息就可以写自己网站的逻辑了。

猜你喜欢

转载自blog.csdn.net/fancheng614/article/details/85917539