springboot整合阿里支付

  • Post author:
  • Post category:其他


前言:

  1. 项目中需要给订单生成支付二维码,然后扫码支付,支付成功回调,后端处理支付成功的业务
  2. 需要到支付宝开放平台申请沙箱账号(地址:https://open.alipay.com/platform/home.htm),小编用的是沙箱的支付环境(地址:https://openhome.alipay.com/platform/appDaily.htm?tab=info)
  3. 项目地址(gitee): https://gitee.com/qinenqi/online

    springboot整合阿里支付 实现订单的支付宝支付(属于 online_project服务)

    在这里插入图片描述



springboot 整合支付宝支付二维码

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

  1. 修改配置文件
# APPID
alipay.appId:2016092400588349
alipay.privateKey:请填写自己的秘钥
alipay.notifyUrl:88/api/project/applyController/notify
alipay.signType:RSA2
alipay.charset:utf-8
alipay.gatewayUrl:https://openapi.alipaydev.com/gateway.do
spring.interface.ip:请填写自己的回调地址
  1. 新建实体类 ApplyOrder.java

import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.format.annotation.DateTimeFormat;
import java.io.Serializable;
import java.time.LocalDateTime;


@AllArgsConstructor
@NoArgsConstructor
@Data
@Slf4j
public class ApplyOrder implements Serializable {

    private Long id;

    /**
     * 订单编号  order_no
     */
    private String orderNo;

    /**
     *  订单价格  price
     */
    private String price;

    /**
     *  订单状态  1000:未支付 2000:已支付 3000:支付失败 4000:默认
     */
    private int status;

    /**
     * 订单内容  订单内容
     */
    private String content;

    /**
     *  商家信息  shop_name
     */
    private String shopName;

    /**
     * 订单描述  description
     */
    private String description;

    /**
     * 创建时间  create_time
     */
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime createTime;

    /**
     * 更新时间  update_time
     */
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime updateTime;

    /**
     *  备注  remark
     */
    private String remark;

    /**
     *  二维码url  code_url
     */
    private String codeUrl;


}

  1. 新建控制器 ApplyOrderController.java

import com.example.onlinecommon.utils.R;
import com.example.onlineproject.entry.ApplyOrder;
import com.example.onlineproject.service.ApplyOrderService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;

@RestController
@RequestMapping("/applyController")
@Slf4j
public class ApplyOrderController {

    @Autowired
    private ApplyOrderService applyOrderService;

    /**
     *  根据订单 id 获取订单信息和支付二维码信息
     * @param id
     * @return
     */
    @RequestMapping("/getApplyOrderCode")
    public R getApplyOrderCode(@RequestParam Long id){
        ApplyOrder applyOrderCode = applyOrderService.getApplyOrderCode(id);
        return R.ok(applyOrderCode);
    }

    /**
     * 阿里支付宝 回调
     * @param request
     * @return
     */
    @PostMapping("/notify")
    public String alipayNotify(HttpServletRequest request){
        boolean signVerified = applyOrderService.checkSign(request.getParameterMap());

        if(signVerified){//验证成功  total_amount
            System.out.println("验证成功,去更新状态");
            String out_trade_no = new String(request.getParameter("out_trade_no")); //商户订单号
            String trade_no = new String(request.getParameter("trade_no"));//支付宝交易号
            String trade_status = new String(request.getParameter("trade_status"));//交易状态
            String price = new String(request.getParameter("total_amount"));//交易金额
            log.info("交易状态——trade_status:" + trade_status);

            //判断该笔订单是否在商户网站中已经做过处理
            //如果没有做过处理,根据订单号(out_trade_no)在商户网站的订单系统中查到该笔订单的详细,并执行商户的业务程序
            //如果有做过处理,不执行商户的业务程序
            if(trade_status.equals("TRADE_FINISHED")){
                //交易结束,不可退款
                //注意:退款日期超过可退款期限后(如三个月可退款),支付宝系统发送该交易状态通知
                //可执行修改订单状态等
                return ("finished");
            }else if (trade_status.equals("TRADE_SUCCESS")){
                log.info("交易支付成功");
                //交易支付成功
                //注意:付款完成后,支付宝系统发送该交易状态通知
                //可执行修改订单状态等
//                return ("success");
                return ("false");
            }else if (trade_status.equals("WAIT_BUYER_PAY")) {
                //交易创建,等待买家付款
                //可执行修改订单状态等
                return ("wait");
            }else{
                //未付款交易超时关闭,或支付完成后全额退款(交易失败)
                //可执行修改订单状态等
                return ("close");
            }
        }else{
            System.out.println("验证失败,不去更新状态");
            //可执行修改订单状态等
            return ("fail");
        }

    }
}

  1. 新建service 和实现类 ApplyOrderService.java ApplyOrderServiceImpl.java

import com.baomidou.mybatisplus.extension.service.IService;
import com.example.onlineproject.entry.ApplyOrder;
import java.util.Map;

public interface ApplyOrderService extends IService<ApplyOrder> {

    /**
     *  根据订单id 获取该订单的支付信息
     * @param id
     * @return
     */
    public ApplyOrder getApplyOrderCode(Long id);

    /**
     * 回调方法必须调用的验签方法,在回调结果前调用,确保是由支付宝发起的请求
     * @return boolean
     */
    public  boolean checkSign(Map<String,String[]> requestParams);
}

import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayTradePrecreateRequest;
import com.alipay.api.response.AlipayTradePrecreateResponse;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.onlinecommon.utils.TimeUtil;
import com.example.onlineproject.entry.ApplyOrder;
import com.example.onlineproject.mapper.ApplyOrderMapper;
import com.example.onlineproject.service.ApplyOrderService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;



@Service
@Slf4j
public class ApplyOrderServiceImpl extends ServiceImpl<ApplyOrderMapper, ApplyOrder> implements ApplyOrderService {



    @Value("${alipay.appId}")
    private String appId;

    @Value("${alipay.privateKey}")
    private String privateKey;

    @Value("${alipay.publicKey}")
    private String publicKey;

    @Value("${alipay.gatewayUrl}")
    private String gateway;

    @Value("${spring.interface.ip}")
    private String ip;

    @Value("${server.port}")
    private String port;

    @Value("${alipay.notifyUrl}")
    private String notifyUrl;

    @Autowired
    private ApplyOrderMapper applyOrderMapper;

    /**
     *  根据订单id 获取该订单的支付信息
     * @param id
     * @return
     */
    public ApplyOrder getApplyOrderCode(Long id){
        ApplyOrder applyOrder = applyOrderMapper.selectById(id);
        applyOrder = aliPay(applyOrder);
        return applyOrder;
    }

    /**
     *  1. 二维码有效期:默认2小时(计算时间是生成二维码链接开始计算)
     *  2. 电脑网站支付生成的二维码,有效期默认为1分钟。
     *  3. A用户使用支付宝扫码二维码生成订单后 ,B用户再去扫描同一二维码则会报“二维码已失效,请商家更换二维码后重新支付”
     * @param order
     * @return
     */
    public ApplyOrder aliPay(ApplyOrder order) {
        String shopName = order.getShopName();
        String orderNo = order.getOrderNo();
        String price = order.getPrice();

        AlipayTradePrecreateRequest request = new AlipayTradePrecreateRequest();
        // 支付请求
        request.setBizContent("{" +
                "    \"out_trade_no\":\"" + orderNo + "\"," +//商户订单号
                "    \"total_amount\":\"" + price + "\"," +
                "    \"subject\":\"" + shopName + "当面付" + "\"," +
                "    \"store_id\":\"00100\"," + // (必填) 商户门店编号,通过门店号和商家后台可以配置精准到门店的折扣信息,详询支付宝技术支持
                "    \"timeout_express\":\"5m\"}");//订单允许的最晚付款时间
        AlipayTradePrecreateResponse response = null;

        String url = "http://" + ip + ":" + notifyUrl;  // 需要经过网关的   http://127.0.0.1:88/api/project/applyController/notify, 请根据自己的情况进行处理
        request.setNotifyUrl(url); // 接口通知方式

        //支付宝二维码URL
        String qrCode = "";
        AlipayClient alipayClient = new DefaultAlipayClient(gateway, appId, privateKey, "json", "utf-8", publicKey, "RSA2");
        try {
            response = alipayClient.execute(request);
            if(response.isSuccess()){
                System.out.println("调用成功");
            } else {
                System.out.println("调用失败");
            }
            if (!response.isSuccess()) {
                throw new Exception("生成支付宝订单失败:" + response.getMsg());
            }
            qrCode = response.getQrCode();
        }  catch (Exception e) {
            e.printStackTrace();
        }
        order.setCodeUrl(qrCode);
        LocalDateTime currentTime = TimeUtil.getCurrentTime();
        order.setUpdateTime(currentTime);

        UpdateWrapper updateWrapper = new UpdateWrapper();
        updateWrapper.eq("id", order.getId());
        updateWrapper.set("code_url", qrCode);
        updateWrapper.set("update_time", currentTime);
        applyOrderMapper.update(null, updateWrapper);
        return order;
    }


    /**
     * 回调方法必须调用的验签方法,在回调结果前调用,确保是由支付宝发起的请求
     * @return boolean
     */
    public  boolean checkSign(Map<String,String[]> requestParams){
        Map<String,String> params = new HashMap<String,String>();//将异步通知中收到的所有参数都存放到 map 中
        for (Iterator<String> 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] + ",";
            }
            params.put(name, valueStr);
        }
        boolean signVerified = false; //调用SDK验证签名
        try {
            signVerified = AlipaySignature.rsaCheckV1(params, publicKey, "utf-8", "RSA2");
        } catch (AlipayApiException e) {
            log.error("支付宝验签接口请求失败,resp={}", e.getErrMsg());
        }
        return signVerified;
    }

}

  1. 新建mapper: ApplyOrderMapper.java

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.onlineproject.entry.ApplyOrder;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;

@Mapper
@Repository
public interface ApplyOrderMapper extends BaseMapper<ApplyOrder> {
}

后端效果:

在这里插入图片描述



前端页面:

请根据自己的情况,完善前端vue页面

这是支付宝的支付页面



版权声明:本文为weixin_41695138原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。