Springboot+MyBatisPlus+Mysql+vue实现支付宝支付

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS PostgreSQL,集群系列 2核4GB
简介: Springboot+MyBatisPlus+Mysql+vue实现支付宝支付

文章目录

前言

一、支付宝沙箱环境准备

二、开发环境搭建

1.数据库脚本执行。

2 依赖添加

3 配置支付宝支付相关参数

4. 配置支付宝客户端类

三、支付宝支付api接口

1.下单接口

支付时序图

2 支付通知回调处理订单

3.支付失败关闭订单

4.订单退款

5、查询订单

6.对账

四.前端

1.下单页面

2.订单列表

3.对账页面

账单列表

总结

前言

本篇通过使用Springboot+MybatisPlus+Mysql+vue实现支付宝网页支付,下单,下单通知,查询订单,关闭订单,退款等功能,前端使用单页面的Vue+elementui+axiso发送请求后台。对账估计是沙箱环境的原因提示账单不存在

一、支付宝沙箱环境准备

1)注册支付宝开发者账号。

2)注册完成登录之后进入控制台->沙箱-》创建应用。

3)配置应用环境(支付宝公钥,应用私钥,应用公钥,支付宝网关地址,配置接口内容加密方式,查看APPID)。详细的配置过程这里就不多介绍。


二、开发环境搭建

1.数据库脚本执行。

-- test.`order` definition

CREATE TABLE `order` (

 `order_id` int NOT NULL AUTO_INCREMENT COMMENT '订单ID',

 `order_no` varchar(50) DEFAULT NULL COMMENT '订单号',

 `product_id` int DEFAULT NULL COMMENT '产品id',

 `user_id` int DEFAULT NULL COMMENT '用户ID',

 `order_num` int DEFAULT NULL COMMENT '订单产品数量',

 `order_amt` decimal(10,2) DEFAULT NULL COMMENT '订单金额',

 `order_status` varchar(10) DEFAULT NULL COMMENT '订单状态',

 `pay_status` varchar(10) DEFAULT NULL COMMENT '支付状态',

 `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',

 `update_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '更新时间',

 `create_user` varchar(10) DEFAULT NULL COMMENT '创建人',

 `update_user` varchar(10) DEFAULT NULL COMMENT '更新人',

 `code_url` varchar(100) DEFAULT NULL COMMENT '订单二维码连接',

 `pay_type` varchar(10) DEFAULT NULL COMMENT '支付类别',

 PRIMARY KEY (`order_id`)

) ENGINE=InnoDB AUTO_INCREMENT=21 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='订单表';

-- test.payment_info definition

CREATE TABLE `payment_info` (

 `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '支付记录id',

 `order_no` varchar(50) DEFAULT NULL COMMENT '商户订单编号',

 `transaction_id` varchar(50) DEFAULT NULL COMMENT '支付系统交易编号',

 `payment_type` varchar(20) DEFAULT NULL COMMENT '支付类型',

 `trade_type` varchar(20) DEFAULT NULL COMMENT '交易类型',

 `trade_state` varchar(50) DEFAULT NULL COMMENT '交易状态',

 `payer_total` decimal(10,0) DEFAULT NULL COMMENT '支付金额(分)',

 `content` text COMMENT '通知参数',

 `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',

 `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',

 PRIMARY KEY (`id`)

) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

-- test.product definition

CREATE TABLE `product` (

 `product_id` int NOT NULL AUTO_INCREMENT COMMENT '商品ID',

 `product_name` varchar(100) DEFAULT NULL COMMENT '商品名称',

 `product_type` varchar(10) DEFAULT NULL,

 `product_price` decimal(10,2) DEFAULT NULL COMMENT '商品价格',

 `create_by` varchar(100) DEFAULT NULL COMMENT '创建人',

 `update_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '更新时间',

 `update_by` varchar(100) DEFAULT NULL COMMENT '更新人',

 `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',

 PRIMARY KEY (`product_id`),

 KEY `product_product_type_IDX` (`product_type`,`product_name`) USING BTREE

) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='商品表';

-- test.refund_info definition

CREATE TABLE `refund_info` (

 `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '退款单id',

 `order_no` varchar(50) DEFAULT NULL COMMENT '商户订单编号',

 `refund_no` varchar(50) DEFAULT NULL COMMENT '商户退款单编号',

 `refund_id` varchar(50) DEFAULT NULL COMMENT '支付系统退款单号',

 `total_fee` decimal(10,2) DEFAULT NULL COMMENT '原订单金额(分)',

 `refund` decimal(10,2) DEFAULT NULL COMMENT '退款金额(分)',

 `reason` varchar(50) DEFAULT NULL COMMENT '退款原因',

 `refund_status` varchar(10) DEFAULT NULL COMMENT '退款状态',

 `content_return` text COMMENT '申请退款返回参数',

 `content_notify` text COMMENT '退款结果通知参数',

 `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',

 `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',

 PRIMARY KEY (`id`)

) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

