Java后台支付宝支付接入及详解

上一篇讲了微信支付的三种支付方式(扫码支付、App支付、小程序支付)的接入,今天继续说说以电商项目为代表的Java后端支付宝支付接入及实现。

Java后台支付宝支付接入及详解_第1张图片
image

支付宝支付接入实现在接入前,我们先看看支付宝支付的官方文档:https://open.alipay.com/developmentDocument.htm

Java后台支付宝支付接入及详解_第2张图片
image

本次我主要讲的是“App支付”及“电脑网站支付(扫码支付)”的接入实现。一,准备工作需要有一个支付宝账号,然后登录进入支付宝开放平台,如果之前没有申请入驻过开放平台,第一次进入后需要填相关资料申请,再进入开发者中心,选择创建移动应用。

Java后台支付宝支付接入及详解_第3张图片
image

在选择“支付接入”后,填写对应的资料并添加相应的功能。等申请的应用通过后,再配置相应的开发者设置选项。包含回调地址、接口加密方式及配置密钥。

Java后台支付宝支付接入及详解_第4张图片
image

密钥配置可参考官方文档:https://docs.open.alipay.com/291/106103/。

二,业务流程及原理

扫码支付业务流程图:

Java后台支付宝支付接入及详解_第5张图片
image

App支付业务流程图:

Java后台支付宝支付接入及详解_第6张图片
image

支付宝支付(扫码支付和App支付)业务流程大致总结如下: 1,客户在商户平台下单,生成订单信息;2,调用商户平台的支付接口,商户后台封装参数通过SDK发起支付请求;3,扫码支付方式支付宝后台返回一个html片段(form表单代码),输出到tml页面,展示付款二维码;App支付方式时返回App端发起付款请求的参数,后台再传给App,App端通过请求SDK调起支付宝支付服务;4,扫码支付方式时,客户可用手机的支付宝直接扫码支付或点击右边的“登录账户付款”,登录支付宝支付;app支付时在上一步已经调起了付款服务,只需输入密码付款。5,付款成功后,会跳转到支付宝支付成功的页面,3s跳转到商户的支付成功展示的页面;同时支付宝后台通过异步线程调用回调接口,更新订单付款记录的状态。注意:回调接口只要成功要给支付宝返回“success”,否则支付宝后台认为调用不成功,会多次重复调用。三,编码接入实现

首先,我们需要到支付宝开放平台下载Java版的SDK,然后可以手动将下载到本地的jar导入到maven库,然后在pom文件里配置,依赖如下:



     com.alipay
     sdk-java
     ${alipay-sdk-java.version}

注:我这里的版本号是 20180104135026

使用SDK很是方便,它里面已经封装了签名&验签、HTTP 接口请求等基础功能。只需要我们根据SDK提供的方法传参使用。

AlipayClient alipayClient = new DefaultAlipayClient(URL,APP_ID,APP_PRIVATE_KEY,FORMAT,CHARSET,ALIPAY_PUBLIC_KEY,SIGN_TYPE);

Service接口:

public interface PaymentService {
      /**
       * 

支付宝扫码支付

* * @param orderNo * @param money * @return * @throws Exception */ Map aliQrPayment(String orderNo, double money) throws Exception; /** *

支付宝App支付

* * @param orderNo * @param money * @return * @throws Exception */ Map aliAppPayment(String orderNo, double money) throws Exception; /** *

支付宝回调服务

* * @param orderId * @param tradeNo * @return * @throws Exception */ int aliNotify(String orderNo,String tradeNo) throws Exception; }

Service实现类代码(部分):

@Service(value = "paymentService")
public class PaymentServiceImpl implements PaymentService {
      private static Logger LOGGER = LoggerFactory.getLogger(PaymentServiceImpl.class);
      
      @Autowired
      private PaymentRecordMapper paymentRecordMapper;
  
