zl程序教程

您现在的位置是:首页 >  后端

当前栏目

沙箱支付宝支付 SpringBoot+Vue前后端分离项目 实战

SpringBootVue项目 实战 分离 支付 前后 支付宝
2023-09-11 14:21:24 时间

一、教学讲解视频

对应教程视频:B站视频教程

二、支付宝有关的配置代码

pom.xml依赖:

<!-- 支付宝支付jar包 -->
<dependency>
  <groupId>com.alipay.sdk</groupId>
  <artifactId>alipay-sdk-java</artifactId>
  <version>3.1.0</version>
</dependency>

AliPayUtil.java代码:

package com.yjq.programmer.util;

import com.alibaba.fastjson.JSON;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.request.AlipayTradePagePayRequest;
import com.yjq.programmer.config.AliPayConfig;
import com.yjq.programmer.domain.AliPayBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * @author 杨杨吖
 * @QQ 823208782
 * @WX yjqi12345678
 * @create 2021-11-07 10:23
 */

/**
 * 支付宝支付工具类
 */
@Component
public class AliPayUtil {

    @Autowired
    private AliPayConfig alipayConfig;

    /**
     * 支付接口
     * @param alipayBean
     * @return
     * @throws AlipayApiException
     */
    public String pay(AliPayBean alipayBean) throws AlipayApiException {
        // 1、获得初始化的AlipayClient
        String serverUrl = alipayConfig.getGatewayUrl();
        String appId = alipayConfig.getAppId();
        String privateKey = alipayConfig.getPrivateKey();
        String format = "JSON";
        String charset = alipayConfig.getCharset();
        String alipayPublicKey = alipayConfig.getPublicKey();
        String signType = alipayConfig.getSignType();
        String returnUrl = alipayConfig.getReturnUrl();
        String notifyUrl = alipayConfig.getNotifyUrl();
        AlipayClient alipayClient = new DefaultAlipayClient(serverUrl, appId, privateKey, format, charset, alipayPublicKey, signType);
        // 2、设置请求参数
        AlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest();
        // 页面跳转同步通知页面路径
        alipayRequest.setReturnUrl(returnUrl);
        // 服务器异步通知页面路径
        alipayRequest.setNotifyUrl(notifyUrl);
        // 封装参数
        alipayRequest.setBizContent(JSON.toJSONString(alipayBean));
        // 3、请求支付宝进行付款,并获取支付结果
        String result = alipayClient.pageExecute(alipayRequest).getBody();
        // 返回付款信息
        return result;
    }
}

AliPayConfig.java代码:

package com.yjq.programmer.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;

/**
 * @author 杨杨吖
 * @QQ 823208782
 * @WX yjqi12345678
 * @create 2021-11-07 10:25
 */
@Configuration
@Component
public class AliPayConfig {
    /**
     * 应用ID,您的APPID,收款账号既是您的APPID对应支付宝账号
     */
    private String appId = "2016110300790563";

    /**
     * 商户私钥,您的PKCS8格式RSA2私钥  填上你的私钥
     */
    private String privateKey = "";

    /**
     * 支付宝公钥,  填上你的公钥
     */
    private String publicKey = "";

    /**
     * 服务器异步通知页面路径需http://格式的完整路径,不能加?id=123这类自定义参数
     */
    private String notifyUrl = "http://localhost:8080/user/order";

    /**
     * 页面跳转同步通知页面路径 需http://格式的完整路径,不能加?id=123这类自定义参数
     */
    private String returnUrl = "http://localhost:8080/user/order";

    /**
     * 签名方式
     */
    private String signType = "RSA2";

    /**
     * 字符编码格式
     */
    private String charset = "UTF-8";

    /**
     * 支付宝网关
     */
    private String gatewayUrl = "https://openapi.alipaydev.com/gateway.do";

    /**
     * 支付宝网关
     */
    private String logPath;

    public String getAppId() {
        return appId;
    }

    public void setAppId(String appId) {
        this.appId = appId;
    }

    public String getPrivateKey() {
        return privateKey;
    }

    public void setPrivateKey(String privateKey) {
        this.privateKey = privateKey;
    }