-- test.stock definition

CREATE TABLE `stock` (

 `stock_id` int NOT NULL AUTO_INCREMENT COMMENT '库存主键',

 `product_id` int NOT NULL COMMENT '商品ID',

 `stock_num` int DEFAULT NULL COMMENT '库存数量',

 `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',

 `create_by` varchar(100) DEFAULT NULL COMMENT '创建人',

 `update_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '更新时间',

 `update_by` varchar(100) DEFAULT NULL COMMENT '更新人',

 PRIMARY KEY (`stock_id`),

 KEY `stock_product_id_IDX` (`product_id`) USING BTREE,

 CONSTRAINT `stock_FK` FOREIGN KEY (`product_id`) REFERENCES `product` (`product_id`)

) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='库存表';

2 依赖添加

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0"

        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

   <modelVersion>4.0.0</modelVersion>

   <parent>

       <groupId>org.springframework.boot</groupId>

       <artifactId>spring-boot-starter-parent</artifactId>

       <version>2.3.6.RELEASE</version>

       <relativePath/> <!-- lookup parent from repository -->

   </parent>

   <groupId>com.elite.springboot</groupId>

   <artifactId>Springboot16WechatAliPay</artifactId>

   <version>1.0-SNAPSHOT</version>

   <properties>

       <maven.compiler.source>8</maven.compiler.source>

       <maven.compiler.target>8</maven.compiler.target>

       <java.version>1.8</java.version>

   </properties>

   <dependencies>

       <!--web-->

       <dependency>

           <groupId>org.springframework.boot</groupId>

           <artifactId>spring-boot-starter-web</artifactId>

       </dependency>

       <!--一引入alipay sdk-->

       <dependency>

           <groupId>com.alipay.sdk</groupId>

           <artifactId>alipay-sdk-java</artifactId>

           <version>4.22.0.ALL</version>

       </dependency>

       <!--引入微信支付api-->

       <dependency>

           <groupId>com.github.wechatpay-apiv3</groupId>

           <artifactId>wechatpay-apache-httpclient</artifactId>

           <version>0.3.0</version>

       </dependency>

       <dependency>

           <groupId>mysql</groupId>

           <artifactId>mysql-connector-java</artifactId>

       </dependency>

       <dependency>

           <groupId>com.baomidou</groupId>

           <artifactId>mybatis-plus-boot-starter</artifactId>

           <version>3.4.1</version>

       </dependency>

       <!--druid数据源-->

       <dependency>

           <groupId>com.alibaba</groupId>

           <artifactId>druid</artifactId>

           <version>1.2.8</version>

       </dependency>

       <dependency>

           <groupId>cn.hutool</groupId>

           <artifactId>hutool-all</artifactId>

           <version>5.1.4</version>

       </dependency>

       <dependency>

           <groupId>commons-lang</groupId>

           <artifactId>commons-lang</artifactId>

           <version>2.6</version>

       </dependency>

       <dependency>

           <groupId>com.alibaba</groupId>

           <artifactId>fastjson</artifactId>

           <version>1.2.76</version>

       </dependency>

       <dependency>

           <groupId>com.google.code.gson</groupId>

           <artifactId>gson</artifactId>

       </dependency>

       <!--lombok-->

       <dependency>

           <groupId>org.projectlombok</groupId>

           <artifactId>lombok</artifactId>

           <optional>true</optional>

       </dependency>

       <dependency>

           <groupId>junit</groupId>

           <artifactId>junit</artifactId>

           <version>4.12</version>

           <scope>test</scope>

       </dependency>

       <dependency>

           <groupId>org.springframework.boot</groupId>

           <artifactId>spring-boot-starter-test</artifactId>

           <scope>test</scope>

       </dependency>

   </dependencies>

   <build>

       <!-- 项目打包时会将java目录中的*.xml文件也进行打包 -->

       <resources>

           <resource>

               <directory>src/main/java</directory>

               <includes>

                   <include>**/*.xml</include>

               </includes>

               <filtering>false</filtering>

           </resource>

       </resources>

       <plugins>

           <plugin>

               <groupId>org.springframework.boot</groupId>

               <artifactId>spring-boot-maven-plugin</artifactId>

               <configuration>

                   <excludes>

                       <exclude>

                           <groupId>org.projectlombok</groupId>

                           <artifactId>lombok</artifactId>

                       </exclude>

                   </excludes>

               </configuration>

           </plugin>

       </plugins>

   </build>

</project>

3 配置支付宝支付相关参数

##支付宝支付配置信息

alipayconfig:

 # 应用ID,您的APPID,收款账号既是您的APPID对应支付宝账号,开发时使用沙箱提供的APPID,生产环境改成自己的APPID

 app_id: APPID

 # 商户私钥,您的PKCS8格式RSA2私钥

 privateKey: 商户私钥

 # 支付宝公钥,查看地址:https://openhome.alipay.com/platform/keyManage.htm 对应APPID下的支付宝公钥。

 publicKey: 支付宝公钥

 # 服务器异步通知页面路径 需http://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问

 notify_url:  https://38bc-183-131-162-121.jp.ngrok.io/springboot/alipay/notify

 # 页面跳转同步通知页面路径 需http://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问(其实就是支付成功后返回的页面)

 return_url:页面跳转同步通知页面路

 # 返回格式

 format: json

 #  签名方式

 sign_type: RSA2

 # 字符编码格式

 charset: utf-8

 # 支付宝网关,这是沙箱的网关

 gatewayUrl: https://openapi.alipaydev.com/gateway.do

 # 支付宝网关

 logPath: C:\\

4. 配置支付宝客户端类

package com.elite.springboot.config;

import com.alipay.api.AlipayClient;

import com.alipay.api.DefaultAlipayClient;

import lombok.Data;

import org.springframework.boot.context.properties.ConfigurationProperties;

import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Configuration;

import org.springframework.context.annotation.PropertySource;

/**

* 支付宝支付配置类

*/

