【APP支付】关于APP支付宝支付那些事_alipaytradeapppayrequest-程序员宅基地

技术标签: 【总结】  支付宝支付  APP支付  

昨天整理了关于APP微信支付的东西,今天在整理代码之后,来谈谈支付宝的APP支付。

两者有很大相似之处,也有区别,只要理解了一个,另一个就很好理解了,如果是第一次做服务端的支付的话,建议先看看上面那篇APP微信支付,我是从微信支付那边过来的,再看支付宝支付,就感觉很顺利了。

闲话少说,开始发招!

先看一下开发文档,创建应用:https://docs.open.alipay.com/200/105310/在这里插入图片描述
创建自己的应用之后,拿到一些开发中使用的信息,具体请看下面的配置文件里的信息。

首先是基础的配置文件AlipayConfig.java

package com.thinkgem.jeesite.modules.alipay;
public class AlipayConfig  {
    

    // 合作身份者ID,以2088开头由16位纯数字组成的字符串
    public static String partner = "2088**********3";

 // 6.请求网关地址
    public static String URL = "https://openapi.alipay.com/gateway.do";    

    public static String service = "mobile.securitypay.pay";//固定值
    //商家账号
    public static String seller_id = "[email protected]";
    //私钥
    public static String private_key = "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCUED+fmRDKV47vmJFtMl8EVZYlLHRCc98WP6QG19UP5J0EZsoSi/rOkG/LEHn83i5+uIfoMEvnr5/K9vvviulzdnrne3w852H7UgcSX/WyBQeamGH+8K0ReXVs2G+jno9oBoi5x5wchIjhoZ9eRRfk0Q89HVtcGjnkwqsXLHOAq3Ckpw5gfuzrXAV8RFS38hoBVs9e+fP+yZN6CEsJc0gHNsyBmm4/lhBhzKK1GFmHQ2iAJUI+pLjuYekILSioPChUFdnGkveRuk1xFN+dFW322P9sJI5E2cvkjZn1B47K3xIBD/UO14tmRL72JKGS6/QAltxa6AUBTAgMBAAECggEAbU1Bax51W5cJXYOdfsfcg/M+mStbyFnVx5FntOpvTXsIJhSJ4q09pi9st9XWwHRIhiuFeqU+GWUZXF6R4laZxonym8kGd/8F7OcT5YWNW/hmivnOaf5LwxIFlVQpyAlAfaHmQcr9R8gqmi9lNRXUn4fcxUsf5+2IGxuMwpZRg6Vz8P1pIlMZkK3XDtYSxHue9LluttzvZRIFuX23dNa2xWP392ClregMQfauv7zFh+UtmgC1xA7L+d6borg7eQSV6ic3j0rw5UOA8fAqxd2Qi4TMzDtASW5Y2tQemN3N+S3niqM2K/dKSN1wQKBgQDJKVMpuWSUgPs3o81sfdasfaIh2BaHmTTgx7bQyOyEK4dAWLA7L6pCKba1jgMkP15jP/WOupNN5w/LqrQxC1mta8rcqg+WjkzfYw4gCfmwKlafmfCu5IYALmTu38GMJMPdT4Gc7alvqU6+qF1VVpVZ5DBpuGL7XYQ6FVXTMWwKBgQC8bVFj3UDXwioB7GJ04kAhGSTGerNpIgNQ48P6+88jhQmtrURBq33AonRce7c8Zwm/acdaQoJlbrfN6cUMDJg7ZYWoQfdWfnBcS8oRosFyMP6LCPNuyOXEZrTxs5QkdQ7OfeghjKzBkKZksA/oahzqiFwOMftMN9aQKBgQC3lTFCaOFz7epWsvTsd0f1WhkQ4rLjBBtl29vJS6c5vJxjWXJXas1PLU3UwjA2G+wHMpJlyto70CH9dNxkWgdz3VYmoF3pu3DV5y265mCTHBd23uBaaHZYkcz2knK1Zug08YzdzwWutiADM49DTHV49bWQ1vfhJvI69EQKBgF5aW0QneZ3Qw1o9NTwUQ0qPnaOHlfp8tskiluyFWgrM+LQy5Q/ofHydkZ+feLLplVWzN33beI6iyeJA9oA4MAC08HrfQVh3P/Kj7/vAPEeaYfTjppuDOghCgByDP+IgrRm5+Tq8FiqtcuiLOomf6mjB5A89/D1XNgDpAoGAREPrq9QW2kiZfujfseHX98my8Bop0O+GEvnbBTVa7t34QlfuKorfRBoCy0zPeqDxzLzODhDD3+7iAtL3o/kk7/HoYRLeEaEoCv978c9GQxL+8fYuyNYRt2IOTxqVv2+hOS6Gll8vlyZ6iPgsx2kpcDhINpQUBMGGIBbOLhWFdEoD7Y=";
    // 商户的公钥钥
    public static String public_key ="MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEsAlBA/n5kQyleO75iRbfsTJfBFWWJSx0QnPfFj+kBtfVD+SdBGbKEov6zpBvyxB5/N4ufriH6DBL56+fyvb774rpsc3Z653t8POddh+1IHEl/1sgUHmsdphh/fdvCtEXl1bNhvo56PaAaIucecHISI4aGfXkUX5NEPPawWUR1bXBo55MKrFyxFPQxRLQchzgKtwpKcOYhH7s61wFfERUt/IaAVbPXvnz/smTeghLCXNIBzbMgZpuP5YQYcyitRhZh0NogCVCPqS47mHpCC0oqDwoVBXZxpL3kbpNcRTfnRVt9tj/bCSORNnL5I2fdZ9QeOyt8SAQ/1DteLZkS+9iShkuv0AJbcWugFAUwIDAQAB";
    // 支付宝的公钥,无需修改该值(不要删除也不要修改,在接收通知的时候需要进行签名认证)
    public static String ali_public_key= "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoQWVkXQUeUrfL6Dxya22OY+qlS2Q13MwHOk4c2joFERAuOzh5E6ckyHGI1jXXIwHjZDkjH8XR0q4jJjj32AX9Oi/phYObO65+WKrrVpxYzfLqQSttpjIsbI48AL4rswqW0CeS+MTYhZv6hwuLnB5q1FClV7pg8lWBtp25L2ikasnZ19D8b8a/+yBphbBGjNn4RiArZwthpZJtpM7LgqyXMrZYtk5gi5hBLBzPs16Q71erDRRsHK9OLxahgNyX6C5q9kHflKvYcOY61QPqghsU3Gq+Z2wkp2oOJ4QssQ9c8+vbO/tcDOLYosacOJhUy0xFmS2nDX7eCSnoUFZMnL7tQIDAQAB";
    // 字符编码格式 目前支持 gbk 或 utf-8
    public static String input_charset = "utf-8";
    // 签名方式 不需修改
    public static String sign_type = "RSA2";

