Java服务端接入支付宝APP支付及微信APP支付

这次整理一下支付宝APP支付的Java服务端和安卓客户端的集成过程,主要是记录自己接入的过程,方便日后接入。

本文中的案例代码只贴入关键的部分,主要记录支付的流程及原理,默认环境是微信/支付宝审核已经通过(没有审核过的同学先去审核),

附件为我项目中 java服务端 支付宝APP/微信APP支付(可能与你们的业务逻辑不同,路子很野,酌情下载)。



csdn站内下载:点击打开链接



首先介绍

支付宝APP支付


官方文档:https://docs.open.alipay.com/204

支付宝使用沙箱环境进行本章的介绍

流程介绍



1.商家APP前端下单,发送给JAVA后台金额等信息(根据业务),后台生成订单信息,保存到数据库。

2.后端使用支付宝加签方法把订单信息签名返给APP前端。

3.前端根据签名信息唤起支付宝APP进行支付。

4.用户在支付宝中完成支付/不支付

5-7.返回同步和异步支付结果,后端需要在异步中根据支付宝异步通知做逻辑处理。

不过我是没有写同步返回的,因为支付宝的支付结果是以异步通知为准。

接入准备


1.计入支付宝开放平台-沙箱环境


2.打开 https://docs.open.alipay.com/291/105971  下载支付宝生成RSA秘钥的工具

双击运行 RSA签名验签工具.bat


选择2048位,生成密钥

打开沙箱环境中


如果你是第一次设置的话,应该显示设置应用公钥 ,吧。。。(我也忘了),复制你的应用公钥,粘贴进去,保存


接着设置应用的网关,这个就是支付宝的网关,分为开发和正式,我这个网关是测试的。大家沙箱环境也用这个

授权回调地址,就是你异步通知访问路径,这个地址必须是在80端口,别的端口不行。

这里提一下,支付宝和你是使用公钥私钥来交换数据的,对于公私钥,这里有一篇文章介绍的很生动清楚。

http://blog.csdn.net/aa93226aa/article/details/50789774

编码

1.导入支付宝开发的jar包。

<!-- 支付宝 -->
		<dependency>
			<groupId>com.alibaba</groupId>
			<artifactId>alipay</artifactId>
			<version>1.0</version>
		</dependency>
		<dependency>
			<groupId>com.alibaba</groupId>
			<artifactId>commons-logging</artifactId>
			<version>1.1.1</version>
		</dependency>
		<dependency>
			<groupId>com.alipay</groupId>
			<artifactId>sdk-java</artifactId>
			<version>20171201160035</version>
		</dependency>


2.SystemValue.class

这是一个常量类,保存了支付宝的一些信息。

public class SystemValue {
	/**
	 * 支付宝公钥
	 */
	public static String  ALIPAY_PUBLIC_KEY ="";
	 * 支付宝应用私钥
	 */
	public static String  ALIPAY_PRIVATE_KEY ="";
	/**
	 * 支付宝APPID
	 */
	public static String  ALIPAY_APPID ="";
	/**
	 * 支付宝网关
	 */
	public static String  ALIPAY_WEBWAY ="";
	/**
	 * 支付宝编码
	 */
	public static String  ALIPAY_CHARSET ="utf-8";
	/**
	 * 支付宝回调地址
	 */
	public static String  ALIPAY_NOTIFY_URL ="";

}

注释写的很清楚,大家换成你们自己的就行了。

