1.进入支付宝官网,扫码进入,网址:https://open.alipay.com/platform/home.htm
2.找到开发服务进入下面的研发服务
3.在手机上面下载支付宝沙箱
4.沙箱账号里面有一个商家信息,一个是买家信息
账号余额可以自动更改不过不能太多有上限,可惜这都是假的
5.找到自己的开发信息
6.这是自己的:应用私钥和支付宝公钥
7.支付流程
2.创建Spring Boot项目
创建SpringBoot的流程就不写了
1.1 这里只粘贴一下我的pom.xml依赖:org.springframework.boot spring-boot-starter-weborg.projectlombok lomboktrue org.springframework.boot spring-boot-starter-testtest org.junit.vintage junit-vintage-enginecom.alipay.sdk alipay-easysdk2.0.2
这个里面只有基本的web、lombok、支付宝的sdk依赖。
1.2 下面就是我的项目结构结构介绍:
1.PaymentBO是接收controller层的入参,如商品id、购买数量等等,结合具体的业务而定
2.PayController是控制器,负责分发请求,主要是处理用户的支付请求,以及支付宝的回调
3.ProjectInit是项目初始化时执行的一些操作,适合在整个过程中只需要执行一次的业务
4.PayService是真正的服务层,主要的业务代码在这里
5.OrderUtil是一个订单工具类,主要是生成随机订单号
6.index.html是模拟下单支付的页面
7.return.html是支付完成之后的页面
3.编写支付页面和回调页面
在index.html里面的代码:
确认订单
您的订单信息如下,请确认无误后支付:
这个里面就是您的订单详细信息,在这里我就不多写了,想写的话可以自己设置一些样式
在return.html里面的代码:
支付成功
您已成功购买此商品,感谢您的支持
回调地址肯定要外网可以访问,要不然支付宝怎么会调用得到呢?但是我们作为开发者可能没有自己到服务器和域名,所以我们使用内网穿透工具natapp获取临时域名,在这里我就不说怎么搭建内网穿透了
映射完成之后,启动项目,用临时域名测试一下下面的页面:
3.配置Spring Boot项目&初始化支付宝SDK
1.新版本的SDK 把大部分操作都封装到了Factory类中,但是Factory类在使用之前需要我们配置一下参数,且全局配置一次即可,所以我们把这部分代码拿到ProjectInit类中,在项目启动时执行一次:
alipay: appId: 换成自己的APPID privateKey: 换成自己的私钥 publicKey: 换成自己的公钥 #支付网关配置,这一项是写死的,正式环境是openapi.alipay.com gateway: openapi.alipaydev.com #支付成功之后的回调页面,只是一个友好页面。主要换成你自己映射的临时域名 returnUrl: http://frnqxw.natappfree.cc/return.html #支付成功的接口回调 notifyUrl:
2. 新版本的SDK 把大部分操作都封装到了Factory类中,但是Factory类在使用之前需要我们配置一下参数,且全局配置一次即可,所以我们把这部分代码拿到ProjectInit类中,在项目启动时执行一次:
import com.alipay.easysdk.factory.Factory;
import com.alipay.easysdk.kernel.Config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;
@Component
public class ProjectInit implements ApplicationRunner {
//应用id
@Value("${alipay.appId}")
private String appId;
//私钥
@Value("${alipay.privateKey}")
private String privateKey;
//公钥
@Value("${alipay.publicKey}")
private String publicKey;
//支付宝网关
@Value("${alipay.gateway}")
private String gateway;
//支付成功后的接口回调地址,不是回调的友好页面,不要弄混了
@Value("${alipay.notifyUrl}")
private String notifyUrl;
@Override
public void run(ApplicationArguments args) throws Exception {
//初始化支付宝SDK
Factory.setOptions(getOptions());
System.out.println("**********支付宝SDK初始化完成**********");
}
private Config getOptions() {
//这里省略了一些不必要的配置,可参考文档的说明
Config config = new Config();
config.protocol = "https";
config.gatewayHost = this.gateway;
config.signType = "RSA2";
config.appId = this.appId;
// 为避免私钥随源码泄露,推荐从文件中读取私钥字符串而不是写入源码中
config.merchantPrivateKey = this.privateKey;
//注:如果采用非证书模式,则无需赋值上面的三个证书路径,改为赋值如下的支付宝公钥字符串即可
config.alipayPublicKey = this.publicKey;
//可设置异步通知接收服务地址(可选)
config.notifyUrl = notifyUrl;
return config;
}
}
3.1 编写下单支付接口
既然要下单,肯定少不了传参,所以我们这里简单的声明一个PaymentBO类
import lombok.Data;
import java.math.BigDecimal;
@Data
public class PaymentBO {
//省略其他的业务参数,如商品id、购买数量等
//商品名称
private String subject;
//总金额
private BigDecimal total = BigDecimal.ZERO;
}
然后在OrderUtil编写如下代码:
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
public static String getOrderNo () {
DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS");
LocalDateTime localDateTime = Instant.ofEpochMilli(System.currentTimeMillis()).atZone(ZoneOffset.ofHours(8)).toLocalDateTime();
return df.format(localDateTime);
}
}
接下来我们只需要Factory.Payment.Page.pay就可以发起一个支付请求,所以我们在PayService编写以下代码:
mport com.alipay.easysdk.factory.Factory;
import com.alipay.easysdk.payment.facetoface.models.AlipayTradePayResponse;
import com.alipay.easysdk.payment.page.models.AlipayTradePagePayResponse;
import com.course.java.alipay.bo.PaymentBO;
import com.course.java.alipay.util.OrderUtil;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
@Service
public class PayService {
//支付成功后要跳转的页面
@Value("${alipay.returnUrl}")
private String returnUrl;
public Object pay (PaymentBO bo) throws Exception {
//从存储介质(如MySQL、Redis)查询商品信息、总金额等敏感信息
//…………省略相关代码,这里直接赋值…………
bo.setSubject("游戏充值")
bo.setTotal(new BigDecimal(648.00));
//调用sdk,发起支付
AlipayTradePagePayResponse response = Factory.Payment
//选择网页支付平台
.Page()
//调用支付方法,设置订单名称、我们自己系统中的订单号、金额、回调页面
.pay(bo.getSubject() , OrderUtil.getOrderNo(), bo.getTotal().toString() , returnUrl);
//这里的response.body,就是一个可以直接加载的html片段,
// 这里为了简单我直接返回这个片段,前端直接
return response.body;
}
}
[点击并拖拽以移动]
再往下,编写PayController:
import com.course.java.alipay.bo.PaymentBO;
import com.course.java.alipay.service.PayService;
import lombok.AllArgsConstructor;
import org.springframework.web.bind.annotation.*;
import java.util.Map;
@RestController
@RequestMapping(value = "/payController")
@AllArgsConstructor
public class PayController {
private PayService payService;
@GetMapping(value = "//confirm/i" , produces = {"text/html;charset=UTF-8"})
public Object pay (@RequestParam(required = false) PaymentBO bo) throws Exception {
//这个接口其实应该是post方式的,但是我这里图方便,直接以get方式访问,
//且返回格式是text/html,这样前端页面就能直接显示支付宝返回的html片段
//真实场景下由post方式请求,返回code、msg、data那种格式的标准结构,让前端拿到data里的
//html片段之后自行加载
//由于我这里并没有真正的传参数,所以象征性的new一下,避免空指针
bo = new PaymentBO();
return payService.pay(bo);
}
}
4. 支付测试
在手机上打开沙箱版支付宝,登录买家帐号,扫码支付:
到这里支付宝支付流程就完了



