支付宝支付功能
时序图
在本地Maven仓库安装sdk
- mvn install:install-file -DgroupId=com.alipay -DartifactId=alipay-sdk -Dversion=3.0.0 -Dpackaging=jar -Dfile=alipay-sdk-java20180104135026.jar
在pom.xml中导入
<dependency>
<groupId>com.alipay</groupId>
<artifactId>alipay-sdk</artifactId>
<version>3.0.0</version>
</dependency>
调用支付宝生成二维码
1. 如何保证消息的幂等性?(第三方交易编号)
2.时序图
导入alipay.properties
alipay_url=https://openapi.alipaydev.com/gateway.do
app_id=2016103000778093
app_private_key=MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDf6+I2ykInMNpnsmcQUYrEiOBo5kjQrwpuyY9yhmDV4rgTre6uSa7vzknmo48+aNFQNL9y69cnClKHyq+dB7o8nMXfv4zd8tfepElUqxGw2LH3KFtid1ricc8dZQzodczhWOSDcHeub6ESA1tTdK+4eDGbPjX6yp/Hq2aegt1+gAzuUQQCCg6u8N4T53z4Uc1T5232Kw9jTRRr0+UOuXV11A8P3vBA/ry7TDEgGhnJk/GzV3ln5Y56vPuuUBvAZVaa59zFkUAUy4xKC4YcKcugVqGHwUSkkgCzlhp4kydgkaGwSCcbp/Qw+vw4b5K4aR+aiTKRvAm93DG2O8aX5LFFAgMBAAECggEBAMrIPYZMyHfhYAjEoV0/2yF8q22UDqEdw57s3gFi/FL2DKmVvC8N/2SgNoCt4k0sc1HlUvNp7OAoEvFydnMIynmVqASm3ZUqFKBFuzr36P90XkZrv8Z+PEoRsvT1zCjAdZgl/luiAGByKzW64HvFklTGVHY4cn35/ZS+/iHSdW/WKG+hj6LhgRG+Jsb1c4nmpe2hovdtxvUY7Sb7E7ygKFfqCZXUZR5vGAI7zlaVNmd8Gv18ww6rsDPTACjQcBlIehEa1m0HaYOdizNGeHSea2l/r9/x5ccEfk8JBNuF351OhzG2vPIq40/lj4d4tbTfE1o1kYareG+5VXwIbRgHsQECgYEA/k3ls42FN5XGOFxqd5YpBx6siGN/yY5j1dnw5mPWFiFnmOMsAvDxHjPt9myOVhW8Q8OXXYtvYMX9/yIfwxXyfrSUI1QrrYppcI0GUZNDjh2bbqzmSLB38n0fVsmgMbyibjII3JaCo0sV54ciXPJUzYYxBj+qpDqomMTLsKF9KWECgYEA4WofR+moPHUstywulYgBExJI6ahNQ9XKoq8l1QKSQlW3T0+9tNaR3+oEJ46MLtO1KV7SSHs8B7umohZ/5g9jYNoQgadxvhNWbJXJgBeVLJgI4IFRpZqh1eHAcj6BG1w4IT8XPiDMtmW/rXOKl9y2c5j+npt12/8Or9L36OTqHmUCgYAM/cXCSnSHxmr97hqySUWHS5Xc0dhxX4jSH/QikO8a6lH0iYZyEAUBWf3KHPmYhDu96nwNF1Z1RygWpJOiz7g3qNn4hBBHKU8BpPKxsCg/VlveZ47MH9fA14uGT36Ti+NwZbX2Luo1lVxlG44x2V9jsHtIqm/5O9XpGASf3WAbgQKBgDPIHB15+JLC3B3MAXuKPazy41sBtZYis6UBlTBEofKpHC4VBGBZdjM43/FyVpOfQJubU7Ug0h54pgPQJVtlJ5AlJ+uQ2pkuegkBs8NAJ52R42AndOkVB55JeNsFrsTpP1+rzZwRDtXLs+eVhj3yjtspRzyKO93ozqfnT9npVDrdAoGAN1eITpbqJ4rzay/K4yESfflzaHE+szr7wzeSCta3x0BBqh/rbj92dUxcm+brVufFI2z6gahbRyCmPd5PBHFwu34cNUzQ+0lm9PrzRL+Zz/UOShctX0WfrEQWCn1SVcHblLNxiF8O7gNIqd8oFyybAkpU9sk21rgUz6mgIyj54IM=
alipay_public_key=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAkBLAabYiepY4M1j9ZbGTXt5CuO2YcqjjRZYBNpLYFFw01EQmfIz5cer6tLZ7VK/hvNX0al3xlc4c/YFQrdj3jxz5XSl6qxCbD3HHjbUXzKf7fFbkp9wPixGe+9ZvcR8bHp7FbAUBtMu4jqeNleEF33TP0PIisw3lFUTIrWitsMF99gVPzzryKHJm/8lZNrRi29t1Y1ZaWd9xIlRQiHEtxIusWTvzw3IIm4EKIeP5CAvsnUVOLY/3pmVcAnBHu9KvlmTE5gPs77zHn4iInsGph4qToahpyGsNAIghS83JSNruyND9XBXKw1weUOfx7pKyXSdONTamElql/xGVJ307+wIDAQAB
return_payment_url=http://payment.gmall.com/alipay/callback/return
notify_payment_url=http://60.205.215.91/alipay/callback/notify
return_order_url=http://order.gmall.com/list
AlipayConfig
@Configuration
@PropertySource("classpath:alipay.properties")
public class AlipayConfig {
@Value("${alipay_url}")
private String alipay_url;
@Value("${app_private_key}")
private String app_private_key;
@Value("${app_id}")
private String app_id;
public final static String format="json";
public final static String charset="utf-8";
public final static String sign_type="RSA2";
public static String return_payment_url;
public static String notify_payment_url;
public static String return_order_url;
public static String alipay_public_key;
@Value("${alipay_public_key}")
public void setAlipay_public_key(String alipay_public_key) {
AlipayConfig.alipay_public_key = alipay_public_key;
}
@Value("${return_payment_url}")
public void setReturn_url(String return_payment_url) {
AlipayConfig.return_payment_url = return_payment_url;
}
@Value("${notify_payment_url}")
public void setNotify_url(String notify_payment_url) {
AlipayConfig.notify_payment_url = notify_payment_url;
}
@Value("${return_order_url}")
public void setReturn_order_url(String return_order_url) {
AlipayConfig.return_order_url = return_order_url;
}
@Bean
public AlipayClient alipayClient(){
AlipayClient alipayClient=new DefaultAlipayClient(alipay_url,app_id,app_private_key,format,charset, alipay_public_key,sign_type );
return alipayClient;
}
}
生成二维码页面
@RequestMapping("alipay/submit")
@ResponseBody
public String alipaysubmit(HttpServletRequest request, HttpServletResponse httpResponse) {
String orderId = request.getParameter("orderId");
//通过orderId查询orderInfo
OrderInfo orderInfo = orderService.getOrderInfo(orderId);
//保存支付记录
PaymentInfo paymentInfo = new PaymentInfo();
//属性赋值
paymentInfo.setOrderId(orderId);
paymentInfo.setOutTradeNo(orderInfo.getOutTradeNo());
paymentInfo.setTotalAmount(orderInfo.getTotalAmount());
paymentInfo.setSubject("买东西");
paymentInfo.setPaymentStatus(PaymentStatus.UNPAID);
paymentService.savePaymentInfo(paymentInfo);
//生成二维码
//AlipayClient alipayClient = new DefaultAlipayClient( "https://openapi.alipay.com/gateway.do" , APP_ID, APP_PRIVATE_KEY, FORMAT, CHARSET, ALIPAY_PUBLIC_KEY, SIGN_TYPE); //获得初始化的AlipayClient
AlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest(); //创建API对应的request
alipayRequest.setReturnUrl(AlipayConfig.return_payment_url);
alipayRequest.setNotifyUrl(AlipayConfig.notify_payment_url); //在公共参数中设置回跳和通知地址
// alipayRequest.setReturnUrl( "http://domain.com/CallBack/return_url.jsp" );
// alipayRequest.setNotifyUrl( "http://domain.com/CallBack/notify_url.jsp" ); //在公共参数中设置回跳和通知地址
// //alipayRequest.putOtherTextParam("app_auth_token", "201611BB8xxxxxxxxxxxxxxxxxxxedcecde6");//如果 ISV 代商家接入电脑网站支付能力,则需要传入 app_auth_token,使用第三方应用授权;自研开发模式请忽略
//参数
Map<String,Object> map = new HashMap<>();
map.put("out_trade_no",paymentInfo.getOutTradeNo());
map.put("product_code","FAST_INSTANT_TRADE_PAY");
map.put("total_amount",paymentInfo.getTotalAmount());
map.put("subject",paymentInfo.getSubject());
alipayRequest.setBizContent(JSON.toJSONString(map));
// alipayRequest.setBizContent( "{" +
// " \"out_trade_no\":\"20150320010101001\"," +
// " \"product_code\":\"FAST_INSTANT_TRADE_PAY\"," +
// " \"total_amount\":88.88," +
// " \"subject\":\"Iphone6 16G\"," +
// " \"body\":\"Iphone6 16G\"," +
// " \"passback_params\":\"merchantBizType%3d3C%26merchantBizNo%3d2016010101111\"," +
// " \"extend_params\":{" +
// " \"sys_service_provider_id\":\"2088511833207846\"" +
// " }" +
// " }" ); //填充业务参数
String form= "" ;
try {
form = alipayClient.pageExecute(alipayRequest).getBody(); //调用SDK生成表单
} catch (AlipayApiException e) {
e.printStackTrace();
}
httpResponse.setContentType( "text/html;charset=UTF-8");
// httpResponse.getWriter().write(form); //直接将完整的表单html输出到页面
// httpResponse.getWriter().flush();
// httpResponse.getWriter().close();
return form;
}
支付宝支付后的异步回调
-
在通知返回参数列表中,除去 sign、sign_type 两个参数外,凡是通知返回回来的参数皆是待验签的参数。
-
将剩下参数进行 url_decode,然后进行字典排序,组成字符串,得到待签名字符串
-
将签名参数(sign)使用 base64 解码为字节码串。
-
使用 RSA 的验签方法,通过签名字符串、签名参数(经过 base64 解码)及支付宝公钥验证签名。
-
需要严格按照如下描述校验通知数据的正确性**:**
-
商户需要验证该通知数据中的 out_trade_no 是否为商户系统中创建的订单号;
-
判断 total_amount 是否确实为该订单的实际金额(即商户订单创建时的金额);
-
校验通知中的 seller_id 是否为 out_trade_no 这笔单据的对应的操作方(有的时候,一个商户可能有多个 seller_id);
-
验证 app_id 是否为该商户本身。
-
-
上述 1、2、3、4 有任何一个验证不通过,则表明本次通知是异常通知,务必忽略。 在上述验证通过后商户必须根据支付宝不同类型的业务通知,正确的进行不同的业务处理,并且过滤重复的通知结果数据。在支付宝的业务通知中,只有交易通知状态为 TRADE_SUCCESS 或 TRADE_FINISHED 时,支付宝才会认定为买家付款成功。
验签
//异步回调
@RequestMapping("alipay/callback/notify")
public String callbacknotify(@RequestParam Map<String, String> paramsMap,HttpServletRequest request) {
//paramsMap = ... //将异步通知中收到的所有参数都存放到map中
boolean signVerified = false; //调用SDK验证签名
try {
signVerified = AlipaySignature.rsaCheckV1(paramsMap, AlipayConfig.alipay_public_key, AlipayConfig.charset, AlipayConfig.sign_type);
} catch (AlipayApiException e) {
e.printStackTrace();
}
String out_trade_no = paramsMap.get("out_trade_no");
if(signVerified){
// TODO 验签成功后,按照支付结果异步通知中的描述,对支付结果中的业务内容进行二次校验,校验成功后在response中返回success并继续商户自身业务处理,校验失败返回failure
//对业务的二次校验
//只有交易通知状态为 TRADE_SUCCESS 或 TRADE_FINISHED 时,支付宝才会认定为买家付款成功。
//需要得到trade_status
String trade_status = paramsMap.get("trade_status");
if ("TRADE_SUCCESS".equals(trade_status)||"TRADE_FINISHED".equals(trade_status)) {
//根据out_trade_no查询paymentInfo
PaymentInfo paymentInfo = new PaymentInfo();
paymentInfo.setOutTradeNo(out_trade_no);
PaymentInfo paymentInfoHas = paymentService.getPaymentInfo(paymentInfo);
if (paymentInfoHas.getPaymentStatus()==PaymentStatus.PAID || paymentInfoHas.getPaymentStatus()==PaymentStatus.ClOSED) {
return "failure";
}
//更新交易记录状态
PaymentInfo paymentInfoUPD = new PaymentInfo();
paymentInfoUPD.setPaymentStatus(PaymentStatus.PAID);
paymentInfoUPD.setCallbackTime(new Date());
paymentService.updatePaymentInfo(out_trade_no,paymentInfoUPD);
return "success";
}
}else{
// TODO 验签失败则记录异常日志,并在response中返回failure.
return "failure";
}
return "failure";
}
退款接口
Controller
/**
* 根据oredrId退款
*/
@RequestMapping("refund")
@ResponseBody
public String refund(String orderId) {
Boolean result = paymentService.refund(orderId);
return ""+result;
}
service.impl
@Override
public Boolean refund(String orderId) {
//通过orderId获取数据
OrderInfo orderInfo = orderService.getOrderInfo(orderId);
String outTradeNo = orderInfo.getOutTradeNo();
//AlipayClient alipayClient = new DefaultAlipayClient("https://openapi.alipay.com/gateway.do","app_id","your private_key","json","GBK","alipay_public_key");
AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
Map<String,Object> map = new HashMap<>();
map.put("out_trade_no",outTradeNo);
map.put("refund_amount",orderInfo.getTotalAmount());
map.put("refund_reason","不买了");
request.setBizContent(JSON.toJSONString(map));
// request.setBizContent("{" +
// " \"out_trade_no\":\"20150320010101001\"," +
// " \"trade_no\":\"2014112611001004680073956707\"," +
// " \"refund_amount\":200.12," +
// " \"refund_reason\":\"正常退款\"," +
// " \"out_request_no\":\"HZ01RF001\"," +
// " \"operator_id\":\"OP001\"," +
// " \"store_id\":\"NJ_S_001\"," +
// " \"terminal_id\":\"NJ_T_001\"" +
// " }");
AlipayTradeRefundResponse response = null;
try {
response = alipayClient.execute(request);
} catch (AlipayApiException e) {
e.printStackTrace();
}
if(response.isSuccess()){
//更新状态
System.out.println("调用成功");
return true;
} else {
System.out.println("调用失败");
return false;
}
}
评论区