@Configuration

@ConfigurationProperties(prefix = "alipayconfig")

@Data

public class AlipayConfig {

   // 应用ID,您的APPID,收款账号既是您的APPID对应支付宝账号,开发时使用沙箱提供的APPID,生产环境改成自己的APPID

   private String app_id;

   // 商户私钥,您的PKCS8格式RSA2私钥

   private String privateKey;

   // 支付宝公钥,查看地址:https://openhome.alipay.com/platform/keyManage.htm 对应APPID下的支付宝公钥。

   private String publicKey;

   // 服务器异步通知页面路径 需http://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问

   private String notify_url;

   // 页面跳转同步通知页面路径 需http://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问(其实就是支付成功后返回的页面)

   private String return_url;

   //返回格式

   private String format;

   // 签名方式

   private String sign_type;

   // 字符编码格式

   private String charset;

   // 支付宝网关,这是沙箱的网关

   private String gatewayUrl;

   // 支付宝网关

   private String logPath;

   /**

    * 获取alipayclient

    */

   @Bean(name="alipayClient")

   public AlipayClient getAlipayClient() {

       //调用RSA签名方式

       AlipayClient client = new DefaultAlipayClient(gatewayUrl, app_id,

               privateKey,format, charset, publicKey, sign_type);

//        AlipayTradeWapPayRequest alipay_request = new AlipayTradeWapPayRequest();

//

//        // 封装请求支付信息

//        AlipayTradeWapPayModel model = new AlipayTradeWapPayModel();

//        model.setOutTradeNo(out_trade_no);

//        model.setSubject(subject);

//        model.setTotalAmount(total_amount);

//        model.setBody(body);

//        model.setTimeoutExpress(timeout_express);

//        model.setProductCode(product_code);

//        alipay_request.setBizModel(model);

//        // 设置异步通知地址

//        alipay_request.setNotifyUrl(AlipayConfig.notify_url);

//        // 设置同步地址

//        alipay_request.setReturnUrl(AlipayConfig.return_url);

       return client;

   }

}

