基于 java !!!!!!!
支付宝支付相对微信支付比较容易(有沙箱环境,不需要xml转换、金额转换、客户端验证回调等),一般的普通支付只需要一个配置文件、一个回调地址(支付成功进行自己项目逻辑处理)
现在默认你是建好项目的,从沙箱环境一步步开始(沙箱环境和正式环境一样(也就是你公司的账号)到时候只需修改下配置参数即可)
1.登录支付宝(这里默认你是申请过开发的)>开发者中心>研发服务>沙箱应用,会看到你的APPID和支付网关(沙箱环境是dev.com,正式环境不带dev),还有RSA2(验签使用,证明你绑定的是这个支付宝账号,这个由支付宝工具生成,可百度或看文档,这里默认你是生成,并且已经上传到支付宝,这个可以秘钥可以反复生成更换,只需要保持一致即可),如果早已经设置好直接看第3步。
2.申请好沙箱应用后会默认有一个买家(客户端)、卖家(需要收款的账号,也是填入配置文件的账号)账号,可以下载支付宝给出的沙箱版支付宝APP可以无限充值金额,下载后登陆给出的买家账号即可,默认登陆密码和支付密码都是11111
3.开始进行项目开发,如果没有建好项目可根据支付宝给的Demo跑一遍,不过Demo是小脚本写的,不是很通俗易懂,但不影响使用(Demo也需修改配置文件),这里默认你已经建好项目,项目框架无所谓(这里是使用的SSM)
1.将相关jar包引入项目,有些jar包根据项目需求导入(如jackson相关的),alipay-sdk是必须的(在maven仓库可以搜到)
com.alipay.sdk
alipay-sdk-java
3.1.0
com.alibaba
fastjson
1.2.21
2.将Demo中的AlipayConfig 文件复制到你的项目当中
参数解释:
1.商户appid 就是你注册的应用的appid,进入支付宝开发页面就会显示(复制即可)
2.私钥 就是你用工具生成的本地私钥,公钥要上传到支付宝中,私钥自己保存下来复制到参数中(可先用支付宝工具比对一下生成的公私钥是否一致,如果不一致也没注意,排查bug你会崩溃的)
3.服务器异步通知地址 就是用户支付后支付宝会通知你的服务器支付的结果(通过或不通过) 如果用的ssm则controller一个地址即可(注意:必须需要外网能够访问,localhost是不行的,如果是测试阶段,可以下载个内网穿透工具,如花生壳)
4.页面跳转同步通知页面路径 就是支付后让其跳转的一个页面(支付成功后会自动退出支付宝然后跳向你设置的页面,一般为支付成功页面),可以不设置
5.请求网关地址 就是要请求支付宝的地址(注意:黑色箭头标注的是正式环境配置,沙箱环境需要在alipay后面加dev,声明其为测试环境网关,也就是alipaydev.com)
6.支付宝公钥 就是支付宝的公钥,点开应用>查看支付宝公钥复制填入即可
7.其他与配置文件一致即可
4.现在编写代码,支付宝需要你给它传入4个必要参数,这里为了方便理解就不放出自己的逻辑代码(如金额需BigDecimal,验证金钱正确性,重复提交、创建未支付订单等等,只给出必要代码),方法名称就不展示了,就是@Controller @RequesMapping之类的,下图所示的代码都是在方法中,(至于那些参数如:商品名称等怎么获得的看自己的项目架构,注意:apiAlipayVo是我获取参数的实体工具类,不是支付宝的方法),详情看注释
// 超时时间 可空
String timeout_express="2m";
// 销售产品码 必填
String product_code="QUICK_WAP_WAY";
/**********************/
// 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(apiAlipayVo.getOrderNum());
//!商品名称
model.setSubject(apiAlipayVo.getSubjectName());
//!商品价格
model.setTotalAmount(String.valueOf(apiAlipayVo.getTotal()));
//!商品介绍
model.setBody(apiAlipayVo.getBody());
//超时时间
model.setTimeoutExpress(timeout_express);
//产品销售码
model.setProductCode(product_code);
//将参数传入到 BizModel中
alipay_request.setBizModel(model);
//异步回调地址
alipay_request.setNotifyUrl(AlipayConfig.notify_url);
//同步回调地址
alipay_request.setReturnUrl(AlipayConfig.return_url);
// String form = "";
try {
// 调用SDK生成表单
//get方式生成表单 主要解决在微信中对支付宝屏蔽问题,如果不是在微信中可post提交,将form的注释解开,result注释掉即可
String result= client.pageExecute(alipay_request,"get").getBody();
System.out.println(result);
//form = client.pageExecute(alipay_request).getBody();
// System.out.println(form);
} catch (AlipayApiException e) {
e.printStackTrace();
rrVo.setMsg("生成表单失败!");
}
5.前端写法,我用的是form表单提交方式,还有后台拼接字段提交方法,form提交方式更容易理解,所以本次用的是这种方法
(注意:后台拼接方法不能和form表单提交方法一起使用!注意!注意!注意!,也就是如果你用的是后台拼接参数方法,上面代码中的set赋值方法一个也不能使用,会被覆盖的)下面是前端form表单写法:详细看注释
//前台写法
//form中什么也不用填写
//ajax将所需参数传递到后台,也就是set赋值的地方,form表单在后台拼接好后,因为前台target是打开一个新的页面 则将返回值success(data)
//填充到body中 $("body").html(data)即可,可以后台输出一下拼接好的form表单,会有一个自动提交的操作
6.此时如果没有错误,会自动唤起支付宝app,如果错误一般是验签错误,可百度查看一些错误,这里默认成功,支付完成后支付宝会给你返回支付结果,你需要你个外网能访问的地址去接收,地址就是你config配置好的地址。并不需要任何参数
public ResultResponseVo callBack(HttpServletResponse response,HttpServletRequest request) throws IOException, AlipayApiException {
response.setContentType("text/html;charset=utf-8");
response.reset();
//获取支付宝POST过来反馈信息
response.getOutputStream();
PageData pd = new PageData();
ResultResponseVo rrVo = new ResultResponseVo(); //我自己的封装类,用于返回参数,不是支付宝参数,包括 public ResultResponseVo
try {
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 = new String(request.getParameter("out_trade_no").getBytes("ISO-8859-1"),"UTF-8");
System.out.println("商户订单号"+out_trade_no);
//支付宝交易号
String trade_no = new String(request.getParameter("trade_no").getBytes("ISO-8859-1"),"UTF-8");
System.out.println("支付宝交易号"+trade_no);
//交易状态
String trade_status = new String(request.getParameter("trade_status").getBytes("ISO-8859-1"),"UTF-8");
boolean verify_result = AlipaySignature.rsaCheckV1(params, AlipayConfig.ALIPAY_PUBLIC_KEY, AlipayConfig.CHARSET, "RSA2");
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//设置日期格式
//验证成功后,进行业务逻辑
if(verify_result){
//这里就可以进行你项目的业务逻辑,想要什么参数,查看文档即可
response.getOutputStream().println("success"); //请不要修改或删除
response.getOutputStream().close();
rrVo.setData("success");
}else{//验证失败
response.getOutputStream().println("fail");
rrVo.setResult(HttpResultStatus.FAIL);
rrVo.setMsg("订单出现异常,验签失败!");
return rrVo;
}
} catch (Exception e) {
e.printStackTrace();
}
rrVo.setResult(HttpResultStatus.SUCCESS);
rrVo.setMsg(HttpResultStatus.SUCCESS.getMsg());
return rrVo;
}
注意: success那一句不可以删除,支付宝会每隔一段时间给你这个地址发送一次请求,如果见不到success它会一直发送,直到22小时后,if()之后可以进行你的业务逻辑代码,想获取什么值可以去支付宝文档查询《异步回调地址》,这里就差不多可以完成普通的支付流程
坑点:
1.如果你是在公众号或微信浏览器中使用支付宝支付,他会让你复制链接出去支付,但他会屏蔽你的hidden隐藏域(因为支付宝表单提交参数里用的是input type=hidden属性),会出现验签发源地错误,解决办法:使用上图的get方式提交,让其变成一个url链接而不是form表单
2.如果你是在公众号或微信浏览器中使用支付宝支付,复制链接后你是回调不回来的,就是不会再一步发挥你微信中的项目页面,只会返回到手机浏览器中的页面,暂无解决办法,只能一步步返回(这里的逻辑需要自己去写,避免返回时出现重复支付等现象)
3.公私钥一定要匹配,如果找不到问题,先换一遍公私钥或者检测是否匹配!
4.上图代码中的注释很有用!
最后,如果不会搞不懂
可以点击此头像,输入三遍一样的问题,会转接人工客服,这一点很好,但人工客服水平不一,需要自己判断。
这是一个简单的支付流程,不涉及退款,积分、花呗支付等等功能。