写在前面
你们好,我是小庄。很高兴能和你们一起学习SpringBoot的支付功能。如果您对Java感兴趣的话可关注我的动态.
写博文是一种习惯,在这过程中能够梳理和巩固知识点。
一、支付宝测试开发环境前期准备
1.Java支付的demo
下载地址:https://docs.open.alipay.com/270/106291/
2.解压并打开内容。大致的内容如下:
import java.io.FileWriter;
import java.io.IOException;
public class AlipayConfig {
// 应用ID,您的APPID,收款账号既是您的APPID对应支付宝账号,开发时使用沙箱提供的APPID,生产环境改成自己的APPID
public static String APP_ID = "";
// 商户私钥,您的PKCS8格式RSA2私钥
public static String APP_PRIVATE_KEY = "";
// 支付宝公钥,查看地址:https://openhome.alipay.com/platform/keyManage.htm 对应APPID下的支付宝公钥。
public static String ALIPAY_PUBLIC_KEY = "";
// 服务器异步通知页面路径 需http://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问
public static String notify_url = "";
// 页面跳转同步通知页面路径 需http://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问(其实就是支付成功后返回的页面)
public static String return_url = "";
// 签名方式
public static String SIGN_TYPE = "RSA2";
// 字符编码格式
public static String CHARSET = "utf-8";
// 支付宝网关,这是沙箱的网关
public static String GATEWAYURL = "https://openapi.alipaydev.com/gateway.do";
// 支付宝网关
public static String log_path = "C:\\";
//↑↑↑↑↑↑↑↑↑↑请在这里配置您的基本信息↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
/**
* 写日志,方便测试(看网站需求,也可以改成把记录存入数据库)
* @param sWord 要写入日志里的文本内容
*/
public static void logResult(String sWord) {
FileWriter writer = null;
try {
writer = new FileWriter(log_path + "alipay_log_" + System.currentTimeMillis()+".txt");
writer.write(sWord);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (writer != null) {
try {
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
3.免费注册蚂蚁金服开发者账号
点击进入注册
或者复制:https://open.alipay.com 访问
4.进入沙箱环境进行配置
在沙箱账号里面进行充值虚拟金额
5.下载工具生成密钥
下载链接网页
下载安装后进入工具
打开密钥文件路径
设置加密配置
搞定完前期准备后,下面代码配置
二.实现支付宝支付接口
1.在pom.xml文件添加依赖
<!--支付宝支付-->
<dependency>
<groupId>com.alipay.sdk</groupId>
<artifactId>alipay-sdk-java</artifactId>
<version>3.0.0</version>
</dependency>
2.配置config类
这里就是上面的demo,我再复制一遍,将开发环境的内容一一对应填入
import java.io.FileWriter;
import java.io.IOException;
public class AlipayConfig {
// 应用ID,您的APPID,收款账号既是您的APPID对应支付宝账号,开发时使用沙箱提供的APPID,生产环境改成自己的APPID
public static String APP_ID = "";
// 商户私钥,您的PKCS8格式RSA2私钥
public static String APP_PRIVATE_KEY = "";
// 支付宝公钥,查看地址:https://openhome.alipay.com/platform/keyManage.htm 对应APPID下的支付宝公钥。
public static String ALIPAY_PUBLIC_KEY = "";
// 服务器异步通知页面路径 需http://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问
public static String notify_url = "";
// 页面跳转同步通知页面路径 需http://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问(其实就是支付成功后返回的页面)
public static String return_url = "";
// 签名方式
public static String SIGN_TYPE = "RSA2";
// 字符编码格式
public static String CHARSET = "utf-8";
// 支付宝网关,这是沙箱的网关
public static String GATEWAYURL = "https://openapi.alipaydev.com/gateway.do";
// 支付宝网关
public static String log_path = "C:\\";
//↑↑↑↑↑↑↑↑↑↑请在这里配置您的基本信息↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
/**
* 写日志,方便测试(看网站需求,也可以改成把记录存入数据库)
* @param sWord 要写入日志里的文本内容
*/
public static void logResult(String sWord) {
FileWriter writer = null;
try {
writer = new FileWriter(log_path + "alipay_log_" + System.currentTimeMillis()+".txt");
writer.write(sWord);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (writer != null) {
try {
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
3.配置支付接口
import com.alipay.api.AlipayApiException;
/**
* 支付接口
* @author zwz
*
*/
public interface AlipayService {
/**
* web端订单支付
* @param outTradeNo 订单编号(唯一)
* @param totalAmount 订单价格
* @param subject 商品名称
*/
String webPagePay(String outTradeNo,Integer totalAmount,String subject) throws Exception;
/**
* app端订单支付
* @param outTradeNo 订单编号
* @param totalAmount 订单价格
* @param subject 商品名称
*/
String appPagePay(String outTradeNo,Integer totalAmount,String subject) throws Exception;
/**
* 退款
* @param outTradeNo 订单编号
* @param refundReason 退款原因
* @param refundAmount 退款金额
* @param outRequestNo 标识一次退款请求,同一笔交易多次退款需要保证唯一,如需部分退款,则此参数必传
*/
String refund(String outTradeNo,String refundReason,Integer refundAmount,String outRequestNo) throws AlipayApiException;
/**
* 交易查询
* @param outTradeNo 订单编号(唯一)
*/
String query(String outTradeNo) throws AlipayApiException;
/**
* 交易关闭
* @param outTradeNo 订单编号(唯一)
*/
String close(String outTradeNo) throws AlipayApiException;
/**
* 退款查询
* @param outTradeNo 订单编号(唯一)
* @param outRequestNo 标识一次退款请求,同一笔交易多次退款需要保证唯一,如需部分退款,则此参数必传
*/
String refundQuery(String outTradeNo,String outRequestNo) throws AlipayApiException;
}
4.配置支付接口实现类
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.AlipayTradeWapPayModel;
import com.alipay.api.request.*;
import com.zwz.config.AlipayConfig;
import org.springframework.stereotype.Service;
@Service("alipayService")
public class AlipayServiceImpI implements AlipayService{
/** 调取支付宝接口 web端支付*/
DefaultAlipayClient alipayClient = new DefaultAlipayClient(
AlipayConfig.GATEWAYURL, AlipayConfig.APP_ID, AlipayConfig.APP_PRIVATE_KEY, "json", AlipayConfig.CHARSET, AlipayConfig.ALIPAY_PUBLIC_KEY, AlipayConfig.SIGN_TYPE);
/** 调取支付宝接口app端支付*/
AlipayClient alipayClients = new DefaultAlipayClient(
AlipayConfig.GATEWAYURL, AlipayConfig.APP_ID, AlipayConfig.APP_PRIVATE_KEY, "json", AlipayConfig.CHARSET, AlipayConfig.ALIPAY_PUBLIC_KEY, AlipayConfig.SIGN_TYPE);
/**
* web端订单支付
*
* @param outTradeNo 订单编号(唯一)
* @param totalAmount 订单价格
* @param subject 商品名称
*/
@Override
public String webPagePay(String outTradeNo, Integer totalAmount, String subject) throws Exception {
AlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest();
/** 同步通知,支付完成后,支付成功页面*/
alipayRequest.setReturnUrl(AlipayConfig.return_url);
/** 异步通知,支付完成后,需要进行的异步处理*/
alipayRequest.setNotifyUrl(AlipayConfig.notify_url);
alipayRequest.setBizContent("{" +
" \"out_trade_no\":\""+outTradeNo+"\"," +
" \"product_code\":\"FAST_INSTANT_TRADE_PAY\"," +
" \"total_amount\":"+totalAmount+"," +
" \"subject\":\""+subject+"\"," +
" \"body\":\""+"商品介绍"+"\"," +
"\"product_code\":\"FAST_INSTANT_TRADE_PAY\"}");
/**转换格式*/
String result = alipayClient.pageExecute(alipayRequest).getBody().replace('\"','\'').replace('\n',' ');
return result;
}
/**
* app端订单支付
*
* @param outTradeNo 订单编号
* @param totalAmount 订单价格
* @param subject 商品名称
*/
@Override
public String appPagePay(String outTradeNo, Integer totalAmount, String subject) throws Exception {
AlipayTradeWapPayRequest alipayRequest=new AlipayTradeWapPayRequest();
/** 同步通知,支付完成后,支付成功页面*/
alipayRequest.setReturnUrl(AlipayConfig.return_url);
/** 异步通知,支付完成后,需要进行的异步处理*/
alipayRequest.setNotifyUrl(AlipayConfig.notify_url);
/**销售产品码(固定)*/
String productCode="QUICK_WAP_WAY";
/** 进行赋值 */
AlipayTradeWapPayModel wapPayModel=new AlipayTradeWapPayModel();
wapPayModel.setOutTradeNo(outTradeNo);
wapPayModel.setSubject(subject);
wapPayModel.setTotalAmount(totalAmount.toString());
wapPayModel.setBody("商品名称");
wapPayModel.setTimeoutExpress("200000m");
wapPayModel.setProductCode(productCode);
alipayRequest.setBizModel(wapPayModel);
/** 格式转换*/
String result = alipayClients.pageExecute(alipayRequest).getBody().replace('\"','\'').replace('\n',' ');
return result;
}
/**
* 退款
*
* @param outTradeNo 订单编号
* @param refundReason 退款原因
* @param refundAmount 退款金额
* @param outRequestNo 标识一次退款请求,同一笔交易多次退款需要保证唯一,如需部分退款,则此参数必传
*/
@Override
public String refund(String outTradeNo, String refundReason, Integer refundAmount, String outRequestNo) throws AlipayApiException {
AlipayTradeRefundRequest alipayRequest = new AlipayTradeRefundRequest();
/** 调取接口*/
alipayRequest.setBizContent("{\"out_trade_no\":\""+ outTradeNo +"\","
+ "\"refund_amount\":\""+ refundAmount +"\","
+ "\"refund_reason\":\""+ refundReason +"\","
+ "\"out_request_no\":\""+ outRequestNo +"\"}");
String result = alipayClient.execute(alipayRequest).getBody();
return result;
}
/**
* 交易查询
*
* @param outTradeNo 订单编号(唯一)
*/
@Override
public String query(String outTradeNo) throws AlipayApiException {
AlipayTradeQueryRequest alipayRequest = new AlipayTradeQueryRequest();
/**请求接口*/
alipayRequest.setBizContent("{\"out_trade_no\":\""+ outTradeNo +"\","+"\"trade_no\":\""+ "" +"\"}");
/**转换格式*/
String result = alipayClient.execute(alipayRequest).getBody();
return result;
}
/**
* 交易关闭
*
* @param outTradeNo 订单编号(唯一)
*/
@Override
public String close(String outTradeNo) throws AlipayApiException {
AlipayTradeCloseRequest alipayRequest = new AlipayTradeCloseRequest();
alipayRequest.setBizContent("{\"out_trade_no\":\""+ outTradeNo +"\"," +"\"trade_no\":\""+ "" +"\"}");
String result = alipayClient.execute(alipayRequest).getBody();
return result;
}
/**
* 退款查询
*
* @param outTradeNo 订单编号(唯一)
* @param outRequestNo 标识一次退款请求,同一笔交易多次退款需要保证唯一,如需部分退款,则此参数必传
*/
@Override
public String refundQuery(String outTradeNo, String outRequestNo) throws AlipayApiException {
AlipayTradeFastpayRefundQueryRequest alipayRequest = new AlipayTradeFastpayRefundQueryRequest();
/** 请求接口*/
alipayRequest.setBizContent("{\"out_trade_no\":\""+ outTradeNo +"\","
+"\"out_request_no\":\""+ outRequestNo +"\"}");
/** 格式转换*/
String result = alipayClient.execute(alipayRequest).getBody();
return result;
}
}
5.配置Contorller
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class PayController {
@Autowired
@Qualifier("alipayService")
private AlipayService alipayService;
@RequestMapping("/pay")
public String payController(@RequestParam("WIDout_trade_no") String id,@RequestParam("WIDsubject") String name,@RequestParam("WIDtotal_amount") String amount ) throws Exception {
Integer pay=Integer.valueOf(amount);
String pays = alipayService.webPagePay(id, pay, name);
return pays;
}
}
然后配置一个html页面,用来模拟数据库实现支付接口
这里我就配置一个简单的页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/pay" method="post">
订单号:<input type="text" name="WIDout_trade_no" required><br/>
订单名称:<input type="text" name="WIDsubject" required><br/>
付款金额:<input type="text" name="WIDtotal_amount" required><br/>
<input type="submit" value="下单"> <input type="reset" value="重置">
</form>
</body>
</html>