一、配置
配置
-
用户注册
首先用公司相关信息在蚂蚁金服开放平台注册一个支付宝账户(https://openhome.alipay.com/platform/home.htm)

然后在进入开放平台后进入开发者中心>网页&移动应用接入中

接着和支付宝签约,接入支付功能(手机网站支付)

-
配置和获取相关开发信息
进入申请的支付功能页面,配置授权回调地址和密钥

ok,现在我们获取了APPID、支付宝网关、授权回调地址、商户私钥、应用公钥、支付宝公钥等相关信息,开发时我将会把他们写到配置文件中
另外,我们还需要一个支付宝的SDK,请大家自行下载
到此,所需的全部准备工作完成,大家可以愉快的开发了
二、开发
支付逻辑
-
支付逻辑
- 商户系统调用支付宝预下单接口alipay.trade.precreate,获得该订单二维码图片地址。
- 发起轮询获得支付结果:等待5秒后调用交易查询接口alipay.trade.query通过支付时传入的商户订单号(out_trade_no)查询支付结果(返回参数TRADE_STATUS),如果仍然返回等待用户付款(WAIT_BUYER_PAY),则再次等待5秒后继续查询,直到返回确切的支付结果(成功TRADE_SUCCESS 或 已撤销关闭TRADE_CLOSED),或是超出轮询时间。在最后一次查询仍然返回等待用户付款的情况下,必须立即调用交易撤销接口alipay.trade.cancel将这笔交易撤销,避免用户继续支付。
- 这里是列表文本除了主动轮询,也可以通过接受异步通知获得支付结果。
- 和微信支付差异的地方就在支付宝返回查询用户付款状态的方式,支付宝除了主动轮询查询支付状态,还可以异步获取。在项目里我们将这两种方式交叉使用。
公共请求参数
-
公共请求参数

与支付无关的业务逻辑
-
与支付无关的业务逻辑
这部分代码已经在上篇文章微信支付中贴出,这里就不再重新贴一遍了
封装固定参数
-
封装固定参数
package com.andata.conf; /* * *类名:AlipayConfig *功能:基础配置类 *详细:设置帐户有关信息及返回路径 *提示:如何获取安全校验码和合作身份者ID *1.用您的签约支付宝账号登录支付宝网站(www.alipay.com) *2.点击“商家服务”(https://b.alipay.com/order/myOrder.htm) *3.点击“查询合作者身份(PID)”、“查询安全校验码(Key)” *安全校验码查看时,输入支付密码后,页面呈灰色的现象,怎么办? *解决方法: *1、检查浏览器配置,不让浏览器做弹框屏蔽设置 *2、更换浏览器或电脑,重新登录查询。 */ public class AlipayConfig { //ServiceURL public static String ServiceUrl="https://openapi.alipay.com/gateway.do"; //APP支付宝支付业务:app_id public static String app_id = "20180xxxxxxxxxxxxxx"; // 商户的私钥,使用支付宝自带的openssl工具生成。 public static String private_key = "xxxxxxxxxxxxxxxxxxx"; // 应用的公钥,无需修改该值 public static String ali_public_key = "xxxxxxxxxxxxxxxxxxxxx"; // 支付宝的公钥,去open.alipay.com对应应用下查看。 public static String zfb_public_key = "xxxxxxxxxxxxxxxxxxxxx"; // 字符编码格式 目前支持 gbk 或 utf-8 public static String input_charset = "UTF-8"; }
AliPayController
1package com.andata.controller; 2import com.alipay.api.AlipayApiException; 3import com.alipay.api.AlipayClient; 4import com.alipay.api.DefaultAlipayClient; 5import com.alipay.api.internal.util.AlipaySignature; 6import com.alipay.api.request.AlipayTradeCancelRequest; 7import com.alipay.api.request.AlipayTradePrecreateRequest; 8import com.alipay.api.request.AlipayTradeQueryRequest; 9import com.alipay.api.response.AlipayTradeCancelResponse; 10import com.alipay.api.response.AlipayTradePrecreateResponse; 11import com.alipay.api.response.AlipayTradeQueryResponse; 12import com.andata.conf.AlipayConfig; 13import com.andata.pojo.ProductOrders; 14import com.andata.service.ProOrdersService; 15import com.andata.util.QRCodeUtil; 16import net.sf.json.JSONObject; 17import org.apache.ibatis.annotations.Param; 18import org.springframework.stereotype.Controller; 19import org.springframework.web.bind.annotation.RequestMapping; 20import org.springframework.web.bind.annotation.ResponseBody; 21 22import javax.annotation.Resource; 23import javax.servlet.ServletOutputStream; 24import javax.servlet.http.HttpServletRequest; 25import javax.servlet.http.HttpServletResponse; 26import java.io.IOException; 27import java.util.HashMap; 28import java.util.Iterator; 29import java.util.Map; 30 31@Controller 32public class AliPayController { 33 @Resource 34 private ProOrdersService proOrdersService; 35 /** 36 * 支付逻辑 37 * 1、商户系统调用支付宝预下单接口alipay.trade.precreate,获得该订单二维码图片地址。 38 * 2、发起轮询获得支付结果:等待5秒后调用交易查询接口alipay.trade.query通过支付时传入的商户订单号(out_trade_no)查询支付结果(返回参数TRADE_STATUS), 39 如果仍然返回等待用户付款(WAIT_BUYER_PAY),则再次等待5秒后继续查询,直到返回确切的支付结果(成功TRADE_SUCCESS 或 已撤销关闭TRADE_CLOSED), 40 或是超出轮询时间。在最后一次查询仍然返回等待用户付款的情况下,必须立即调用交易撤销接口alipay.trade.cancel将这笔交易撤销,避免用户继续支付。 41 * 3、除了主动轮询,也可以通过接受异步通知获得支付结果 42 */ 43 /** 44 * 阿里订单取消接口 45 * 请求返回值示例: 46 * {"alipay_trade_cancel_response":{"code":"40004","msg":"Business Failed","sub_code":"ACQ.INVALID_PARAMETER","sub_msg":"参数无效","out_trade_no":"20150320010101002", 47 * "retry_flag":"N"},"sign":""} 48 * @return 49 * @throws AlipayApiException 50 */ 51 @RequestMapping(value = "aliremove.do") 52 @ResponseBody 53 private Map<String, Object> remove(@Param("orderid")String orderid) throws AlipayApiException { 54 AlipayClient alipayClient = new DefaultAlipayClient(AlipayConfig.ServiceUrl, AlipayConfig.app_id, AlipayConfig.private_key, "json", AlipayConfig.input_charset, AlipayConfig.zfb_public_key, "RSA2"); //获得初始化的AlipayClient 55 AlipayTradeCancelRequest request = new AlipayTradeCancelRequest();//创建API对应的request类 56 Map<String,Object> returnmap=new HashMap<>(); 57 try { 58 //判断订单是否完成支付,完成支付的订单禁止撤销 59 int i = this.proOrdersService.selectOrderStatus(orderid); 60 if (i==1) 61 { 62 returnmap.put("type","0"); 63 returnmap.put("data","订单已支付,撤销订单失败"); 64 }else { 65 Map<String,Object> map=new HashMap<>(); 66 map.put("out_trade_no",orderid); 67 String returndata = JSONObject.fromObject(map).toString(); 68 request.setBizContent(returndata); //设置业务参数 69 AlipayTradeCancelResponse response = alipayClient.execute(request);//通过alipayClient调用API,获得对应的response类 70 JSONObject query_response = JSONObject.fromObject(response.getBody()).getJSONObject("alipay_trade_cancel_response"); 71 String code = query_response.getString("code"); 72 String msg = query_response.getString("msg"); 73 if (code.equals("10000") && msg.equals("Success")) { 74 System.out.println("阿里订单取消接口调用成功!"); 75 returnmap.put("type","1"); 76 returnmap.put("data","撤销订单成功"); 77 }else { 78 System.out.println("撤销订单请求失败"); 79 returnmap.put("type","0"); 80 returnmap.put("data",query_response.getString("sub_msg")); 81 System.out.println(query_response);//返回失败信息 82 } 83 //根据response中的结果继续业务逻辑处理 84 } 85 }catch (Exception e) 86 { 87 System.out.println("撤销订单异常"); 88 e.printStackTrace(); 89 } 90 return returnmap; 91 } 92 93 /** 94 * 阿里交易查询接口 95 * out_trade_no 支付时传入的商户订单号,与trade_no必填一个 96 * trade_no 支付时返回的支付宝交易号,与out_trade_no必填一个 97 * 请求返回值示例: 98 * {"alipay_trade_query_response":{"code":"10000","msg":"Success","buyer_logon_id":"159****4027","buyer_pay_amount":"0.01","buyer_user_id":"2088012351746164", 99 * "fund_bill_list":[{"amount":"0.01","fund_channel":"PCREDIT"}],"invoice_amount":"0.01","out_trade_no":"020910312752381","point_amount":"0.00","receipt_amount":"0.01", 100 * "send_pay_date":"2018-02-09 10:31:45","total_amount":"0.01","trade_no":"2018020921001004160275738069","trade_status":"TRADE_SUCCESS"}, 101 * "sign":""} 102 * @return 103 * @throws Exception 104 */ 105 @RequestMapping(value="/aliget") 106 @ResponseBody 107 private Map<String, Object> get(@Param("orderid")String orderid) throws AlipayApiException{ 108 AlipayClient alipayClient = new DefaultAlipayClient(AlipayConfig.ServiceUrl, AlipayConfig.app_id, AlipayConfig.private_key, "json", AlipayConfig.input_charset, AlipayConfig.zfb_public_key, "RSA2"); //获得初始化的AlipayClient 109 AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();//创建API对应的request类 110 Map<String,Object> map=new HashMap<>(); 111 map.put("out_trade_no",orderid); 112 String returndata = JSONObject.fromObject(map).toString(); 113 request.setBizContent(returndata); //设置业务参数 114 AlipayTradeQueryResponse response = alipayClient.execute(request);//通过alipayClient调用API,获得对应的response类 115 JSONObject jsonObject = JSONObject.fromObject(response.getBody()).getJSONObject("alipay_trade_query_response"); 116 String code = jsonObject.getString("code"); 117 String msg = jsonObject.getString("msg"); 118 Map<String,Object> returnmap=new HashMap<>(); 119 if (code.equals("10000") && msg.equals("Success")) 120 { 121 System.out.println("交易查询请求成功"); 122 String trade_status = jsonObject.getString("trade_status"); 123 if (trade_status.equals("TRADE_SUCCESS")) 124 { 125 returnmap.put("type","1"); 126 returnmap.put("data","支付成功"); 127 }else { 128 returnmap.put("type","0"); 129 returnmap.put("data",trade_status); 130 } 131 }else { 132 System.out.println("交易查询请求失败"); 133 returnmap.put("type","0"); 134 returnmap.put("data",jsonObject.getString("sub_msg")); 135 System.out.println(jsonObject);//返回失败信息 136 } 137 return returnmap; 138 } 139 /** 140 * @name 预下单请求,阿里获取二维码接口 141 * @throws AlipayApiException 142 * @Param out_trade_no 商户订单号,64个字符以内、只能包含字母、数字、下划线;需保证在商户端不重复 143 * @Param total_amount 订单总金额,单位为元,精确到小数点后两位,取值范围[0.01,100000000] 如果同时传入了【打折金额】,【不可打折金额】, 144 * 【订单总金额】三者,则必须满足如下条件:【订单总金额】=【打折金额】+【不可打折金额】 145 * @Param subject 订单标题 146 * @Param store_id 商户门店编号 147 * @Param timeout_express 该笔订单允许的最晚付款时间,逾期将关闭交易。 148 * 取值范围:1m~15d。m-分钟,h-小时,d-天,1c-当天(1c-当天的情况下,无论交易何时创建,都在0点关闭)。 该参数数值不接受小数点, 如 1.5h,可转换为 90m。 149 */ 150 @RequestMapping(value="/alipay.do") 151 @ResponseBody 152 private Map list(HttpServletResponse responses, @Param("orderid")String orderid) throws AlipayApiException{ 153 AlipayClient alipayClient = new DefaultAlipayClient(AlipayConfig.ServiceUrl, AlipayConfig.app_id, AlipayConfig.private_key, "json", AlipayConfig.input_charset, AlipayConfig.zfb_public_key, "RSA2"); //获得初始化的AlipayClient 154 AlipayTradePrecreateRequest request = new AlipayTradePrecreateRequest();//创建API对应的request类 155 156 Map<String,Object> map=new HashMap<>(); 157 if (orderid.isEmpty()) 158 { 159 map.put("type","2"); 160 map.put("data","订单号不能为空"); 161 return map; 162 } 163 //设置回调地址 164 request.setNotifyUrl("http://www.andata.com.cn/aliPayCallBack.do"); 165 //根据订单号查询订单信息 166 ProductOrders productOrders = this.proOrdersService.selectByOrderId(orderid); 167 Map<String,Object> maps=new HashMap<>(); 168 maps.put("out_trade_no",productOrders.getOrdernumber()); 169 maps.put("total_amount","0.01"); 170 maps.put("subject","小编机器人纠错"); 171 maps.put("store_id","XB001"); 172 maps.put("timeout_express","1m"); 173 //把订单信息转换为json对象的字符串 174 String postdata = JSONObject.fromObject(maps).toString(); 175 request.setBizContent(postdata); 176 AlipayTradePrecreateResponse response = alipayClient.execute(request); 177 String body = response.getBody(); 178 JSONObject jsonObject = JSONObject.fromObject(body); 179 String qr_code = jsonObject.getJSONObject("alipay_trade_precreate_response").getString("qr_code"); 180 //流输出 181 ServletOutputStream sos = null; 182 try { 183 sos = responses.getOutputStream(); 184 //生成二维码 185 QRCodeUtil.encode(qr_code, sos); 186 } catch (IOException e) { 187 e.printStackTrace(); 188 } catch (Exception e) { 189 e.printStackTrace(); 190 } 191 return map; 192 } 193 194 /** 195 * 支付宝支付成功回调 196 */ 197 @RequestMapping(value = "aliPayCallBack.do") 198 @ResponseBody 199 public void aliPayCallBack(HttpServletResponse response, HttpServletRequest request) { 200 System.out.println("支付宝回调成功"); 201 try { 202 //获取支付宝POST过来反馈信息 203 Map<String,String> params = new HashMap<String,String>(); 204 Map requestParams = request.getParameterMap(); 205 for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext();) { 206 String name = (String) iter.next(); 207 String[] values = (String[]) requestParams.get(name); 208 String valueStr = ""; 209 for (int i = 0; i < values.length; i++) { 210 valueStr = (i == values.length - 1) ? valueStr + values[i] 211 : valueStr + values[i] + ","; 212 } 213 //乱码解决,这段代码在出现乱码时使用。 214 //valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8"); 215 params.put(name, valueStr); 216 } 217 boolean flag = AlipaySignature.rsaCheckV1(params, AlipayConfig.zfb_public_key, AlipayConfig.input_charset,"RSA2"); 218 // 获取支付宝的通知返回参数,可参考技术文档中页面跳转同步通知参数列表(以下仅供参考)// 219 String order_no = request.getParameter("out_trade_no"); // 获取订单号 220 221// String trade_no = request.getParameter("trade_no"); // 支付宝交易号 222// String total_amount = request.getParameter("total_amount"); // 获取总金额 223// String subject = new String(request.getParameter("subject") 224// .getBytes("ISO-8859-1"), "gbk");// 商品名称、订单名称 225// String body = ""; 226// if (request.getParameter("body") != null) { 227// body = new String(request.getParameter("body").getBytes( 228// "ISO-8859-1"), "gbk");// 商品描述、订单备注、描述 229// } 230// String buyer_email = request.getParameter("buyer_email"); // 买家支付宝账号 231 String trade_status = request.getParameter("trade_status"); // 交易状态 232 // 获取支付宝的通知返回参数,可参考技术文档中页面跳转同步通知参数列表(以上仅供参考)// 233 if (flag==true) {// 验证成功 234 try{ 235 int i = this.proOrdersService.updateByOrderId(order_no); 236 if (i==1) 237 { 238 System.out.println("支付宝订单支付成功!"); 239 } 240 }catch (Exception e) 241 { 242 System.out.println("支付宝支付异常"); 243 e.printStackTrace(); 244 } 245 } 246 response.getWriter().write("success"); 247 } catch (Exception e) { 248 e.printStackTrace(); 249 } 250 } 251}
现在,基本的代码都贴完了,生成二维码的逻辑和微信一样,拿到code_url后,用二维码生成工具类生成二维码,把他贴到网页上需要支付的页面,就成功了~