java 對接支付寶支付

對接支付寶支付的前提:

1,商戶開通支付能力

登錄螞蟻金服 開放平臺:https://open.alipay.com/platform/home.htm

需要開通 的功能選項有:

創建應用,類型是:網頁&移動應用

設置應用的RSA 等各項參數,界面如下:

支付寶推薦使用RSA2 加密方式,老版的加密方式只有RSA 和md5,沒有RSA2.

本項目使用RSA2 加密方式

2,對接支付寶依賴的jar包

 <!-- https://mvnrepository.com/artifact/net.guerlab/sdk-alipay-core -->
        <dependency>
            <groupId>net.guerlab</groupId>
            <artifactId>sdk-alipay-core</artifactId>
            <version>1.0.3</version>
        </dependency>

 

我寫了一個專門封裝對接支付寶的Service 層

見代碼:https://gitee.com/kunlunsoft/pay_service.git

項目結構:

發起支付 控制器(需根據實際情況修改):

下面的"/order/startPay"接口

package com.girltest.web.controller.pay;

import com.common.annotation.NoLogin;
import com.common.bean.BaseResponseDto;
import com.common.dict.Constant2;
import com.common.util.RedisHelper;
import com.common.util.SystemHWUtil;
import com.girltest.dao.AlipayNotifySuccessDao;
import com.girltest.dao.BusinessOrderDao;
import com.girltest.entity.BusinessOrder;
import com.house.ujiayigou.thirdpart.alipay.config.AlipayConfig;
import com.house.ujiayigou.thirdpart.alipay.info.PayFormInfo;
import com.string.widget.util.RandomUtils;
import com.string.widget.util.ValueWidget;
import com.time.util.TimeHWUtil;
import com.yunmasoft.service.pay.AlipayNotifySuccessService;
import com.yunmasoft.service.pay.alipay.AliPayService;
import com.yunmasoft.service.pay.alipay.PayOperation;
import com.yunmasoft.service.pay.alipay.PayService;
import oa.entity.AlipayNotifySuccess;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.math.BigDecimal;
import java.util.Date;

/**
 * Created by tonyjiang on 15/8/28.
 */

@Controller
public class PayOrderController {

    @Resource(name = "alipay")
    private AliPayService aliPayService;
    public static org.slf4j.Logger HttpClientRestLogger = LoggerFactory.getLogger("pay_log");
    //    @Resource
//    private OrderDetailViewModel orderDetailViewModel;
    @Resource
    private AlipayNotifySuccessDao alipayNotifySuccessDao;
    @Resource
    private AlipayNotifySuccessService alipayNotifySuccessService;
    @Resource
    private BusinessOrderDao businessOrderDao;

    /***
     * 抹掉小數點後面的零頭
     *
     * @param orderPrice
     * @return
     */
    private static String removeDecimalPoint(BigDecimal orderPrice) {
        String formatPrice = ValueWidget.formatBigDecimal(orderPrice);

        return formatPrice;
    }

    private static void checkOrderStatus(int orderStatus) {
        if (orderStatus == Constant2.ORDERSTATUS_PAID_ALREADY) {
            //支付完成,調到支付成功頁
//            LogicBusinessException.throwException("alreadyPaid");
        } else if (orderStatus == Constant2.ORDERSTATUS_CANCELLED) {
            //已經取消了訂單
//            LogicBusinessException.throwException("alreadyCancel");
        }
    }


    /***
     * 通過redis 獲取訂單的支付結果:是否支付成功
     * @param request
     * @param response
     * @param httpSession
     * @param model
     * @param orderNo
     * @return
     */
    @RequestMapping("/order/payOrderResult")
    @ResponseBody
    public String getOrderPayResult(HttpServletRequest request, HttpServletResponse response, HttpSession httpSession, Model model,
                                    @RequestParam(value = "orderNo", required = true) String orderNo) {
        BaseResponseDto baseResponseDto = new BaseResponseDto(PayService.isPaySuccess(orderNo));
        return baseResponseDto.toJson();
    }


    /***
     * 下單頁
     * @param model
     * @param request
     * @param response
     * @param release
     * @return
     */
    @RequestMapping(value = "/order/place", produces = SystemHWUtil.RESPONSE_CONTENTTYPE_JSON_UTF)
    public String json2(Model model, HttpServletRequest request, HttpServletResponse response
            , @RequestParam(required = false, defaultValue = "true") Boolean release) {
        String orderNo = "Xr20001" + RandomUtils.getNextInt();
        model.addAttribute("orderNo", orderNo);
        return "pay/wap/placeorder";
    }

