1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > springboot整合支付宝沙箱支付

springboot整合支付宝沙箱支付

时间:2020-08-12 17:17:57

相关推荐

springboot整合支付宝沙箱支付

springboot整合支付宝沙箱支付

1.简介

支付宝开发平台地址:/develop/sandbox/app

对于学生来说,目前网上确实没有比较统一而且质量好的支付教程。因为支付对个人开发者尤其是学生来说不太友好。因此,自己折腾两天,算是整理了一篇关于支付宝沙箱支付的文章。况且个人是不能申请支付(wx和alipay)都一样。幸亏有支付宝沙箱这个环境。其实跟正式环境差不多,就换下配置即可。

整体流程

2.配置说明

要记住这几个重要的配置

appId这个是appIdprivateKey商户私钥publicKey支付宝公钥, 即对应APPID下的支付宝公钥notifyUrl支付成功后异步回调地址(注意是必须是公网地址)returnUrl#支付后回调地址signType签名类型 一般写 RSA2charsetutf-8formatjson#网关地址 在支付宝开发平台复制拷贝下来gatewayUrl: /gateway.dologPath: F:\ 日志路径

3.springboot整合支付宝沙箱支付代码

需要导入依赖

<dependency><groupId>com.alipay.sdk</groupId><artifactId>alipay-sdk-java</artifactId><version>4.33.39.ALL</version></dependency>

3.1 配置类

package com.hjt.config;import lombok.Data;import org.springframework.boot.context.properties.ConfigurationProperties;import org.springframework.cloud.context.config.annotation.RefreshScope;import org.springframework.context.annotation.Configuration;import org.springframework.context.annotation.PropertySource;@RefreshScope@Configuration@ConfigurationProperties(prefix = "alipay")@Data/**** @author: hjt* @Date: /11/13/19:19* @Description: 支付宝配置类(读取配置文件)*/public class MyAliPayConfig {/*** APPID*/private String appId;/*** 商户私钥, 即PKCS8格式RSA2私钥*/private String privateKey;/*** 支付宝公钥*/private String publicKey;/*** 服务器异步通知页面路径,需http://格式的完整路径* 踩坑:不能加?type=abc这类自定义参数*/private String notifyUrl;/*** 页面跳转同步通知页面路径,需http://格式的完整路径* 踩坑:不能加?type=abc这类自定义参数*/private String returnUrl;/*** 签名方式*/private String signType;/*** 字符编码格式*/private String charset;/**** 参数编码格式 json*/private String format;/*** 支付宝网关*/private String gatewayUrl;/*** 日志打印地址*/private String logPath;}

3.2 生成订单信息(以java为例,官网例子)

