一、前期准备:

SpringBoot对接支付宝当面付和手机网站支付_springboot 支付宝当面付_Biubiubiuexo的博客-CSDN博客

配置成功后获得到我们开发需要的:支付宝公钥、商户私钥、应用ID

  • 服务商开通链接:支付宝服务商平台
  • 开通服务商之后获取app_auth_token
  • 注:支付宝规定服务商和商户账号需要分离,服务商没有支付能力
  • 服务商开通流程

二、代码实现:

1.新建Merchant商户实体类:

package com.yuheng.payment.models;import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;/*** 收款商户* @author michael* @since  2022/11/15*/
@Getter
@Setter
@Builder
@AllArgsConstructor
public class Merchant {/*** 应用appID*/private String appId;/*** 应用密钥*/private String alipayAppKey;/*** 商户密钥*/private String mchKey;/*** 第三方应用商户token(若为空则为普通支付模式,不为空为服务商代调用模式)*/private String appAuthToken;}

2.支付宝服务层:

package com.yuheng.payment.services;import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.AlipayTradePrecreateModel;
import com.alipay.api.domain.AlipayTradeQueryModel;
import com.alipay.api.domain.AlipayTradeWapPayModel;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayTradePrecreateRequest;
import com.alipay.api.request.AlipayTradeQueryRequest;
import com.alipay.api.request.AlipayTradeWapPayRequest;
import com.alipay.api.response.AlipayTradeWapPayResponse;
import com.ijpay.alipay.AliPayApi;
import com.ijpay.alipay.AliPayApiConfig;
import com.ijpay.alipay.AliPayApiConfigKit;
import com.ijpay.core.kit.HttpKit;
import com.ijpay.core.kit.WxPayKit;
import com.yuheng.payment.constants.PayStatus;
import com.yuheng.payment.exceptions.InternalRuntimeException;
import com.yuheng.payment.exceptions.PrePayResponseException;
import com.yuheng.payment.models.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Map;import static java.lang.System.out;/*** 支付宝官方* @author michael* @since  2022/11/15*/
public class ZhifubaoService implements SuperService {private static final Logger log = LoggerFactory.getLogger(ZhifubaoService.class);private static String serviceUrl = "https://openapi.alipay.com/gateway.do";/*** 支付宝扫码支付* @param request* @param merchant* @return* @throws AlipayApiException*/@Overridepublic PrePayResponse zfbQr(PrePayRequest request, Merchant merchant) throws AlipayApiException {AlipayClient alipayClient = new DefaultAlipayClient(serviceUrl,merchant.getAppId(),merchant.getMchKey(),"json","UTF-8",merchant.getAppKey(),"RSA2");AlipayTradePrecreateRequest alipayTradePrecreateRequest = new AlipayTradePrecreateRequest();alipayTradePrecreateRequest.setReturnUrl(request.getReturnUrl());alipayTradePrecreateRequest.setNotifyUrl(request.getNotifyUrl());JSONObject bizContent = new JSONObject();bizContent.put("out_trade_no", request.getOrderNo());// 传入金额单位为 分,换成支付宝单位 元bizContent.put("total_amount", Double.toString(request.getAmount() / 100.00));bizContent.put("subject", request.getBody());alipayTradePrecreateRequest.setBizContent(bizContent.toString());String resultStr = null;// 为第三方应用代调用模式if (StrUtil.isNotEmpty(merchant.getAppAuthToken())){alipayTradePrecreateRequest.putOtherTextParam("app_auth_token", merchant.getAppAuthToken());resultStr = alipayClient.execute(alipayTradePrecreateRequest,null,merchant.getAppAuthToken()).getBody();}else {// 普通商家模式resultStr = alipayClient.execute(alipayTradePrecreateRequest).getBody();}JSONObject jsonObject = JSONObject.parseObject(resultStr).getJSONObject("alipay_trade_precreate_response");String code = jsonObject.getString("code");if (!"10000".equals(code)){log.error("支付发起失败{}", jsonObject.getString("sub_msg"));}String qrCode = jsonObject.getString("qr_code");String outTradeNo = jsonObject.getString("out_trade_no");
//        return jsonObject.getJSONObject("alipay_trade_precreate_response").getString("qr_code");return PrePayResponse.builder().orderNo(outTradeNo).isRedirect(false).payText(qrCode).payStatus(PayStatus.PAYING).build();}/*** 手机网页支付* @param* @param merchant* @param request* @return* @throws AlipayApiException*/@Overridepublic PrePayResponse zfbWeb(PrePayRequest request, Merchant merchant) throws AlipayApiException, IOException {AlipayClient alipayClient = new DefaultAlipayClient(serviceUrl,merchant.getAppId(),merchant.getMchKey(),"json","UTF-8",merchant.getAppKey(),"RSA2");AlipayTradeWapPayRequest alipayTradeWapPayRequest = new AlipayTradeWapPayRequest();alipayTradeWapPayRequest.setNotifyUrl(request.getNotifyUrl());alipayTradeWapPayRequest.setReturnUrl(request.getReturnUrl());JSONObject bizContent = new JSONObject();bizContent.put("out_trade_no", request.getOrderNo());// 传入金额单位为 分,换成支付宝单位 元bizContent.put("total_amount", Double.toString(request.getAmount() / 100.00));bizContent.put("subject", request.getBody());bizContent.put("product_code", "QUICK_WAP_WAY");alipayTradeWapPayRequest.setBizContent(bizContent.toString());// 为第三方应用代调用模式if (StrUtil.isNotEmpty(merchant.getAppAuthToken())){alipayTradeWapPayRequest.putOtherTextParam("app_auth_token", merchant.getAppAuthToken());}AlipayTradeWapPayResponse alipayTradeWapPayResponse = alipayClient.pageExecute(alipayTradeWapPayRequest,"get");String path = alipayTradeWapPayResponse.getBody();return PrePayResponse.builder().payText(path).isRedirect(false).payStatus(PayStatus.PAYING).build();}/*** @param request* 支付宝异步通知* @return*/@Overridepublic PayNotify payNotify(HttpServletRequest request) {// 获取支付宝POST过来反馈信息Map<String, String> params = AliPayApi.toMap(request);log.debug("收到支付宝支付原始通知:"+params);PayNotify notifyResponse = PayNotify.builder().orderNo(params.get("out_trade_no")).outOrderNo(params.get("trade_no")).payStatus(PayStatus.PAYING).build();if ("TRADE_SUCCESS".equals( params.get("trade_status"))) {notifyResponse.setPayTime(timeFormat(params.get("gmt_payment")));notifyResponse.setPayStatus(PayStatus.PAID);}notifyResponse.setRawSignObject(params);return notifyResponse;}/*** 签名验证* @param response* @param merchant* @return* @throws AlipayApiException*/@Overridepublic boolean verifyPayNotify(PayNotify response, Merchant merchant) throws AlipayApiException {return AlipaySignature.rsaCheckV1((Map<String, String>) response.getRawSignObject(), merchant.getAppKey(), "UTF-8", "RSA2");}/*** 根据订单号进行查询* @param orderNo 内部订单编号* @param merchant 商户信息* @return* @throws AlipayApiException*/@Overridepublic PayResult payOrderQuery(String orderNo, Merchant merchant) throws AlipayApiException {AlipayClient alipayClient = new DefaultAlipayClient(serviceUrl,merchant.getAppId(),merchant.getMchKey(),"json","GBK",merchant.getAppKey(),"RSA2");AlipayTradeQueryRequest alipayTradeQueryRequest = new AlipayTradeQueryRequest();JSONObject bizContent = new JSONObject();bizContent.put("out_trade_no", orderNo);alipayTradeQueryRequest.setBizContent(bizContent.toString());alipayTradeQueryRequest.putOtherTextParam("app_auth_token",merchant.getAppAuthToken());String body =  alipayClient.execute(alipayTradeQueryRequest).getBody();JSONObject jsonObject = JSONObject.parseObject(body).getJSONObject("alipay_trade_query_response");String code = jsonObject.getString("code");if (!"10000".equals(code)){throw new InternalRuntimeException("发起查询失败,原因["+code+":"+ jsonObject.getString("sub_msg")+"]");}String tradeStatus = jsonObject.getString("trade_status");PayStatus payStatus;switch (tradeStatus){case "TRADE_FINISHED" :payStatus = PayStatus.FINISHED;break;case "TRADE_SUCCESS" :payStatus = PayStatus.PAID;break;case "TRADE_CLOSED" :payStatus = PayStatus.CLOSE;break;default:payStatus = PayStatus.PAYING;}return PayResult.builder().outOrderNo(jsonObject.getString("trade_no")).orderNo(jsonObject.getString("out_trade_no")).payStatus(payStatus).build();}/*** 时间戳转时间字符串* @param timeStr 时间戳Long* @return String 时间*/private Long timeFormat(String timeStr){DateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmss");try {return dateFormat.parse(timeStr).getTime();} catch (ParseException e) {e.printStackTrace();}return null;}/*** 时间戳转时间字符串* @param time 时间戳Long* @return String 时间*/private String timeFormat(Long time){return new SimpleDateFormat("yyyyMMddHHmmss").format(time);}}

3.支付宝实现层:

private static Merchant getMerchant(){return Merchant.builder().appId("服务商的应用ID").mchKey("服务商的商户密钥").alipayAppKey("服务商的支付宝公钥").appAuthToken("商户授权成功后得到的TOKEN").build();}/*** 二维码扫码支付*/@Testpublic void testPay(){Client client = Client.newInstance(PaySuper.ALIPAY);PrePayRequest request = PrePayRequest.builder().amount(1).body("支付宝扫码支付测试").payMethod(PayMethod.ZFB_QR).notifyUrl("你的异步通知地址").build();PrePayResponse response = client.prePay(request,getMerchant());System.out.println(JSONUtil.toJsonStr(response));}/*** 根据外部订单号进行查询*/@Testpublic void testQuery(){Client client = Client.newInstance(PaySuper.ALIPAY);PayResult response = client.payOrderQuery("订单号",getMerchant());System.out.println(JSONUtil.toJsonStr(response));}/*** 注意:订单创建实际创建时间也为用户支付时间,非唤起收银台时间。* @param*/@Testpublic void wapPay(){Client client = Client.newInstance(PaySuper.ALIPAY);PrePayRequest request = PrePayRequest.builder().amount(1).body("支付宝网页支付测试").payMethod(PayMethod.ZFB_WEB).returnUrl("你的回调地址").notifyUrl("你的异步通知地址").build();PrePayResponse prePayResponse = client.prePay(request, getMerchant());System.out.println(JSONUtil.toJsonStr(prePayResponse));}@Testpublic static void main(String[] args) throws AlipayApiException {Client client = Client.newInstance(PaySuper.ALIPAY);//回调的待验签字符串String resultInfo = "异步通知地址返回的通知信息";//对待签名字符串数据通过&进行拆分String [] temp = resultInfo.split("&");HashMap<String, String> map =  new HashMap<String, String>();//把拆分数据放在map集合内for (int i = 0; i < temp.length; i++) {String[] arr = temp[i].split("=", 2); //通过"="号分割成2个数据String[] tempAagin = new String[arr.length]; //再开辟一个数组用来接收分割后的数据for (int j = 0; j < arr.length; j++) {tempAagin[j] = arr[j];}map.put(tempAagin[0], tempAagin[1]);}System.out.println(map);//验签方法PayNotify payNotify = PayNotify.builder().rawSignObject(map).build();boolean signVerified = client.verifyPayNotify(payNotify,getMerchant());if(signVerified){// TODO 验签成功后System.out.println("success");}else{System.out.println("fail");}}

4.商户授权服务商平台 :授权流程https://opensupport.alipay.com/support/helpcenter/198/201602494631?ant_source=manual&recommend=9784af7814a1ec663089e796d8a7b4ce

(1)拼接授权URL:

public String AuthorizationUrl(String mchId,String outAppId) throws AlipayApiException {// 第一步拼接授权地址,商户扫码进行授权com.yuheng.payment.models.Merchant serviceMerchant = getServiceMerchant(outAppId);AlipayClient alipayClient = new DefaultAlipayClient(serviceUrl,serviceMerchant.getAppId(),serviceMerchant.getMchKey(),"json","GBK",serviceMerchant.getAppKey(),"RSA2");AlipayOpenAuthAppauthInviteCreateRequest request = new AlipayOpenAuthAppauthInviteCreateRequest();String redirectUrl = getRedirectUrl();JSONObject bizContent = new JSONObject();bizContent.put("auth_app_id",serviceMerchant.getAppId());bizContent.put("redirect_url",redirectUrl);request.setBizContent(bizContent.toString());AlipayOpenAuthAppauthInviteCreateResponse response = alipayClient.execute(request);System.out.println("::::::::::::" + response.getTaskPageUrl());return "https://openauth.alipay.com/oauth2/appToAppAuth.htm?app_id="+ serviceMerchant.getAppId()  // 第三方应用ID+"&redirect_uri="+"http://192.168.1.189:8005/api/merchant/redirect"+"&state="+mchId;/*return "https://openauth.alipay.com/oauth2/appToAppAuth.htm?app_id="+ appId  // 第三方应用ID+"&redirect_uri="+"https://xqht.hnyuheng.net/";*/}@Override@Transactional(rollbackFor = Exception.class)public void updateAppAuthTokenById(String appAuthToken, String id) {merchantRepository.addAppAuthTokenById(appAuthToken,id);}@Overridepublic MerchantDto selectServiceMerchant(String appId) {Merchant merchant = merchantRepository.findByAppIdAndIsService(appId,true);return merchantMapper.toDto(merchant);}private String getRedirectUrl(){return RequestHolder.getAppUrl() + "/api/merchant/redirect/";}

(2)商户点击链接或扫码成功授权后回调地址返回app_auth_token(回调地址一定要与第三方应用配置的回调地址一模一样)

授权回调接口:

package com.yuheng.modules.mch.rest;import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.request.AlipayOpenAuthTokenAppRequest;
import com.alipay.api.response.AlipayOpenAuthTokenAppResponse;
import com.yuheng.annotation.AnonymousAccess;
import com.yuheng.exception.BadRequestException;
import com.yuheng.modules.mch.constant.PayType;
import com.yuheng.modules.mch.domain.MchApp;
import com.yuheng.modules.mch.service.MchAppService;
import com.yuheng.modules.mch.service.MerchantService;
import com.yuheng.modules.mch.service.dto.MerchantDto;
import com.yuheng.payment.constants.PaySuper;
import com.yuheng.payment.models.Merchant;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;/*** 支付宝商户授权成功后返回地址* @author liuzhaojun* @createDate 2023-03-29 10:13*/
@Slf4j
@RestController
@RequestMapping("/api/merchant/redirect")
@RequiredArgsConstructor
public class AlipayRedirectURLController {// 服务环境@Value("${alipay.serviceUrl}")private String serviceUrl;private final MerchantService merchantService;private final MchAppService mchAppService;@GetMapping@AnonymousAccesspublic ResponseEntity<Object> redirectURL(@RequestParam(value = "app_id") String outAppId, @RequestParam("state") String mchId, @RequestParam("source") String source, @RequestParam("app_auth_code") String appAuthCode) throws AlipayApiException {// 商户同意授权之后支付宝回调参数--->用appAuthCode换取appAuthTokenMerchant serviceMerchant = getServiceMerchant(outAppId);if (ObjectUtil.isNull(serviceMerchant)) throw new BadRequestException("未查到服务商信息");AlipayClient alipayClient = new DefaultAlipayClient(serviceUrl,outAppId,serviceMerchant.getMchKey(),"json","GBK",serviceMerchant.getAppKey(),"RSA2");System.out.println("app_id=" + outAppId + ";source=" + source + ";app_auth_code=" +appAuthCode + ";state=" + mchId);JSONObject bizContent = new JSONObject();// 授权方式为通过授权码授权bizContent.put("grant_type","authorization_code");bizContent.put("code",appAuthCode);AlipayOpenAuthTokenAppRequest request = new AlipayOpenAuthTokenAppRequest();request.setBizContent(bizContent.toString());AlipayOpenAuthTokenAppResponse response = alipayClient.execute(request);if(response.isSuccess()){System.out.println("Token:::::::::::" + response.getAppAuthToken());System.out.println("RefreshToken:::::::::::" + response.getAppRefreshToken());// 新增字段app_auth_tokenmerchantService.updateAppAuthTokenById(response.getAppAuthToken(),mchId);// 将商户状态改为激活merchantService.enable(mchId);return new ResponseEntity<>(HttpStatus.OK);} else {String errorInfo = JSONObject.toJSONString(response);log.error("调用失败" + errorInfo);return new ResponseEntity<>(errorInfo,HttpStatus.BAD_REQUEST);}}private Merchant getServiceMerchant(String outAppId){// 此处appId是支付宝应用ID (应用表的外部应用ID) => 查出上游为支付宝且绑定了支付宝第三方应用的商户信息MchApp mchApp = mchAppService.findByOutAppId(outAppId, PaySuper.ALIPAY.getName(), PayType.ALIPAY_THIRD.getCode());// 查出服务商信息(以字段is_service为判断依据)MerchantDto merchantDto = merchantService.selectServiceMerchant(mchApp.getId());return new Merchant(mchApp.getOutAppId(), mchApp.getOutAppSecret(),merchantDto.getOutMchId(),merchantDto.getOutMchKey(),"");}}

关于回调地址:

对接支付宝服务商当面付手机网页支付相关推荐

  1. 支付宝当面付扫码支付支付后不回调_对接支付宝当面付进行电脑网站和手机网站收款教程...

    对接支付宝当面付进行电脑网站和手机网站收款教程 第一步:风铃自动卡密发卡平台前端搭建 第二步:对接支付宝当面付进行电脑网站和手机网站收款 项目地址:https://github.com/Tai7sy/ ...

  2. 支付宝 当面付(扫描支付) 对接逻辑

    支付宝 当面付(扫描支付) 对接逻辑 这两天给网站 博客下方添加了 打赏功能 使用的是 支付宝的 当面付功能 特此记录一下,觉得不错的可以在下方打赏 嘿嘿 ,下面先来看一下效果图. 1.当面付产品介绍 ...

  3. 支付宝当面付扫码支付接口开发

    最近公司要做一个有关支付的相关项目,需要对接支付宝的支付接口,实现扫描二维码支付功能,为此研究了一下支付宝相关业务.主要依据就是支付宝的相关接口文档: https://docs.open.alipay ...

  4. 支付宝当面付-扫码支付

    1.需要jar包 2.请求支付 private static AlipayTradeService tradeService;@Autowiredstatic {/** 一定要在创建AlipayTra ...

  5. 新版支付宝开放平台 手机网页支付 整个流程

    新版支付宝开放平台  手机网页支付 整个流程 在支付宝签约如下产品 然后,使用支付宝最新的签名工具生成商户的私钥和公钥 值得注意的是,如果是.net c# 请选择PKCS1,我只采用1024密钥长度. ...

  6. 支付宝手机网页支付java demo调试问题和解决办法

    在使用支付宝手机网页支付的时候遇到一些问题跟大家分享一下. 1.生成签名的时候,使用Base64加密时报错:DerInputStream.getLength():lengthTag = 127, to ...

  7. php手机网站支付宝_php支付宝手机网页支付类实例

    本文实例讲述了php支付宝手机网页支付类.分享给大家供大家参考.具体分析如下: 此处注意: ① 该类是用在Yii框架里面的,没有去掉一些框架的东西. ② 本类不能不做任何修改而使用. 1. PHP代码 ...

  8. 支付宝手机网页支付之golang版

    本文章主要是通过golang实现了支付宝手机网页支付的简单封装,封装的基本都是请求的必传参数,如果需要其他参数,可以自己修改BizContent结构体来满足自己的需求. 封装的文件大体分为4个文件: ...

  9. android 仿支付页面,【android仿系列进阶篇】android 支付宝手机网页支付

    最近在做android-,恩,就说这么多吧 1,准备工作 当然了,假设你已经有了pid(partner)和商户账户(seller),并且开通了手机网页支付功能. 下载的包里面,打开[手机网页即时到账接 ...

最新文章

  1. linux下的ping脚本,Linux下检测服务器Ping值的Shell脚本
  2. iOS 完美解决 interactivePopGestureRecognizer 卡住的问题
  3. 移动端应用类型及特点
  4. ASP.NET CORE MVC 2.0 如何在Filter中使用依赖注入来读取AppSettings
  5. 数据结构+算法面试100题~~~摘自CSDN,作者July
  6. 关于使用 jquery Validate 使用出现的问题
  7. Spring MVC –使用@ResponseBody轻松实现基于REST的JSON服务
  8. cpu system linux,LINUX system BOOT
  9. UI 07 _ 导航视图控制器 与 属性传值
  10. VC下发布的Release版程序的异常捕捉
  11. Windows 7服务器版 2008 R2安装图解
  12. centos 6.8部署nginx
  13. 转:tomcat7源码导入Eclipse
  14. 【IIOT】欧姆龙PLC数采之CP2E
  15. 佳能ts9020墨盒不识别_打印机 篇一:Canon 佳能 TS9120 开箱使用体验、墨水和无线网连接...
  16. 音乐鉴赏 周海宏 网络课程 题库(Ctrl+f查找)点赞哦
  17. cad怎么将图层后置_Auto CAD2014图层后置快捷键是什么啊?
  18. 安卓10和android区别,华为8月9日发布安卓10.0系统 华为EMUI 10.0功能及适配机型 华为安卓系统和鸿蒙OS区别...
  19. 评估智能对话机器人的7大数据指标
  20. BHEX创始人巨建华鲲鹏会分享:创业路上从不孤单

热门文章

  1. 摩根士丹利 java笔试_摩根士丹利面经之笔试和试题
  2. 4. MySQL数据库管理系统(MySQL的下载安装、配置、补丁 一站式)
  3. 〖Python 数据库开发实战 - Redis篇⑤〗- Redis 的常用配置参数
  4. 【rtthread设备】第一篇:pin设备
  5. 与计算机相关的1000字论文,计算机毕业论文1000字-计算机毕业论文范文500字?
  6. SQL学习之where语句
  7. 前端自动化测试框架Jest介绍和使用
  8. CF - 784A. Numbers Joke - 瞎猜
  9. AI工具合集!一共600+覆盖全行业,除了ChatGPT,那你也会喜欢这些其他的AI工具
  10. 解决WIN10的cmd无法使用的问题