    //APPID
    public static String APPID = "2018060507535980";        
    // 支付宝支付回调 
    public static String NOTIFY_URL = "http://花生壳ip/ejtapp/PayCtrl/AliPayNotify.do";
    // 8.返回格式
   public static String FORMAT = "json" ;
   }

有了这些数据之后,我们便可以开始写支付的接口了。

首先是APP端访问此接口,参数为订单id,服务端将订单数据传到支付宝,换取支付参数返回给APP端

	/**
	 * 支付宝会员充值
	 * 
	 * @param request
	 * @param response
	 * @param data
	 * @return
	 */
	@RequestMapping("/AliPayRecharge")
	@ResponseBody
	public JSONObject AliPayRecharge(HttpServletRequest request, HttpServletResponse response, String data) {
    
		System.out.println("=======续费充值支付======");
		JSONObject obj = JSON.parseObject(data);
		String orderId = obj.getString("orderId");
		ShopMemberRechargeRecord findByOrderId = shopMemberRechargeRecordService.findByOrderId(orderId);
		String aliPay = alipayUtil.aliPay(findByOrderId);
		System.out.println("=======返回信息======");
		return JsonUtil.getJson(10, aliPay, null);
	}

如果有多种订单,可以共用一个支付接口,这时多了一个订单类型的参数,此参数决定了后面要传入的订单实体类,如下

	/**
	 * 支付宝支付接口获取支付参数给前端app
	 * 
	 * @param request
	 * @param response
	 * @param data
	 * @return
	 */
	@RequestMapping("/AliPay")
	@ResponseBody
	public JSONObject AliPay(HttpServletRequest request, HttpServletResponse response, String data) {
    
		System.out.println("===============支付宝统一下单接口==============");
		JSONObject obj = JSON.parseObject(data);
		String orderId = obj.getString("orderId");
		String orderType = obj.getString("orderType");	// 如果有多种订单需要支付,便可以加上此参数
		System.out.println("============orderType:" + orderType + "==============");
		String aliPay = null;
		if (orderType.equals("order")) {
    	// 商品订单
			ShopOrder findByOrderId = shopOrderService.findByOrderId(orderId);
			aliPay = alipayUtil.aliPay(findByOrderId);
		}else if (orderType.equals("renew")) {
    	// 会员续费订单
			ShopMemberRechargeRecord findByOrderId = shopMemberRechargeRecordService.findByOrderId(orderId);
			aliPay = alipayUtil.aliPay(findByOrderId);
		}else {
    		// 余额充值订单
			ShopPdRecharge recharge = shopPdRechargeService.selectByPdrSn(orderId);
			try {
    
				aliPay = alipayUtil.aliPay(recharge);
			} catch (UnsupportedEncodingException e) {
    
				e.printStackTrace();
				System.out.println("===============支付宝统一下单失败==============");
				return JsonUtil.getJson(20, "支付宝统一下单失败", null);
			}
		}
		System.out.println("============接口返回参数aliPay:" + aliPay + "==============");
		System.out.println("===============支付宝统一下单结束==============");
		return JsonUtil.getJson(10, aliPay, null);
	}

然后是alipayUtil.java

package com.thinkgem.jeesite.modules.alipay;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;

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.request.AlipayTradeAppPayRequest;
import com.alipay.api.response.AlipayTradeAppPayResponse;
import com.thinkgem.jeesite.modules.ejt.entity.ShopMemberRechargeRecord;
import com.thinkgem.jeesite.modules.ejt.entity.ShopOrder;
import com.thinkgem.jeesite.modules.ejt.entity.ShopPdRecharge;

