支付宝网页支付接入(沙箱环境)

£可爱£侵袭症+ 提交于 2019-12-09 09:15:34

1、生成RSA密匙

    关于RSA介绍和使用 传送门

    注意:工具生成的是应用公匙应用私匙

2、沙箱配置公匙

    将生成的应用公匙粘贴到途中箭头部分,保存提交,之后,点击查看支付宝公匙,并复制粘贴到本地一个单独的txt文件中,备用。

    详细可的参考官网的视频 传送门



    3、下载官网Demo,往自己的项目中添加支付的功能

             Demo下载地址 传送门
            我自己使用的是Spring boot项目,使用maven引用alipay的包。
            
      <dependency>
			<groupId>com.alipay.sdk</groupId>
			<artifactId>alipay-sdk-java</artifactId>
			<version>3.0.1</version>
		</dependency>

    4、创建支付Controller

            操作完第1、2步之后会保留三个钥匙一定要分清楚。应用公钥、应用私钥、支付宝公匙。

            注意:项目中配置的是支付宝公匙和应用私匙,很多初学者这块会把应用公匙当成支付宝公匙使用。

            需要用到的参数    

@Controller
@RequestMapping(value = "/alipay")
public class alipay {

	// 应用ID,您的APPID,收款账号既是您的APPID对应支付宝账号
	public static String app_id = "";

	// 商户私钥,您的PKCS8格式RSA2私钥
	public static String merchant_private_key = "";

	// 支付宝公钥,查看地址:https://openhome.alipay.com/platform/keyManage.htm 对应APPID下的支付宝公钥。
	public static String alipay_public_key = "";
	
	// 服务器异步通知页面路径 需http://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问
	public static String notify_url = "http://公网地址/alipay/notifyUrl";

	// 页面跳转同步通知页面路径 需http://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问
	public static String return_url = "http://公网地址/alipay/returnUrl";

	// 签名方式
	public static String sign_type = "RSA2";

	// 字符编码格式
	public static String charset = "utf-8";
	
	//沙箱网关
	public static String gatewayUrl ="https://openapi.alipaydev.com/gateway.do";

	// 仅支持JSON
	public static String format = "JSON";
}


