前言
本文使用SpringBoot+SpringMVC对接支付宝电脑网站支付接口。接下来将详细讲解开发步骤及一些常见问题。
1.首先打开支付宝开放平台,
2.点击研发服务。因为正式接入需要企业签约,所以我们这里先用沙盒模式进行模拟接入,完成签约后将程序中的部分参数替换即可。
3.点击沙盒应用,查看APPID等参数
4.设置RSA2密钥
使用官方密钥生成工具生成密钥,将生成的密钥填入
时序图
正式开发
依赖pom.xml
org.springframework.boot
spring-boot-starter-parent
2.2.4.RELEASE
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-devtools
runtime
true
org.projectlombok
lombok
true
org.springframework.boot
spring-boot-starter-thymeleaf
2.2.4.RELEASE
org.springframework.boot
spring-boot-starter-test
test
org.junit.vintage
junit-vintage-engine
com.alipay.sdk
alipay-sdk-java
4.10.124.ALL
目录层级
关键代码
AlipayConfig类
创建DefaultAlipayClient所需参数,文档中提及DefaultAlipayClient只需要创建一次,后续可直接调用,所以这里使用了双重校验锁方式创建单例对象。
如果不清楚双重校验锁的朋友可以看这篇博客:双重校验锁
package online.xybh.pay_demo.pay.alipay;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import org.springframework.stereotype.Component;
@Component
public class AlipayConfig {
/**
* 支付宝网关(https://openapi.alipay.com/gateway.do)
* 沙盒网关(https://openapi.alipaydev.com/gateway.do)
*/
public static String URL = "https://openapi.alipaydev.com/gateway.do";
/**
* 创建应用时产生的应用号
*/
public static String APP_ID = "你的APPID";
/**
* 开发者私钥
*/
public static String APP_PRIVATE_KEY = "你的开发者私钥";
/**
* 参数返回格式, 只支持json
*/
public static String FORMAT = "json";
/**
* 编码集,支持GBK/UTF-8,根据自己工程编码进行调整
*/
public static String CHARSET = "UTF-8";
/**
* 支付宝公钥
*/
public static String ALIPAY_PUBLIC_KEY = "你的支付宝公钥";
/**
* 签名算法类型
*/
public static String SIGN_TYPE = "RSA2";
/**
* 回调地址
*/
public static String RETURN_URL = "你的回调地址";
/**
* 异步通知地址
*/
public static String NOTIFY_URL;
/**
* 私有化构造方法
*/
private AlipayConfig(){}
private volatile static AlipayClient instance = null;
/**
* 双重校验锁,单例模式
* @return 支付宝请求客户端实例
*/
public static AlipayClient getInstance(){
if(instance == null){
synchronized (AlipayConfig.class){
if(instance == null){
instance = new DefaultAlipayClient(URL, APP_ID, APP_PRIVATE_KEY, FORMAT, CHARSET, ALIPAY_PUBLIC_KEY, SIGN_TYPE);
}
}
}
return instance;
}
}
AlipayTrade类
这个类主要完成与支付宝的常用对接,如支付,退款,查询是否成功支付等。这里我们只完成支付功能。
package online.xybh.pay_demo.pay.alipay;
import com.alibaba.fastjson.JSON;
import com.alipay.api.AlipayApiException;
import com.alipay.api.request.AlipayTradePagePayRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.util.Map;
@Slf4j
@Component
public class AlipayTrade {
public String trade(Map content){
AlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest();
alipayRequest.setReturnUrl(AlipayConfig.RETURN_URL);
alipayRequest.setBizContent(JSON.toJSONString(content));
String form = "";
try {
form = AlipayConfig.getInstance().pageExecute(alipayRequest).getBody();
} catch (AlipayApiException e) {
log.error("支付宝构建表单失败", e);
}
log.debug("支付宝构建表单"+form);
return form;
}
}
这里用来lombok中的Slf4j注解,如果不需要的话可以与下面的log.error,log.debug一同删除。
Service
PayService接口
package online.xybh.pay_demo.service;
public interface PayService {
/**
* @param total 订单总金额
* @param subject 订单标题
* @param body 订单详情
* @param goodsId 商品id
* @param goodsName 商品名
* @param quantity 数量
* @param price 单价
* @return 支付表单
*/
String pay(double total, String subject, String body, String goodsId, String goodsName, int quantity, double price);
}
这里只写了一部分常用参数,如需其他参数可看alipay.trade.page.pay
PayServiceImpl实现类
package online.xybh.pay_demo.service.impl;
import online.xybh.pay_demo.pay.alipay.AlipayTrade;
import online.xybh.pay_demo.service.PayService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.UUID;
@Service
public class PayServiceImpl implements PayService {
@Autowired
private AlipayTrade alipayTrade;
@Override
public String pay(double total, String subject, String body, String goodsId, String goodsName, int quantity, double price){
HashMap content = new HashMap<>();
content.put("out_trade_no", UUID.randomUUID().toString());
content.put("product_code", "FAST_INSTANT_TRADE_PAY");
content.put("total_amount", String.valueOf(total));
content.put("subject", subject);
content.put("body", body);
content.put("goods_id", goodsId);
content.put("goods_name", goodsName);
content.put("quantity", String.valueOf(quantity));
content.put("price", String.valueOf(price));
return alipayTrade.trade(content);
}
}
测试
首页 IndexController
package online.xybh.pay_demo.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class IndexController {
@RequestMapping({"/", "/index"})
public String index(Model model){
return "index";
}
}
支付 PayController
package online.xybh.pay_demo.controller;
import online.xybh.pay_demo.service.PayService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Controller
public class PayController {
@Autowired
private PayService payService;
@PostMapping("/pay")
public String pay(@RequestParam String subject,
@RequestParam String body,
@RequestParam String goodsId,
@RequestParam String goodsName,
@RequestParam int quantity,
@RequestParam double price,
HttpServletResponse response){
String form = payService.pay(quantity*price, subject, body, goodsId, goodsName, quantity, price);
response.setContentType("text/html;charset=" + "UTF8");
try {
response.getWriter().write(form);
response.getWriter().flush();
response.getWriter().close();
} catch (IOException e) {
e.printStackTrace();
}
return "callback";
}
}
回调 CallBackController
package online.xybh.pay_demo.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
public class CallBackController {
@GetMapping("CallBack/alipay_back")
public String callback(){
return "/callback";
}
}
index.html
Title订单标题: | |
订单描述: | |
商品编号: | |
商品名称: | |
商品数量: | |
商品单价: | |
实现效果
1.商品详情
2.支付页面