我们在做开发时很多时候会涉及到支付功能,常见会对接支付宝和微信支付,本文将对JAVA对接支付宝进行详细的讲解。
在进行开发编码之前我们首选需要去申请开发所需要的支付宝一些配置,即支付宝沙盒环境的申请、
支付宝沙盒环境申请
1.1 注册
登录支付宝开发者网站 https://developers.alipay.com/ ,使用个人的支付宝扫码登录后,填写个人信息并提交
1.2 沙盒环境设置
按如下图所示进入沙盒环境设置页面
打开页面 https://opendocs.alipay.com/open/291/105971 下载公私钥生成工具,安装后生成应用的公钥和私钥
生成公私钥如下图
将公私钥保存好,后面程序中要用到,同时将公钥复制到沙盒环境的设置中,如下图
保存会生成一个支付宝的公钥,这个公钥用于后续的支付宝支付后的回调验签使用
至此。沙盒环境设置完毕。
开发部分
我们模拟一个简单的订单支付功能,只有一个简单的金额字段
2.1 数据库表结构
CREATE TABLE `user_order_t` (
`order_id` int(11) NOT NULL AUTO_INCREMENT COMMENT '订单Id',
`user_id` varchar(64) DEFAULT NULL COMMENT '用户Id',
`order_no` varchar(64) NOT NULL COMMENT '订单号',
`order_amount` decimal(16,4) NOT NULL COMMENT '订单金额',
`order_status` int(11) NOT NULL COMMENT '0 待付款 1 已付款 -1 已取消',
`create_time` varchar(32) NOT NULL COMMENT '创建时间',
`last_update_time` varchar(32) NOT NULL COMMENT '最后修改时间',
PRIMARY KEY (`order_id`)
) ENGINE=InnoDB AUTO_INCREMENT=19 DEFAULT CHARSET=utf8mb4;
2.2 项目结构
新建一个springboot项目,结构如图
2.3 pom依赖
<?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 https://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.2.5.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.devin</groupId>
<artifactId>alipay_demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>alipay_demo</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>tk.mybatis</groupId>
<artifactId>mapper-spring-boot-starter</artifactId>
<version>2.0.4</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
<version>2.0.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.0.1</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.17</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.1</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.22</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
<version>2.1.8.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-test</artifactId>
<version>2.2.6.RELEASE</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.2.5.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.57</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.5</version>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.10</version>
</dependency>
<dependency>
<groupId>com.alipay.sdk</groupId>
<artifactId>alipay-sdk-java</artifactId>
<version>3.4.27.ALL</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>maven-ali</id>
<url>http://maven.aliyun.com/nexus/content/groups/public//</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
<updatePolicy>always</updatePolicy>
<checksumPolicy>fail</checksumPolicy>
</snapshots>
</repository>
</repositories>
</project>
2.4 模型的定义
2.4.1 订单model
package com.devin.alipay_demo.entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import java.math.BigDecimal;
/**
* @author Devin Zhang
* @className UserOrder
* @description TODO
* @date 2020/5/12 10:49
*/
@Table(name = "user_order_t")
public class UserOrder {
@Id
@GeneratedValue(strategy= GenerationType.IDENTITY)
private Integer orderId;
private String orderNo;
private String userId;
private BigDecimal orderAmount;
private Integer orderStatus;
private String createTime;
private String lastUpdateTime;
public Integer getOrderId() {
return orderId;
}
public void setOrderId(Integer orderId) {
this.orderId = orderId;
}
public String getOrderNo() {
return orderNo;
}
public void setOrderNo(String orderNo) {
this.orderNo = orderNo;
}
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public BigDecimal getOrderAmount() {
return orderAmount;
}
public void setOrderAmount(BigDecimal orderAmount) {
this.orderAmount = orderAmount;
}
public Integer getOrderStatus() {
return orderStatus;
}
public void setOrderStatus(Integer orderStatus) {
this.orderStatus = orderStatus;
}
public String getCreateTime() {
return createTime;
}
public void setCreateTime(String createTime) {
this.createTime = createTime;
}
public String getLastUpdateTime() {
return lastUpdateTime;
}
public void setLastUpdateTime(String lastUpdateTime) {
this.lastUpdateTime = lastUpdateTime;
}
}
2.4.2 支付宝调用参数封装model
package com.devin.alipay_demo.dto;
/**
* @author Devin Zhang
* @className AlipayBean
* @description TODO
* @date 2020/5/12 11:33
*/
public class AlipayBean {
/**
* 商户订单号,必填
*/
private String out_trade_no;
/**
* 订单名称,必填
*/
private String subject;
/**
* 付款金额,必填
* 根据支付宝接口协议,必须使用下划线
*/
private String total_amount;
/**
* 商品描述,可空
*/
private String body;
/**
* 超时时间参数
*/
private String timeout_express = "10m";
/**
* 产品编号
*/
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;
}
}
2.5 工具类
2.5.1 支付宝参数读取
package com.devin.alipay_demo.util;
import org.springframework.beans.factory.config.PropertiesFactoryBean;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
/**
* @author Devin Zhang
* @className AlipayProperties
* @description 读取支付宝配置
* @date 2020/5/12 11:16
*/
@Component
public class AlipayProperties {
private static final String APP_ID = "appId";
private static final String PRIVATE_KEY = "privateKey";
private static final String PUBLIC_KEY = "publicKey";
private static final String NOTIFY_URL = "notifyUrl";
private static final String RETURN_URL = "returnUrl";
private static final String SIGN_TYPE = "signType";
private static final String CHARSET = "charset";
private static final String GATEWAY_URL = "gatewayUrl";
private static final String LOG_PATH = "logPath";
/**
* 保存加载配置参数
*/
private static Map<String, String> propertiesMap = new HashMap<>();
/**
* 加载属性
*/
@PostConstruct
public void loadProperties() throws Exception {
// 获得PathMatchingResourcePatternResolver对象
PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
try {
// 加载resource文件(也可以加载resources)
Resource resources = resolver.getResource("classpath:config/alipay.properties");
PropertiesFactoryBean config = new PropertiesFactoryBean();
config.setLocation(resources);
config.afterPropertiesSet();
Properties prop = config.getObject();
// 循环遍历所有得键值对并且存入集合
for (String key : prop.stringPropertyNames()) {
propertiesMap.put(key, (String) prop.get(key));
}
} catch (Exception e) {
throw new Exception("配置文件加载失败");
}
}
public String getAppId() {
return propertiesMap.get(APP_ID);
}
public String getPrivateKey() {
return propertiesMap.get(PRIVATE_KEY);
}
public String getPublicKey() {
return propertiesMap.get(PUBLIC_KEY);
}
public String getNotifyUrl() {
return propertiesMap.get(NOTIFY_URL);
}
public String getReturnUrl() {
return propertiesMap.get(RETURN_URL);
}
public String getSignType() {
return propertiesMap.get(SIGN_TYPE);
}
public String getCharset() {
return propertiesMap.get(CHARSET);
}
public String getGatewayUrl() {
return propertiesMap.get(GATEWAY_URL);
}
public String getLogPath() {
return propertiesMap.get(LOG_PATH);
}
}
2.5.2 支付宝工具类
package com.devin.alipay_demo.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.devin.alipay_demo.dto.AlipayBean;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
/**
* @author Devin Zhang
* @className AliPayUtil
* @description TODO
* @date 2020/5/12 10:47
*/
@Component
public class AliPayUtil {
@Resource
private AlipayProperties alipayProperties;
/**
* 支付接口
*
* @param alipayBean 封装的支付宝入参
* @return 返回支付结果
* @throws AlipayApiException 抛出异常
*/
public String pay(AlipayBean alipayBean) throws AlipayApiException {
// 1、获得初始化的AlipayClient
String serverUrl = alipayProperties.getGatewayUrl();
String appId = alipayProperties.getAppId();
String privateKey = alipayProperties.getPrivateKey();
String format = "json";
String charset = alipayProperties.getCharset();
String alipayPublicKey = alipayProperties.getPublicKey();
String signType = alipayProperties.getSignType();
String returnUrl = alipayProperties.getReturnUrl();
String notifyUrl = alipayProperties.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、请求支付宝进行付款,并获取支付结果
return alipayClient.pageExecute(alipayRequest).getBody();
}
}
2.5.3 订单状态枚举
package com.devin.alipay_demo.util;
/**
* @author Devin Zhang
* @className OrderEnum
* @description TODO
* @date 2020/5/12 11:43
*/
public enum OrderEnum {
ORDER_STATUS_PAID(1, "已支付"),
ORDER_STATUS_NOT_PAY(0, "待支付"),
ORDER_STATUS_CANCEL(2, "已取消");
private int status;
private String statusName;
OrderEnum(int status, String statusName) {
this.status = status;
this.statusName = statusName;
}
public int getStatus(){
return this.status;
}
}
2.6 dao
2.6.1 订单操作dao
因为使用了通用mapper tkmybatis,所以dao只是实现了相应的父类
package com.devin.alipay_demo.dao;
import com.devin.alipay_demo.entity.UserOrder;
import tk.mybatis.mapper.common.Mapper;
import tk.mybatis.mapper.common.MySqlMapper;
/**
* @author Devin Zhang
* @className UserOrderMapper
* @description TODO
* @date 2020/5/12 10:54
*/
public interface UserOrderMapper extends Mapper<UserOrder>, MySqlMapper<UserOrder> {
}
2.6.2 对应的mapper xml文件
同样,xml文件中内容也为空
1 <?xml version="1.0" encoding="UTF-8" ?>
2 <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
3 <mapper namespace="com.devin.alipay_demo.dao.UserOrderMapper" >
4
5 </mapper>
2.7 service
service中定义的下单等方法,其中下单时回去调用支付宝
package com.devin.alipay_demo.service;
import com.alipay.api.AlipayApiException;
import com.devin.alipay_demo.dao.UserOrderMapper;
import com.devin.alipay_demo.dto.AlipayBean;
import com.devin.alipay_demo.entity.UserOrder;
import com.devin.alipay_demo.util.AliPayUtil;
import com.devin.alipay_demo.util.OrderEnum;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.springframework.stereotype.Service;
import tk.mybatis.mapper.entity.Example;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.Date;
import java.util.UUID;
/**
* @author Devin Zhang
* @className OrderService
* @description TODO
* @date 2020/5/12 10:53
*/
@Service
public class OrderService {
@Resource
private UserOrderMapper userOrderMapper;
@Resource
private AliPayUtil aliPayUtil;
/**
* 下单
*
* @param orderAmount 订单金额
* @return 返回支付结果页面内容
* @throws AlipayApiException
*/
public String orderPay(BigDecimal orderAmount) throws AlipayApiException {
//1. 产生订单
UserOrder order = new UserOrder();
order.setOrderNo(System.currentTimeMillis() + "");
order.setUserId(UUID.randomUUID().toString());
order.setOrderAmount(orderAmount);
order.setOrderStatus(OrderEnum.ORDER_STATUS_NOT_PAY.getStatus());
String format = "yyyy-MM-dd HH:mm:ss";
order.setCreateTime(DateFormatUtils.format(new Date(), format));
order.setLastUpdateTime(DateFormatUtils.format(new Date(), format));
userOrderMapper.insert(order);
//2. 调用支付宝
AlipayBean alipayBean = new AlipayBean();
alipayBean.setOut_trade_no(order.getOrderNo());
alipayBean.setSubject("充值:" + order.getOrderAmount());
alipayBean.setTotal_amount(orderAmount.toString());
String pay = aliPayUtil.pay(alipayBean);
System.out.println("pay:" + pay);
return pay;
}
/**
* 根据订单号查询订单
*
* @param orderNo
* @return 返回订单信息
*/
public UserOrder getOrderByOrderNo(String orderNo) {
Example example = new Example(UserOrder.class);
Example.Criteria criteria = example.createCriteria();
criteria.andEqualTo("orderNo", orderNo);
return userOrderMapper.selectOneByExample(example);
}
/**
* 更新订单
*
* @param userOrder 订单对象
* @return 返回更新结果
*/
public int updateOrder(UserOrder userOrder) {
return userOrderMapper.updateByPrimaryKeySelective(userOrder);
}
}
2.8 Controller
package com.devin.alipay_demo.controller;
import com.alipay.api.AlipayApiException;
import com.alipay.api.internal.util.AlipaySignature;
import com.devin.alipay_demo.entity.UserOrder;
import com.devin.alipay_demo.service.OrderService;
import com.devin.alipay_demo.util.AlipayProperties;
import com.devin.alipay_demo.util.OrderEnum;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
/**
* @author Devin Zhang
* @className OrderController
* @description TODO
* @date 2020/5/12 10:53
*/
@Controller
@RequestMapping("/order")
public class OrderController {
@Resource
private OrderService orderService;
@Resource
private AlipayProperties alipayProperties;
/**
* 跳转到下单页面
*
* @return
*/
@RequestMapping("/goPay")
public String goPay() {
return "pay";
}
/**
* 下单,并调用支付宝
*
* @param orderAmount
* @return
* @throws AlipayApiException
*/
@PostMapping("/pay")
public void pay(BigDecimal orderAmount, HttpServletResponse httpResponse) throws Exception {
String payResult = orderService.orderPay(orderAmount);
httpResponse.setContentType("text/html;charset=" + alipayProperties.getCharset());
httpResponse.getWriter().write(payResult);
httpResponse.getWriter().flush();
httpResponse.getWriter().close();
}
/**
* 支付成功的跳转页面
*
* @return
*/
@RequestMapping("/goPaySuccPage")
public String goPaySuccPage() {
return "pay_succ";
}
/**
* 支付成功的回调接口
*
* @return
*/
@ResponseBody
@RequestMapping("/notifyPayResult")
public String notifyPayResult(HttpServletRequest request) {
System.out.println("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<进入支付宝回调->>>>>>>>>>>>>>>>>>>>>>>>>");
// 1.从支付宝回调的request域中取值放到map中
Map<String, String[]> requestParams = request.getParameterMap();
Map<String, String> params = new HashMap();
for (String name : requestParams.keySet()) {
String[] values = 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);
}
//2.封装必须参数
// 商户订单号
String outTradeNo = params.get("out_trade_no");
//交易状态
String tradeStatus = params.get("trade_status");
System.out.println("outTradeNo:" + outTradeNo + " tradeStatus:" + tradeStatus);
//3.签名验证(对支付宝返回的数据验证,确定是支付宝返回的)
boolean signVerified = false;
try {
//3.1调用SDK验证签名
signVerified = AlipaySignature.rsaCheckV1(params, alipayProperties.getPublicKey(), alipayProperties.getCharset(), alipayProperties.getSignType());
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("--------------->验签结果:" + signVerified);
//4.对验签进行处理
if (signVerified) {
//验签通过
//只处理支付成功的订单: 修改交易表状态,支付成功
if ("TRADE_FINISHED".equals(tradeStatus) || "TRADE_SUCCESS".equals(tradeStatus)) {
//根据订单号查找订单,防止多次回调的问题
UserOrder orderByOrder = orderService.getOrderByOrderNo(outTradeNo);
if (orderByOrder != null && orderByOrder.getOrderStatus() == OrderEnum.ORDER_STATUS_NOT_PAY.getStatus()) {
//修改订单状态
orderByOrder.setOrderStatus(OrderEnum.ORDER_STATUS_PAID.getStatus());
orderByOrder.setLastUpdateTime(DateFormatUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss"));
orderService.updateOrder(orderByOrder);
}
return "success";
} else {
return "failure";
}
} else {
//验签不通过
System.err.println("-------------------->验签失败");
return "failure";
}
}
}
2.9 启动类
package com.devin.alipay_demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import tk.mybatis.spring.annotation.MapperScan;
@MapperScan("com.devin.alipay_demo.dao")
@SpringBootApplication
public class AlipayDemoApplication {
public static void main(String[] args) {
SpringApplication.run(AlipayDemoApplication.class, args);
}
}
2.10 支付宝的配置 alipay.properties
其中私钥是我们生成的私钥,支付宝公钥可以从开发者沙盒环境拿到
其中notifyUrl 和 returnUrl 我使用natapp ,将内网的映射到外网,以方便做测试
# 应用ID,您的APPID,收款账号既是您的APPID对应支付宝账号
appId:2016102400751401
# 商户私钥,您的PKCS8格式RSA2私钥
privateKey:MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDncMvgR0vP05DtLHSIoboaSd7mCzVMzS3VSxl0RdHf/HPFWcqzZqAgtDOPGd9fWcr3M65HcGEY4F69Rn5SKuBHTuq+QJFkq7i2Px/EtbCjBWK1bMyk+fYwYwgFQ7YB4bYp2ssDAf6fDB0sDdylnAZY4Pr3OyRZFLRsbZvLAMpc5pymtTMa3knbIruxsKkj4Fc0QVAkOZCgnV2tD+KucZAoO88K1MBSnZyiO06cFX6vclpv1W7rb+pLs+2x6bxNNRMy4wf/LWrqkZlFnZrxRyF30FoJGaQY4rSJZ5FOHoputO/H0TAKT3hUjLOlauo9awo7oh/VJq55xMy8TQJU2tE/AgMBAAECggEBALRrEPPAgI/9nH/XZOzSLnKp3XI1kJJTbIRWq/whJY/XjCRvb/3UZcW41Gycva3mILv+dMDKEVdEKXahin3hYL8V/Rbc3Lq+xxqDMO+2t4EOBLnrm8iL92gW+zynYS4sV0ZfglzQ5D32QpOCJtyPOb91ew7Z8ubiphfUhluFPTuXK0MCt5n12tBI8kelGQsf3GP0xCEM1um6Ic3tDKOWwQjH0/CvssIZo5dzdc4WBv1Jgh1YconqT6oLOjfitLs6Py9K8jIrFLE1RWzt0/8L5fEyPqquqrmhML5Dce5qztdxeGDWVqVm/KFZJe8k5l8HtUlQYX7SaJ80G2UZEROQJ2kCgYEA9rszfwhF5rFQJNBKlrOl023IuSVhKmt0o8B/hR1d34y88I7cHGJ6a4+MMookpvKIEAOvdf0r/d0Z6MrQ1ptwkimm2Qa0jbFRSiG7GDJk3gVfpaNOvO3KdGWnbeJ4np51i1I80HGt9HeavyxGSeLI144A8CgK66vPkKF1FBX/vTUCgYEA8CKLzBdg26yG9SRRINA+ATaQM1myitggjk8p1dv7erFeYpKzzIWjvKZvH+kiFtAo0HLhTyF7a8V14m6znVU2SJ22GbBauXmFTjjhCbQvqUwgUjM57oH9EJMCxE9brIPV3VHdEtibQFhS36lg47NM6A5tGCEPb+Bt6dXhtLpJhyMCgYAeCQfpzO4FeUxSTvDli5UCOfkXYM+FRHN8g7CCWeLVleJiPmHZKrvQYDcm594yXI/nsysm59z1GHdQ+W+W0HFRubRP8xsDrLRCm/yUo33X8TuFhG3PXfspVD6fh9Q7KvsQLMCud0g/3FeAMjmUQQFGDElc8uLxcYbhCmagPVVWiQKBgHFNO3y+gxrjGoJL8mNzHe5gmkVASzerpiC/RVP8iXloesozwdX8MDdwp/n8e/MboEZKDfjSKXO+JVMDPIg9jnFQyHzycrwUlEtGFxgHBn3wx0dBmFHqz0aktqd9chnB0oSsfYzI2ufPRLr3JhoJnX3YYK0D3E7DK9kq62Xkh5DVAoGBAPW3Ltan5MT9Ry5D6W6ROPoPfl4Sy7C13FjFlujC8LcwsGoIt3+cKntDv7CJuiLoBDf+JtF9v8OSMlhYzy1ozLpVrO7Xn2k1fO76sotlXxsI3cqwnUlkcOuF7TpnHWGVnFGj7/9bPdIOEfnikdDTmxvqUSD9QdvhVtWfFECr2hlw
# 支付宝公钥,不是应用公钥 查看地址:https://openhome.com/platform/keyManage.htm 对应APPID下的支付宝公钥。
publicKey:MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqOl0nOy/amFKACzBMpO2uvibXOJbehvdMFUMxJMomtYp1RfqvTddsPtGPtX6EX8LFzKB5HC4Ew8rMlh+qvCQctcJfLOsYgK1W8dReLqRxsvMDBtrvDPGVKJwJFmRCbvqWX5b4BOj2fhCP1q0GfS9wsYTP08Xvwq2bDx4OpqdMMi04MPNomIgjgIZmUKeUepsOb0K7rUsgB0OZ6h2RxwKX8BTh2I8AiCU1bvYu6dKpikXz0x72JUg5l69gQCWe6CYHlUSu+gakTz648/GZ6pJXiMzQeemdcytczHrbzA7b3GqtnC5Fj+mxe5E3Upi5MOm82Tl6H3GOyXJ1OuKXdJj1wIDAQAB
# 服务器异步通知页面路径需http://格式的完整路径,不能加?id=123这类自定义参数
notifyUrl:http://mf5s4k.natappfree.cc/order/notifyPayResult
# 页面跳转同步通知页面路径 需http://格式的完整路径,不能加?id=123这类自定义参数
returnUrl:http://mf5s4k.natappfree.cc/order/goPaySuccPage
# 签名方式
signType:RSA2
# 字符编码格式
charset:utf-8
# 支付宝网关
gatewayUrl:https://openapi.alipaydev.com/gateway.do
# 日志路径
logPath:"d:\\data\\"
2.11 应用设置application.yml
# https://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html spring\u914D\u7F6E\u7684\u6587\u6863
server:
port: 10086
spring:
servlet:
multipart:
max-request-size: 100MB #最大请求文件的大小
max-file-size: 20MB #设置单个文件最大长度
mvc:
view:
prefix: /
suffix: .html
datasource:
platform: mysql
type: com.alibaba.druid.pool.DruidDataSource
initialSize: 3
minIdle: 1
maxActive: 500
maxWait: 60000
timeBetweenEvictionRunsMillis: 60000
minEvictableIdleTimeMillis: 30000
validationQuery: select 1
testOnBorrow: true
poolPreparedStatements: true
maxPoolPreparedStatementPerConnectionSize: 20
driverClassName: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/order_db?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=utf-8&useAffectedRows=true&rewriteBatchedStatements=true
username: root
password: root
mybatis:
# config-location: classpath:mybatis-config.xml
mapper-locations: classpath:mapper/*.xml
type-aliases-package: com.devin.alpay_demo.entity
# configuration:
# log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
#配置分页插件pagehelper
pagehelper:
helperDialect: mysql
reasonable: true
supportMethodsArguments: true
params: count=countSql
2.12 下单页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>order pay</title>
<script type="text/javascript" src="/js/jquery-1.8.2.js"></script>
</head>
<body>
<form action="/order/pay" method="post">
金额:<input id="orderAmount" name="orderAmount"><br>
<input type="submit">
</form>
</body>
</html>
2.13 支付成功跳转页面
该页面即为上面支付宝配置的returnUrl
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
充值成功!
</body>
</html>
启动程序,访问 http://localhost:10086/order/goPay,输入金额后点击去支付,可以看到订单已经产生,并跳转到支付宝扫码支付页面
下载支付宝沙盒app,登录测试账号,扫码付款后可以看到,可以付款成功,并且回调也调用成功,订单状态变为已支付。
沙盒支付宝下载: https://sandbox.alipaydev.com/user/downloadApp.htm
沙盒测试账号可以在开发者平台上看到
至此,支付宝的对接完成。
完整的代码git地址: https://github.com/devinzhang0209/alipay_demo.git