支付宝支付详细流程

news/2024/7/20 1:23:22 标签: 小程序, 微信, 阿里云

1、二维码的生成

  • 二维码生成坐标

<!-- zxing生成二维码 -->
        <dependency>
            <groupId>com.google.zxing</groupId>
            <artifactId>core</artifactId>
            <version>3.3.3</version>
        </dependency>
        <dependency>
            <groupId>com.google.zxing</groupId>
            <artifactId>javase</artifactId>
            <version>3.3.3</version>
        </dependency>
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.4</version>
  • 二维码生成工具类①

package com.xuechengpluscommon.utils;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import org.apache.commons.lang3.StringUtils;

import javax.imageio.ImageIO;
import javax.servlet.ServletOutputStream;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.HashMap;

/**
 * @author Mr.M
 * @version 1.0
 * @description 二维码生成工具
 * @date 2022/10/3 0:03
 */
public class QRCodeUtil {
    /**
     * 生成二维码
     *
     * @param content 二维码对应的URL
     * @param width   二维码图片宽度
     * @param height  二维码图片高度
     * @return
     */
    public String createQRCode(String content, int width, int height) throws IOException {
        String resultImage = "";
        //除了尺寸,传入内容不能为空
        if (!StringUtils.isEmpty(content)) {
            ServletOutputStream stream = null;
            ByteArrayOutputStream os = new ByteArrayOutputStream();
            //二维码参数
            @SuppressWarnings("rawtypes")
            HashMap<EncodeHintType, Comparable> hints = new HashMap<>();
            //指定字符编码为“utf-8”
            hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
            //L M Q H四个纠错等级从低到高,指定二维码的纠错等级为M
            //纠错级别越高,可以修正的错误就越多,需要的纠错码的数量也变多,相应的二维吗可储存的数据就会减少
            hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.M);
            //设置图片的边距
            hints.put(EncodeHintType.MARGIN, 1);

            try {
                //zxing生成二维码核心类
                QRCodeWriter writer = new QRCodeWriter();
                //把输入文本按照指定规则转成二维吗
                BitMatrix bitMatrix = writer.encode(content, BarcodeFormat.QR_CODE, width, height, hints);
                //生成二维码图片流
                BufferedImage bufferedImage = MatrixToImageWriter.toBufferedImage(bitMatrix);
                //输出流
                ImageIO.write(bufferedImage, "png", os);
                /**
                 * 原生转码前面没有 data:image/png;base64 这些字段,返回给前端是无法被解析,所以加上前缀
                 */
                resultImage = new String("data:image/png;base64," + EncryptUtil.encodeBase64(os.toByteArray()));
                return resultImage;
            } catch (Exception e) {
                e.printStackTrace();
                throw new RuntimeException("生成二维码出错");
            } finally {
                if (stream != null) {
                    stream.flush();
                    stream.close();
                }
            }
        }
        return null;
    }

    public static void main(String[] args) throws IOException {
        QRCodeUtil qrCodeUtil = new QRCodeUtil();
        System.out.println(qrCodeUtil.createQRCode("http://192.168.101.1:63030/orders/alipaytest", 200, 200));
    }
}
  • 二维码生成工具类②

package com.xuechengpluscommon.utils;


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.Base64;

public class EncryptUtil {
    private static final Logger logger = LoggerFactory.getLogger(EncryptUtil.class);

    public static String encodeBase64(byte[] bytes){
        String encoded = Base64.getEncoder().encodeToString(bytes);
        return encoded;
    }

    public static byte[]  decodeBase64(String str){
        byte[] bytes = null;
        bytes = Base64.getDecoder().decode(str);
        return bytes;
    }

    public static String encodeUTF8StringBase64(String str){
        String encoded = null;
        try {
            encoded = Base64.getEncoder().encodeToString(str.getBytes("utf-8"));
        } catch (UnsupportedEncodingException e) {
            logger.warn("不支持的编码格式",e);
        }
        return encoded;

    }