public class alipayUtil {
    
	
	 //实例化客户端
	public static AlipayClient alipayClient = new DefaultAlipayClient(AlipayConfig.URL, AlipayConfig.APPID, AlipayConfig.private_key , AlipayConfig.FORMAT, AlipayConfig.input_charset, AlipayConfig.public_key, AlipayConfig.sign_type);
	
	/**
	 * 商品订单
	 * @param order
	 * @return
	 * @throws UnsupportedEncodingException 
	 */
	public static String aliPay(ShopOrder order) throws UnsupportedEncodingException{
    
			//实例化具体API对应的request类,类名称和接口名称对应,当前调用接口名称:alipay.trade.app.pay
	        AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();
	        //SDK已经封装掉了公共参数,这里只需要传入业务参数。以下方法为sdk的model入参方式(model和biz_content同时存在的情况下取biz_content)。
	        AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
	        //model.setPassbackParams(URLEncoder.encode(body.toString()));;  //描述信息  添加附加数据
	        model.setSubject("e境通-商城消费"); //商品标题
	        model.setOutTradeNo(order.getOrderSn()+""); //商家订单编号
	        model.setTimeoutExpress("30m"); //超时关闭该订单时间
	        model.setTotalAmount(order.getOrderAmount());  //订单总金额
	        model.setProductCode("QUICK_MSECURITY_PAY"); //销售产品码,商家和支付宝签约的产品码,为固定值QUICK_MSECURITY_PAY
	        model.setPassbackParams(URLEncoder.encode("order", "GBK"));	//公用回传参数passback_params
	        request.setBizModel(model);
	        request.setNotifyUrl(AlipayConfig.NOTIFY_URL);  //回调地址
	        String orderStr = "";
	        try {
    
	                //这里和普通的接口调用不同,使用的是sdkExecute
	                AlipayTradeAppPayResponse response = alipayClient.sdkExecute(request);
	                orderStr = response.getBody();
	                System.out.println(orderStr);//就是orderString 可以直接给客户端请求,无需再做处理。
	            } catch (AlipayApiException e) {
    
	                e.printStackTrace();
	        }
	        return orderStr;
	    }
	
	/**
	 * 余额充值
	 * @param recharge
	 * @return
	 * @throws UnsupportedEncodingException 
	 */
	public static String aliPay(ShopPdRecharge recharge) throws UnsupportedEncodingException{
    
		//实例化具体API对应的request类,类名称和接口名称对应,当前调用接口名称:alipay.trade.app.pay
		AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();
		//SDK已经封装掉了公共参数,这里只需要传入业务参数。以下方法为sdk的model入参方式(model和biz_content同时存在的情况下取biz_content)。
		AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
		//model.setPassbackParams(URLEncoder.encode(body.toString()));;  //描述信息  添加附加数据
		model.setSubject("e境通-余额充值"); //商品标题
		model.setOutTradeNo(Long.toString(recharge.getPdrSn())); //商家订单编号
		model.setTimeoutExpress("30m"); //超时关闭该订单时间
		model.setTotalAmount(recharge.getPdrAmount());  //订单总金额
		model.setProductCode("QUICK_MSECURITY_PAY"); //销售产品码,商家和支付宝签约的产品码,为固定值QUICK_MSECURITY_PAY
		model.setPassbackParams(URLEncoder.encode("recharge", "GBK"));	//公用回传参数passback_params
		request.setBizModel(model);
		request.setNotifyUrl(AlipayConfig.NOTIFY_URL);  //回调地址
		String orderStr = null;
		try {
    
			//这里和普通的接口调用不同,使用的是sdkExecute
			AlipayTradeAppPayResponse response = alipayClient.sdkExecute(request);
			orderStr = response.getBody();
			//System.out.println(orderStr);//就是orderString 可以直接给客户端请求,无需再做处理。
		} catch (AlipayApiException e) {
    
			e.printStackTrace();
		}
		return orderStr;
	}
	
    /**
     * 会员充值订单
     * @param findByOrderId
     * @return
     * @throws UnsupportedEncodingException 
     */
	public static String aliPay(ShopMemberRechargeRecord findByOrderId) throws UnsupportedEncodingException {
    
		//实例化具体API对应的request类,类名称和接口名称对应,当前调用接口名称:alipay.trade.app.pay
        AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();
        //SDK已经封装掉了公共参数,这里只需要传入业务参数。以下方法为sdk的model入参方式(model和biz_content同时存在的情况下取biz_content)。
        AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
        //model.setPassbackParams(URLEncoder.encode(body.toString()));;  //描述信息  添加附加数据
        model.setSubject("e境通-会员充值"); //商品标题
        model.setOutTradeNo(findByOrderId.getMrrSn()+""); //商家订单编号
        model.setTimeoutExpress("30m"); //超时关闭该订单时间
        model.setTotalAmount(findByOrderId.getMrrAmount());  //订单总金额
        model.setProductCode("QUICK_MSECURITY_PAY"); //销售产品码,商家和支付宝签约的产品码,为固定值QUICK_MSECURITY_PAY
        model.setPassbackParams(URLEncoder.encode("renew", "GBK"));	//公用回传参数passback_params
        request.setBizModel(model);
        request.setNotifyUrl(AlipayConfig.NOTIFY_URL);  //回调地址
        String orderStr = "";
        try {
    
                //这里和普通的接口调用不同,使用的是sdkExecute
                AlipayTradeAppPayResponse response = alipayClient.sdkExecute(request);
                orderStr = response.getBody();
                System.out.println(orderStr);//就是orderString 可以直接给客户端请求,无需再做处理。
            } catch (AlipayApiException e) {
    
                e.printStackTrace();
        }
        return orderStr;
	}
}


