支付宝沙箱之电脑网站支付

《支付宝沙箱链接》

《电脑网站支付快速接入文档》

引入SKD:

Maven依赖

代码:

public class AlipayVO implements Serializable {

    private static final long serialVersionUID = 1L;
    /**
     * 订单名称
     */
    private String subject;
    /**
     * 商户网站唯一订单号
     */
    private String out_trade_no;
    /**
     * 该笔订单允许的最晚付款时间
     */
    private String timeout_express;
    /**
     * 付款金额
     */
    private String total_amount;
    /**
     * 销售产品码,与支付宝签约的产品码名称
     */
    private String product_code;

    // 省略getter和setter
}
/* *
 *类名:AlipayConfig
 *功能:基础配置类
 *详细:设置帐户有关信息及返回路径
 *修改日期:2017-04-05
 *说明:
 *以下代码只是为了方便商户测试而提供的样例代码,商户可以根据自己网站的需要,按照技术文档编写,并非一定要使用该代码。
 *该代码仅供学习和研究支付宝接口使用,只是提供一个参考。
 */

public class AlipayConfig {

    //↓↓↓↓↓↓↓↓↓↓请在这里配置您的基本信息↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓

    // 应用ID,您的APPID,收款账号既是您的APPID对应支付宝账号
    public static String app_id = "";

    // 商户私钥,您的PKCS8格式RSA2私钥
    public static String merchant_private_key = "";

    // 支付宝公钥,查看地址:https://openhome.alipay.com/platform/keyManage.htm 对应APPID下的支付宝公钥。
    public static String alipay_public_key = "";

    // 服务器异步通知页面路径  需http://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问
    public static String notify_url = "http://vz6snm.natappfree.cc/ocPortal/alipay/notify";

    // 页面跳转同步通知页面路径 需http://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问
    public static String return_url = "http://localhost/ocPortal/alipay/return";

    // 签名方式
    public static String sign_type = "RSA2";

    // 字符编码格式
    public static String charset = "UTF-8";

    // 支付宝网关
    // 正式环境
    // public static String gateway_url = "https://openapi.alipay.com/gateway.do";
    // 沙箱环境
    public static String gateway_url = "https://openapi.alipaydev.com/gateway.do";

    //↑↑↑↑↑↑↑↑↑↑请在这里配置您的基本信息↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
}

@RequestMapping("/alipay")
@Controller
public class AlipayController {

    /**
     * 支付网站扫码支付接口-统一下单支付接口
     * @return
     * @throws AlipayApiException
     */
    @RequestMapping(value = "/pay", method = RequestMethod.GET)
    @ResponseBody
    private String alipayPay(@RequestParam("subscribeId") Long subscribeId) throws AlipayApiException {

        UserSubscribe userSubscribe = subscribeService.getById(subscribeId);

        AlipayVO vo = new AlipayVO();
        vo.setOut_trade_no(UUID.randomUUID().toString().replace("-", ""));
        vo.setTotal_amount("0.01");
        vo.setSubject("商品名称");
        vo.setProduct_code("FAST_INSTANT_TRADE_PAY"); //这个是固定的
        String json = new Gson().toJson(vo);

        AlipayClient alipayClient = new DefaultAlipayClient(AlipayConfig.gateway_url, AlipayConfig.app_id, AlipayConfig.merchant_private_key, "json", AlipayConfig.charset, AlipayConfig.alipay_public_key, AlipayConfig.sign_type);
        // 设置请求参数
        AlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest();
        alipayRequest.setReturnUrl(AlipayConfig.return_url);
        alipayRequest.setNotifyUrl(AlipayConfig.notify_url);
        alipayRequest.setBizContent(json);
        String result = alipayClient.pageExecute(alipayRequest).getBody();
        return result; //这里生成一个表单,会自动提交
    }

