支付宝SDK依赖
<!--支付宝-->
<dependency>
<groupId>com.alipay.sdk</groupId>
<artifactId>alipay-sdk-java</artifactId>
<version>3.3.4.ALL</version>
</dependency>
支付宝参数配置类
@Component
@Configuration
public class AliDevPayConfig implements Serializable {
/**
* 支付宝服务器主动通知商户服务器里指定的页面http/https路径
* 异步请求,地址必须是公网可以访问的才行,不能有任何参数
* 例如:项目发布地址/本项目名/接口名
*/
public static String NOTIFY_URL;
public static String RETURN_URL;
@Value("${alipay.aliPayReturnUrl}")
public void setReturnUrl(String returnUrl) {
RETURN_URL = returnUrl;
}
@Value("${alipay.aliPayNotifyUrl}")
public void setNotifyUrl(String notifyUrl) {
NOTIFY_URL = notifyUrl;
}
public String getNotifyUrl() {
return NOTIFY_URL;
}
public String getReturnUrl() {
return RETURN_URL;
}
/**支付宝分配给开发者的应用ID*/
public static String aliPayAppId = "开发者id";
/**支付宝网关*/
public static String aliPayGateWay = "https://openapi.alipay.com/gateway.do";
/**私钥*/
public static String aliPayPrivateKey = "你的私钥";
/**支付宝公钥*/
public static String aliPayPublicKey = "你的公钥";
/**仅支持JSON*/
public static String FORMAT = "JSON";
/**请求使用的编码格式,如utf-8,gbk,gb2312等*/
public static String CHARSET = "utf-8";
/**商户生成签名字符串所使用的签名算法类型,目前支持RSA2和RSA,推荐使用RSA2*/
public static String SIGN_TYPE = "RSA2";
}
因为我的项目有多个环境,会有多个对应的配置文件,所以我选择用@Value注入的方式。
配置文件的url配置如下:
alipay:
aliPayNotifyUrl: 异步回调url
aliPayReturnUrl: 同步回调url
Controller
@Resource
PayService payService;
@RequestMapping(value = "/ali", method = RequestMethod.POST)
@ApiOperation(value="[支付宝]充值")
public Result<String> alipayTopup(@RequestBody AliPayRechargeDTO aliPayRechargeDTO){
return Result.getSuccess(payService.saveAliPayRechangeBill(aliPayRechargeDTO));
}
@RequestMapping(value = "/alipaynotice", method = RequestMethod.POST)
@ApiOperation(value="[支付宝专用]支付宝充值接口异步回调接口")
public String paynotice(HttpServletRequest request){
return payService.alipayNotify(request);
}
DTO对象传入你所需要的参数,比如金额,账户id等等。
Service
@Slf4j
@Service
public class PayService{
public String saveAliPayRechangeBill(AliPayRechargeDTO rechargeDTO){
BigDecimal totalAmount = rechargeDTO.getRechargeTotalAmount();
//实例化客户端(参数:网关地址、商户appid、商户私钥、格式、编码、支付宝公钥、加密类型),为了取得预付订单信息
AlipayClient alipayClient = new DefaultAlipayClient(AliDevPayConfig.aliPayGateWay, AliDevPayConfig.aliPayAppId,
AliDevPayConfig.aliPayPrivateKey, AliDevPayConfig.FORMAT, AliDevPayConfig.CHARSET,
AliDevPayConfig.aliPayPublicKey, AliDevPayConfig.SIGN_TYPE);
//实例化具体API对应的request类,类名称和接口名称对应,当前调用接口名称:alipay.trade.app.pay
AlipayTradeAppPayRequest ali_request = new AlipayTradeAppPayRequest();
//SDK已经封装掉了公共参数,这里只需要传入业务参数。以下方法为sdk的model入参方式
AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
//对一笔交易的具体描述信息。如果是多种商品,请将商品描述字符串累加传给body。
model.setBody("xx商品介绍");
//商品名称
model.setSubject("xx商品");
//商户订单号(根据业务需求自己生成)
model.setOutTradeNo("你自己业务账单的id");
//交易超时时间 这里的30m就是30分钟
model.setTimeoutExpress("30m");
//支付金额 后面保留2位小数点..不能超过2位
model.setTotalAmount(totalAmount.toString());
//销售产品码(固定值)
model.setProductCode("QUICK_MSECURITY_PAY");
ali_request.setBizModel(model);
//异步回调地址(后台)
ali_request.setNotifyUrl(AliDevPayConfig.NOTIFY_URL);
log.info("Alipay异步通知的地址为:" + ali_request.getNotifyUrl());
try{
// 这里和普通的接口调用不同,使用的是sdkExecute
//返回支付宝订单信息(预处理)
AlipayTradeAppPayResponse alipayTradeAppPayResponse = alipayClient.sdkExecute(ali_request);
//就是orderString 可以直接给APP请求,无需再做处理。
String alipayTransferId = alipayTradeAppPayResponse.getBody();
log.info("需要返回给支付宝的数据 alipayTransferId:" + alipayTransferId);
return alipayTransferId;
}catch (AlipayApiException e){
e.printStackTrace();
}
return null;
}
public String alipayNotify(HttpServletRequest request) {
log.info("支付宝异步返回支付结果开始");
//1.从支付宝回调的request域中取值
//获取支付宝返回的参数集合
Map<String, String[]> aliParams = request.getParameterMap();
log.info("支付宝Post过来的反馈信息:" + aliParams.toString());
//用以存放转化后的参数集合
Map<String, String> conversionParams = new HashMap<String, String>();
for (Iterator<String> iter = aliParams.keySet().iterator(); iter.hasNext();) {
String key = iter.next();
String[] values = aliParams.get(key);
String valueStr = "";
for (int i = 0; i < values.length; i++) {
valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ",";
}
// 乱码解决,这段代码在出现乱码时使用。如果mysign和sign不相等也可以使用这段代码转化
//valueStr = new String(valueStr.getBytes("ISO-8859-1"), "UTF-8");
conversionParams.put(key, valueStr);
}
log.info("支付宝返回参数集合:"+conversionParams);
String status=aliPayCheck(conversionParams);
return status;
}
public String aliPayCheck(Map conversionParams){
log.info("=支付宝异步请求逻辑处理=");
//签名验证(对支付宝返回的数据验证,确定是支付宝返回的)
boolean signVerified = false;
try {
//调用SDK验证签名
String alipayPublicKey = AliDevPayConfig.aliPayPublicKey;
String charset = AliDevPayConfig.CHARSET;
String signType = AliDevPayConfig.SIGN_TYPE;
signVerified = AlipaySignature.rsaCheckV1(conversionParams, alipayPublicKey, charset, signType);
//对验签进行处理.
if (signVerified) {
log.info("+++++++++++支付宝回调签名认证成功+++++++++++");
// 按照支付结果异步通知中的描述,对支付结果中的业务内容进行1\2\3\4二次校验,校验成功后在response中返回success,校验失败返回failure 支付宝官方建议校验的值(out_trade_no、total_amount、sellerId、app_id)
//验签通过 获取交易状态
String tradeStatus = (String)conversionParams.get("trade_status");
//只处理支付成功的订单: 修改交易表状态,支付成功
//只有交易通知状态为TRADE_SUCCESS或TRADE_FINISHED时,支付宝才会认定为买家付款成功。
if (tradeStatus.equals("TRADE_SUCCESS") ||tradeStatus.equals("TRADE_FINISHED")) {
//TODO 获取支付宝通知完成充值后续业务
//交易成功 获取商户账单id
String billId = (String) conversionParams.get("out_trade_no");
//支付宝交易流水号
String ali_pay_no = (String) conversionParams.get("trade_no");
//TODO 修改业务订单信息
//TODO 余额到账,消息推送
return "success";
} else {
return "fail";
}
}else{ //验签不通过
log.info("++验签不通过 !++");
return "fail";
}
} catch (AlipayApiException e) {
log.info("+++验签失败 !+++");
e.printStackTrace();
}
return "fail";
}
}
以上saveAliPayRechangeBill方法返回的类型如下
app_id=2015052600090779&biz_content=%7B%22timeout_express%22%3A%2230m%22%2C%22seller_id%22%3A%22%22%2C%22product_code%22%3A%22QUICK_MSECURITY_PAY%22%2C%22total_amount%22%3A%220.01%22%2C%22subject%22%3A%221%22%2C%22body%22%3A%22%E6%88%91%E6%98%AF%E6%B5%8B%E8%AF%95%E6%95%B0%E6%8D%AE%22%2C%22out_trade_no%22%3A%22IQJZSRC1YMQB5HU%22%7D&charset=utf-8&format=json&method=alipay.trade.app.pay¬ify_url=http%3A%2F%2Fdomain.merchant.com%2Fpayment_notify&sign_type=RSA2×tamp=2016-08-25%2020%3A26%3A31&version=1.0&sign=cYmuUnKi5QdBsoZEAbMXVMmRWjsuUj%2By48A2DvWAVVBuYkiBj13CFDHu2vZQvmOfkjE0YqCUQE04kqm9Xg3tIX8tPeIGIFtsIyp%2FM45w1ZsDOiduBbduGfRo1XRsvAyVAv2hCrBLLrDI5Vi7uZZ77Lo5J0PpUUWwyQGt0M4cj8g%3D
以上结果等价于如下,但上面才是正常的返回结果。
body="test"&_input_charset="UTF-8"&it_b_pay="1d"&total_fee="1"&subject="test"¬ify_url="http://www.bejson.com/api/alipay/testpayotify.php"&service="mobile.securitypay.pay"&seller_id="cw@bejson.com"&partner="2088301"&out_trade_no="2088301971894011"&payment_type="1"&show_url="http://www.dcloud.io/helloh5/"&sign="RtUKAGMfelb5sl2az4YKhxst051l94FSkpk9xoD91Hbpr2PKnWjHIafTWqNLyxGibde%2BKwcq9Y8cDN0qU%2FsO6hXjch0B4GaMJHBxZQM%2FnJK2YGxPPOWFKKL5rBKVJ%2BrX4OImfSQIyKKUpAEFG6uFfek2hh%2FPFJSXk2Phvmrb8U%3D"&sign_type="RSA"
调用时,请核对所有支付宝所必要的参数,参考支付宝参数
至此就已经差不多完成支付宝的接入了,如果有其他问题可以百度或者留言,如果有什么错误,欢迎多多指正批评。:)