这里alipayUtil 中的aliPay方法内部,使用的参数可以在文档中找到:
在这里插入图片描述
在这里插入图片描述
可以将上面文档中的业务参数放到model里面,具体参考model.setPassbackParams(URLEncoder.encode("recharge", "GBK")); //公用回传参数passback_params

APP端调用AliPay接口之后,拿到支付参数,即可调其支付宝支付页面。

然后再用户输入支付密码之后,支付宝开始访问AlipayConfig.NOTIFY_URL这个回调地址,这里需要保证回调地址可以用外网访问得到,如果没有域名,可以使用花生壳,做一个内网渗透即可,花生壳的使用,请参考这篇APP微信支付

那么回调方法是怎样的呢?即是支付宝文档中的异步通知接口:https://docs.open.alipay.com/204/105301/
在这里插入图片描述
具体的参数请参考文档,下面的触发条件说明,当用户支付成功之后,支付宝会触发异步回调通知。
在这里插入图片描述
接着看回调方法:

/**
	 * 支付宝回调
	 * 
	 * @param request
	 * @param response
	 * @return
	 * @throws UnsupportedEncodingException 
	 */
	@RequestMapping("/AliPayNotify")
	@ResponseBody
	public String AliPayNotify(HttpServletRequest request, HttpServletResponse response) throws UnsupportedEncodingException {
    
		System.out.println("==========支付宝统一回调==========");
		Map<String, String> params = new HashMap<String, String>();
		// 1.从支付宝回调的request域中取值
		@SuppressWarnings("unchecked")
		Map<String, String[]> requestParams = request.getParameterMap();

		for (Iterator<String> iter = requestParams.keySet().iterator(); iter.hasNext();) {
    
			String name = iter.next();
			String[] values = requestParams.get(name);
			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"), "gbk");
			params.put(name, valueStr);
		}
		System.out.println("params:" + params);
		String orderType = params.get("passback_params");	//公用回传参数订单类型
		System.out.println("公用回传参数orderType:" + orderType);
		String outTradeNo = params.get("out_trade_no");
		
		String paySn = params.get("trade_no");
		String totalFee = params.get("total_amount");
		boolean signVerified = false;
		// 调用SDK验证签名
		try {
    
			signVerified = AlipaySignature.rsaCheckV1(params, AlipayConfig.ali_public_key, AlipayConfig.input_charset,
					AlipayConfig.sign_type);
		} catch (AlipayApiException e) {
    
			e.printStackTrace();
		}
		System.out.println("=======验证签名:" + signVerified + "======");
		if (signVerified) {
    
			System.out.println("=================================================");
			System.out.println("=============支付成功,下面开始更新订单数据===========");
			System.out.println("=================================================");
			boolean notifyUpdate = notifyUpdate(orderType, outTradeNo, paySn, "alipay", totalFee);
			if (notifyUpdate) {
    
				return "success";
			}
		}
		return "failure";
	}