    /***
     * 步驟:
     * 1,獲取當前用戶信息
     * 2,根據訂單號查詢訂單詳情
     * 3,校驗訂單狀態和支付方式
     * 4,跳轉到第三方支付
     * @param request
     * @param response
     * @param httpSession
     * @param model
     * @param orderNo
     * @param callback
     * @return
     * @throws Exception
     */
    @RequestMapping("/order/startPay")
    @NoLogin
    public String startPay(HttpServletRequest request, HttpServletResponse response, HttpSession httpSession, Model model,
                           @RequestParam(value = "orderNo", required = true) String orderNo,
                           @RequestParam(value = "callback", required = false) String callback
            , BigDecimal shouldPay) throws Exception {


        //p判斷該訂單號是否已經存在
        AlipayNotifySuccess alipayNotifySuccess = this.alipayNotifySuccessService.getAlipayNotifySuccess(orderNo);
        if (null != alipayNotifySuccess) {
            model.addAttribute("errorMessage", "該訂單號已經存在,orderNo:" + orderNo);
            return "pay/alipay";
        }

        // 判斷訂單號是否存在
        BusinessOrder businessOrder = this.businessOrderDao.get("orderNo", orderNo);
        if (null == businessOrder) {
            model.addAttribute("errorMessage", "該訂單號不存在,orderNo:" + orderNo);
            return "pay/alipay";
        }
/*
        //保存訂單
        businessOrder = new BusinessOrder();
        businessOrder.setOrderNo(orderNo);
        businessOrder.setTotalPrice(shouldPay);

        CreateTimeUtil.fillTime(businessOrder);
        this.businessOrderDao.add(businessOrder);*/
        //獲取當前用戶信息

        //7.應付金額
        String strShouldPay = null;
        if (ValueWidget.isNullOrEmpty(shouldPay)) {
            shouldPay=businessOrder.getPrice();
        }
        strShouldPay = ValueWidget.formatBigDecimal(shouldPay);
        //8. 賬戶
        String sellerAccount = AlipayConfig.seller_email;

        //9.其它
//        RedisHelper.getInstance().saveKeyCache(PayService.REDIS_KEY_STORE_ORDER_PAY_TIME, orderNo, TimeHWUtil.formatDate(new Date(), TimeHWUtil.YYYYMMDD_NO_LINE));
        String orderName = businessOrder.getProductBaseInfo().getDisplayName();
        //10.
        com.house.ujiayigou.thirdpart.alipay.info.PayFormInfo payFormInfo = new PayFormInfo();
        payFormInfo.setOut_trade_no(orderNo);
        payFormInfo.setSubject(orderName);
        payFormInfo.setBody(orderName);
        payFormInfo.setTotal_amount(strShouldPay);
        payFormInfo.setSeller_id(sellerAccount);
        String form = aliPayService.preparePostRequest(payFormInfo);
        HttpClientRestLogger.error("form:" + form);
        model.addAttribute("form", form);

        return "pay/alipay";


    }