    /**
     * 支付宝服务器异步通知页面
     * @param request
     * @param out_trade_no 商户订单号
     * @param trade_no 支付宝交易凭证号
     * @param trade_status 交易状态
     * @return
     * @throws AlipayApiException
     */
    @RequestMapping("/notify")
    @ResponseBody
    public String alipayNotify(HttpServletRequest request, String out_trade_no, String trade_no, String trade_status) throws AlipayApiException {
        Map<String, String> params = getParamsMap(request);
        System.out.println("notify out_trade_no:" + out_trade_no);
        System.out.println("notify trade_no:" + trade_no);
        System.out.println("notify trade_status:" + trade_status);
        System.out.println("notify subject" + params.get("subject"));
        // 验证签名
        boolean signVerified = AlipaySignature.rsaCheckV1(params, AlipayConfig.alipay_public_key, AlipayConfig.charset, AlipayConfig.sign_type);
        System.out.println("notify signVerified:" + signVerified);
        if (signVerified) {
            // 处理业务逻辑,更细订单状态等
            // 支付成功
            if("TRADE_SUCCESS".equals(trade_status)){
            
                // return success可阻止支付宝继续回调
                return "success";
            }
            return "fail";
        } else {
            return "fail";
        }
    }

    /**
     * 支付宝服务器同步通知页面
     * @param request
     * @param out_trade_no 商户订单号
     * @param trade_no 支付宝交易凭证号
     * @param total_amount 交易状态
     * @return
     * @throws AlipayApiException
     */
    @RequestMapping("/return")
    public String alipayReturn(HttpServletRequest request, String out_trade_no, String trade_no, String total_amount) throws AlipayApiException {
        Map<String, String> params = getParamsMap(request);
        System.out.println("return out_trade_no:" + out_trade_no);
        System.out.println("return trade_no:" + trade_no);
        System.out.println("return total_amount:" + total_amount);
        // 验证签名
        boolean signVerified = AlipaySignature.rsaCheckV1(params, AlipayConfig.alipay_public_key, AlipayConfig.charset, AlipayConfig.sign_type);

        System.out.println("return signVerified:"+signVerified);
        if(signVerified) {

        } else {

        }
        return "redirect:/user/subscribe.html";
    }

    private Map<String, String> getParamsMap(HttpServletRequest request) {
        Map<String,String> params = new HashMap<>();
        Map requestParams = request.getParameterMap();
        for (Iterator 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] + ",";
            }
            //乱码解决,这段代码在参数出现乱码时使用
//            try {
//                valueStr = new String(valueStr.getBytes("ISO-8859-1"), "UTF-8");
                params.put(name, valueStr);
//            } catch (UnsupportedEncodingException e) {
//                e.printStackTrace();
//            }
        }
        return params;
    }
}

注意:
1、异步回调的路径必须暴露在外网下,而同步回调路径可根据环境选择
2、异步回调路径是被支付宝调用的,所以需要注意是否会被自己系统的登录拦截功能所拦截
3、修改订单的状态最好在异步回调里处理,同步回调只负责用户浏览器的跳转
4、AlipayConfig的参数需要确保正确

问题:

1、支付宝回调验签失败解决办法

支付宝有两个重载的方法。如果使用的是RSA加密的话,就调用下面这个方法。

boolean signVerified = AlipaySignature.rsaCheckV1(params, AlipayConfig.ALIPAY_PUBLIC_KEY, "UTF-8");

如果使用的是RSA2加密的话,就调用下面这个方法。

boolean signVerified = AlipaySignature.rsaCheckV1(params, AlipayConfig.ALIPAY_PUBLIC_KEY, "UTF-8", "RSA2");

2、支付宝同步和异步验签结果不一致的解决方法

同步验签正确、而异步验签错误,可能是参数中有中文乱码导致的,一般就是subject这个参数,可以在回调函数中打印出该参数,查看是否乱码。

valueStr = new String(valueStr.getBytes("ISO-8859-1"), "UTF-8");

猜你喜欢

转载自blog.csdn.net/Code_shadow/article/details/84564145
今日推荐