三、支付宝支付api接口

1.下单接口

支付时序图

ee0461d38b544613a99d6eac9121f2fe.png

下单请求代码示例:

@Transactional(rollbackFor = Exception.class)

   @Override

   public R createOrder(Integer product_id) {

       try{

           log.info("创建订单开始......");

           //创建订单

           Order orderInfo = orderService.createOrderByProductId(product_id, PayTypeEnum.ALIPAY.getPayType());

           log.info("创建订单结束:"+orderInfo.toString());

           log.info("调用支付开始.....");

           //调用支付宝接口

           AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();

           //配置需要的公共请求参数

           request.setNotifyUrl(alipayConfig.getNotify_url());

           //支付完成后配置returnUrl

           request.setReturnUrl(alipayConfig.getReturn_url());

           /**

            * out_trade_no String 必选 64 商户订单号。由商家自定义,64个字符以内,仅支持字母、数字、下划线且需保证在商户端不重复。 20150320010101001

            * total_amount Price 必选 11 订单总金额,单位为元,精确到小数点后两位,取值范围为 [0.01,100000000]。金额不能为0。 88.88

            * subject String 必选 256 订单标题。注意:不可使用特殊字符,如 /,=,& 等。 Iphone6 16G

            * product_code String 必选 64 销售产品码,与支付宝签约的产品码名称。注:目前电脑支付场景下仅支持FAST_INSTANT_TRADE_PAY FAST_INSTANT_TRADE_PAY

            */

           //组装当前业务方法的请求参数

           JSONObject bizContent = new JSONObject();

           bizContent.put("out_trade_no", orderInfo.getOrderNo());

           bizContent.put("total_amount", orderInfo.getOrderAmt());

           bizContent.put("subject", productService.getById(product_id).getProductName());

           bizContent.put("product_code", "FAST_INSTANT_TRADE_PAY");

           request.setBizContent(bizContent.toString());

           //执行请求,调用支付宝接口

           AlipayTradePagePayResponse response = alipayClient.pageExecute(request);

           log.info("调用支付结束:"+response.getBody());

           if(response.isSuccess()){

               log.info("调用成功,返回结果 ===> " + response.getBody());

               return R.ok(response.getBody());

           } else {

               log.info("调用失败,返回码 ===> " + response.getCode() + ", 返回描述 ===> " + response.getMsg());

               throw new RuntimeException("创建支付交易失败");

               //return R.fail(400,"创建支付交易失败:"+response.getMsg());

           }

       } catch (AlipayApiException e) {

           e.printStackTrace();

           throw new RuntimeException("创建支付交易失败");

           //return R.fail(400,"创建支付交易失败:"+e.getErrMsg());

       }

   }