    /**
     * 1,獲取訂單;
     * 2,價格;
     * 3,Identify;
     * 4,第三方支付相關接口service;
     * 5,callback
     * 6,coupon
     * 7,應付金額
     * 8,賬戶
     * 9,其它
     * 10,
     *
     * @param access_token
     * @param orderNo
     * @param payType
     * @param callback
     * @return
     */
    public String postThirdPayAction(String access_token, String orderNo, String payType, String callback) {
        //訂單
       /* OrderInfoBean orderInfo = orderBusiness.getOrderInfoByOrderNo(access_token, orderNo);
        if (orderInfo == null || orderInfo.getItems().size()==0) {
            LogicBusinessException.throwException("cannotMatchOrder");
        }
        checkOrderStatus(orderInfo.orderStatus);
        if (orderInfo.orderStatus != Constant.ORDERSTATUS_ORDERS_SUBMITTED) {
            LogicBusinessException.throwException("20506");
        }*/
        //2.價格
        BigDecimal price = null;//orderBusiness.getOrderMoney(orderInfo);
        if (price == null) {
//            LogicBusinessException.throwException("cannotPay");
        }
        //3.Identify
        String identifier = null;//orderBusiness.getPayIdentify(orderNo, access_token, userInfo, price);


        PayOperation service = null;//(PayOperation) SpringMVCUtil.getBean( payType);
        if (service == null) {
//            LogicBusinessException.throwException("service is null");
        }

        //5.callback
        if (ValueWidget.isNullOrEmpty(callback)) {
            callback = "https:/order/view?orderNo=" + orderNo /*+ "&orgId=" + orgId*/;//千萬不要URL轉碼
        }
        //6.coupon
        BigDecimal coupon = null;
        /*if (Constant.useDebugCouponValue) {
            coupon = new BigDecimal(Constant.couponValue);
        } else {*/
        coupon = new BigDecimal(0);
//        }

        //7.應付金額
        BigDecimal shouldPay = price.subtract(coupon.compareTo(price) < 0 ? coupon : new BigDecimal(0));//
        String strShouldPay = ValueWidget.formatBigDecimal(shouldPay);
        //8. 賬戶
        String sellerAccount = AlipayConfig.seller_email;

        //9.其它
        RedisHelper.getInstance().saveKeyCache(PayService.REDIS_KEY_STORE_ORDER_PAY_TIME, orderNo, TimeHWUtil.formatDate(new Date(), TimeHWUtil.YYYYMMDD_NO_LINE));
        String orderName = "xxx服務";
        //10.
        com.house.ujiayigou.thirdpart.alipay.info.PayFormInfo payFormInfo = new PayFormInfo();
        payFormInfo.setOut_trade_no(orderNo);
        payFormInfo.setSubject(orderName);
        payFormInfo.setBody(orderName);
        payFormInfo.setTotal_amount(strShouldPay);
        payFormInfo.setSeller_id(sellerAccount);
        String form = service.preparePostRequest(payFormInfo);

        return form;

    }


}

 

支付回調控制器(需根據實際情況修改):

下面的"/notify"接口

import com.common.dict.Constant2;
import com.common.util.*;
import com.yunmasoft.service.pay.alipay.PayOperation;
import com.io.hw.json.HWJacksonUtils;
import com.string.widget.util.ValueWidget;
import oa.util.SpringMVCUtil;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Map;

@Controller
@RequestMapping("/pay")
public class PayController {
    public static Logger logger = Logger.getRootLogger();

    @RequestMapping(value = "notify", produces = {SystemHWUtil.RESPONSE_CONTENTTYPE_JSON_UTF})
    @ResponseBody
    public String callback(
            @RequestParam(required = false) String method,
            @RequestParam(required = false) String out_trade_no/*訂單號*/,
            @RequestParam(required = false) String trade_no,
            @RequestParam(required = false) String trade_status,
            @RequestParam(required = false) String extra_common_param,
            @RequestParam(required = false) String notifyUrl,
            @RequestParam(required = false) String body/*只有支付寶手機網站支付纔有*/,
            HttpServletResponse response,
            HttpServletRequest request) {
        //userIdAndLoginnameAndOrgId 在請求參數中
        // 1.獲取訂單號
        if (ValueWidget.isNullOrEmpty(out_trade_no)) {
            out_trade_no = request.getParameter("outer_trade_no");
        }

        // 2.暢捷支付沒有extra_common_param,兼容暢捷支付
        if (ValueWidget.isNullOrEmpty(extra_common_param) && !ValueWidget.isNullOrEmpty(notifyUrl)) {//added by huangweii
            Map argMap = RequestUtil.parseQueryString(notifyUrl);
            extra_common_param = (String) argMap.get("chanpay");
        }

        logger.info(HWJacksonUtils.getJsonP(request.getParameterMap()));


        // 3.兼容extra_common_param爲空的情況
        boolean isAlipayMobile = false;
        if (ValueWidget.isNullOrEmpty(extra_common_param)) {//added by huangweii,extra_common_param爲空,說明是xx支付
            String extra_common_paramSuffix = RedisHelper.getInstance().getCache("store_" + out_trade_no + "_Identifier") +
                    "::" + RedisHelper.getInstance().getCache("store_" + out_trade_no + "_userinfo");
            if (ValueWidget.isNullOrEmpty(request.getParameter("out_trade_no"))) {
                extra_common_param = "chanpay::" + extra_common_paramSuffix;
            } else {
                isAlipayMobile = true;
                extra_common_param = "alipay::" + extra_common_paramSuffix;
            }

        }

        // 4. 緩存日誌
//        String currentCache = RedisHelper.getInstance().getKeyCache(Constant.REDIS_ID_STORE, out_trade_no) + "<br>";
//        RedisHelper.getInstance().saveKeyCacheAndExpire(Constant.REDIS_ID_STORE, out_trade_no, currentCache +request.getRequestURI()+ extra_common_param + ",notifyUrl:" + notifyUrl);

        logger.info("extra_common_param:" + extra_common_param);
        // 獲取支付寶POST過來反饋信息

        Map requestParams = request.getParameterMap();

        Map<String, String> params = WebServletUtil.getParamMap(requestParams);
//        params.put("userIdAndLoginnameAndOrgId", userIdAndLoginnameAndOrgId);


        // 5.獲取service
        PayOperation service = null;
        if (extra_common_param != null && extra_common_param.contains("::")) {

            String[] info = extra_common_param.split("::");
            service = (PayOperation) SpringMVCUtil.getBean(request, info[0]);
        }

        if (service == null) {
            return "fail";
        }


        // 6.驗籤
        String verity_ok = service.verify(WebServletUtil.getParamMap(requestParams));

        if (!verity_ok.equals("success")) {
            logger.error(params.toString());
            logger.error("verify fail");
            return verity_ok;
        }

        // 7. 緩存日誌
//        currentCache = RedisHelper.getInstance().getKeyCache(Constant.REDIS_ID_STORE, out_trade_no) + "<br>";
//        RedisHelper.getInstance().saveKeyCacheAndExpire(Constant.REDIS_ID_STORE, out_trade_no, currentCache + "verity->" + verity_ok);

        

        // 8.回調,調用確認訂單接口
        try {
            String pay_ok = service.payNotify(out_trade_no, trade_no, trade_status, params);
            if (pay_ok != null) {
                logger.debug(pay_ok + "");
                return pay_ok; // 請不要修改或刪除
            }
        } catch (Exception ex) {
            logger.error("payNOtify error:", ex);
            return "fail";
        }


        return "fail";

    }