      @Override
        public Map aliQrPayment(String orderNo, double money) throws Exception {
          LOGGER.info("【支付宝扫码支付】 订单编号="+orderId+",支付金额="+money);
          double payAmount = PayUtil.getPayAmountByEnv(PROJECT_ENV,money);
          Map retMap = new HashMap();
          //添加或更新支付记录到数据库
          int results = this.addOrUpdatePaymentRecord(orderNo, payAmount, PayConstant.PAY_METHOD_ALI, PayConstant.PAY_TRADE_TYPE_QR, false, null,null);
          if(results < 0){
            retMap.put("returnCode", "FAIL");
            retMap.put("returnMsg", "此订单已支付!");
            LOGGER.info("【支付宝扫码支付】  此订单已支付!");
          }else if(results == 0){
            retMap.put("returnCode", "FAIL");
            retMap.put("returnMsg", "支付记录生成或更新失败!");
            LOGGER.info("【支付宝扫码支付】 支付记录生成或更新失败!");
          }else{
            //扫码支付
            String param = PayConstant.ALI_PAY_WEB_PARAMS;
            //返回页面
            String returnUrl = "http://" + PayConfig.PC_SHOP_DOMAIN + PayConstant.ALI_PAY_RETURN_URL+orderNo;
            //调用SDK获得初始化的AlipayClient
            AlipayClient alipayClient = new DefaultAlipayClient("https://openapi.alipay.com/gateway.do", PayConfig.ALI_APP_ID, PayConfig.ALI_PAY_PRIVATE_KEY, "json", "UTF-8", PayConfig.ALI_PAY_PUBLIC_KEY, "RSA"); 
              AlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest();//创建API对应的request
              alipayRequest.setReturnUrl(returnUrl);
              alipayRequest.setNotifyUrl(this.getNotifyUrl(PayConstant.PAY_TYPE_ALI));
              alipayRequest.setBizContent("{" +
                  "\"out_trade_no\":\""+ orderId +"\"," +
                  "\"product_code\":\"FAST_INSTANT_TRADE_PAY\"," +
                  "\"total_amount\":\""+payAmount+"\"," +
                  "\"subject\":\""+param+"\"," +
                  "\"body\":\""+param+"\"" +
                  "}");
              String form = alipayClient.pageExecute(alipayRequest).getBody(); //调用SDK生成表单
            //封装返回实体
            retMap.put("returnCode", PayConstant.SUCCESS);
            retMap.put("returnMsg", PayConstant.OK);
            retMap.put("body", form);
          }
          return retMap;
        }
      @Override
      @Transactional(readOnly=false,rollbackFor={Exception.class})
      public Map aliAppPayment(String orderNo, double money) throws Exception{
          LOGGER.info("【支付宝App支付】开始下单, 订单编号="+orderId);
          Map resultsMap = new HashMap();
          //根据不同服务环境生成支付金额
          double payAmount = PayUtil.getPayAmountByEnv(PROJECT_ENV, money);
          //添加或更新支付记录
          int results = this.addOrUpdatePaymentRecord(.....);
          if(flag < 0){
            resultsMap.put("returnCode", "FAIL");
            resultsMap.put("returnMsg", "此订单已支付!");
            LOGGER.info("【支付宝App支付】 此订单已支付!");
          }else if(flag == 0){
            resultsMap.put("returnCode", "FAIL");
            resultsMap.put("returnMsg", "支付记录生成或更新失败!");
            LOGGER.info("【支付宝App支付】 支付记录生成或更新失败!");
          }else{
            //获得初始化的AlipayClient
            AlipayClient alipayClient = new DefaultAlipayClient("https://openapi.alipay.com/gateway.do", 
            PayConfig.ALI_APP_ID, PayConfig.ALI_PAY_PRIVATE_KEY, "json", "UTF-8", PayConfig.ALI_PAY_PUBLIC_KEY, "RSA"); 
            //实例化具体API对应的request类
            AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();
            //SDK已经封装掉了公共参数,这里只需要传入业务参数。以下方法为sdk的model入参方式(model和biz_content同时存在的情况下取biz_content)。
            AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
            model.setBody(BaseConstants.PLATFORM_COMPANY_NICKAME);
            model.setSubject(BaseConstants.PLATFORM_COMPANY_PREFIX+orderNo);
            model.setOutTradeNo(orderNo);
            model.setTimeoutExpress("24h");
            model.setTotalAmount(String.valueOf(money));            
            model.setProductCode("QUICK_MSECURITY_PAY");
            request.setBizModel(model);
            request.setNotifyUrl(this.getNotifyUrl(PayConstant.PAY_TYPE_ALI));
            //这里和普通的接口调用不同,使用的是sdkExecute
            AlipayTradeAppPayResponse response = alipayClient.sdkExecute(request);
            String orderString = response.getBody();
            resultsMap.put("payParams", orderString);
            resultsMap.put("returnCode", "SUCCESS");
            resultsMap.put("returnMsg", "OK");
          }
          return resultMap;
      }
      