2 支付通知回调处理订单

 /**

    * 支付通知

    */

   @PostMapping("/notify")

   public String notify(@RequestParam Map<String, String> params){

       String result = "failure";

       try {

           //异步通知验签

           boolean signVerified = AlipaySignature.rsaCheckV1(

                   params,

                   alipayConfig.getPublicKey(),

                   AlipayConstants.CHARSET_UTF8,

                   AlipayConstants.SIGN_TYPE_RSA2); //调用SDK验证签名

           if(!signVerified){

              //验签失败则记录异常日志,并在response中返回failure.

               log.error("支付成功异步通知验签失败!");

               return result;

           }

           // 验签成功后

           log.info("支付成功异步通知验签成功!");

           //按照支付结果异步通知中的描述,对支付结果中的业务内容进行二次校验,

           //1 商户需要验证该通知数据中的 out_trade_no 是否为商户系统中创建的订单号

           String outTradeNo = params.get("out_trade_no");

           Order order = orderService.getOrderByOrderNo(outTradeNo);

           if(order == null){

               log.error("订单不存在");

               return result;

           }

           //2 判断 total_amount 是否确实为该订单的实际金额(即商户订单创建时的金额)

           String totalAmount = params.get("total_amount");

           int totalAmountInt = new BigDecimal(totalAmount).intValue();

           int totalFeeInt = order.getOrderAmt().intValue();

           if(totalAmountInt != totalFeeInt){

               log.error("金额校验失败");

               return result;

           }

           //3 校验通知中的 seller_id(或者 seller_email) 是否为 out_trade_no 这笔单据的对应的操作方

           /*String sellerId = params.get("seller_id");

           String sellerIdProperty = config.getProperty("alipay.seller-id");

           if(!sellerId.equals(sellerIdProperty)){

               log.error("商家pid校验失败");

               return result;

           }*/

           //4 验证 app_id 是否为该商户本身

           String appId = params.get("app_id");

           String appIdProperty = alipayConfig.getApp_id();

           if(!appId.equals(appIdProperty)){

               log.error("appid校验失败");

               return result;

           }

           //在支付宝的业务通知中,只有交易通知状态为 TRADE_SUCCESS时,

           // 支付宝才会认定为买家付款成功。

           String tradeStatus = params.get("trade_status");

           if(!"TRADE_SUCCESS".equals(tradeStatus)){

               log.error("支付未成功");

               return result;

           }

           //处理业务 修改订单状态 记录支付日志

           aliPayService.processOrder(params);

           //校验成功后在response中返回success并继续商户自身业务处理,校验失败返回failure

           result = "success";

       } catch (AlipayApiException e) {

           e.printStackTrace();

       }

       return result;

   }

3.支付失败关闭订单

 

   /**

    * 取消订单业务

    * @param orderNo

    */

   private boolean closeOrder(String orderNo) {

       /**

        * trade_no String 特殊可选 64 该交易在支付宝系统中的交易流水号。最短 16 位,最长 64 位。和out_trade_no不能同时为空,如果同时传了 out_trade_no和 trade_no,则以 trade_no为准。 2013112611001004680073956707

        * out_trade_no String 特殊可选 64 订单支付时传入的商户订单号,和支付宝交易号不能同时为空。 trade_no,out_trade_no如果同时存在优先取trade_no HZ0120131127001

        * operator_id String 可选 28 商家操作员编号 id,由商家自定义。 YX01

        */

       try {

           log.info("关单接口的调用,订单号 ===> {}", orderNo);

           AlipayTradeCloseRequest request = new AlipayTradeCloseRequest();

           JSONObject bizContent = new JSONObject();

           bizContent.put("out_trade_no", orderNo);

           log.info("调用取消订单的的入参:"+bizContent.toString());

           request.setBizContent(bizContent.toString());

           AlipayTradeCloseResponse response = alipayClient.execute(request);

           if(response.isSuccess()){

               log.info("调用成功,返回结果 ===> " + response.getBody());

               return true;

           } else {

               log.info("调用失败,返回码 ===> " + response.getCode() + ", 返回描述 ===> " + response.getMsg());

               //throw new RuntimeException("关单接口的调用失败");

               return false;

           }

       } catch (AlipayApiException e) {

           e.printStackTrace();

           throw new RuntimeException("关单接口的调用失败");

       }

   }