    @RequestMapping(value = "payResult")
    public String getPaymentResult(@RequestParam(required = false) String orderid,
                                   @RequestParam(required = false) String userid,
                                   HttpServletRequest request,
                                   HttpServletResponse response,
                                   Model model) throws IOException {
        logger.info("payResult orderid:" + orderid);
        // 獲取支付寶POST過來反饋信息
        Map requestParams = request.getParameterMap();

        Map<String, String> params = WebServletUtil.getParamMap(requestParams);
        String orderId = orderid;
        if (ValueWidget.isNullOrEmpty(orderId)) {
            orderId = params.get("orderid");
        }
        if (orderId == null) {
            orderId = params.get("out_trade_no");
        }
        //暢捷支付點擊[返回商家] TODO
        if (orderId == null) {
            orderId = params.get("orderId");
        }
        logger.info("payResult params:" + params);
        String payResult = params.get("payResult");
        String extra_common_param = params.get("extra_common_param");
        logger.info("payResult extra_common_param:" + extra_common_param);

        if (!Constant2.CHANPAY_ORDER_RESULT_SUCCESS.equals(payResult)) {
            response.sendRedirect("/order/payOrder?orderId=" + orderId /*+ "&orgId=" + service.getOrgId(orderId)*/);
            return null;
        }
        response.sendRedirect("/order/payComplete?orderId=" + orderId /*+ "&orgId=" + service.getOrgId(orderId)*/);
        return null;

    }


}

 實際支付demo:

http://i.yhskyc.com/product/1

各文檔:

電腦網站支付快速接入
https://docs.open.alipay.com/270/105899/
API 詳細說明:
https://docs.open.alipay.com/270/alipay.trade.page.pay/

服務端SDK
https://docs.open.alipay.com/54/103419

RSA私鑰及公鑰生成
https://docs.open.alipay.com/58/103242/
 

RSA私鑰及公鑰生成 工具:

https://gitee.com/kunlunsoft/http_request_tool

上圖中2048 對應RSA2

相關項目:

https://github.com/liuyu520/io0007

https://gitee.com/kunlunsoft/oa_framework

注意:

1,本項目使用新版支付寶支付

即時到賬新老版本接口對比
https://docs.open.alipay.com/270/106759

2,新版支付寶支付,就算僅使用PC端網頁支付,也需要創建一個應用,老版不需要.

3,電腦端網頁支付應該使用:
AlipayTradePagePayRequest,而不是AlipayTradePayRequest;

4,對業務參數(非公共參數),進行 json 序列化時,
一定使用阿里自己的類:
JSONWriter writer = new JSONWriter();
String body=writer.write(model, true);

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章