/**
	 * 加签参数
	 * 
	 * @param amount
	 * @param body
	 * @return
	 */
	public String aliPaySignPrams(Orders orders) {
		// 实例化客户端
		AlipayClient alipayClient = new DefaultAlipayClient(SystemValue.ALIPAY_WEBWAY, SystemValue.ALIPAY_APPID,
				SystemValue.ALIPAY_PRIVATE_KEY, "json", SystemValue.ALIPAY_CHARSET, SystemValue.ALIPAY_PUBLIC_KEY,
				"RSA2");
		// 实例化具体API对应的request类,类名称和接口名称对应,当前调用接口名称:alipay.trade.app.pay
		AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();
		// SDK已经封装掉了公共参数,这里只需要传入业务参数。以下方法为sdk的model入参方式(model和biz_content同时存在的情况下取biz_content)。
		AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();

		model.setSubject(); // 商品标题
		model.setOutTradeNo(orders.getOrderid()); // 商家订单编号
		// model.setTimeoutExpress("525600m"); //超时关闭该订单时间,默认15天
		model.setTotalAmount(); // 订单总金额
		model.setProductCode("QUICK_MSECURITY_PAY"); // 销售产品码,商家和支付宝签约的产品码,为固定值QUICK_MSECURITY_PAY
		request.setBizModel(model);
		request.setNotifyUrl(SystemValue.ALIPAY_NOTIFY_URL); // 回调地址
		String orderStr = "";
		try {
			// 这里和普通的接口调用不同,使用的是sdkExecute
			AlipayTradeAppPayResponse response = alipayClient.sdkExecute(request);
			orderStr = response.getBody();
			logger.info("订单str:" + orderStr);
		} catch (AlipayApiException e) {
			e.printStackTrace();
		}
		return orderStr;
	}

把报错的换成你们的就行,商品标题/订单号/时间/金额/回调(我这里是order订单信息已经生成并且保存到数据库中了,订单状态为等待支付)

执行到这里return 的 orderStr就是生成签名的结果,然后你把这个orderStr返给前端,让他们去唤起支付宝支付,接下来,需要写一个异步通知,回调

@RequestMapping(value = "/getAliPayNotify")
	public void getnotify(HttpServletRequest request, HttpServletResponse response) {
		logger.info("进入支付宝回调");
		// 获取支付宝GET过来反馈信息
		String reqWay = "";
		if ("GET".equals(request.getMethod())) {
			reqWay = "GET";
		}
		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] + ",";
			}
			// 乱码解决,这段代码在出现乱码时使用。如果mysign和sign不相等也可以使用这段代码转化
			if ("GET".equals(reqWay)) {
				try {
					valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");
				} catch (UnsupportedEncodingException e) {
					logger.info("不支持的编码:" + e.getMessage());
					e.printStackTrace();
				}
			}
			params.put(name, valueStr);
		}
		String trade_no = request.getParameter("trade_no"); // 支付宝交易号
		String trade_status = request.getParameter("trade_status"); // 支付状态
		String out_trade_no = request.getParameter("out_trade_no"); // 系统订单号
		logger.info("支付宝交易号:" + trade_no + ", 返回状态:" + trade_status + ",订单号  :" + out_trade_no);

		Map<String, Object> map = new HashMap<String, Object>();
		String result = "";
		if ("TRADE_SUCCESS".equals(trade_status)) {
			synchronized (this) {

				try {//保存订单信息
					orderService.modifyOrdersInfo(orders);
					result = "success";
				} catch (Exception e) {
					result = "fail";
					e.printStackTrace();
				}

			}
		} else {

			result = "fail";
		}
		map.put(result, result);
		ResponseUtils.renderText(response, result);
	}

这是异步的方法,因为我们在沙箱环境配置了回调的地址,支付宝会在付款之后,发给我们异步通知,当我们获取到这个通知,比对支付宝的信息,当TRADE_SUCCESS时,可以进入处理业务的逻辑,并且返回success,否则支付宝会认为你没收到通知,会一直发给你。如果失败就返回fail。

到这为止,反观支付流程,我们已经完成了支付宝的后端APP支付接入。

测试

1.进入https://openhome.alipay.com/platform/appDaily.htm?tab=tool  下载沙箱钱包

2.进入https://docs.open.alipay.com/54/104509/  下载iOS&Android版资源

3.需要你有安卓原生开发功底,打开Androidstudio,导入Android的Demo

4.打开PayDemoActivity.java,配置APPID,配置RSA2_PRIVATE