    public static String  decodeUTF8StringBase64(String str){
        String decoded = null;
        byte[] bytes = Base64.getDecoder().decode(str);
        try {
            decoded = new String(bytes,"utf-8");
        }catch(UnsupportedEncodingException e){
            logger.warn("不支持的编码格式",e);
        }
        return decoded;
    }

    public static String encodeURL(String url) {
        String encoded = null;
        try {
            encoded =  URLEncoder.encode(url, "utf-8");
        } catch (UnsupportedEncodingException e) {
            logger.warn("URLEncode失败", e);
        }
        return encoded;
    }


    public static String decodeURL(String url) {
        String decoded = null;
        try {
            decoded = URLDecoder.decode(url, "utf-8");
        } catch (UnsupportedEncodingException e) {
            logger.warn("URLDecode失败", e);
        }
        return decoded;
    }

    public static void main(String [] args){
        String str = "abcd{'a':'b'}";
        String encoded = EncryptUtil.encodeUTF8StringBase64(str);
        String decoded = EncryptUtil.decodeUTF8StringBase64(encoded);
        System.out.println(str);
        System.out.println(encoded);
        System.out.println(decoded);

        String url = "== wo";
        String urlEncoded = EncryptUtil.encodeURL(url);
        String urlDecoded = EncryptUtil.decodeURL(urlEncoded);

        System.out.println(url);
        System.out.println(urlEncoded);
        System.out.println(urlDecoded);
    }


}
  • 测试生成二维码