注意回调方法,返回的数据是有要求的,如果更新订单成功需要返回"success",否则返回"failure"
如果商户反馈给支付宝的字符不是success这7个字符,支付宝服务器会不断重发通知,直到超过24小时22分钟。一般情况下,25小时以内完成8次通知(通知的间隔频率一般是:4m,10m,10m,1h,2h,6h,15h

最后是查询订单接口,即用服务器主动查询订单支付状态,然后返回给APP端:

	/**
	 * 支付宝查询订单接口
	 * 
	 * @param request
	 * @param response
	 * @param data
	 * 				orderType 订单类型
	 * 				result  支付结果 支付结果是APP输入交易密码之后 支付宝返回的信息
	 * @return
	 */
	@ResponseBody
	@RequestMapping("AliPayRecordQuery")
	public JSONObject AliPayRecordQuery(HttpServletRequest request, HttpServletResponse response, String data) {
    
		System.out.println("===============支付宝订单查询接口==============");
		try {
    
			JSONObject json = JSON.parseObject(data);
			String orderType = json.getString("orderType");
			System.out.println("=======订单类型:" + orderType + "======");
			String result = json.getString("result");
			System.out.println("result:" + result);
			JSONObject jsonResult = JSON.parseObject(result);
			String AliPayResponse = jsonResult.getString("alipay_trade_app_pay_response");
			System.out.println("AliPayResponse:" + AliPayResponse);
			JSONObject jsonResp = JSON.parseObject(AliPayResponse);
			
			String outTradeNo = jsonResp.getString("out_trade_no");
			String paySn = jsonResp.getString("trade_no");
			String totalFee = jsonResp.getString("total_amount");
			
			Map<String, String> params = JSONObject.parseObject(jsonResp.toJSONString(),
					new TypeReference<Map<String, String>>() {
    
					});
			String sign = jsonResult.getString("sign");
			params.put("sign", sign);
			boolean re = AlipaySignature.rsa256CheckContent(AliPayResponse, sign, AlipayConfig.ali_public_key,
					AlipayConfig.input_charset);
			// AlipaySignature.rsa256Sign(content, privateKey, charset)
			if (jsonResp.getString("code").equals("10000")) {
    
				System.out.println("==================此订单已支付成功================");
				System.out.println("==============下面做判断订单状态是否更新=============");
				System.out.println("========如果没有更新需要更新,证明回调里面出现异常=============");
				boolean queryAndUpdate = queryAndUpdate(orderType, "alipay", outTradeNo, paySn, totalFee);
				if (queryAndUpdate) {
    
					System.out.println("===============支付宝订单查询成功==============");
					return JsonUtil.getJson(10, null, "支付成功");
				}
				return JsonUtil.getJson(30, null, "支付成功,系统内部错误");	// 回调失败情况下 订单查询中修改订单状态出错
			} else {
    
				return JsonUtil.getJson(20, null, "支付失败");
			}
		} catch (Exception e) {
    
			return JsonUtil.getJson(40, null, "系统内部错误");
		}
	}

这里将我用到的订单支付成功之后更新数据库的方法,也贴出来,刻意忽略下面这些方法。

	/**
	 * 回调函数中更新数据库订单或记录
	 * @param orderType 订单种类:order订单,renew续费或注册, recharge充值
	 * @param orderNum 订单编号
	 * @param paySn	支付单号
	 * @param payType 支付方式 wechat alipay
	 * @param totalFee 实际支付金额
	 * @return
	 */
	public boolean notifyUpdate(String orderType, String orderNum, String paySn, String payType, String totalFee){
    
		System.out.println("totalFee:" + totalFee);
		if (orderType.equals("order")) {
    
			ShopOrder findByOrderNo = shopOrderService.findByOrderNo(orderNum);
			System.out.println("orderFee:" + findByOrderNo.getOrderAmount());
			if (totalFee.equals(findByOrderNo.getOrderAmount())) {
    
				findByOrderNo.setPaySn(paySn);
				findByOrderNo.setOrderState("20");
				findByOrderNo.setPaymentCode(payType);
				findByOrderNo.setPaymentTime(ZoscDateUtil.getTime());
				// 更新订单状态
				int selective = shopOrderService.updateByPrimaryKeySelective(findByOrderNo);
				if (selective > 0) {
    
					System.out.println("===============更新商品订单成功==============");
					return true;
				}
			}
		}else if (orderType.equals("renew")) {
    
			boolean updateRecordLog = updateRecordLog(orderNum, payType, paySn, totalFee);
			return updateRecordLog;
		}else {
    
			ShopPdRecharge recharge = shopPdRechargeService.selectByPdrSn(orderNum);
			if (totalFee.equals(recharge.getPdrAmount())) {
    
				recharge.setPdrPaymentCode(payType);
				if (payType.equals("wechat")) {
    
					recharge.setPdrPaymentName("微信");
				}else {
    
					recharge.setPdrPaymentName("支付宝");
				}
				recharge.setPdrTradeSn(paySn);
				recharge.setPdrPaymentTime(ZoscDateUtil.getTime());
				recharge.setPdrPaymentState("1");
				int updateRecharge = shopPdRechargeService.updateByPrimaryKeySelective(recharge);
				
				ShopMember member = shopMemberService.findByMemberId(recharge.getPdrMemberId());
				String oldBalance = member.getAvailablePredeposit();
				String newBalance = BigDecimalUtil.strAdd(oldBalance, recharge.getPdrAmount());
				member.setAvailablePredeposit(newBalance);
				int updateMember = shopMemberService.updateByPrimaryKeySelective(member);
				
				if (updateRecharge + updateMember > 1) {
    
					System.out.println("===============更新充值订单成功==============");
					return true;
				}
			}
		}
		return false;
	}

	/**
	 * 订单查询 判断订单状态是否更新完成模块
	 * @param orderType
	 * @param payType
	 * @param orderNum
	 * @param transactionId
	 * @return boolean
	 */
	public boolean queryAndUpdate(String orderType, String payType, String orderNum, String transactionId, String totalFee){
    
		boolean notifyUpdate = false;
		System.out.println("orderType:" + orderType);
		if (orderType.equals("order")) {
    
			ShopOrder findByOrderNo = shopOrderService.findByOrderNo(orderNum);
			System.out.println("OrderState:" + findByOrderNo.getOrderState());
			if (findByOrderNo.getOrderState().equals("20")) {
    
				notifyUpdate = true;
			} else {
    
				notifyUpdate = notifyUpdate(orderType, orderNum, transactionId, payType, totalFee);
			}
		}else if (orderType.equals("renew")) {
    
			ShopMemberRechargeRecord rechargeRecord = shopMemberRechargeRecordService.findByOrderId(orderNum);
			if (rechargeRecord.getMrrPaymentState().equals("1")) {
    
				notifyUpdate = true;
			}else {
    
				notifyUpdate = notifyUpdate(orderType, orderNum, transactionId, payType, totalFee);
			}
		}else {
    
			ShopPdRecharge recharge = shopPdRechargeService.selectByPdrSn(orderNum);
			if (recharge.getPdrPaymentState().equals("1")) {
    
				notifyUpdate = true;
			}else {
    
				notifyUpdate = notifyUpdate(orderType, orderNum, transactionId, payType, totalFee);
			}
		}
		return notifyUpdate;
	}

	/**
	 * 会员续费支付成功之后更新数据库模块
	 * @param orderNum  订单编号
	 * @param payCode	支付方式
	 * @param serialNum	支付单号
	 * @param totalFee  实际支付金额
	 * @return
	 */
	public boolean updateRecordLog(String orderNum, String payCode, String serialNum, String totalFee){
    
		
		ShopMemberRechargeRecord rechargeRecord = shopMemberRechargeRecordService.findByOrderId(orderNum);
		if (totalFee.equals(rechargeRecord.getMrrAmount())) {
    
			ShopMemberRechargeLog rechargeLog = shopMemberRechargeLogService.selectByMrrSn(rechargeRecord.getMrrSn());
			// 更新record表
			String mrrAddTime = ZoscDateUtil.getTime();
			rechargeRecord.setMrrAddTime(mrrAddTime);
			rechargeRecord.setMrrPaymentState("1");
			if (payCode.equals("alipay")) {
    
				rechargeRecord.setMrrPaymentName("支付宝");
				rechargeRecord.setMrrPaymentCode("alipay");
			}else{
    
				rechargeRecord.setMrrPaymentName("微信");
				rechargeRecord.setMrrPaymentCode("wechat");
			}
			rechargeRecord.setMrrTradeSn(serialNum);
			// 判断支付类型
			// 获取当前会员的有效期限
			ShopMemberRechargeRecord lastRenewRecord = shopMemberRechargeRecordService.selectLastRenew(rechargeRecord.getMrrMemberId());
			String mrrExpirationTime = lastRenewRecord.getMrrExpirationTime();
			System.out.println("到期时间是否为0:" + mrrExpirationTime);
			long expirationTime = Long.parseLong(mrrExpirationTime);
			long now = System.currentTimeMillis()/1000;
			Long yearLater = null;
			if ((expirationTime == 0) || (now > expirationTime)) {
    // 第一次注册会员 或者 会员已过期续费  
				Date date = new Date();
				yearLater = DateUtil.getDaysLater(date, 365);
				System.out.println("首次注册会员有效期:" + yearLater);
			}else {
    	// 会员有效期内续费
				yearLater = DateUtil.timestampDaysLater(mrrExpirationTime, 365);
			}
			rechargeRecord.setMrrExpirationTime(Long.toString(yearLater));
			System.out.println(rechargeRecord);
			shopMemberRechargeRecordService.updateByPrimaryKeySelective(rechargeRecord);
			
			// 更新log表
			rechargeLog.setMrlAddTime(mrrAddTime);
			rechargeLog.setExpirationTime(rechargeRecord.getMrrExpirationTime());
			String rechargeType = rechargeLog.getRechargeType();
			String rechargeState = null;
			String rechargeDesc = null;
			if ("recharge".equals(rechargeType)) {
    
				rechargeState = "充值成功";
				rechargeDesc = "充值成功,充值单号:" + orderNum;
			} else {
    
				rechargeState = "续费成功";
				rechargeDesc = "续费成功,充值单号:" + orderNum;
			}
			rechargeLog.setRechargeState(rechargeState);
			rechargeLog.setRechargeDesc(rechargeDesc);
			rechargeLog.setMrrAmount(rechargeRecord.getMrrAmount());
			shopMemberRechargeLogService.updateByPrimaryKey(rechargeLog);
			
			
			// 更新会员标志
			ShopMember member = shopMemberService.findByMemberId(rechargeRecord.getMrrMemberId());
			if ("0".equals(member.getIsPlatformMember())) {
    
				member.setIsPlatformMember("1");
				shopMemberService.updateByPrimaryKeySelective(member);
			}
			
			System.out.println("=======会员充值更新数据库完毕=======");
			return true;
		}
		return false;
	}

到这里APP支付宝支付就算结束了,有什么问题或建议,欢迎评论交流。



这次换了一个项目,又写了一遍支付,又发现了一些新的问题。

第一点就是,刚开始由于产品那边给的支付宝账号下面申请了好几个应用,我直接去项目名那个应用下面,一顿复制粘贴,弄好了,就兴高采烈的让安卓测试,然后问题就来了。。。。。

第一次测的时候,安卓那边点击付款,直接报错了,提示【交易订单处理失败 请稍后再试 ALI38173】,然后安卓问我,是啥情况,他那边也是从别的项目里直接拷贝过来的,问我能不能用,我也是一脸懵逼,我也不知道安卓怎么处理返回的预支付订单信息,然后我就搜了一下,这一搜不要紧,搜到蚂蚁金服社区文档里,有这么一说:
在这里插入图片描述
然后我就回去对比我写的参数,发现,之前项目里传的参数,这里我也都传了,怎么还会报错呢????

然后又开始对比开发文档里面的请求参数,发现有几个确实没传,但是之前的项目也没有传,就能正常使用。可能不是因为这个。然后安卓那边给我说好像写错了,改了一下再试试。

然后我就等,那边说改好了测了一下,又出现新的问题了。

然后我突然想到,现在使用的参数是同事给我的,会不会出错了,然后我就要来账号,自己去蚂蚁金服开发平台去找,然后找到了项目名对应的应用,发现这里虽然显示了已上线,但是好像没有添加APP支付的功能。

在这里插入图片描述
这肯定行不通。。。。。。。然后找组长问问,这个要不要用另一个项目里的数据进行测试,然后组长给我说,就是用另一个。。。。。

对比一下这个,里面是有签约的APP支付的功能的。
在这里插入图片描述
刚开始没有想到换新的私钥和公钥,后来同事给我说,要不你重新生成一对秘钥,然后修改一下支付宝上的。

我这才重新生成秘钥,生成秘钥的工具,蚂蚁金服开发平台上也有,这里提供一个传送门。很详细的生成一对新的秘钥,然后将公钥设置在应用的后面,如下图:
在这里插入图片描述

换了之后,一次就成功了,真的舒服。。。。。。。

但是到查询订单的时候,按照上面的写法,安卓那边需要将支付的结果result传过来,之前那个项目,是安卓直接传的result了,我直接在后面截取,然后判断("code").equals("10000")这个条件了,但是感觉怪怪的,其中有一句验签那个AlipaySignature.rsa256CheckContent()也没有使用,当时也没有想着查一下,结果这次,安卓那边不知道怎么取result这个值了,这就让我很为难了。

再后来安卓找到result参数之后,一直查询支付失败,我看了一下后发现,我又将AlipaySignature.rsa256CheckContent()的结果和jsonResp.getString("code").equals("10000")这个条件取并集,来验证,结果一直是支付失败,哈哈。。。这里着实把安卓给坑了一把。。。。。。。

然后我打印这个AlipaySignature.rsa256CheckContent()一直是false,查了很多,都说第一步要验证是不是使用了支付宝的公钥,我查了一下,这个方法里面确实是用了支付的公钥,后来发现预下单支付接口里面,我使用的却是自己生成的公钥和私钥,进行加密的,导致这里一直失败。

然后我查到别人写的关于查询订单支付状态的接口,感觉就比我的好,这里记录一下:

这里不用再让安卓传result了,直接传个订单编号或者id就好了。这里我将查询方法抽离出来了。

	/**
	 * 查询订单使用
	 * @param orderId
	 */
	public static boolean checkAlipay(long orderId){
    
		logger.info("==================向支付宝发起查询,查询商户订单号为:"+orderId);
		
		//实例化客户端(参数:网关地址、商户appid、商户私钥、格式、编码、支付宝公钥、加密类型),为了取得预付订单信息
		AlipayClient alipayClient = new DefaultAlipayClient(AlipayConfig.URL, AlipayConfig.APPID, 
		        AlipayConfig.PRIVATE_KEY, AlipayConfig.FORMAT, AlipayConfig.CHARSET, 
		        AlipayConfig.ALIPAY_PUBLIC_KEY,AlipayConfig.SIGNTYPE);
		
		AlipayTradeQueryRequest alipayTradeQueryRequest = new AlipayTradeQueryRequest();
		alipayTradeQueryRequest.setBizContent("{" +
		"\"out_trade_no\":\""+orderId+"\"" +
		"}");
		try {
    
			AlipayTradeQueryResponse alipayTradeQueryResponse = alipayClient.execute(alipayTradeQueryRequest);
			System.out.println("alipayTradeQueryResponse:" + alipayTradeQueryResponse);
			return alipayTradeQueryResponse.isSuccess();	// 不知道为什么能这样返回,但是能用
		} catch (AlipayApiException e) {
    
			e.printStackTrace();
			return false;
		}
	}

返回的这一句,也可以换一下,方法类型直接返回AlipayTradeQueryResponse ,然后在后台请求的查询接口里面直接获取需要的参数就好了,后面需要的流水单号,订单编号,支付金额,都可以在AlipayTradeQueryResponse这个实体类里面直接使用get方法取到。比如获取订单金额,直接使用alipayTradeQueryResponse.getTotalAmount()

这样的话,查询订单的接口里面就很简单了,只需要判断数据库是否更新就好了。

这次踩坑得益于这篇博客,没看懂的同学,可以看一下这篇博客,很详细:https://blog.csdn.net/ouyzc/article/details/79551714

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/linmengmeng_1314/article/details/87826451

智能推荐

oracle 12c 集群安装后的检查_12c查看crs状态-程序员宅基地

文章浏览阅读1.6k次。安装配置gi、安装数据库软件、dbca建库见下:http://blog.csdn.net/kadwf123/article/details/784299611、检查集群节点及状态:[root@rac2 ~]# olsnodes -srac1 Activerac2 Activerac3 Activerac4 Active[root@rac2 ~]_12c查看crs状态

解决jupyter notebook无法找到虚拟环境的问题_jupyter没有pytorch环境-程序员宅基地

文章浏览阅读1.3w次,点赞45次,收藏99次。我个人用的是anaconda3的一个python集成环境,自带jupyter notebook,但在我打开jupyter notebook界面后,却找不到对应的虚拟环境,原来是jupyter notebook只是通用于下载anaconda时自带的环境,其他环境要想使用必须手动下载一些库:1.首先进入到自己创建的虚拟环境(pytorch是虚拟环境的名字)activate pytorch2.在该环境下下载这个库conda install ipykernelconda install nb__jupyter没有pytorch环境

国内安装scoop的保姆教程_scoop-cn-程序员宅基地

文章浏览阅读5.2k次,点赞19次,收藏28次。选择scoop纯属意外,也是无奈,因为电脑用户被锁了管理员权限,所有exe安装程序都无法安装,只可以用绿色软件,最后被我发现scoop,省去了到处下载XXX绿色版的烦恼,当然scoop里需要管理员权限的软件也跟我无缘了(譬如everything)。推荐添加dorado这个bucket镜像,里面很多中文软件,但是部分国外的软件下载地址在github,可能无法下载。以上两个是官方bucket的国内镜像,所有软件建议优先从这里下载。上面可以看到很多bucket以及软件数。如果官网登陆不了可以试一下以下方式。_scoop-cn

Element ui colorpicker在Vue中的使用_vue el-color-picker-程序员宅基地

文章浏览阅读4.5k次,点赞2次,收藏3次。首先要有一个color-picker组件 <el-color-picker v-model="headcolor"></el-color-picker>在data里面data() { return {headcolor: ’ #278add ’ //这里可以选择一个默认的颜色} }然后在你想要改变颜色的地方用v-bind绑定就好了,例如:这里的:sty..._vue el-color-picker

迅为iTOP-4412精英版之烧写内核移植后的镜像_exynos 4412 刷机-程序员宅基地

文章浏览阅读640次。基于芯片日益增长的问题,所以内核开发者们引入了新的方法,就是在内核中只保留函数,而数据则不包含,由用户(应用程序员)自己把数据按照规定的格式编写,并放在约定的地方,为了不占用过多的内存,还要求数据以根精简的方式编写。boot启动时,传参给内核,告诉内核设备树文件和kernel的位置,内核启动时根据地址去找到设备树文件,再利用专用的编译器去反编译dtb文件,将dtb还原成数据结构,以供驱动的函数去调用。firmware是三星的一个固件的设备信息,因为找不到固件,所以内核启动不成功。_exynos 4412 刷机

Linux系统配置jdk_linux配置jdk-程序员宅基地

文章浏览阅读2w次,点赞24次,收藏42次。Linux系统配置jdkLinux学习教程,Linux入门教程(超详细)_linux配置jdk

随便推点

matlab(4):特殊符号的输入_matlab微米怎么输入-程序员宅基地

文章浏览阅读3.3k次,点赞5次,收藏19次。xlabel('\delta');ylabel('AUC');具体符号的对照表参照下图:_matlab微米怎么输入

C语言程序设计-文件(打开与关闭、顺序、二进制读写)-程序员宅基地

文章浏览阅读119次。顺序读写指的是按照文件中数据的顺序进行读取或写入。对于文本文件,可以使用fgets、fputs、fscanf、fprintf等函数进行顺序读写。在C语言中,对文件的操作通常涉及文件的打开、读写以及关闭。文件的打开使用fopen函数,而关闭则使用fclose函数。在C语言中,可以使用fread和fwrite函数进行二进制读写。‍ Biaoge 于2024-03-09 23:51发布 阅读量:7 ️文章类型:【 C语言程序设计 】在C语言中,用于打开文件的函数是____,用于关闭文件的函数是____。

Touchdesigner自学笔记之三_touchdesigner怎么让一个模型跟着鼠标移动-程序员宅基地

文章浏览阅读3.4k次,点赞2次,收藏13次。跟随鼠标移动的粒子以grid(SOP)为partical(SOP)的资源模板,调整后连接【Geo组合+point spirit(MAT)】,在连接【feedback组合】适当调整。影响粒子动态的节点【metaball(SOP)+force(SOP)】添加mouse in(CHOP)鼠标位置到metaball的坐标,实现鼠标影响。..._touchdesigner怎么让一个模型跟着鼠标移动

【附源码】基于java的校园停车场管理系统的设计与实现61m0e9计算机毕设SSM_基于java技术的停车场管理系统实现与设计-程序员宅基地

文章浏览阅读178次。项目运行环境配置:Jdk1.8 + Tomcat7.0 + Mysql + HBuilderX(Webstorm也行)+ Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。项目技术:Springboot + mybatis + Maven +mysql5.7或8.0+html+css+js等等组成,B/S模式 + Maven管理等等。环境需要1.运行环境:最好是java jdk 1.8,我们在这个平台上运行的。其他版本理论上也可以。_基于java技术的停车场管理系统实现与设计

Android系统播放器MediaPlayer源码分析_android多媒体播放源码分析 时序图-程序员宅基地

文章浏览阅读3.5k次。前言对于MediaPlayer播放器的源码分析内容相对来说比较多,会从Java-&amp;amp;gt;Jni-&amp;amp;gt;C/C++慢慢分析,后面会慢慢更新。另外,博客只作为自己学习记录的一种方式,对于其他的不过多的评论。MediaPlayerDemopublic class MainActivity extends AppCompatActivity implements SurfaceHolder.Cal..._android多媒体播放源码分析 时序图

java 数据结构与算法 ——快速排序法-程序员宅基地

文章浏览阅读2.4k次,点赞41次,收藏13次。java 数据结构与算法 ——快速排序法_快速排序法