小工具知识网

当前位置: 首页 > 行业知识 > Java接入支付宝支付功能(APP支付)

行业知识

Java接入支付宝支付功能(APP支付)

2026-10-25 21:11:00 来源:互联网转载

客户就是上帝这句话一点都没错, 之前开发的一个专门接支付的项目,起初项目原型是接入支付宝支付,用的是客户公司的商户号. 后来因为种种原因导致客户商户号出现问题,联系我们看能不能把支付宝支付换成微信支付. 客户要求嘛, 改吧. 就把项目的支付从支付宝换到了微信.

本以为到此就结束了,没想到前几天 客户又要求换回支付宝,只不过用我们公司的商户.具体原因也说不清,反正就是不用微信支付了,又要换回支付宝, 没办法 改呗.

但是这次换支付宝我整整写了一个下午, 开发期间有几个需要注意的坑, 下面会说. 

首先准备工作:

一、appid, 登录支付宝开放平台点击右上角控制台

选择你要用的商户,点击进去

进去之后在页面左上角有商户的信息, 我圈出来的位置就是你的appid

二、public_key和private_key 接口加签方式(密钥/证书)

开发设置 > 开发信息 > 接口加签方式(密钥/证书)> 设置。

配置流程:

  1. 设置加签方式,选择密钥->下一步

  2. 生成密钥文件

    a.需要下载一个支付宝开放平台密钥工具.

         b.打开密钥工具,进入生成密钥功能

    c.加签方式选择密钥,加密算法选择RSA2. 

    d.点击生成密钥,工具会自动生成应用公钥(public_key)和应用私钥(private_key)点击打开文件位置就能找到生成的公私钥文件, 私钥一定妥善保管,代码里需要用也就是这个private_key

    e.复制应用公钥字符串

    f.返回开放平台控制台中,点击下一步

3.上传应用公钥,粘贴复制的应用公钥字符串,点击确认上传.此时需要输入短信验证码或支付密码完成安全验证.

4.密钥配置完成.

public_key就是你复制的应用公钥字符串,或者复制这个

private_key就是上面让你保存好的应用私钥

三、支付宝API文档

https://open.alipay.com/api

进去之后会有一些示例什么的,大家看看就行,要根据自己项目实际情况来看 需要对接哪些API, 我们只是对接了一个支付功能,目前退款和其他的API还没有接入 所以这期只写一下关于支付的功能.

点击查看文档进去之后会看到一些公共参数和请求参数

要想完整的接入支付宝,请求参数是必须规范的,一定要仔细看文档,懂了之后 再去写代码.

四、完善代码

ps:我们是SSM项目,没有用到pom,大家用boot项目的话,下面是sdk依赖,我们只是下的jar包

依赖:

  com.alipay.sdk  alipay-sdk-java  4.9.28.ALL

jar包:

https://pan.baidu.com/s/1bnmfYNRaDmLe27BFlN0gTA

提取码:1234 /没有

创建AlipayConfig类