4.订单退款

 @Transactional(rollbackFor = Exception.class)

   @Override

   public void refund(String orderNo, String reason) {

       try {

           log.info("调用退款API");

           //创建退款单

           RefundInfo refundInfo = refundsInfoService.createRefundByOrderNoForAliPay(orderNo, reason);

           //调用统一收单交易退款接口

           AlipayTradeRefundRequest request = new AlipayTradeRefundRequest ();

           //组装当前业务方法的请求参数

           JSONObject bizContent = new JSONObject();

           bizContent.put("out_trade_no", orderNo);//订单编号

           BigDecimal refund = new

                   BigDecimal(refundInfo.getRefund().toString());

           //BigDecimal refund = new BigDecimal("2").divide(new BigDecimal("100"));

           bizContent.put("refund_amount", refund);//退款金额:不能大于支付金额

           bizContent.put("refund_reason", reason);//退款原因(可选)

           request.setBizContent(bizContent.toString());

           log.info("退款API的入参:"+bizContent.toString());

           //执行请求,调用支付宝接口

           AlipayTradeRefundResponse response = alipayClient.execute(request);

           if(response.isSuccess()){

               log.info("调用成功,返回结果 ===> " + response.getBody());

               //更新订单状态

               orderService.updateStatusByOrderNo(orderNo,OrderStatus.REFUND_SUCCESS);

               //更新退款单

               refundsInfoService.updateRefundForAliPay(

                       refundInfo.getRefundNo(),

                       response.getBody(),

                       OrderStatus.REFUND_SUCCESS.getType()); //退款成功

           } else {

                log.info("调用失败,返回码 ===> " + response.getCode() + ", 返回描述 ===> "

                       + response.getMsg());

               //更新订单状态

               orderService.updateStatusByOrderNo(orderNo,

                       OrderStatus.REFUND_ABNORMAL);

               //更新退款单

               refundsInfoService.updateRefundForAliPay(

                       refundInfo.getRefundNo(),

                       response.getBody(),

                       OrderStatus.REFUND_ABNORMAL.getType()); //退款失败

           }

       } catch (AlipayApiException e) {

           e.printStackTrace();

           throw new RuntimeException("创建退款申请失败");

       }

   }

5、查询订单

/**

    * 查询订单

    * @param orderNo

    * @return 返回订单查询结果,如果返回null则表示支付宝端尚未创建订单

    */

   @Override

   public String queryOrder(String orderNo) {

       /**

        * out_trade_no String 特殊可选 64 订单支付时传入的商户订单号,和支付宝交易号不能同时为空。

        * trade_no,out_trade_no如果同时存在优先取trade_no 20150320010101001

        * trade_no String 特殊可选 64 支付宝交易号,和商户订单号不能同时为空 2014112611001004680 073956707

        * org_pid String 可选 16 银行间联模式下有用,其它场景请不要使用;

        * 双联通过该参数指定需要查询的交易所属收单机构的pid; 2088101117952222

        * query_options String[] 可选 1024 查询选项,商户传入该参数可定制本接口同步响应额外返回的信息字段,数组格式。支持枚举如下:trade_settle_info:返回的交易结算信息,包含分账、补差等信息;

        * fund_bill_list:交易支付使用的资金渠道;

        * voucher_detail_list:交易支付时使用的所有优惠券信息;

        * discount_goods_detail:交易支付所使用的单品券优惠的商品优惠信息;

        * mdiscount_amount:商家优惠金额; trade_settle_info

        */

       try {

           log.info("查单接口调用 ===> {}", orderNo);

           AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();

           JSONObject bizContent = new JSONObject();

           bizContent.put("out_trade_no", orderNo);

           request.setBizContent(bizContent.toString());

           AlipayTradeQueryResponse response = alipayClient.execute(request);

           if(response.isSuccess()){

               log.info("调用成功,返回结果 ===> " + response.getBody());

               return response.getBody();

           } else {

               log.info("调用失败,返回码 ===> " + response.getCode() + ", 返回描述 ===> " + response.getMsg());

               //throw new RuntimeException("查单接口的调用失败");

               return null;//订单不存在

           }

       } catch (AlipayApiException e) {

           e.printStackTrace();

           throw new RuntimeException("查单接口的调用失败");

       }

   }

