Java SpringMVC 支付宝-手机网站支付接口

首先就是申请支付宝第三方接口,获取到APPID,应用发布前也可以用支付宝的沙箱环境,服务器要开启外网访问权限,因为支付宝需要返回异步通知(notify_url)和同步通知(return_url)

支付宝最近推出的支付宝接口2.0,网上有很多教程都是之前版本的,但支付宝给出了兼容方案

第三方支付原理

  以上简要说明了支付过程,当然其中省略了一些步骤(比如购物车,订单等),我们重点来看支付流程。

  2.1用户向商城网站发起确认订单的请求

  2.2商城网站接收到请求保存订单数据到数据库或其他存储介质

  2.3返回订单确认页面,页面上应该显示订单金额等信息

  2.4用户确认支付,发起支付请求。注:支付请求是发送到支付网关(比如支付宝、网银在线)而不是发送到商城网站。

  2.5显示支付页面

  2.6用户填写认证信息(账号密码等)提交

  2.7这里有两个步骤一个是扣款成功后页面跳转到支付结果页面(展示给用户),另一个是支付通知,这两步没有先后顺序可能同时执行,商城网站接收到支付通知后根据验证规则验证信息的有效性,并作出相应的更改操作(例:有效则更改订单为已付款状态,无效则记录非法请求信息)。

  以支付宝为例:如果实现在网站中集成支付宝接口,首先要有一个支付宝账号,接下来向支付宝申请在线支付业务,签署协议。协议生效后有支付宝一方会给网站方一个合作伙伴ID,和安全校验码,有了这两样东西就可以按照支付宝接口文档开发支付宝接口了,在上图的几个步骤中只有4和7两个步骤在商城与支付网关之间有信息交互。在步骤4中指将数据发送到支付网关(支付宝),在步骤7中是的通知验证部分,验证网关请求网站某地址,网站按验证规则对信息进行验证记录并作出响应

  (1).第一步要先能够跳转到支付宝的支付界面(可以本地测试)。

  (2).第二部完成支付跳转回商家界面(必须线上测试,因为返回回来,支付宝找不到你的localhost:8080;所以必须要有域名(地址))。

支付宝开放平台下载demo和SDK(Java版本),然后根据自己所需要,拷贝进它的源代码,也可以全部拷入,但是不一定都用得到。

数据交互方式可以用jsp,也可以用控制器。支付宝给的demo是用的jsp实现。

首先导入支付宝的两个jar包:

但是感觉用控制器(Controller)更好做一些:alipay-sdk-java20170307171631.jar;commons-logging-1.1.1.jar

代码:

配置参数

package com.alipay.config;
public class AlipayConfig {
	// 商户appid这是从支付宝开放平台获取的APPID
	public static String APPID = "";

	// 私钥 pkcs8格式的
	public static String RSA_PRIVATE_KEY = "";

	// 服务器异步通知页面路径 需http://或者https://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问
	public static String notify_url = "http://www.****.cn/PayTest/notify_url";

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

	// 请求网关地址
	public static String URL = "https://openapi.alipay.com/gateway.do";

	// 编码
	public static String CHARSET = "UTF-8";

	// 返回格式
	public static String FORMAT = "json";

	// 支付宝公钥
	public static String ALIPAY_PUBLIC_KEY = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoUg6+XycCWdQRp2qpHN5b8mw1+juv4dbcYFA61dVivDHH2sqdcL2EFfFO1Msa66T9IeFqJFyod8bVmG8vF3iql12zpceY+eHEZHmkxCBqlivLTJIfChkDmiBlARlnsZ8vK8A01VvlNdgq3g/o6+OzY/frei5bVcMVyIFBjg0fdV9vzOzb4CrQn390JLJ80aA8o5TsvlCeUHg4zAMDUyOm2suAuvgiqekEVS/qvRO+I2O1GTp3dJjPNsdmRVxNsxoU8DEApMLNYmxHiWZpFhRxRdH54ugHWkNmFGyT5y/S1g7dq/nfVgriycZ3BoKtoG4eep7cpK1rnRk+aEpLm9FmQIDAQAB";

	// 日志记录目录
	public static String log_path = "/log";

	// RSA2
	public static String SIGNTYPE = "RSA2";
}

支付