@Test
    void contextLoads() {
        try {
            String helloWorld = new QRCodeUtil().createQRCode("http://d6nt2p.natappfree.cc/pay/test", 200, 200);
            System.out.println(helloWorld);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
  • 结果(二维码内容如果是网址则会跳转,如果是接口,则返回接口数据)

2、订单号生成工具类

package com.xuechengpluscommon.utils;

import java.util.Random;

/**
 * snow flow .
 *
 */
public final class IdWorkerUtils {

    private static final Random RANDOM = new Random();

    private static final long WORKER_ID_BITS = 5L;

    private static final long DATACENTERIDBITS = 5L;

    private static final long MAX_WORKER_ID = ~(-1L << WORKER_ID_BITS);

    private static final long MAX_DATACENTER_ID = ~(-1L << DATACENTERIDBITS);

    private static final long SEQUENCE_BITS = 12L;

    private static final long WORKER_ID_SHIFT = SEQUENCE_BITS;

    private static final long DATACENTER_ID_SHIFT = SEQUENCE_BITS + WORKER_ID_BITS;

    private static final long TIMESTAMP_LEFT_SHIFT = SEQUENCE_BITS + WORKER_ID_BITS + DATACENTERIDBITS;

    private static final long SEQUENCE_MASK = ~(-1L << SEQUENCE_BITS);

    private static final IdWorkerUtils ID_WORKER_UTILS = new IdWorkerUtils();

    private long workerId;

    private long datacenterId;

    private long idepoch;

    private long sequence = '0';

    private long lastTimestamp = -1L;

    private IdWorkerUtils() {
        this(RANDOM.nextInt((int) MAX_WORKER_ID), RANDOM.nextInt((int) MAX_DATACENTER_ID), 1288834974657L);
    }

    private IdWorkerUtils(final long workerId, final long datacenterId, final long idepoch) {
        if (workerId > MAX_WORKER_ID || workerId < 0) {
            throw new IllegalArgumentException(String.format("worker Id can't be greater than %d or less than 0", MAX_WORKER_ID));
        }
        if (datacenterId > MAX_DATACENTER_ID || datacenterId < 0) {
            throw new IllegalArgumentException(String.format("datacenter Id can't be greater than %d or less than 0", MAX_DATACENTER_ID));
        }
        this.workerId = workerId;
        this.datacenterId = datacenterId;
        this.idepoch = idepoch;
    }

    /**
     * Gets instance.
     *
     * @return the instance
     */
    public static IdWorkerUtils getInstance() {
        return ID_WORKER_UTILS;
    }

    public synchronized long nextId() {
        long timestamp = timeGen();
        if (timestamp < lastTimestamp) {
            throw new RuntimeException(String.format("Clock moved backwards.  Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));
        }
        if (lastTimestamp == timestamp) {
            sequence = (sequence + 1) & SEQUENCE_MASK;
            if (sequence == 0) {
                timestamp = tilNextMillis(lastTimestamp);
            }
        } else {
            sequence = 0L;
        }

        lastTimestamp = timestamp;

        return ((timestamp - idepoch) << TIMESTAMP_LEFT_SHIFT)
                | (datacenterId << DATACENTER_ID_SHIFT)
                | (workerId << WORKER_ID_SHIFT) | sequence;
    }

    private long tilNextMillis(final long lastTimestamp) {
        long timestamp = timeGen();
        while (timestamp <= lastTimestamp) {
            timestamp = timeGen();
        }
        return timestamp;
    }

    private long timeGen() {
        return System.currentTimeMillis();
    }

    /**
     * Build part number string.
     *
     * @return the string
     */
    public String buildPartNumber() {
        return String.valueOf(ID_WORKER_UTILS.nextId());
    }

    /**
     * Create uuid string.
     *
     * @return the string
     */
    public String createUUID() {
        return String.valueOf(ID_WORKER_UTILS.nextId());
    }

    public static void main(String[] args) {
        System.out.println(IdWorkerUtils.getInstance().nextId());
    }
}

3、导入阿里支付坐标

<dependency>
    <groupId>com.alipay.sdk</groupId>
    <artifactId>alipay-sdk-java</artifactId>
    <version>4.34.0.ALL</version>
</dependency>

这里需要三个重要的数据:(沙箱模式或者已是商户才可以拥有)

  1. APPID(appid)

  1. RSA_PRIVATE_KEY(应用密匙)

  1. ALIPAY_PUBLIC_KEY(应用公匙)

4、进行订单支付(被动获取订单支付状态)

详细地址:电脑网站支付快速接入 - 支付宝文档中心 (alipay.com)

 @RequestMapping("/aliyuntest/pc")
    public void aliyuntest (HttpServletRequest httpRequest,
                            HttpServletResponse httpResponse)   throws  ServletException, IOException  {
        AlipayClient alipayClient =  new  DefaultAlipayClient(AlipayConfig.URL, AlipayConfig.APPID, AlipayConfig.RSA_PRIVATE_KEY, AlipayConfig.FORMAT, AlipayConfig.CHARSET, AlipayConfig.ALIPAY_PUBLIC_KEY, AlipayConfig.SIGNTYPE);  //获得初始化的AlipayClient
        AlipayTradePagePayRequest alipayRequest =  new  AlipayTradePagePayRequest(); //创建API对应的request
//        alipayRequest.setReturnUrl( "http://192.168.31.196:63100/pay/payNotify" );
        alipayRequest.setNotifyUrl( "http://d6nt2p.natappfree.cc/pay/payNotify" ); //在公共参数中设置回跳和通知地址
        alipayRequest.setBizContent( "{"  +
            "    \"out_trade_no\":\"2012523432526230\","  +
            "    \"product_code\":\"FAST_INSTANT_TRADE_PAY\","  +
            "    \"total_amount\":5688.88,"  +
            "    \"subject\":\"Iphone14pro 8+256G\","  +
            "    \"body\":\"Iphone14pro 8+256G\","  +
            "    \"passback_params\":\"merchantBizType%3d3C%26merchantBizNo%2012523432526230\","  +
            "    \"extend_params\":{"  +
            "    \"sys_service_provider_id\":\"201413352010\""  +
            "    }" +
            "  }" ); //填充业务参数
        String form= "" ;
        try  {
            form = alipayClient.pageExecute(alipayRequest).getBody();  //调用SDK生成表单
        }  catch  (AlipayApiException e) {
            e.printStackTrace();
        }
        httpResponse.setContentType( "text/html;charset="  + AlipayConfig.CHARSET);
        httpResponse.getWriter().write(form); //直接将完整的表单html输出到页面
        httpResponse.getWriter().flush();
        httpResponse.getWriter().close();
    }
  • alipayRequest.setBizContent()的内容可以自己进行替换

  • alipayRequest.setNotifyUrl()里面的地址必须公网也可以访问,即意味着无法使用本地服务器路径,这里使用内网穿透

  • 详细地址:(4条消息) 使用natapp实现内网穿透详细教程_小龙Hibernation的博客-CSDN博客

  • 接口测试:

5、主动获取订单支付状态

@GetMapping("/queryPayResult")
    @ResponseBody
    public String queryPayResult() throws AlipayApiException {
        AlipayClient alipayClient = new DefaultAlipayClient(AlipayConfig.URL,AlipayConfig.APPID,AlipayConfig.RSA_PRIVATE_KEY,AlipayConfig.FORMAT,AlipayConfig.CHARSET,AlipayConfig.ALIPAY_PUBLIC_KEY,AlipayConfig.SIGNTYPE);
        AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
        JSONObject bizContent = new JSONObject();
        bizContent.put("out_trade_no", "2012523432526225");
//bizContent.put("trade_no", "2023021722001443820502204183");
        request.setBizContent(bizContent.toString());
        AlipayTradeQueryResponse response = alipayClient.execute(request);
        System.out.println("____________________________________");
        String body = response.getBody();
        System.out.println("____________________________________");
        if(response.isSuccess()){
            System.out.println("调用成功");
        } else {
            System.out.println("调用失败");
        }
        return body;
    }

将商品Id输入之后便可查询结果

6、被动获取订单支付结果

@RequestMapping("/payNotify")
    public void payNotify(HttpServletRequest request,HttpServletResponse response) throws IOException, AlipayApiException {
        Map<String,String> params = new HashMap<String,String>();
        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] + ",";
            }
            //乱码解决,这段代码在出现乱码时使用。如果mysign和sign不相等也可以使用这段代码转化
            //valueStr = new String(valueStr.getBytes("ISO-8859-1"), "gbk");
            params.put(name, valueStr);
        }
        //获取支付宝的通知返回参数,可参考技术文档中页面跳转同步通知参数列表(以下仅供参考)//
        //商户订单号

        String out_trade_no = new String(request.getParameter("out_trade_no").getBytes("ISO-8859-1"),"UTF-8");
        //支付宝交易号

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

        //交易状态
        String trade_status = new String(request.getParameter("trade_status").getBytes("ISO-8859-1"),"UTF-8");

        //获取支付宝的通知返回参数,可参考技术文档中页面跳转同步通知参数列表(以上仅供参考)//
        //计算得出通知验证结果
        //boolean AlipaySignature.rsaCheckV1(Map<String, String> params, String publicKey, String charset, String sign_type)
        boolean verify_result = AlipaySignature.rsaCheckV1(params, AlipayConfig.ALIPAY_PUBLIC_KEY, AlipayConfig.CHARSET, "RSA2");

        if(verify_result){//验证成功
            //
            //请在这里加上商户的业务逻辑程序代码

            //——请根据您的业务逻辑来编写程序(以下代码仅作参考)——

            if(trade_status.equals("TRADE_FINISHED")){
                //判断该笔订单是否在商户网站中已经做过处理
                //如果没有做过处理,根据订单号(out_trade_no)在商户网站的订单系统中查到该笔订单的详细,并执行商户的业务程序
                //请务必判断请求时的total_fee、seller_id与通知时获取的total_fee、seller_id为一致的
                //如果有做过处理,不执行商户的业务程序

                //注意:
                //如果签约的是可退款协议,退款日期超过可退款期限后(如三个月可退款),支付宝系统发送该交易状态通知
                //如果没有签约可退款协议,那么付款完成后,支付宝系统发送该交易状态通知。
            } else if (trade_status.equals("TRADE_SUCCESS")){
                //判断该笔订单是否在商户网站中已经做过处理
                //如果没有做过处理,根据订单号(out_trade_no)在商户网站的订单系统中查到该笔订单的详细,并执行商户的业务程序
                //请务必判断请求时的total_fee、seller_id与通知时获取的total_fee、seller_id为一致的
                //如果有做过处理,不执行商户的业务程序
                log.info("=========================支付成功=========================");
                //注意:
                //如果签约的是可退款协议,那么付款完成后,支付宝系统发送该交易状态通知。
            }

            //——请根据您的业务逻辑来编写程序(以上代码仅作参考)——
            response.getWriter().println("success");
          //请不要修改或删除

            //
        }else{//验证失败
            response.getWriter().println("fail");

        }

http://www.niftyadmin.cn/n/75935.html

相关文章

资讯汇总230217

230217 22:48 【美联储理事鲍曼&#xff1a;美国通胀仍旧太高】美联储理事鲍曼表示&#xff0c;美国通胀仍旧太高&#xff1b;美国当前的经济数据不一致&#xff0c;不同寻常的低失业率是一个好迹象&#xff1b;让通胀回到目标还有很长的路要走&#xff1b;需要继续加息&#x…

珞珈1号-数据预处理流程

珞珈1号-数据预处理流程 1、重投影Albers 2、重采样 3、辐射校正–将INT32转化为浮点型真实数据 4、统一量纲(eg:和NPP同一量纲) 5、去噪 1、重投影Albers 参考这篇文章 2、重采样 输入想要重采样的数据&#xff0c;其中X和Y是你想要的大小&#xff0c;125即是重采样至125m …

MybatisPlus------条件构造器Wrapper以及QueryWrapper用法(七)

MybatisPlus------条件构造器Wapper&#xff08;七&#xff09; Wrapper:条件构造器抽象类&#xff0c;最顶端父类 AbstarctWrapper&#xff1a;用于查询条件封装&#xff0c;生成sql的where条件。 QueryWrapper&#xff1a;查询条件封装&#xff08;可以用于查询、删除&#x…

BZOJ4403 序列统计

题目描述 给定三个正整数N、L和R&#xff0c;统计长度在1到N之间&#xff0c;元素大小都在L到R之间的单调不降序列的数量。输出答案对106310^631063取模的结果。 输入 输入第一行包含一个整数T&#xff0c;表示数据组数。 第2到第T1行每行包含三个整数N、L和R&#xff0c;N、…

vscode构建Vue3.0项目(vite,vue-cli)

构建Vue3.0项目构建Vue3.0项目1.使用Vite构建vue项目的方法以及步骤1. 安装vite2. 运行vite vue 项目3.说明2.使用vue-cli构建vue项目的方法以及步骤1.安装全局vue cli —— 脚手架2、VSCode3.报错4.运行构建Vue3.0项目 1.使用Vite构建vue项目的方法以及步骤 1. 安装vite n…

ChatGPT及相关产品体验与研究

ChatGPT及相关产品体验与研究 我的Github博客仓库链接&#xff1a;ChatGPT及相关产品体验与研究 - Github 一、ChatGPT介绍 1. ChatGPT概述 一句话描述ChatGPT&#xff1a;一个能够通过对话得到你想要的答案的聊天机器人。 ChatGPT 是由 OpenAI 开发的一种基于深度学习的自然…

8月起,《PMBOK®指南(第七版)》将被采用,考PMP的注意了!

PMP第七版教材采用时间定了&#xff01;&#xff01;&#xff01;2023年【8月开始】第一次使用第七版教材&#xff0c;通知明显指出&#xff0c;第六版的关键知识任然还是有效的。第七版做的调整还是蛮大的&#xff0c;首次提出了项目管理的 12 项原则和8个项目绩效域&#xff…

java学习----网络编程

网络编程入门 网络编程概述 计算机网络 ​ 计算机网络是指地理位置不同的具有独立功能的计算机及其外部设备&#xff0c;通过通信线路连接起来&#xff0c;在网络操作系统&#xff0c;网络管理软件及网络通信协议的管理协调下&#xff0c;实现资源共享和信息传递的计算机系统…