6.对账

@Override

   public String queryBill(String billDate, String type) {

       /**

        * bill_type String 必选 20 账单类型,商户通过接口或商户经开放平台授权后其所属服务商通过接口可以获取以下账单类型,支持:

        * trade:商户基于支付宝交易收单的业务账单;

        * signcustomer:基于商户支付宝余额收入及支出等资金变动的账务账单。 trade

        * bill_date String 必选 15 账单时间:

        * * 日账单格式为yyyy-MM-dd,最早可下载2016年1月1日开始的日账单。不支持下载当日账单,只能下载前一日24点前的账单数据(T+1),当日数据一般于次日 9 点前生成,特殊情况可能延迟。

        * * 月账单格式为yyyy-MM,最早可下载2016年1月开始的月账单。不支持下载当月账单,只能下载上一月账单数据,当月账单一般在次月 3 日生成,特殊情况可能延迟。 2016-04-05

        * smid String 可选 20 二级商户smid 2088123412341234

        * AlipayClient alipayClient = new DefaultAlipayClient("https://openapi.alipay.com/gateway.do","app_id","your private_key","json","GBK","alipay_public_key","RSA2");

        * AlipayDataDataserviceBillDownloadurlQueryRequest request = new AlipayDataDataserviceBillDownloadurlQueryRequest();

        * request.setBizContent("{" +

        * "  \"bill_type\":\"trade\"," +

        * "  \"bill_date\":\"2016-04-05\"," +

        * "  \"smid\":\"2088123412341234\"" +

        * "}");

        * AlipayDataDataserviceBillDownloadurlQueryResponse response = alipayClient.execute(request);

        * if(response.isSuccess()){

        * System.out.println("调用成功");

        * } else {

        * System.out.println("调用失败");

        * }

        */

       try {

           log.info("账单类型:"+type+",日期:"+billDate);

           AlipayDataDataserviceBillDownloadurlQueryRequest request = new

                   AlipayDataDataserviceBillDownloadurlQueryRequest();

           JSONObject bizContent = new JSONObject();

           bizContent.put("bill_type", type);

           bizContent.put("bill_date", billDate);

           bizContent.put("smid","2088123412341234");

           request.setBizContent(bizContent.toString());

           AlipayDataDataserviceBillDownloadurlQueryResponse response = alipayClient.execute(request);

           if(response.isSuccess()){

               log.info("调用成功,返回结果 ===> " + response.getBody());

               //获取账单下载地址

               Gson gson = new Gson();

               HashMap<String, LinkedTreeMap> resultMap =

                       gson.fromJson(response.getBody(), HashMap.class);

               LinkedTreeMap billDownloadurlResponse =

                       resultMap.get("alipay_data_dataservice_bill_downloadurl_query_response");

               String billDownloadUrl =

                       (String)billDownloadurlResponse.get("bill_download_url");

               return billDownloadUrl;

           } else {

               log.info("调用失败,返回码 ===> " + response.getCode() + ", 返回描述 ===> "

                       + response.getMsg());

               throw new RuntimeException("申请账单失败");

           }

       } catch (AlipayApiException e) {

           e.printStackTrace();

           throw new RuntimeException("申请账单失败");

       }

   }

四.前端

1.下单页面

db95987d034c424caaea5d7421a15fc7.png

2.订单列表

订单列表可以操作退款

a8c8a5364b87401eabcda29c2174d5a7.png

3.对账页面

2fc801aff68049c2bd22003b48ba4d03.png

总结

本篇通过一个简单简单的前端页面+springboot+mybatisplus实现支付宝支付,了解支付宝api接口的调用以及简单的下单业务逻辑。