if(request.getParameter("WIDout_trade_no")!=null){
	// 商户订单号,商户网站订单系统中唯一订单号,必填
    String out_trade_no = new String(request.getParameter("WIDout_trade_no").getBytes("ISO-8859-1"),"UTF-8");

	// 订单名称,必填
    //String subject = new String(request.getParameter("WIDsubject").getBytes("ISO-8859-1"),"UTF-8");
	String subject = request.getParameter("WIDsubject");
	//System.out.println(subject);
    
	// 付款金额,必填
    String total_amount=new String(request.getParameter("WIDtotal_amount").getBytes("ISO-8859-1"),"UTF-8");

    // 商品描述,可空
    String body = new String(request.getParameter("WIDbody").getBytes("ISO-8859-1"),"UTF-8");

    // 超时时间 可空
    String timeout_express="2m";

    // 销售产品码 必填
    String product_code="QUICK_WAP_PAY";

    /**********************/
    // SDK 公共请求类,包含公共请求参数,以及封装了签名与验签,开发者无需关注签名与验签     
    //调用RSA签名方式
    AlipayClient client = new DefaultAlipayClient(AlipayConfig.URL, AlipayConfig.APPID, AlipayConfig.RSA_PRIVATE_KEY, AlipayConfig.FORMAT, AlipayConfig.CHARSET, AlipayConfig.ALIPAY_PUBLIC_KEY,AlipayConfig.SIGNTYPE);
    AlipayTradeWapPayRequest alipay_request=new AlipayTradeWapPayRequest();

    // 封装请求支付信息
    AlipayTradeWapPayModel model=new AlipayTradeWapPayModel();
    model.setOutTradeNo(out_trade_no);
    model.setSubject(subject);
    model.setTotalAmount(total_amount);
    model.setBody(body);
    model.setTimeoutExpress(timeout_express);
    model.setProductCode(product_code);
    alipay_request.setBizModel(model);

    // 设置异步通知地址
    alipay_request.setNotifyUrl(AlipayConfig.notify_url);

    // 设置同步地址
    alipay_request.setReturnUrl(AlipayConfig.return_url);   

    // form表单生产
    String form = "";

	try {
		// 调用SDK生成表单
		form = client.pageExecute(alipay_request).getBody();
		response.setContentType("text/html;charset=" + AlipayConfig.CHARSET); 
	    response.getWriter().write(form);//直接将完整的表单html输出到页面 
	    response.getWriter().flush(); 
	    response.getWriter().close();
	} catch (AlipayApiException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	}
}

Controller

 异步通知处理支付宝会以json格式返回相应参数

支付状态trade_status的值有四种

Java SpringMVC 支付宝-手机网站支付接口_第1张图片

@RequestMapping(value="notify_url")
public String notify_url(HttpServletRequest request,HttpServletResponse response) throws AlipayApiException{
	Map params = new HashMap();
	Map requestParams = request.getParameterMap();

	for (Iterator 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] + ",";
		}

		//乱码解决,这段代码在出现乱码时使用。如果mysign和sign不相等也可以使用这段代码转化
		//valueStr = new String(valueStr.getBytes("ISO-8859-1"), "gbk");
		params.put(name, valueStr);
	}

	//获取支付宝的通知返回参数,可参考技术文档中页面跳转同步通知参数列表(以下仅供参考)//
	//商户订单号
	String out_trade_no = request.getParameter("out_trade_no");

	//支付宝交易号
	String trade_no = request.getParameter("trade_no");

	//交易状态
	String trade_status = request.getParameter("trade_status");

	//获取支付宝的通知返回参数,可参考技术文档中页面跳转同步通知参数列表(以上仅供参考)//
	//计算得出通知验证结果
	//boolean AlipaySignature.rsaCheckV1(Map params, String publicKey, String charset, String sign_type)
	boolean verify_result = AlipaySignature.rsaCheckV1(params, AlipayConfig.ALIPAY_PUBLIC_KEY, AlipayConfig.CHARSET, AlipayConfig.SIGNTYPE);

	if(verify_result){//验证成功
		//////////////////////////////////////////////////////////////////////////////////////////
		//请在这里加上商户的业务逻辑程序代码
		//——请根据您的业务逻辑来编写程序(以下代码仅作参考)——

		if(trade_status.equals("TRADE_FINISHED")){
			//判断该笔订单是否在商户网站中已经做过处理
			//注意:
			//如果签约的是可退款协议,退款日期超过可退款期限后(如三个月可退款),支付宝系统发送该交易状态通知
			//如果没有签约可退款协议,那么付款完成后,支付宝系统发送该交易状态通知。
		} else if (trade_status.equals("TRADE_SUCCESS")){
			//判断该笔订单是否在商户网站中已经做过处理
			service.updatePayStatus(out_trade_no);
			//注意:
			//如果签约的是可退款协议,那么付款完成后,支付宝系统发送该交易状态通知。
		}
		//——请根据您的业务逻辑来编写程序(以上代码仅作参考)——
		System.out.println("success");	//请不要修改或删除
	}else{//验证失败
		System.out.println("fail");
	}
	return trade_status;
}

      理论上异步方法要快于同步方法,因为中间还有一个跳转流程。所以如果要将支付宝返回来的信息存入数据库,逻辑一般是写在异步方法里面,同步方法只作为页面跳转(支付完成后的跳转)一般不需要验签。如果把逻辑写在同步方法里面,客户在支付成功直接关闭窗口,活动会被关闭,就访问不到控制器了。

       而异步方法访问的方法是要在浏览器上直接访问到的!但是一般我们网站都做了权限过滤的,要先去判断是否登录,没登录一般跳转登录界面。但是不论你是用的过滤器还是 shiro,还是其它的,总之你要暴露出这个方法要让支付宝能访问!

你可能感兴趣的:(后端Java框架)