5.找到onCreate方法,加入代码,该代码意思是:使用沙箱环境。不加该代码,会引起错误(系统繁忙)。

EnvUtils.setEnv(EnvUtils.EnvEnum.SANDBOX);
6.打包服务端代码上传服务器,使用postMan访问支付宝生成签名方法,获得签名。

7.打开安卓代码中,PayDemoActivity.java中payV2方法中的orderInfo变量,替换你刚刚服务端生成的签名字符串

final String orderInfo =“”;


8.运行Demo,完成支付。

微信支付


官方文档:https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=8_1


流程介绍


1.商家APP前端下单(或后台下单),发送给JAVA后台金额等信息(根据业务),后台生成订单信息,保存到数据库。

2.后端发送请求给微信生成预支付id

3.后端把预支付id及其他参数签名返回前端

4.前端根据签名信息唤起微信APP进行支付

5.用户在微信中完成支付/不支付

6-7.返回同步和异步支付结果,后端需要在异步中根据微信异步通知做逻辑处理。
在异步中需要判断微信异步通知是否处理,如果没处理,继续走自己逻辑,处理了则忽略。

这里我们可以看到微信只是比支付宝多了一步生成prepayId


这里微信的代码我只贴关键的部分,所涉及到的类都在附件中。

生成签名方法:

/**
 * weChat微信加签
 * @param orders
 * @param request
 * @param response
 * @return
 */
	public String weChatSignPrams(Orders orders, HttpServletRequest request, HttpServletResponse response) {
		Map<String, Object> map = new HashMap<String, Object>();
		// 获取生成预支付订单的请求类
		PrepayIdRequestHandler prepayReqHandler = new PrepayIdRequestHandler(request, response);
		String totalFee = orders.getPaymoney() + "";
		int total_fee = (int) (Float.valueOf(totalFee) * 100);
		prepayReqHandler.setParameter("appid", ConstantUtil.APP_ID);
		prepayReqHandler.setParameter("body", ConstantUtil.BODY);
		prepayReqHandler.setParameter("mch_id", ConstantUtil.MCH_ID);
		String nonce_str = WXUtil.getNonceStr();
		prepayReqHandler.setParameter("nonce_str", nonce_str);
		prepayReqHandler.setParameter("notify_url", ConstantUtil.NOTIFY_URL);
		String out_trade_no = orders.getOrderid();
		prepayReqHandler.setParameter("out_trade_no", out_trade_no);
		prepayReqHandler.setParameter("spbill_create_ip", request.getRemoteAddr());
		String timestamp = WXUtil.getTimeStamp();
		prepayReqHandler.setParameter("time_start", timestamp);
		System.out.println(String.valueOf(total_fee));
		prepayReqHandler.setParameter("total_fee", String.valueOf(total_fee));
		prepayReqHandler.setParameter("trade_type", "APP");
		/**
		 * 注意签名(sign)的生成方式,具体见官方文档(传参都要参与生成签名,且参数名按照字典序排序,最后接上APP_KEY,转化成大写)
		 */
		prepayReqHandler.setParameter("sign", prepayReqHandler.createMD5Sign());
		prepayReqHandler.setGateUrl(ConstantUtil.GATEURL);
		String prepayid;
		try {
			prepayid = prepayReqHandler.sendPrepay();
			// 若获取prepayid成功,将相关信息返回客户端
			if (prepayid != null && !prepayid.equals("")) {

				String signs = "appid=" + ConstantUtil.APP_ID + "&noncestr=" + nonce_str
						+ "&package=Sign=WXPay&partnerid=" + ConstantUtil.PARTNER_ID + "&prepayid=" + prepayid
						+ "×tamp=" + timestamp + "&key=" + ConstantUtil.APP_KEY;
				map.put("code", 200);
				map.put("info", "success");
				map.put("prepayid", prepayid);
				try {
					String oldPhone = (String) request.getAttribute("oldPhone");
					String openid =userService.findWeChatIdByPhone(oldPhone,"type");
					map.put("openid", openid);
				} catch (Exception e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				/**
				 * 签名方式与上面类似
				 */
				map.put("sign", Md5Util.MD5Encode(signs, "utf8").toUpperCase());
				map.put("appid", ConstantUtil.APP_ID);
				map.put("timestamp", timestamp); // 等于请求prepayId时的time_start
				map.put("noncestr", nonce_str); // 与请求prepayId时值一致
				map.put("package", "Sign=WXPay"); // 固定常量
				map.put("partnerid", ConstantUtil.PARTNER_ID);
			} else {
				map.put("code", 400);
				map.put("info", "获取prepayid失败");
			}
		} catch (Exception e) {
			// TODO Auto-generated catch block
			map.put("code", 405);
			map.put("info", "系统异常");
		}

		return GsonUtils.GsonString(map);

	}

我们只需要把这个map返回给前端,让他去调用支付接口就可以了。


异步:

/**
	 * 接收微信支付成功通知
	 * 
	 * @param request
	 * @param response
	 * @throws IOException
	 */

	@RequestMapping(value = "/getTenPayNotify")
	public void getTenPayNotify(HttpServletRequest request, HttpServletResponse response) throws IOException {
		System.out.println("微信支付回调");
		PrintWriter writer = response.getWriter();
		InputStream inStream = request.getInputStream();
		ByteArrayOutputStream outSteam = new ByteArrayOutputStream();
		byte[] buffer = new byte[1024];
		int len = 0;
		while ((len = inStream.read(buffer)) != -1) {
			outSteam.write(buffer, 0, len);
		}
		outSteam.close();
		inStream.close();
		String result = new String(outSteam.toByteArray(), "utf-8");
		System.out.println("微信支付通知结果:" + result);
		Map<String, String> map = null;
		try {
			/**
			 * 解析微信通知返回的信息
			 */
			map = XMLUtil.doXMLParse(result);
		} catch (JDOMException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println("=========:" + result);
		// 若支付成功,则告知微信服务器收到通知
		if (map.get("return_code").equals("SUCCESS")) {
			if (map.get("result_code").equals("SUCCESS")) {
				System.out.println("充值成功!");
				Orders orders = orderService.selectOrdersInfoByOrderId(map.get("out_trade_no"));
		
				// 判断通知是否已处理,若已处理,则不予处理
				if (orders.getWechatpaytradeno() == null) {
					System.out.println("通知微信后台");
					orders.setEnd_time(System.currentTimeMillis() + "");
					orders.setPaytype("微信");
					orders.setStatus("TRADE_SUCCESS");
					String Wechatpaytradeno =map.get("transaction_id");
					orders.setWechatpaytradeno(Wechatpaytradeno);
				
					synchronized (this) {
						BigDecimal add =new BigDecimal("0.00");
						try {
							if(StringUtils.equals("recharge", orders.getOrdertype())){
								String myWalletBalance = userService.getMyWalletBalance(orders.getPhone());
								System.out.println("钱包余额为:"+myWalletBalance);
								BigDecimal old =new BigDecimal(myWalletBalance);
								 add = old.add(orders.getPaymoney());
							}
							
							orderService.modifyOrdersInfo(orders,add);
						} catch (Exception e) {
							result = "fail";
							e.printStackTrace();
						}
						String notifyStr = XMLUtil.setXML("SUCCESS", "");
						writer.write(notifyStr);
						writer.flush();
					}
				}
			}

这里和支付宝一样,都需要判断订单的状态,这里为“SUCCESS” 表示成功,这里需要注意的是,微信需要在异步中判断这个通知是否被处理过,处理过则忽略,我这里是默认没处理,让他每次异步都走这个未处理。

这就是微信支付接入的流程,总结一下就是微信支付文档很乱,而且是xml的,各种解析,要各种类配合使用。


  • 9
    点赞
  • 48
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

LawsonJin

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值