1.蚂蚁金服账号申请及其配置
蚂蚁金服官网:https://open.alipay.com/platform/home.htm
支付包账号登录就好,然后正常注册就可以
注册完成后会跳到一个页面,选择研发服务
沙箱应用:要设置一个应用公钥
用到一个工具叫RSA签名验签工具windows版本的,这个网上一搜全是,也可以找我要,QQ:3367273643
然后打开是这样子的,我们启动这个bat文件
他会弹出一个东西,直接点击生成密钥就可以了
只用公钥,粘贴复制到网上的设置应用公钥,两个都设置。我这里之前已经粘过了,所以没粘之前的效果看不到,总之有两个让你设置公钥的地方,你全部设置就可以
2.SpringBoot框架整合
先建一个简单的springboot项目,什么都没有。
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 http://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.1.4.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.jk</groupId>
<artifactId>zfb-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>zfb-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>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- 沙箱支付 -->
<dependency>
<groupId>com.alipay.api</groupId>
<artifactId>k12-alipay-sdk</artifactId>
<version>0.0.1-beta</version>
</dependency>
<!-- 前台jar -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
需要建三个配置类,代码如下所示,需要改的地方,我已经写好备注,到时候你们肯定是写你们自己的连接信息。
AlipayConfig类:
package com.jk.conf;
import java.io.FileWriter;
import java.io.IOException;
public class AlipayConfig {
// 应用ID,您的APPID,收款账号既是您的APPID对应支付宝账号
public static String app_id = "2016093000627977";
// 商户私钥,您的PKCS8格式RSA2私钥
public static String merchant_private_key = "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCNOIem6oWNySazObXjHzJCOLGdGMC8RC8SstAd0R8RPPCYx1UX2uZSeNu1r5wJ3m5aAYkGQoKzTF492IRwwXAihNCnw+KAQUNO49jjW1GrfAS+qXyXb5KgxbSL31IxHSSUcnWl9eBBquEIFPqJ7i0rFy8+yDih7X4Lm+W+Qt1I9EqJmnFJiD0bu4p5ycWsdsyqJDdq93g7khR3PdvnrOa29dbgIvaJkkpdxpxVaEC1YJwDZajO8D2mFeLaFNOes83m8s+97GgVcOm5cwPLZlMVlHPdq+t4QxV5UZafwn9Zz0Av+AQSVKUQ58c0pGFQNaEwy0yTnBuqw8U1ijfrIjxVAgMBAAECggEAd3n6GleTwk8KNNuAbLT5+liou/YzKZSuFq29sVw5YoYiL7+E2HfUILYre90ksJzE09U0rl0a4sKbgMtr0VF2o12mgikRudx9K4NM/Z1GzURRZ1VRGXXFoctiYmv/x5mWVxk3O793iVcep43IIWWmRSyKRh1y/FxHJV8x0fQT7yGfb8hCPieR1OC5307YZyE1EeDjI9g0CRHE0y2/f3NFoJOTaqHp2uFSdnBePQ0zhkmhxck8bGXjuDsdNcqrEWus59YDC2yiexYB48Aiz5GC0/ESSZElVOUnL4T3nOMYh/yWAyxXArXj/yGNxseAxSCFkOrvX61FSg/jOk5yRLmNgQKBgQD+ZqnJhbB5SH4SOwFUtzC+a7mnsE+17SHe4MGDY8w6tMC/43h0sCy9b5aL0XzX0ldm0ST0c7cGsKPEGGTPYucYW124NCSfTzqKC2c0lBNWc4Uf188stKJKlhs3FjYKJv+QEuOGDyNDgcfE/ltOyBCRBspj2l3QZQ+TDNhMhb+TEQKBgQCOG8HbMplLquSt57N4wHvFJmhScpEeBiBJqJweGBCOOEJGuhTMylboeGIS6N7bllvmXdVkjlVZzIQS83qe0FjRfX740Y806tn7ITJU+/cWDq6ukhO/zFfLtM9OERziL1Mnx+SQ2soAN3BlwVsgmhJXmj45DvPJuCpsv8cEXCSNBQKBgQDDF1PJWR6WQ8N6k4lXwAw/WzlKoWjfaPR6iP2dluC9fHP8M6LiSWBl/bcDjikhEQs5q9WdKUgId1l/Pf3BFGWIRji+1C3phcasqkYBCjUyLPDAFK2p6PQ0IpzIR941NubxQ6r72Yv/bv0V0sGOztn1fbGjlYgwEfA5orYVKNRbIQKBgE/dibWHWmAMSzjxXwweIXFLhJXRjX0yNDMxb4v6OlOziov1SHtPvEgqX/QArD784ek2ExfQZmdxaUi9TcyzizcxMIrmO3WiB5/7qC3a7aKX3dR+hFrmnPD/TQKy22jC8BkLXomKbLxya9jEMlLARE63gQDQRnK37h/wKAlrP5+BAoGBAM/fjeLkbu+cQBO4KO25U1O9m/iAYkomjMA1kWLBsFUTxKHzgnku1Y0N+xqMjB9VMjY+NkR9nxpEsujMDwNbzCfgyLaKlD2rtkIqP2HBjHXiddUbNOgLWp/z37RQdbE7C7xMn+3o9Kx+s8WhsnRcg0UZiBjtzb15g98ZfbclKd/V";
// 支付宝公钥,查看地址:https://openhome.alipay.com/platform/keyManage.htm 对应APPID下的支付宝公钥。
public static String alipay_public_key = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAjTiHpuqFjckmszm14x8yQjixnRjAvEQvErLQHdEfETzwmMdVF9rmUnjbta+cCd5uWgGJBkKCs0xePdiEcMFwIoTQp8PigEFDTuPY41tRq3wEvql8l2+SoMW0i99SMR0klHJ1pfXgQarhCBT6ie4tKxcvPsg4oe1+C5vlvkLdSPRKiZpxSYg9G7uKecnFrHbMqiQ3avd4O5IUdz3b56zmtvXW4CL2iZJKXcacVWhAtWCcA2WozvA9phXi2hTTnrPN5vLPvexoFXDpuXMDy2ZTFZRz3avreEMVeVGWn8J/Wc9AL/gEElSlEOfHNKRhUDWhMMtMk5wbqsPFNYo36yI8VQIDAQAB";
// 服务器异步通知页面路径 需http://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问
public static String notify_url = "http://kyd.free.idcfengye.com/notify";
// 页面跳转同步通知页面路径 需http://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问
public static String return_url = "http://kyd.free.idcfengye.com/returnUrl";
// 签名方式
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 = "D:\\";
//↑↑↑↑↑↑↑↑↑↑请在这里配置您的基本信息↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
/**
* 写日志,方便测试(看网站需求,也可以改成把记录存入数据库)
* @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();
}
}
}
}
}
AlipayDemoController类:
package com.jk.conf;
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.AlipayTradePagePayRequest;
import org.springframework.stereotype.Controller;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.UUID;
@Controller
public class AlipayDemoController {
@RequestMapping(value = "/goAlipay", produces = "text/html; charset=UTF-8")
@ResponseBody
public String goAlipay(HttpServletRequest request, HttpServletRequest response,String price) throws Exception {
//获得初始化的AlipayClient
AlipayClient alipayClient = new DefaultAlipayClient(AlipayConfig.gatewayUrl, AlipayConfig.app_id, AlipayConfig.merchant_private_key, "json", AlipayConfig.charset, AlipayConfig.alipay_public_key, AlipayConfig.sign_type);
//设置请求参数
AlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest();
alipayRequest.setReturnUrl(AlipayConfig.return_url);
alipayRequest.setNotifyUrl(AlipayConfig.notify_url);
//商户订单号,商户网站订单系统中唯一订单号,必填
String out_trade_no = UUID.randomUUID().toString();
//付款金额,必填
String total_amount = price;
//订单名称,必填
String subject = "2016093000627977";
//商品描述,可空
String body = "";
// 该笔订单允许的最晚付款时间,逾期将关闭交易。取值范围:1m~15d。m-分钟,h-小时,d-天,1c-当天(1c-当天的情况下,无论交易何时创建,都在0点关闭)。 该参数数值不接受小数点, 如 1.5h,可转换为 90m。
String timeout_express = "1c";
alipayRequest.setBizContent("{\"out_trade_no\":\""+ out_trade_no +"\","
+ "\"total_amount\":\""+ total_amount +"\","
+ "\"subject\":\""+ subject +"\","
+ "\"body\":\""+ body +"\","
+ "\"timeout_express\":\""+ timeout_express +"\","
+ "\"product_code\":\"FAST_INSTANT_TRADE_PAY\"}");
//请求
String result = alipayClient.pageExecute(alipayRequest).getBody();
System.out.println("返回页面"+ result);
return result;
}
@RequestMapping("/returnUrl")
public String returnUrl(HttpServletRequest request, HttpServletResponse response) throws UnsupportedEncodingException, AlipayApiException {
response.setContentType("text/html;charset=utf-8");
boolean verifyResult = rsaCheckV1(request);
if(verifyResult){
//验证成功
//请在这里加上商户的业务逻辑程序代码,如保存支付宝交易号
//商户订单号
String out_trade_no = new String(request.getParameter("out_trade_no").getBytes("ISO-8859-1"),"UTF-8");
//支付宝交易号
String trade_no = new String(request.getParameter("trade_no").getBytes("ISO-8859-1"),"UTF-8");
String ids = (String) request.getSession().getAttribute("ids");
if(!StringUtils.isEmpty(ids)){
String[] split = ids.split(",");
for (String s : split) {
}
}
return "redirect:view";
}else{
return "redirect:error";
}
}
@RequestMapping("toView")
public String view(String viewName){
return viewName;
}
public boolean rsaCheckV1(HttpServletRequest request){
// https://docs.open.alipay.com/54/106370
// 获取支付宝POST过来反馈信息
Map<String,String> params = new HashMap<>();
Map requestParams = request.getParameterMap();
for (Iterator 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);
}
try {
boolean verifyResult = AlipaySignature.rsaCheckV1(params,
AlipayConfig.merchant_private_key,
AlipayConfig.charset,
AlipayConfig.sign_type);
return verifyResult;
} catch (AlipayApiException e) {
return true;
}
}
@RequestMapping("view")
public String view(){
return "hah";
}
@RequestMapping("notify")
public String notify(HttpServletRequest request) throws AlipayApiException, UnsupportedEncodingException {
// 一定要验签,防止黑客篡改参数
Map<String, String[]> parameterMap = request.getParameterMap();
StringBuilder notifyBuild = new StringBuilder("/****************************** alipay notify ******************************/\n");
parameterMap.forEach((key, value) -> notifyBuild.append(key + "=" + value[0] + "\n") );
// log.info(notifyBuild.toString());
boolean flag = this.rsaCheckV1(request);
if (flag) {
/**
* TODO 需要严格按照如下描述校验通知数据的正确性
*
* 商户需要验证该通知数据中的out_trade_no是否为商户系统中创建的订单号,
* 并判断total_amount是否确实为该订单的实际金额(即商户订单创建时的金额),
* 同时需要校验通知中的seller_id(或者seller_email) 是否为out_trade_no这笔单据的对应的操作方(有的时候,一个商户可能有多个seller_id/seller_email),
*
* 上述有任何一个验证不通过,则表明本次通知是异常通知,务必忽略。
* 在上述验证通过后商户必须根据支付宝不同类型的业务通知,正确的进行不同的业务处理,并且过滤重复的通知结果数据。
* 在支付宝的业务通知中,只有交易通知状态为TRADE_SUCCESS或TRADE_FINISHED时,支付宝才会认定为买家付款成功。
*/
//交易状态
String tradeStatus = new String(request.getParameter("trade_status").getBytes("ISO-8859-1"),"UTF-8");
// 商户订单号
String out_trade_no = new String(request.getParameter("out_trade_no").getBytes("ISO-8859-1"),"UTF-8");
//支付宝交易号
String trade_no = new String(request.getParameter("trade_no").getBytes("ISO-8859-1"),"UTF-8");
//付款金额
String total_amount = new String(request.getParameter("total_amount").getBytes("ISO-8859-1"),"UTF-8");
// TRADE_FINISHED(表示交易已经成功结束,并不能再对该交易做后续操作);
// TRADE_SUCCESS(表示交易已经成功结束,可以对该交易做后续操作,如:分润、退款等);
if(tradeStatus.equals("TRADE_FINISHED")){
//判断该笔订单是否在商户网站中已经做过处理
//如果没有做过处理,根据订单号(out_trade_no)在商户网站的订单系统中查到该笔订单的详细,
// 并判断total_amount是否确实为该订单的实际金额(即商户订单创建时的金额),并执行商户的业务程序
//请务必判断请求时的total_fee、seller_id与通知时获取的total_fee、seller_id为一致的
//如果有做过处理,不执行商户的业务程序
//注意:
//如果签约的是可退款协议,退款日期超过可退款期限后(如三个月可退款),支付宝系统发送该交易状态通知
//如果没有签约可退款协议,那么付款完成后,支付宝系统发送该交易状态通知。
} else if (tradeStatus.equals("TRADE_SUCCESS")){
//判断该笔订单是否在商户网站中已经做过处理
//如果没有做过处理,根据订单号(out_trade_no)在商户网站的订单系统中查到该笔订单的详细,
// 并判断total_amount是否确实为该订单的实际金额(即商户订单创建时的金额),并执行商户的业务程序
//请务必判断请求时的total_fee、seller_id与通知时获取的total_fee、seller_id为一致的
//如果有做过处理,不执行商户的业务程序
//注意:
//如果签约的是可退款协议,那么付款完成后,支付宝系统发送该交易状态通知。
}
return "redirect:view";
}
return "redirect:view";
}
}
CorsMapping类:
package com.jk.conf;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class CorsMapping implements WebMvcConfigurer {
@Override
/**
* 重新跨域支持方法
* CorsRegistry 开启跨域注册
*/
public void addCorsMappings(CorsRegistry registry) {
//addMapping 添加可跨域的请求地址
registry.addMapping("/**")
//设置跨域 域名权限 规定由某一个指定的域名+端口能访问跨域项目
.allowedOrigins("*")
//是否开启cookie跨域
.allowCredentials(false)
//规定能够跨域访问的方法类型
.allowedMethods("GET","POST","DELETE","PUT","OPTIONS")
//添加验证头信息 token
//.allowedHeaders()
//预检请求存活时间 在此期间不再次发送预检请求
.maxAge(3600);
}
}
前台页面:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<button onclick="jiesuan()">结算</button>
</body>
<script>
function jiesuan(){
location.href="/goAlipay?price="+100; //这个数字只是为了演示,实际应用肯定是写活的。
}
</script>
</html>
配置yml文件:
server:
port: 8080
spring:
application:
name: zfb-server
data:
thymeleaf:
encoding: UTF-8
servlet:
content-type: text/html
写一个跳转前台页面的PageController类:
package com.jk.conf;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("page")
public class PageController {
@RequestMapping("toindex")
public String toindex(){
return "list";
}
}
启动项目访问页面:
点击结算:
效果如上:
如果想进行支付操作,需要手机下载沙箱支付宝APP:
下载地址在官网:
直接扫码下载就行,你的登录账号和登录密码是自动生成的,见下图,用这个账号和密码登录就行,支付密码也是自动生成的,无需设置:
扫码支付后:
(余额均为虚假货币,无需担心!)
完成!