接入支付宝支付需要在支付宝开发平台创建应用获取appid,创建后需要审核,所以我们用支付宝提提供的沙箱环境开发测试。
首先登录支付宝开放平台,在开发者中心选择研发服务->沙箱环境->沙箱应用
我们只看必看部分,支付宝给我们提供了测试的appid和网关,密钥需要自己生成。点击设置,可以查看文档,下载支付宝提供的密钥生成工具生成密钥
设置好之后就可以编写代码了
首先创建个支付工具类
public final class AlipayUtil {private static final Logger logger = LoggerFactory.getLogger(AlipayUtil.class);//初始化AlipayClient,支付宝的所有接口都是通过它来调用public static AlipayClient clientInit(){AlipayClient alipayClient = new DefaultAlipayClient("/gateway.do","101400687185","你的私钥","json","UTF-8","设置的支付宝公钥","RSA2");return alipayClient;}/***交易预下单接口 方法一* @return String*/public static AlipayTradePrecreateResponse alipay(String orderNo, String productName, BigDecimal productPrice, String payUrl, String notifyUrl){AlipayClient alipayClient = clientInit();AlipayTradePrecreateModel model = new AlipayTradePrecreateModel();AlipayTradePrecreateRequest request = new AlipayTradePrecreateRequest();//创建API对应的request类model.setOutTradeNo(orderNo);//订单号model.setTotalAmount(productPrice);//订单金额model.setSubject(productName);//订单标题model.setTimeoutExpress("120m");//交易超时时间model.setQrCodeTimeoutExpress("120m");//二维码失效时间//商户外网可以访问的异步地址,不写就是不回调//测试时可以使用花生壳等外网映射工具request.setNotifyUrl("/callback/alipay/notify");request.setBizModel(model);AlipayTradePrecreateResponse response = null;try {response = alipayClient.execute(request);} catch (AlipayApiException e) {logger.error("支付宝下单接口请求失败,resp={}", e.getErrMsg());return null;}return response;}/***交易预下单接口 方法二*(该方法本人没有测试)*集成了交易保障接口(需要终端机器)* @return String*/public static AlipayTradePrecreateResponse alipay(String orderNo, String productName, BigDecimal productPrice, String payUrl, String notifyUrl){AlipayClient alipayClient = clientInit();// 创建扫码支付请求builder,设置请求参数AlipayTradePrecreateRequestBuilder builder = new AlipayTradePrecreateRequestBuilder().setSubject(subject).setTotalAmount(totalAmount).setOutTradeNo(outTradeNo).setUndiscountableAmount(undiscountableAmount).setSellerId(sellerId).setBody(body).setOperatorId(operatorId).setStoreId(storeId).setExtendParams(extendParams).setTimeoutExpress(timeoutExpress)//.setNotifyUrl("http://www.test-notify-")//支付宝服务器主动通知商户服务器里指定的页面http路径,根据需要设置.setGoodsDetailList(goodsDetailList);AlipayF2FPrecreateResult result = tradeService.tradePrecreate(builder);switch (result.getTradeStatus()) {case SUCCESS:log.info("支付宝预下单成功: )");AlipayTradePrecreateResponse response = result.getResponse();dumpResponse(response);// 需要修改为运行机器上的路径String filePath = String.format("/Users/sudo/Desktop/qr-%s.png",response.getOutTradeNo());log.info("filePath:" + filePath);//ZxingUtils.getQRCodeImge(response.getQrCode(), 256, filePath);break;case FAILED:log.error("支付宝预下单失败!!!");break;case UNKNOWN:log.error("系统异常,预下单状态未知!!!");break;default:log.error("不支持的交易状态,交易返回异常!!!");break;}return response;}/*** 统一收单线下交易查询接口* @return AlipayTradeQueryResponse*/public static AlipayTradeQueryResponse queryOrder(String outTradeNo, String tradeNo){AlipayClient alipayClient = clientInit();AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();//创建API对应的request类Map<String, String> params = new HashMap<>();params.put("out_trade_no",outTradeNo);params.put("trade_no",tradeNo);request.setBizContent(JSONUtil.toJSONString(params)); //设置业务参数AlipayTradeQueryResponse response = null;try {response = alipayClient.execute(request);//通过alipayClient调用API,获得对应的response类} catch (AlipayApiException e) {logger.error("支付宝查询接口请求失败,resp={}", e.getErrMsg());}return response;}/*** 回调方法必须调用的验签方法,在回调结果前调用,确保是由支付宝发起的请求* @return boolean*/public static boolean checkSign(Map<String,String[]> requestParams){Map<String,String> params = new HashMap<String,String>();//将异步通知中收到的所有参数都存放到 map 中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);}boolean signVerified = false; //调用SDK验证签名try {signVerified = AlipaySignature.rsaCheckV1(params,"配置的支付宝公钥","utf-8","RSA2");} catch (AlipayApiException e) {logger.error("支付宝验签接口请求失败,resp={}", e.getErrMsg());}return signVerified;}}
更多参数请查看支付宝文档:https://docs./api_1/alipay.trade.precreate
然后在业务代码(service层)中调用预下单方法
AlipayTradePrecreateResponse response = AlipayUtil.alipay(String.valueOf(orderPay.getSerialNumber()), orderInfo.getCourseName(), orderInfo.getPricePaid(), sys.getPayUrl(), sys.getNotifyUrl());if(null == response){return Result.error("调用支付失败,请联系商家");}if(response.isSuccess()){//具体返回数据以实际需求为主/***返回参数其中*out_trade_no为订单号*qr_code为二维码,需要使用二维码生成工具生成二维码返回前端显示*/}else{return Result.error("调用支付失败,请联系商家");}
最后是回调函数:
@Controller@RequestMapping(value = "/callback/alipay")public class CallbackAlipayController extends BaseController {@PostMapping("/notify")public String alipayNotify(HttpServletRequest request){boolean signVerified = AlipayUtil.checkSign(request.getParameterMap());if(signVerified){//验证成功String out_trade_no = new String(request.getParameter("out_trade_no")); //商户订单号String trade_no = new String(request.getParameter("trade_no"));//支付宝交易号String trade_status = new String(request.getParameter("trade_status"));//交易状态//判断该笔订单是否在商户网站中已经做过处理//如果没有做过处理,根据订单号(out_trade_no)在商户网站的订单系统中查到该笔订单的详细,并执行商户的业务程序//如果有做过处理,不执行商户的业务程序if(trade_status.equals("TRADE_FINISHED")){//交易结束,不可退款//注意:退款日期超过可退款期限后(如三个月可退款),支付宝系统发送该交易状态通知//可执行修改订单状态等return ("finished");}else if (trade_status.equals("TRADE_SUCCESS")){//交易支付成功//注意:付款完成后,支付宝系统发送该交易状态通知//可执行修改订单状态等return ("success");}else if (trade_status.equals("WAIT_BUYER_PAY")) {//交易创建,等待买家付款//可执行修改订单状态等return ("wait");}else{//未付款交易超时关闭,或支付完成后全额退款(交易失败)//可执行修改订单状态等return ("close");}}else{System.out.println("验证失败,不去更新状态");//可执行修改订单状态等return ("fail");}}}
可以自己在写个定时任务查询订单状态调用AlipayUtil中的queryOrder方法,根据返回状态修改订单。
至此支付宝扫码支付接入完毕!