注意:支付宝的回调地址必须外网可以访问,需要使用ngrok进行外网映射,这个工具比较简单。

相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
12天前
|
SQL 关系型数据库 MySQL
springboot项目操作mysql出现锁表问题情况
springboot项目操作mysql出现锁表问题情况
25 2
|
12天前
|
XML Java 关系型数据库
springboot 集成 mybatis-plus 代码生成器
本文介绍了如何在Spring Boot项目中集成MyBatis-Plus代码生成器,包括导入相关依赖坐标、配置快速代码生成器以及自定义代码生成器模板的步骤和代码示例,旨在提高开发效率,快速生成Entity、Mapper、Mapper XML、Service、Controller等代码。
springboot 集成 mybatis-plus 代码生成器
|
12天前
|
SQL XML Java
springboot整合mybatis-plus及mybatis-plus分页插件的使用
这篇文章介绍了如何在Spring Boot项目中整合MyBatis-Plus及其分页插件,包括依赖引入、配置文件编写、SQL表创建、Mapper层、Service层、Controller层的创建,以及分页插件的使用和数据展示HTML页面的编写。
springboot整合mybatis-plus及mybatis-plus分页插件的使用
|
1月前
|
前端开发 JavaScript Java
技术分享:使用Spring Boot3.3与MyBatis-Plus联合实现多层次树结构的异步加载策略
在现代Web开发中,处理多层次树形结构数据是一项常见且重要的任务。这些结构广泛应用于分类管理、组织结构、权限管理等场景。为了提升用户体验和系统性能,采用异步加载策略来动态加载树形结构的各个层级变得尤为重要。本文将详细介绍如何使用Spring Boot3.3与MyBatis-Plus联合实现这一功能。
64 2
|
2月前
|
Java 数据库连接 测试技术
SpringBoot 3.3.2 + ShardingSphere 5.5 + Mybatis-plus:轻松搞定数据加解密,支持字段级!
【8月更文挑战第30天】在数据驱动的时代,数据的安全性显得尤为重要。特别是在涉及用户隐私或敏感信息的应用中,如何确保数据在存储和传输过程中的安全性成为了开发者必须面对的问题。今天,我们将围绕SpringBoot 3.3.2、ShardingSphere 5.5以及Mybatis-plus的组合,探讨如何轻松实现数据的字段级加解密,为数据安全保驾护航。
101 1
|
2月前
|
Web App开发 前端开发 关系型数据库
基于SpringBoot+Vue+Redis+Mybatis的商城购物系统 【系统实现+系统源码+答辩PPT】
这篇文章介绍了一个基于SpringBoot+Vue+Redis+Mybatis技术栈开发的商城购物系统,包括系统功能、页面展示、前后端项目结构和核心代码,以及如何获取系统源码和答辩PPT的方法。
|
2月前
|
Java 关系型数据库 MySQL
1、Mybatis-Plus 创建SpringBoot项目
这篇文章是关于如何创建一个SpringBoot项目,包括在`pom.xml`文件中引入依赖、在`application.yml`文件中配置数据库连接,以及加入日志功能的详细步骤和示例代码。
|
2月前
|
NoSQL 关系型数据库 MySQL
SpringBoot 集成 SpringSecurity + MySQL + JWT 附源码,废话不多直接盘
SpringBoot 集成 SpringSecurity + MySQL + JWT 附源码,废话不多直接盘
97 2
|
2月前
|
Java 关系型数据库 MySQL
SpringBoot 集成 Quartz + MySQL
SpringBoot 集成 Quartz + MySQL
76 1
|
1月前
|
Java 数据库连接 开发者
MyBatis-Plus整合SpringBoot及使用
MyBatis-Plus为MyBatis提供了强大的增强,使得在Spring Boot项目中的数据访问层开发变得更加快捷和简便。通过MyBatis-Plus提供的自动CRUD、灵活的查询构造器和简洁的配置,开发者
39 0