      @Override
      @Transactional(readOnly=false,rollbackFor={Exception.class})
      public int aliNotify(String orderNo,String tradeNo) throws Exception{
          LOGGER.info("【支付宝支付回调】回调数据:"+"orderNo="+orderNo+",tradeNo="+tradeNo);
          //TODO 更新支付订单记录业务代码
          //此处添加自己的更新数据业务代码
          return 0;
      }
}

支付Controller接口层:

@RestController
@RequestMapping(value = "/api/payment/")
public class PaymentController {
    private static Logger logger = LoggerFactory.getLogger(PaymentController.class);
    
    @Value("${spring.profiles.active}")
    private String PROJECT_ENV;
    
    @Value("${error.page}")
    private String ERROR_PAGE;
    
    @Autowired
    private PaymentService paymentService;
    
    @Autowired
    private RedisCacheService cacheService;
    
  /**
   * 支付宝扫码支付接口
   * 
   * @param request
   * @return
   * @throws Exception
   */
  @ResponseBody
  @RequestMapping(value="aliQrPay", method=RequestMethod.POST, produces = {"application/json;charset=UTF-8"})
  public JSONObject qrPay(HttpServletRequest request) throws Exception {
        String requestStr = RequestStr.getRequestStr(request);
        if (StringUtils.isEmpty(requestStr)) {
          throw new ParamException();
        }
         JSONObject jsonObj = JSONObject.parseObject(requestStr);
         if(StringUtils.isEmpty(jsonObj.getString("orderNo"))){
           throw new ParamException();
         }
         //验证订单是否存在
         String orderNo = jsonObj.getString("orderNo");
         JSONObject json = getPayOrder(orderNo);
         if(json == null){
           return AjaxUtil.renderFailMsg("订单不存在!");
         }else if(json.getDouble("payPrice") == null || json.getDouble("payPrice") < 0.01){
           return AjaxUtil.renderFailMsg("订单有误,请确认!");
         }else if(json.getInteger("orderStatus") != OrderConstant.PORDER_STATUS_YTJ){
           String msg = orderInfo.getpStatus() == OrderConstant.PORDER_STATUS_YFK?"此订单已支付!":"无效的订单,请确认!";
           return AjaxUtil.renderFailMsg(msg);
         }else{
             //支付宝扫码支付
             Map resMap = paymentService.aliQrPayment(orderNo, json.getDouble("payPrice"));
             if(PayConstant.SUCCESS.equals(resMap.get("returnCode")) && PayConstant.OK.equals(resMap.get("returnMsg"))){
               String code = UUID.randomUUID().toString().replaceAll("-", "").substring(0, 32);
               cacheService.setCacheToRedis(code, resMap.get("body"), BusinessConstant.IMAGE_VERIFY_CODE_EXPIRE);
               logger.info("【Web扫码支付服务】支付宝支付下单成功!");
               return AjaxUtil.renderSuccessMsg(code,"ok");
             }
             logger.info("【Web扫码支付服务】支付宝支付下单失败!原因:"+resMap.get("returnMsg"));
             return AjaxUtil.renderFailMsg(resMap.get("returnMsg"));
         }
    }
    
  /**
   * 支付宝App支付接口
   * 
   * @param request
   * @return
   * @throws Exception
   */
  @ResponseBody
  @RequestMapping(value="aliAppPay", method=RequestMethod.POST, produces = {"application/json;charset=UTF-8"})
  public JSONObject aliAppPay(HttpServletRequest request) throws Exception {
        String requestStr = RequestStr.getRequestStr(request);
        if (StringUtils.isEmpty(requestStr)) {
          throw new ParamException();
        }
         JSONObject jsonObj = JSONObject.parseObject(requestStr);
         if(StringUtils.isEmpty(jsonObj.getString("orderNo"))){
           throw new ParamException();
         }
         //验证订单是否存在
         String orderNo = jsonObj.getString("orderNo");
         JSONObject json = getPayOrder(orderNo);
         if(json == null){
           return AjaxUtil.renderFailMsg("订单不存在!");
         }else if(json.getDouble("payPrice") == null || json.getDouble("payPrice") < 0.01){
           return AjaxUtil.renderFailMsg("订单有误,请确认!");
         }else if(json.getInteger("orderStatus") != OrderConstant.PORDER_STATUS_YTJ){
           String msg = orderInfo.getpStatus() == OrderConstant.PORDER_STATUS_YFK?"此订单已支付!":"无效的订单,请确认!";
           return AjaxUtil.renderFailMsg(msg);
         }else{
             //支付宝app支付
             Map resMap = paymentService.aliAppPayment(orderNo, json.getDouble("payPrice"));
             if("SUCCESS".equals(resMap.get("returnCode")) && "OK".equals(resMap.get("returnMsg"))){
               //统一下单成功
               resMap.remove("returnCode");
               resMap.remove("returnMsg");
               logger.info("【App支付服务】支付宝支付单成功!");
               return AjaxUtil.renderSuccessMsg(resMap);
             }
             logger.info("【App支付服务】支付宝支付单失败!原因:"+resMap.get("returnMsg"));
             return AjaxUtil.renderFailMsg(resMap.get("returnMsg"));
         }
  }
    