public void doPost (HttpServletRequest httpRequest,HttpServletResponse httpResponse) throws ServletException, IOException {AlipayClient alipayClient = new DefaultAlipayClient( "/gateway.do" , APP_ID, APP_PRIVATE_KEY, FORMAT, CHARSET, ALIPAY_PUBLIC_KEY, SIGN_TYPE); //获得初始化的AlipayClient AlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest(); //创建API对应的request alipayRequest.setReturnUrl( "/CallBack/return_url.jsp" );alipayRequest.setNotifyUrl( "/CallBack/notify_url.jsp" ); //在公共参数中设置回跳和通知地址 alipayRequest.setBizContent( "{" +" \"out_trade_no\":\"0320010101001\"," +" \"product_code\":\"FAST_INSTANT_TRADE_PAY\"," +" \"total_amount\":88.88," +" \"subject\":\"Iphone6 16G\"," + " \"body\":\"Iphone6 16G\"," +" \"passback_params\":\"merchantBizType%3d3C%26merchantBizNo%3d010101111\"," +" \"extend_params\":{" +" \"sys_service_provider_id\":\"2088511833207846\"" +" }" +" }" ); //填充业务参数 String form= "" ;try {form = alipayClient.pageExecute(alipayRequest).getBody(); //调用SDK生成表单 } catch (AlipayApiException e) {e.printStackTrace();}httpResponse.setContentType( "text/html;charset=" + CHARSET);httpResponse.getWriter().write(form); //直接将完整的表单html输出到页面 httpResponse.getWriter().flush();httpResponse.getWriter().close();}

以下是我自己业务代码的例子

@Overridepublic void pay(PayInfoDto payInfoDTO, HttpServletResponse httpResponse) throws IOException {/*查询订单id是否存在*/Long orderId = payInfoDTO.getOrderId();/*商品名称*/String subject = "";/*判断订单是否存在*/R<Order> orderInfo = remoteOrderService.getOrderInfo(orderId);if (orderInfo.getCode() != 200) {throw new BaseException(PayException.ORDER_ERROR_PAY_ORDER);}Order order = orderInfo.getData();//订单总金额BigDecimal total = order.getTotal();String proId = order.getProId();/*商品名称以,分割*/String[] split = proId.split(",");for (int i = 0; i < split.length; i++) {R<Product> productInfo = remoteOrderService.getProductInfo(Long.parseLong(split[i]));if (productInfo.getCode() != 200) {throw new BaseException(PayException.ORDER_ERROR_PAY_PRODUCT);}Product product = productInfo.getData();subject = subject + product.getProTitle() + ",";}//进行支付宝支付AlipayOrder alipayOrder = new AlipayOrder();//商户订单号alipayOrder.setOut_trade_no(String.valueOf(orderId));//订单名称alipayOrder.setSubject(subject);alipayOrder.setDescription(subject);//订单总金额alipayOrder.setTotal_amount(total.toString());/*进行支付*/String payBody = alipayUtil.payByAlipay(alipayOrder);log.info("-----------支付信息实体---------{}",payBody);//并把消息推送到mq查询是否支付成功if(StringUtils.isBlank(payBody)){throw new BaseException(PayException.ORDER_ERROR_PAY_BODY);}/*把支付信息写到html网页中*/httpResponse.setContentType("text/html;charset=" + CHARSET);// 直接将完整的表单html输出到页面httpResponse.getWriter().write(payBody);httpResponse.getWriter().flush();httpResponse.getWriter().close();}

3.3支付成功后的异步通知

@Overridepublic String payNotifyUrl(HttpServletRequest request) throws AlipayApiException {log.info("-----------开始进行支付后的异步通知回调-------");/*接收参数*/Map<String, String> params = this.exchangeParams(request);String payContent = JSONUtil.toJsonStr(params);log.info("---------接收的参数--- -----{}",params);/*验证签名(支付宝公钥) 调用SDK验证签名*/boolean signVerified = AlipaySignature.rsaCheckV1(params, aliPayConfig.getPublicKey(), aliPayConfig.getCharset(), aliPayConfig.getSignType());if (signVerified){/*收到支付宝异步通知,返回success,支付宝不再通知 否则会通知你三天三夜*/log.info("-----验签成功-----");/*应该马上返回"success",另起线程执行自己的业务逻辑*/ExecutorService executor = ExecutorBuilder.create().setCorePoolSize(5).setMaxPoolSize(10).setWorkQueue(new LinkedBlockingQueue<>(100)).build();executor.execute(new Runnable(){@Overridepublic void run() {//TODO 幂等性问题后续也要考虑/*支付状态*/String trade_status = params.get("trade_status");/*订单id*/String out_trade_no = params.get("out_trade_no");/*支付成功*/if (PayConstant.TRADE_FINISHED.equals(trade_status) || PayConstant.TRADE_SUCCESS.equals(trade_status)) {Long orderId = Long.valueOf(out_trade_no);/*把对于的订单id改为已支付状态*/R<Order> order = remoteOrderService.updateOrderById(orderId);if(order.getCode()!=PayConstant.CODE){throw new BaseException(PayException.ORDER_ERROR_PAY_ORDER);}/*存对于的支付信息*/PayInfo payInfo = null;payInfo = PayInfo.builder().orderIds(out_trade_no).callbackContent(payContent).callbackTime(LocalDateTime.now()).tradeStatus(trade_status).tradeNo(params.get("trade_no")).buyerId(params.get("buyer_id")).totalAmount(params.get("total_amount")).version(params.get("version")).sellerId(params.get("seller_id")).receiptAmount(params.get("receipt_amount")).gmtCreate(params.get("gmt_create")).gmtPayment(params.get("gmt_payment")).fundBillList(params.get("fund_bill_list")).build();payInfoMapper.insert(payInfo);log.info("-----支付信息插入成功-------");}/* 支付失败 */else{log.error("-------支付失败, 订单id:------{}",out_trade_no);throw new BaseException(PayException.ORDER_ERROR_PAY_BODY);}}});return "success";// TODO 验签成功后,按照支付结果异步通知中的描述,对支付结果中的业务内容进行二次校验,校验成功后在response中返回success并继续商家自身业务处理,校验失败返回failure} else {log.info("-----验签失败-----");return "failure";// TODO 验签失败则记录异常日志,并在response中返回failure.}}

注意!!!异步通知的地址必须是公网地址,这里我采用的是frp内网穿透到本地的地址

需要注意的是,异步通知必须要严格进行验签。

运行效果图:

先生成订单

然后再浏览器直接调用接口

http://localhost:4401/pay/api/v1/pay-info/pay?Authorization=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.YWRtaW4.VaJOloHfQLjacnm6-__pSaeNZ1JbLAdlgeJT3JEptos&orderId=769532559209283584

会直接跳转到支付支付界面

账号密码都是可以在你沙箱账号看得到

支付成功后可见已经回调到我们异步通知自定义的接口了

即我们在这配置的路径

notifyUrl支付成功后异步回调地址(注意是必须是公网地址)

3.4退款操作

商户可使用该接口查询自已通过alipay.trade.refund提交的退款请求是否执行成功。

注意:1. 该接口的返回码10000,仅代表本次查询操作成功,不代表退款成功,当接口返回的refund_status值为REFUND_SUCCESS时表示退款成功,否则表示退款没有执行成功。

\2. 如果退款未成功,商户可以调用退款接口重试,重试时请务必保证退款请求号和退款金额一致,防止重复退款。

\3. 发起退款查询接口的时间不能离退款请求时间太短,建议之间间隔10秒以上。

个人搭建项目代码地址:

/hongjiatao/spring-boot-anyDemo

欢迎收藏点赞三连。谢谢!有问题可以留言博主会24小时内无偿回复。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。