Spring boot--支付宝APP支付安卓老版接口实现(含代码)
来源:互联网 发布:怎么举报一个软件 编辑:程序博客网 时间:2024/04/29 21:48
最近在做一些支付宝相关的支付后台实现,主要用的是Spring boot框架。因为支付宝老版的文档已经十分不详细(新版的也说的不清楚),所以我踩了无数坑,决定写篇博客来帮助后来人。
关于新版支付宝支付,需要APPID,也就是说必须在支付宝那儿建立应用并上线,还必须签约APP支付开通这个服务才能用。
但是本次我使用的是老版APP支付接口,所以并不需要APPID,只要签约支付宝开通APP支付服务就行。
关于流程,前端使用的是DCcloud的H5框架,集成了支付宝客户端SDK,整个流程如下:
用户点击支付按钮->客户端调用自己服务端API->自己服务端生成支付orderinfo(字符串)返回客户端->客户端拿orderinfo调用支付宝客户端SDK->SDK自启动支付宝APP完成支付->支付宝服务端给自己服务端发送异步通知->用户在异步通知验证支付成功后对自己数据库进行操作。
第一步:生成私钥公钥。这个可以用工具生成,需要去下载一键生成RSA密钥工具。下载地址:https://doc.open.alipay.com/docs/doc.htm?spm=a219a.7629140.0.0.pohUoc&treeId=291&articleId=106097&docType=1
第二步:在支付宝网站上上传你的公钥:
为防万一,请将开放平台密钥,mapi网关产品密钥,老版wap支付密钥全部配上你自己生成的公钥。
支付宝异步通知你的时候,请使用mapi网关产品密钥的支付宝公钥进行验证。
第三步:服务端如何生成orderinfo?不多说直接上代码:
package com.ibm.callcenter.controller;import com.alipay.api.AlipayApiException;import com.alipay.api.AlipayClient;import com.alipay.api.DefaultAlipayClient;import com.alipay.api.domain.AlipayTradeAppPayModel;import com.alipay.api.internal.util.AlipaySignature;import com.alipay.api.request.AlipayTradeAppPayRequest;import com.alipay.api.response.AlipayTradeAppPayResponse;import org.springframework.stereotype.Controller;import org.springframework.ui.Model;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestMethod;import org.springframework.web.bind.annotation.RequestParam;import org.springframework.web.bind.annotation.ResponseBody;import com.ibm.callcenter.util.SignUtils;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.UnsupportedEncodingException;import java.net.URLEncoder;import java.text.SimpleDateFormat;import java.util.Date;import java.util.HashMap;import java.util.Iterator;import java.util.Map;@Controller@RequestMapping(value="/alipay")@ResponseBodypublic class test { @RequestMapping(value = "/pay") public String pay(//@RequestParam("fee") String total_fee, HttpServletResponse response1) { Date now = new Date(); SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmss");//可以方便地修改日期格式 String hehe = dateFormat.format( now ); System.out.println(hehe+"test123"); String out_strade_no=hehe+"wentest"; //自己写的订单编号 String private_key="写上你自己生成的与上传公钥相对应的私钥"; String partner="写上你自己的UID(PID)"; String seller_id="写上你支付宝收款的账号"; String body="aiyoubucuo"; String notify_url="写上你异步通知的接口地址,切记需要是外网地址"; String show_url="https://www.baidu.com/"; //支付宝同步跳转地址 String total_fee="0.01"; //支付金额 String subject="test"; String order="service=\"mobile.securitypay.pay\"&partner=\""+partner+"\"&_input_charset=\"UTF-8\"&out_trade_no=\""+out_strade_no+"\"&subject=\""+subject+"\"&payment_type=\"1\"&seller_id=\""+seller_id+"\"&total_fee=\""+total_fee+"\"&body=\""+body+"\"&it_b_pay=\"1d\"¬ify_url=\""+notify_url+"\"&show_url=\""+show_url+"\""; String sign=SignUtils.sign(order,private_key,false); try { // 仅需对sign 做URL编码 sign = URLEncoder.encode(sign, "UTF-8"); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } final String result = order + "&sign=\"" + sign + "\"&" + getSignType(); System.err.println("123"+result); return result; } public String getSignType() { return "sign_type=\"RSA\""; } /** * 异步通知付款状态的Controller * @param request * @param response * @return */ @SuppressWarnings("rawtypes") @RequestMapping(value="/notify",method = RequestMethod.POST ) public String notify(HttpServletRequest request, HttpServletResponse response) throws AlipayApiException { Map<String,String> params = new HashMap<String,String>(); 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); } String CHARSET = "UTF-8"; String ALIPAY_PUBLIC_KEY="写上你支付宝生成的公钥"; String tradeNo = request.getParameter("out_trade_no"); String tradeStatus = request.getParameter("trade_status"); //String notifyId = request.getParameter("notify_id"); //System.err.println(params.toString()); boolean flag = AlipaySignature.rsaCheckV1(params,ALIPAY_PUBLIC_KEY, CHARSET,"RSA"); if(flag){//验证成功 if(tradeStatus.equals("TRADE_FINISHED") || tradeStatus.equals("TRADE_SUCCESS")) { //要写的逻辑。自己按自己的要求写// log.error("ok......."); System.err.println(">>>>>充值成功" + tradeNo); } return "success"; }else{//验证失败 System.out.println("fail yanzheng"); return "web/pay/fail"; } }}把生成签名的两个需要依赖的类也给大家:
package com.ibm.callcenter.util;import java.security.KeyFactory;import java.security.PrivateKey;import java.security.spec.PKCS8EncodedKeySpec;public class SignUtils { private static final String ALGORITHM = "RSA"; private static final String SIGN_ALGORITHMS = "SHA1WithRSA"; private static final String SIGN_SHA256RSA_ALGORITHMS = "SHA256WithRSA"; private static final String DEFAULT_CHARSET = "UTF-8"; private static String getAlgorithms(boolean rsa2) { return rsa2 ? SIGN_SHA256RSA_ALGORITHMS : SIGN_ALGORITHMS; } public static String sign(String content, String privateKey, boolean rsa2) { try { PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec( Base64.decode(privateKey)); KeyFactory keyf = KeyFactory.getInstance(ALGORITHM); PrivateKey priKey = keyf.generatePrivate(priPKCS8); java.security.Signature signature = java.security.Signature .getInstance(getAlgorithms(rsa2)); signature.initSign(priKey); signature.update(content.getBytes(DEFAULT_CHARSET)); byte[] signed = signature.sign(); return Base64.encode(signed); } catch (Exception e) { e.printStackTrace(); } return null; }}以及这个:
package com.ibm.callcenter.util;public final class Base64 {private static final int BASELENGTH = 128;private static final int LOOKUPLENGTH = 64;private static final int TWENTYFOURBITGROUP = 24;private static final int EIGHTBIT = 8;private static final int SIXTEENBIT = 16;private static final int FOURBYTE = 4;private static final int SIGN = -128;private static char PAD = '=';private static byte[] base64Alphabet = new byte[BASELENGTH];private static char[] lookUpBase64Alphabet = new char[LOOKUPLENGTH];static {for (int i = 0; i < BASELENGTH; ++i) {base64Alphabet[i] = -1;}for (int i = 'Z'; i >= 'A'; i--) {base64Alphabet[i] = (byte) (i - 'A');}for (int i = 'z'; i >= 'a'; i--) {base64Alphabet[i] = (byte) (i - 'a' + 26);}for (int i = '9'; i >= '0'; i--) {base64Alphabet[i] = (byte) (i - '0' + 52);}base64Alphabet['+'] = 62;base64Alphabet['/'] = 63;for (int i = 0; i <= 25; i++) {lookUpBase64Alphabet[i] = (char) ('A' + i);}for (int i = 26, j = 0; i <= 51; i++, j++) {lookUpBase64Alphabet[i] = (char) ('a' + j);}for (int i = 52, j = 0; i <= 61; i++, j++) {lookUpBase64Alphabet[i] = (char) ('0' + j);}lookUpBase64Alphabet[62] = (char) '+';lookUpBase64Alphabet[63] = (char) '/';}private static boolean isWhiteSpace(char octect) {return (octect == 0x20 || octect == 0xd || octect == 0xa || octect == 0x9);}private static boolean isPad(char octect) {return (octect == PAD);}private static boolean isData(char octect) {return (octect < BASELENGTH && base64Alphabet[octect] != -1);}/** * Encodes hex octects into Base64 * * @param binaryData * Array containing binaryData * @return Encoded Base64 array */public static String encode(byte[] binaryData) {if (binaryData == null) {return null;}int lengthDataBits = binaryData.length * EIGHTBIT;if (lengthDataBits == 0) {return "";}int fewerThan24bits = lengthDataBits % TWENTYFOURBITGROUP;int numberTriplets = lengthDataBits / TWENTYFOURBITGROUP;int numberQuartet = fewerThan24bits != 0 ? numberTriplets + 1: numberTriplets;char encodedData[] = null;encodedData = new char[numberQuartet * 4];byte k = 0, l = 0, b1 = 0, b2 = 0, b3 = 0;int encodedIndex = 0;int dataIndex = 0;for (int i = 0; i < numberTriplets; i++) {b1 = binaryData[dataIndex++];b2 = binaryData[dataIndex++];b3 = binaryData[dataIndex++];l = (byte) (b2 & 0x0f);k = (byte) (b1 & 0x03);byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2): (byte) ((b1) >> 2 ^ 0xc0);byte val2 = ((b2 & SIGN) == 0) ? (byte) (b2 >> 4): (byte) ((b2) >> 4 ^ 0xf0);byte val3 = ((b3 & SIGN) == 0) ? (byte) (b3 >> 6): (byte) ((b3) >> 6 ^ 0xfc);encodedData[encodedIndex++] = lookUpBase64Alphabet[val1];encodedData[encodedIndex++] = lookUpBase64Alphabet[val2 | (k << 4)];encodedData[encodedIndex++] = lookUpBase64Alphabet[(l << 2) | val3];encodedData[encodedIndex++] = lookUpBase64Alphabet[b3 & 0x3f];}// form integral number of 6-bit groupsif (fewerThan24bits == EIGHTBIT) {b1 = binaryData[dataIndex];k = (byte) (b1 & 0x03);byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2): (byte) ((b1) >> 2 ^ 0xc0);encodedData[encodedIndex++] = lookUpBase64Alphabet[val1];encodedData[encodedIndex++] = lookUpBase64Alphabet[k << 4];encodedData[encodedIndex++] = PAD;encodedData[encodedIndex++] = PAD;} else if (fewerThan24bits == SIXTEENBIT) {b1 = binaryData[dataIndex];b2 = binaryData[dataIndex + 1];l = (byte) (b2 & 0x0f);k = (byte) (b1 & 0x03);byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2): (byte) ((b1) >> 2 ^ 0xc0);byte val2 = ((b2 & SIGN) == 0) ? (byte) (b2 >> 4): (byte) ((b2) >> 4 ^ 0xf0);encodedData[encodedIndex++] = lookUpBase64Alphabet[val1];encodedData[encodedIndex++] = lookUpBase64Alphabet[val2 | (k << 4)];encodedData[encodedIndex++] = lookUpBase64Alphabet[l << 2];encodedData[encodedIndex++] = PAD;}return new String(encodedData);}/** * Decodes Base64 data into octects * * @param encoded * string containing Base64 data * @return Array containind decoded data. */public static byte[] decode(String encoded) {if (encoded == null) {return null;}char[] base64Data = encoded.toCharArray();// remove white spacesint len = removeWhiteSpace(base64Data);if (len % FOURBYTE != 0) {return null;// should be divisible by four}int numberQuadruple = (len / FOURBYTE);if (numberQuadruple == 0) {return new byte[0];}byte decodedData[] = null;byte b1 = 0, b2 = 0, b3 = 0, b4 = 0;char d1 = 0, d2 = 0, d3 = 0, d4 = 0;int i = 0;int encodedIndex = 0;int dataIndex = 0;decodedData = new byte[(numberQuadruple) * 3];for (; i < numberQuadruple - 1; i++) {if (!isData((d1 = base64Data[dataIndex++]))|| !isData((d2 = base64Data[dataIndex++]))|| !isData((d3 = base64Data[dataIndex++]))|| !isData((d4 = base64Data[dataIndex++]))) {return null;}// if found "no data" just return nullb1 = base64Alphabet[d1];b2 = base64Alphabet[d2];b3 = base64Alphabet[d3];b4 = base64Alphabet[d4];decodedData[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4);decodedData[encodedIndex++] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));decodedData[encodedIndex++] = (byte) (b3 << 6 | b4);}if (!isData((d1 = base64Data[dataIndex++]))|| !isData((d2 = base64Data[dataIndex++]))) {return null;// if found "no data" just return null}b1 = base64Alphabet[d1];b2 = base64Alphabet[d2];d3 = base64Data[dataIndex++];d4 = base64Data[dataIndex++];if (!isData((d3)) || !isData((d4))) {// Check if they are PAD charactersif (isPad(d3) && isPad(d4)) {if ((b2 & 0xf) != 0)// last 4 bits should be zero{return null;}byte[] tmp = new byte[i * 3 + 1];System.arraycopy(decodedData, 0, tmp, 0, i * 3);tmp[encodedIndex] = (byte) (b1 << 2 | b2 >> 4);return tmp;} else if (!isPad(d3) && isPad(d4)) {b3 = base64Alphabet[d3];if ((b3 & 0x3) != 0)// last 2 bits should be zero{return null;}byte[] tmp = new byte[i * 3 + 2];System.arraycopy(decodedData, 0, tmp, 0, i * 3);tmp[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4);tmp[encodedIndex] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));return tmp;} else {return null;}} else { // No PAD e.g 3cQlb3 = base64Alphabet[d3];b4 = base64Alphabet[d4];decodedData[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4);decodedData[encodedIndex++] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));decodedData[encodedIndex++] = (byte) (b3 << 6 | b4);}return decodedData;}/** * remove WhiteSpace from MIME containing encoded Base64 data. * * @param data * the byte array of base64 data (with WS) * @return the new length */private static int removeWhiteSpace(char[] data) {if (data == null) {return 0;}// count characters that's not whitespaceint newSize = 0;int len = data.length;for (int i = 0; i < len; i++) {if (!isWhiteSpace(data[i])) {data[newSize++] = data[i];}}return newSize;}}代码与业务逻辑应该很清楚了。有不懂的同学可以评论问我,我再做补充。
阅读全文
1 0
- Spring boot--支付宝APP支付安卓老版接口实现(含代码)
- java--spring boot微信支付服务端实现含代码(app支付、扫码支付等)
- 支付宝支付接口 APP
- Dcloud中mui 微信支付和支付宝支付接口完美实现付款代码(PHP支付宝demo)
- 支付宝APP支付接口-PHP
- C#支付宝支付接口APP版
- 支付宝支付之APP支付接口 服务器端
- java支付宝app支付代码
- Delphi XE10实现移动端支付宝支付接口(含源码)
- Delphi XE10实现移动端支付宝支付接口(含源码)
- 支付宝接口实现
- app接入支付宝接口
- app支付--支付宝支付
- 支付-支付宝APP支付
- 支付--支付宝APP支付
- 搞定支付接口(一) 支付宝即时到账支付接口详细流程和代码
- android集成支付宝app支付(2.0)与升级1.0支付接口
- APP支付宝支付
- git 设置和公钥生成办法1
- 求三角形面积-gyy
- 10016---git checkout 命令详解
- 网页发起临时QQ会话
- 支持向量机通俗导论(理解SVM的三层境界)
- Spring boot--支付宝APP支付安卓老版接口实现(含代码)
- STM32调试相关问题
- MAT内存管理使用
- 刚开通微博
- VR开发——Unity动画系统(V客it学院技术分享)
- C++容器---关联式容器<map>&<multimap>
- 统计机器翻译词对齐模型IBM-model1
- 【LeetCode7】Reverse Integer
- Firebug 和我们say goodbye了你听说了吗?