public class AlipayConfig {      //2023/12/11 观塘新标准测试 商户appid  public static String APPID = "你的appid";  //支付宝私钥  public static String RSA_PRIVATE_KEY = "你的支付宝私钥";  //支付宝公钥  public static String ALIPAY_PUBLIC_KEY = "你的支付宝公钥";  // 服务器异步通知页面路径 需http://或者https://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问  public static String off_line_notify_url ="支付宝异步通知请求地址,必须是外网可以访问的接口";  // 商户可以自定义同步跳转地址  public static String return_url = "无用";  // 线上请求网关地址  public static String URL = "https://openapi.alipay.com/gateway.do";  // 沙箱环境网关地址  // public static String URL = "https://openapi.alipaydev.com/gateway.do";  // 编码  public static String CHARSET = "UTF-8";  //  public static String CHARSET = "GBK";  // 返回格式  public static String FORMAT = "json";  // 日志记录目录  public static String log_path = "/log";  // RSA2  public static String SIGNTYPE = "RSA2";}

下单接口

String doctor_spwz_money = UserService.AdvisoryCodePrice();String tradeno = getTradeNo();if (doctor_spwz_money.equals("0") || null == doctor_spwz_money) {      map.put("msg", "金额不能为0");      map.put("code", "-5");      return map;    }map.put("code_pay_userid", code_pay_userid);    map.put("code_money", doctor_spwz_money);    map.put("username", username);    map.put("tradeno", tradeno);    //创建订单    int i = UserService.insertOrderinfo(map);    //构建支付宝返回类    AlipayTradeAppPayResponse response = null;    // 实例化客户端    AlipayClient alipayClient = new DefaultAlipayClient(       "https://openapi.alipay.com/gateway.do", AlipayConfig.APPID,        AlipayConfig.RSA_PRIVATE_KEY, "json", AlipayConfig.CHARSET,        AlipayConfig.ALIPAY_PUBLIC_KEY, "RSA2");    // 实例化具体API对应的request类,类名称和接口名称对应,当前调用接口名称:alipay.trade.app.pay    AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();    //构建请求参数    JSONObject bizContent = new JSONObject();    bizContent.put("out_trade_no", tradeno);    bizContent.put("total_amount", doctor_spwz_money);    bizContent.put("subject", subject);    bizContent.put("product_code", "QUICK_MSECURITY_PAY");    request.setNotifyUrl(AlipayConfig.off_line_notify_url);    request.setBizContent(bizContent.toString());    try {      //这里和普通的接口调用不同,使用的是sdkExecute      response = alipayClient.sdkExecute(request);      System.out.println("---------------------" + response.getBody() + "---------------------");// 就是orderString      // 可以直接给客户端请求,无需再做处理。    } catch (AlipayApiException e) {      e.printStackTrace();    }    if (response.isSuccess()) {      map.put("code_money",doctor_spwz_money);      map.put("data", response.getBody());      map.put("code", "200");      map.put("msg", "下单成功");      return map;    }else{      map.put("code", "5000");      map.put("msg", "下单失败");      return map;    }
public static String getTradeNo() {    // 自增8位数 00000001    return "TNO" + formatDate(new Date(), "yyyyMMddHHmmssSSS") + "00000001";  }  //自己定义随机字符串就行

异步通知回调接口

// 异步回调  @SuppressWarnings({ "unused", "rawtypes" })  @RequestMapping(value = "NotifyUrl", method = RequestMethod.POST)  @ResponseBody  public String NotifyUrl(HttpServletRequest request) throws IOException {    System.out.println("******************************************************NotifyUrl***************************************************");        final Map params = convertRequestParamsToMap(request); // 将异步通知中收到的待验证所有参数都存放到map中        final String paramsJson = JSON.toJSONString(params);        logger.info("支付宝回调,{}" , paramsJson);        try {            AlipayConfig alipayConfig = new AlipayConfig();// 支付宝配置            // 调用SDK验证签名            boolean signVerified = AlipaySignature.rsaCheckV1(params, AlipayConfig.ALIPAY_PUBLIC_KEY,                AlipayConfig.CHARSET, AlipayConfig.SIGNTYPE);            if (signVerified) {                logger.info("支付宝回调签名认证成功");                // 按照支付结果异步通知中的描述,对支付结果中的业务内容进行二次校验,校验成功后在response中返回success,校验失败返回failure                this.check(params);                // 另起线程处理业务                executorService.execute(new Runnable() {                    @Override                    public void run() {                        AlipayNotifyParam param = buildAlipayNotifyParam(params);                        String trade_status = param.getTrade_status();                        // 支付成功                        if (trade_status.equals("TRADE_SUCCESS")                                || trade_status.equals("TRADE_FINISHED")) {                            // 处理支付成功逻辑                            try {                              String out_trade_no = param.getOut_trade_no();                              String trade_no = param.getTrade_no();                              int i = UserService.udcode_paystatus(out_trade_no, trade_no);                          if (i != 1) {                            logger.info("订单支付成功,但信息保存失败");                          } else {                            logger.info("success");                          }                            } catch (Exception e) {                                logger.error("支付宝回调业务处理报错,params:" + paramsJson, e);                            }                        } else {                            logger.error("没有处理支付宝回调业务,支付宝交易状态:{},params:{}",trade_status,paramsJson);                        }                    }                });                //验签成功之后 直接return success                logger.info("验签成功 return success,业务正在处理中");                return "success";            } else {                logger.info("支付宝回调签名认证失败,signVerified=false, paramsJson:{}", paramsJson);                return "failure";            }        } catch (AlipayApiException e) {            logger.error("支付宝回调签名认证失败,paramsJson:{},errorMsg:{}", paramsJson, e.getMessage());            return "failure";        }    }    // 将request中的参数转换成Map    private static Map convertRequestParamsToMap(HttpServletRequest request) {        Map retMap = new HashMap();        Set entrySet = request.getParameterMap().entrySet();        for (Entry entry : entrySet) {            String name = entry.getKey();            String[] values = entry.getValue();            int valLen = values.length;            if (valLen == 1) {                retMap.put(name, values[0]);            } else if (valLen > 1) {                StringBuilder sb = new StringBuilder();                for (String val : values) {                    sb.append(",").append(val);                }                retMap.put(name, sb.toString().substring(1));            } else {                retMap.put(name, "");            }        }        return retMap;    }    private AlipayNotifyParam buildAlipayNotifyParam(Map params) {        String json = JSON.toJSONString(params);        return JSON.parseObject(json, AlipayNotifyParam.class);    }    /**     * 1、商户需要验证该通知数据中的out_trade_no是否为商户系统中创建的订单号,     * 2、判断total_amount是否确实为该订单的实际金额(即商户订单创建时的金额),     * 3、校验通知中的seller_id(或者seller_email)是否为out_trade_no这笔单据的对应的操作方(有的时候,一个商户可能有多个seller_id/seller_email),     * 4、验证app_id是否为该商户本身。上述1、2、3、4有任何一个验证不通过,则表明本次通知是异常通知,务必忽略。     * 在上述验证通过后商户必须根据支付宝不同类型的业务通知,正确的进行不同的业务处理,并且过滤重复的通知结果数据。     * 在支付宝的业务通知中,只有交易通知状态为TRADE_SUCCESS或TRADE_FINISHED时,支付宝才会认定为买家付款成功。     *      * @param params     * @throws AlipayApiException     */    private void check(Map params) throws AlipayApiException {              String outTradeNo = params.get("out_trade_no");        // 1、商户需要验证该通知数据中的out_trade_no是否为商户系统中创建的订单号,        Order order = getOrderByOutTradeNo(outTradeNo);//这个自己写查询        if (order == null) {            throw new AlipayApiException("out_trade_no错误");        }               // 2、判断total_amount是否确实为该订单的实际金额(即商户订单创建时的金额)        if (!params.get("total_amount").toString().equals(order.getPayPrice().toString())) {          throw new AlipayApiException("error total_amount");    }        // 3、校验通知中的seller_id(或者seller_email)是否为out_trade_no这笔单据的对应的操作方(有的时候,一个商户可能有多个seller_id/seller_email),        // 第三步省略        // 4、验证app_id是否为该商户本身。        if (!params.get("app_id").equals(AlipayConfig.APPID)) {            throw new AlipayApiException("app_id不一致");        }    }
private Order getOrderByOutTradeNo(String outTradeNo){      return UserService.getOrderByOutTradeNo(outTradeNo);    }

到这代码就完成了.

代码中的import:

import java.io.IOException;import java.math.BigDecimal;import java.text.DateFormat;import java.text.SimpleDateFormat;import java.util.Date;import java.util.HashMap;import java.util.Iterator;import java.util.Map;import java.util.Map.Entry;import java.util.Set;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.atomic.AtomicBoolean;import java.util.stream.Collectors;import javax.annotation.Resource;import javax.inject.Qualifier;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpSession;import net.sf.json.JSONArray;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Controller;import org.springframework.stereotype.Repository;import org.springframework.web.bind.annotation.RequestBody;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestMethod;import org.springframework.web.bind.annotation.RequestParam;import org.springframework.web.bind.annotation.ResponseBody;import com.alibaba.fastjson.JSON;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.AlipayTradeAppPayModel;import com.alipay.api.internal.util.AlipaySignature;import com.alipay.api.request.AlipayTradeAppPayRequest;import com.alipay.api.response.AlipayTradeAppPayResponse;import com.ecg.pay.AlipayNotifyParam;import com.ecg.service.WeChatPayService;import com.ecg.util.AlipayConfig;import com.ecg.util.ApplicationContextHelperUtil;import com.fasterxml.jackson.databind.node.ObjectNode;import com.opensymphony.xwork2.util.logging.Logger;import com.opensymphony.xwork2.util.logging.LoggerFactory;import com.yc.pay.core.PayApiProvider;import com.yc.pay.core.wechat.v3.WeChatApiProvider;import com.yc.pay.core.wechat.v3.WeChatDirectPayApi;import com.yc.pay.core.wechat.v3.entity.ResponseSignVerifyParams;import com.yc.pay.vo.Amount;import com.yc.pay.vo.PayParams;

总结: 其实接支付宝支付并不难,只是比较繁琐. 我遇到的问题就是在用户支付成功之后的异步通知回调接口时,处理请求体中的request.getParameterMap(); 

循环处理待验签字符串的时候,处理支付宝回调请求里的数据时,没有处理好,下面把出现问题的代码贴过来, 大家可以看一下具体问题出现在哪我就不做解释了!可以在评论区讨论一下

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  

AlipaySignature.rsaCheckV1 调用支付宝验签方法时报的错

好了感谢大家收看

上一篇:不能发招聘信息吗

下一篇:最右怎么关服务器了?