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

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

如果想学习Java工程化、高性能及分布式、深入浅出。微服务、Spring,MyBatis,Netty源码分析的朋友可以加我的Java高级交流:854630135,群里有阿里大牛直播讲解技术,以及Java大型互联网技术的视频免费分享给大家。

支付宝最近推出的支付宝接口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 支付宝-手机网站支付接口

 

 

 

@RequestMapping(value="notify_url")
	public String notify_url(HttpServletRequest request,HttpServletResponse response) throws AlipayApiException{
		Map<String,String> params = new HashMap<String,String>();
		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<String, String> 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工程化、高性能及分布式、深入浅出。微服务、Spring,MyBatis,Netty源码分析的朋友可以加我的Java高级交流:854630135,群里有阿里大牛直播讲解技术,以及Java大型互联网技术的视频免费分享给大家。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值