  /**
   * 

支付宝扫码支付获取二维码页面

* * @param request * @param response * @throws Exception */ @ResponseBody @RequestMapping(value="getAliPayHtml", method=RequestMethod.GET, produces = {"application/json;charset=UTF-8"}) public void getAlipayInfo(HttpServletRequest request,HttpServletResponse response) throws Exception{ //获取生成二维码的url try { //获取参数 String code = request.getParameter("payCode"); if(!StringUtils.isEmpty(code) && cacheService.isExistKey(code)){ //调用业务层 String html = (String) cacheService.getCacheByKey(code); response.setContentType("text/html;charset=" + "UTF-8"); response.getWriter().write(html);//直接将完整的表单html输出到页面 response.getWriter().flush(); response.getWriter().close(); }else{ String html = error_page; response.setContentType("text/html;charset=" + "UTF-8"); response.getWriter().write(html);//直接将完整的表单html输出到页面 response.getWriter().flush(); response.getWriter().close(); } }catch(Exception e){ logger.error(e.getMessage()); String html = error_page; response.setContentType("text/html;charset=" + "UTF-8"); response.getWriter().write(html);//直接将完整的表单html输出到页面 response.getWriter().flush(); response.getWriter().close(); } } /** * 支付宝支付完成回调 * * @param request * @param response * @return * @throws Exception */ @ResponseBody @RequestMapping(value="aliNotify") public String aliNotify(HttpServletRequest request,HttpServletResponse response) throws Exception { String tradeStatus = request.getParameter("trade_status");//支付状态 if (tradeStatus.equals("TRADE_FINISHED") || tradeStatus.equals("TRADE_SUCCESS")) { String orderNo= request.getParameter("out_trade_no"); //商户订单号 String tradeNo = request.getParameter("trade_no"); //支付宝订单号 //String total_fee = request.getParameter("total_amount");//支付金额 if(paymentService.aliNotify(orderNo,tradeNo) > 0){ logger.info("【支付宝支付回调响应】 响应内容:success!"); return "success"; } } logger.info("【支付宝支付回调响应】 响应内容:fail!"); return "fail"; } }

四,测试

选择要购买的商品,然后下单,再去发起支付。

Java后台支付宝支付接入及详解_第7张图片
image

点击去支付,调用Java后台的支付接口

Java后台支付宝支付接入及详解_第8张图片
image

注:可能有人发现支付时金额怎么从625变成0.01了,这是后台做了处理,方便测试环境测试。支付成功后,跳转到支付宝付款成功页面。

Java后台支付宝支付接入及详解_第9张图片
image

本文章只是给大家讲解原理和接入思路及实现,所以文章里只放了核心业务代码。还有好多工具类及配置等代码,全放到这里来肯定也不现实,如果有需要完整代码的可关注公众号获取。获取方式扫码关注公众号;找到“关于我”>>>"联系我" ;添加我个人微信获取;

推荐阅读:

微信支付之扫码、APP、小程序支付接入详解

SpringBoot电商项目实战 — ElasticSearch接入实现

SpringBoot电商项目实战 — 商品的SPU/SKU实现

SpringBoot电商项目实战 — 数据库服务化切分

Java后台支付宝支付接入及详解_第10张图片
image

扫码关注公众号,发送关键词获取相关资料:

  1. 发送“Springboot”领取电商项目实战源码;

  2. 发送“SpringCloud”领取cloud学习实战资料;

Java后台支付宝支付接入及详解_第11张图片
image

你可能感兴趣的:(Java后台支付宝支付接入及详解)