5、接口① 发起支付的接口实现   

             参考网页支付快速接入 其中发起支付的请求就是抄的这里面的代码 传送门
              
	@ApiOperation(value = "发起支付", notes = "支付宝")
	@RequestMapping(value = "/pay", method = RequestMethod.POST)
	public void pay(HttpServletRequest httpRequest, HttpServletResponse httpResponse)
			throws ServletException, IOException {
		AlipayClient alipayClient = new DefaultAlipayClient(gatewayUrl, app_id, merchant_private_key, format, charset,
				alipay_public_key, sign_type); // 获得初始化的AlipayClient
		AlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest();// 创建API对应的request
		alipayRequest.setReturnUrl(return_url);
		alipayRequest.setNotifyUrl(notify_url);// 在公共参数中设置回跳和通知地址
		alipayRequest.setBizContent("{" + "    \"out_trade_no\":\"2015032001010100"+(int)(Math.random()*1000)+"\","
				+ "    \"product_code\":\"FAST_INSTANT_TRADE_PAY\"," + "    \"total_amount\":"+(int)(Math.random()*10)+0.88+","
				+ "    \"subject\":\"Iphone6 16G\"," + "    \"body\":\"Iphone6 16G 耐克金\","
				+ "    \"passback_params\":\"merchantBizType%3d3C%26merchantBizNo%3d2016010101111\","
				+ "    \"extend_params\":{" + "    \"sys_service_provider_id\":\"2088511833207846\"" + "    }" + "  }");// 填充业务参数
		String form = "";
		try {
			form = alipayClient.pageExecute(alipayRequest).getBody(); // 调用SDK生成表单
		} catch (AlipayApiException e) {
			e.printStackTrace();
		}
		httpResponse.setContentType("text/html;charset=" + charset);
		httpResponse.getWriter().write(form);// 直接将完整的表单html输出到页面
		httpResponse.getWriter().flush();
		httpResponse.getWriter().close();
	}

    6、 接口②:支付宝同步回调

        参考官网demo中return_url.jsp
	@ApiOperation(value = "支付同步回调", notes = "支付宝")
	@RequestMapping(value = "/returnUrl", method = RequestMethod.GET)
	public void returnUrl(HttpServletRequest request, HttpServletResponse response)
			throws IOException, AlipayApiException {
		System.out.println("=================================同步回调=====================================");
		
		// 获取支付宝GET过来反馈信息
		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);
		}

		System.out.println(params);
		boolean signVerified =  AlipaySignature.rsaCheckV1(params, alipay_public_key, charset, sign_type);
		
		// ——请在这里编写您的程序(以下代码仅作参考)——
		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");

			// 付款金额
			String total_amount = new String(request.getParameter("total_amount").getBytes("ISO-8859-1"), "UTF-8");

			System.out.println("商户订单号="+out_trade_no);
			System.out.println("支付宝交易号="+trade_no);
			System.out.println("付款金额="+total_amount);
			
			response.getWriter().write(
					"trade_no:" + trade_no + "<br/>out_trade_no:" + out_trade_no + "<br/>total_amount:" + total_amount);
		} else {
			response.getWriter().write("验签失败");
		}
		response.getWriter().flush();
		response.getWriter().close();
	}

      7、 接口③:支付宝异步回调

          参考官网demo中notify_url.jsp
        @ApiOperation(value = "支付异步回调", notes = "支付宝")
	@RequestMapping(value = "/notifyUrl", method = RequestMethod.POST)
	public void notifyUrl(HttpServletRequest request, HttpServletResponse response)
			throws AlipayApiException, IOException {
		System.out.println("#################################异步回调######################################");
		
		// 获取支付宝POST过来反馈信息
		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);
		}

		System.out.println(params);
		boolean signVerified = AlipaySignature.rsaCheckV1(params, alipay_public_key, charset, 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");

			// 交易状态
			String trade_status = new String(request.getParameter("trade_status").getBytes("ISO-8859-1"), "UTF-8");

			System.out.println("商户订单号="+out_trade_no);
			System.out.println("支付宝交易号="+trade_no);
			System.out.println("交易状态="+trade_status);
			if (trade_status.equals("TRADE_FINISHED")) {
				// 判断该笔订单是否在商户网站中已经做过处理
				// 如果没有做过处理,根据订单号(out_trade_no)在商户网站的订单系统中查到该笔订单的详细,并执行商户的业务程序
				// 如果有做过处理,不执行商户的业务程序

				// 注意:
				// 退款日期超过可退款期限后(如三个月可退款),支付宝系统发送该交易状态通知
			} else if (trade_status.equals("TRADE_SUCCESS")) {
				// 判断该笔订单是否在商户网站中已经做过处理
				// 如果没有做过处理,根据订单号(out_trade_no)在商户网站的订单系统中查到该笔订单的详细,并执行商户的业务程序
				// 如果有做过处理,不执行商户的业务程序

				// 注意:
				// 付款完成后,支付宝系统发送该交易状态通知
			}

			System.out.println("异步回调验证成功");
			response.getWriter().write("success");

		} else {// 验证失败
			System.out.println("异步回调验证失败");
			response.getWriter().write("fail");

			// 调试用,写文本函数记录程序运行情况是否正常
			// String sWord = AlipaySignature.getSignCheckContentV1(params);
			// AlipayConfig.logResult(sWord);
		}
		response.getWriter().flush();
		response.getWriter().close();
	}

    8、其它

    按照官网的代码,支付成功,同步调用成功。但是异步调用中验签返回false,最后网上查的的解决方案是把异步回调接口中处理乱码的那行代码注释掉。第7步中的代码已经是注释掉的。之后测试异步调用正常。

    用支付宝官方的流程图来理解一下整个支付过程

    

    
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!