    public String getPublicKey() {
        return publicKey;
    }

    public void setPublicKey(String publicKey) {
        this.publicKey = publicKey;
    }

    public String getNotifyUrl() {
        return notifyUrl;
    }

    public void setNotifyUrl(String notifyUrl) {
        this.notifyUrl = notifyUrl;
    }

    public String getReturnUrl() {
        return returnUrl;
    }

    public void setReturnUrl(String returnUrl) {
        this.returnUrl = returnUrl;
    }

    public String getSignType() {
        return signType;
    }

    public void setSignType(String signType) {
        this.signType = signType;
    }

    public String getCharset() {
        return charset;
    }

    public void setCharset(String charset) {
        this.charset = charset;
    }

    public String getGatewayUrl() {
        return gatewayUrl;
    }

    public void setGatewayUrl(String gatewayUrl) {
        this.gatewayUrl = gatewayUrl;
    }

    public String getLogPath() {
        return logPath;
    }

    public void setLogPath(String logPath) {
        this.logPath = logPath;
    }
}

AliPayBean.java代码:

package com.yjq.programmer.domain;

/**
 * @author 杨杨吖
 * @QQ 823208782
 * @WX yjqi12345678
 * @create 2021-11-07 10:34
 */
/**
 * 支付实体对象
 * 根据支付宝接口协议,其中的属性名,必须使用下划线,不能修改
 */
public class AliPayBean {
    /**
     * 商户订单号,必填
     *
     */
    private String out_trade_no;
    /**
     * 订单名称,必填
     */
    private String subject;
    /**
     * 付款金额,必填
     * 根据支付宝接口协议,必须使用下划线
     */
    private String total_amount;
    /**
     * 商品描述,可空
     */
    private String body;
    /**
     * 超时时间参数
     */
    private String timeout_express= "5m";
    /**
     * 产品编号
     */
    private String product_code= "FAST_INSTANT_TRADE_PAY";

    public String getOut_trade_no() {
        return out_trade_no;
    }

    public void setOut_trade_no(String out_trade_no) {
        this.out_trade_no = out_trade_no;
    }

    public String getSubject() {
        return subject;
    }

    public void setSubject(String subject) {
        this.subject = subject;
    }

    public String getTotal_amount() {
        return total_amount;
    }

    public void setTotal_amount(String total_amount) {
        this.total_amount = total_amount;
    }

    public String getBody() {
        return body;
    }

    public void setBody(String body) {
        this.body = body;
    }

    public String getTimeout_express() {
        return timeout_express;
    }

    public void setTimeout_express(String timeout_express) {
        this.timeout_express = timeout_express;
    }

    public String getProduct_code() {
        return product_code;
    }

    public void setProduct_code(String product_code) {
        this.product_code = product_code;
    }
}

三、控制层接口代码

控制层StoreController.java文件代码:

package com.yjq.programmer.controller;

import com.yjq.programmer.dto.*;
import com.yjq.programmer.service.IStoreService;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.List;

/**
 * @author 杨杨吖
 * @QQ 823208782
 * @WX yjqi12345678
 * @create 2022-07-06 15:44
 */
@RestController
@RequestMapping("/store")
public class StoreController {

    @Resource
    private IStoreService storeService;
 
 
    /**
     * 使用沙箱支付宝支付订单
     * @param orderDTO
     * @return
     */
    @PostMapping("/order/aliPay")
    public ResponseDTO<String> aliPayOrder(@RequestBody OrderDTO orderDTO){
        return storeService.aliPayOrder(orderDTO);
    }

    /**
     * 沙箱支付宝成功支付回调接口
     * @param orderDTO
     * @return
     */
    @PostMapping("/order/aliPay/success")
    public ResponseDTO<Boolean> aliPayOrderSuccess(@RequestBody OrderDTO orderDTO){
        return storeService.aliPayOrderSuccess(orderDTO);
    }

  
}

四、实体文件返回文件代码

CodeMsg.java返回码文件代码:

public class CodeMsg {

    private Integer code;//错误码

    private String msg;//错误信息

    /**
     * 构造函数私有化即单例模式
     * 该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。
     * @param code
     * @param msg
     */
    private CodeMsg(Integer code, String msg){
        this.code = code;
        this.msg = msg;
    }

    public CodeMsg() {

    }

    public Integer getCode() {
        return code;
    }



    public void setCode(Integer code) {
        this.code = code;
    }



    public String getMsg() {
        return msg;
    }



    public void setMsg(String msg) {
        this.msg = msg;
    }

    //通用错误码定义
    //处理成功消息码
    public static CodeMsg SUCCESS = new CodeMsg(0, "success");
 }

OrderDTO.java实体文件代码:

package com.yjq.programmer.dto;

import com.fasterxml.jackson.annotation.JsonFormat;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;

/**
 * @author 杨杨吖
 * @QQ 823208782
 * @WX yjqi12345678
 * @create 2022-07-16 20:35
 */
public class OrderDTO {

    private String id;

    private String no;

    @JsonFormat(pattern="yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private Date createTime;

    private Integer state;

    private String userId;

    private String address;

    private String remark;

    private BigDecimal totalPrice;


    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getNo() {
        return no;
    }

    public void setNo(String no) {
        this.no = no;
    }

    public Date getCreateTime() {
        return createTime;
    }

    public void setCreateTime(Date createTime) {
        this.createTime = createTime;
    }

    public Integer getState() {
        return state;
    }

    public void setState(Integer state) {
        this.state = state;
    }

    public String getUserId() {
        return userId;
    }

    public void setUserId(String userId) {
        this.userId = userId;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public BigDecimal getTotalPrice() {
        return totalPrice;
    }

    public void setTotalPrice(BigDecimal totalPrice) {
        this.totalPrice = totalPrice;
    }

    public String getRemark() {
        return remark;
    }

    public void setRemark(String remark) {
        this.remark = remark;
    }

}

ResponseDTO.java返回文件代码:

package com.yjq.programmer.dto;

import com.yjq.programmer.bean.CodeMsg;

/**
 * @author 杨杨吖
 * @QQ 823208782
 * @WX yjqi12345678
 * @create 2020-09-20 10:34
 */

/**
 * 返回类数据传输对象  作用于service和controller
 * @param <T>
 */
public class ResponseDTO<T> {
    private Integer code;

    private String msg;

    private T data;

    public Integer getCode() {
        return code;
    }

    public void setCode(Integer code) {
        this.code = code;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }

    public ResponseDTO() {
    }

    private ResponseDTO(Integer code, String msg) {
        this.code = code;
        this.msg = msg;
    }

    private ResponseDTO(Integer code, T data) {
        this.code = code;
        this.data = data;
    }

    private ResponseDTO(Integer code, String msg, T data) {
        this.code = code;
        this.msg = msg;
        this.data = data;
    }

    public static <T> ResponseDTO<T> success(T data) {
        return new ResponseDTO<>(CodeMsg.SUCCESS.getCode(), data);
    }

    public static <T> ResponseDTO<T> successByMsg(T data, String msg) {
        return new ResponseDTO<>(CodeMsg.SUCCESS.getCode(), msg, data);
    }

    public static <T> ResponseDTO<T> errorByMsg(CodeMsg codeMsg) {
        return new ResponseDTO<>(codeMsg.getCode(),codeMsg.getMsg());
    }

}

五、业务逻辑层Service代码

IStoreService.java文件代码

package com.yjq.programmer.service;

import com.yjq.programmer.dto.*;

import java.math.BigDecimal;
import java.util.List;

/**
 * @author 杨杨吖
 * @QQ 823208782
 * @WX yjqi12345678
 * @create 2022-07-06 15:25
 */
public interface IStoreService {


    // 使用沙箱支付宝支付订单
    ResponseDTO<String> aliPayOrder(OrderDTO orderDTO);

 
    // 沙箱支付宝成功支付回调接口
    ResponseDTO<Boolean> aliPayOrderSuccess(OrderDTO orderDTO);

}

里面有一些业务逻辑处理的代码我就不贴了,这个根据自己的业务需求去写就好了,这里我帮大家把支付的最核心代码抽出来
StoreServiceImpl.java文件代码:

package com.yjq.programmer.service.impl;

import com.alipay.api.AlipayApiException;
import com.yjq.programmer.dto.*;
import com.yjq.programmer.service.IStoreService;
import com.yjq.programmer.util.AliPayUtil;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;

/**
 * @author 杨杨吖
 * @QQ 823208782
 * @WX yjqi12345678
 * @create 2022-07-06 15:25
 */
@Service
@Transactional
public class StoreServiceImpl implements IStoreService {

	 @Resource
    private AliPayUtil aliPayUtil;
  
    /**
     * 使用沙箱支付宝支付订单
     * @param orderDTO
     * @return
     */
    @Override
    public ResponseDTO<String> aliPayOrder(OrderDTO orderDTO) {
       
        BigDecimal totalPrice = new BigDecimal("0.00");
        String orderNo = "111111111";
 
        return initAliPay(orderNo, totalPrice);
    }

  

    /**
     * 初始化支付信息
     * @param orderNo
     * @param totalPrice
     * @return
     */
    public ResponseDTO<String> initAliPay(String orderNo, BigDecimal totalPrice) {
        // 封装沙箱支付宝支付信息
        AliPayBean alipayBean = new AliPayBean();
        alipayBean.setOut_trade_no(orderNo);
        alipayBean.setSubject("校园二手市场沙箱支付宝支付");
        alipayBean.setTotal_amount(String.valueOf(totalPrice));
        alipayBean.setBody("欢迎您在校园二手市场上下单!!");
        String pay = null;
        try {
            pay = aliPayUtil.pay(alipayBean);
        } catch (AlipayApiException e) {
            e.printStackTrace();
        }
        return ResponseDTO.success(pay);
    }

    /**
     * 沙箱支付宝成功支付回调接口
     * @param orderDTO
     * @return
     */
    @Override
    public ResponseDTO<Boolean> aliPayOrderSuccess(OrderDTO orderDTO) 	{
        // 这里可以写一些回调的接口逻辑,比如更新订单状态
        // 因为我们这有一个OrderDTO的入参,我们可以使用这个实体里面的订单号字段来获取详细订单信息
        return ResponseDTO.successByMsg(true, "支付成功!");
    }

 
}

六、前端Vue支付页面展示代码

点击支付按钮时候,调用这个payOrder函数
process.env.VUE_APP_SERVER是代表向后端接口请求的地址

  payOrder() {
       let _this = this;
       this.$ajax.post(process.env.VUE_APP_SERVER + "/store/order/aliPay", {}).then((response)=>{
           let resp = response.data;
           if(resp.code === 0){
               // 添加之前先删除一下,如果单页面,页面不刷新,添加进去的内容会一直保留在页面中,二次调用form表单会出错
               const divForm = document.getElementsByTagName('div');
               if (divForm.length) {
                   document.body.removeChild(divForm[0]);
               }
               const div = document.createElement('div');
               div.innerHTML = resp.data; // data就是接口返回的form 表单字符串
               document.body.appendChild(div);
               //document.forms[0].setAttribute('target', '_blank');// 新开窗口跳转
               document.forms[0].submit();
           } else {
               _this.$message.error(resp.msg);
           }
       });
   },

在个人订单页面的mounted生命周期中调用这个payReturn函数,为了判断如果是支付的回调的话,就调用后端的接口进行订单状态修改的一些操作。
process.env.VUE_APP_SERVER是代表向后端接口请求的地址

  payReturn() {
     let _this = this;
     if (this.$route.query && this.$route.query.out_trade_no){
         // 支付回调
         console.log("进入回调...");
         console.log("交易号:"+ this.$route.query.out_trade_no);
         this.$ajax.post(process.env.VUE_APP_SERVER + "/store/order/aliPay/success", {no:  this.$route.query.out_trade_no}).then((response)=>{
             let resp = response.data;
             if(resp.code === 0){
                 _this.$message.success(resp.msg);
             }else{
                 _this.$message.error(resp.msg);
             }
         });
     }

 }