java服务器端微信,支付宝支付和退款

工作需要,写了服务器端的支付和退款功能,包含微信和支付宝,网上也有很多demo可以借鉴,我把我的代码放出来,写的比较简单,有问题的欢迎指正,大家一起学习


微信支付需要调用微信的统一下单接口,而支付宝不用

我写的时候微信和支付宝都单独写了一个工具类,来调用支付,给前端返回需要的数据

ps:支付是可以不需要服务器端的,不过为了安全一点点,所以前端需要调起支付的字段都直接从服务器端返回,前端拿到字段直接调起支付就可以了


	Map<String,String> map = new HashMap<String,String>();
	switch (record.getCheckType()) {
		case 10:
			map = Alipay.prePay(record.getAmount(),out_trade_no);
			return ResponseData.ok(map);
		case 20:
			map = WXPay.prePay(record.getAmount(),out_trade_no);
			return ResponseData.ok(map);
	}

10是支付宝支付,20是微信支付,map里存放前端需要的字段,直接返回给手机端

其中out_trade_no这个是商户自己生成的唯一订单号


public class WXPay {
	
	private static String url = String.format("https://api.mch.weixin.qq.com/pay/unifiedorder");
	
	//统一下单
	public static Map<String,String> prePay(BigDecimal amount,String out_trade_no){
		String entity = genProductArgs(amount,out_trade_no); 

		byte[] buf = Util.httpPost(url, entity);

		String content = new String(buf);
		Map<String,String> xml=decodeXml(content);
		return getRep(xml);
	}

	private static Map<String, String> getRep(Map<String, String> xml) {
		Random random = new Random();
		List<NameValuePair> signParams = new LinkedList<NameValuePair>();
		signParams.add(new BasicNameValuePair("appid", Constants.APP_ID_WX));
		signParams.add(new BasicNameValuePair("noncestr", MD5.getMessageDigest(String.valueOf(random.nextInt(10000)).getBytes())));
//		signParams.add(new BasicNameValuePair("package", "prepay_id="+xml.get("prepay_id")));
		signParams.add(new BasicNameValuePair("package", "Sign=WXPay"));
		signParams.add(new BasicNameValuePair("partnerid", Constants.MCH_ID));
		signParams.add(new BasicNameValuePair("prepayid", xml.get("prepay_id")));
		signParams.add(new BasicNameValuePair("timestamp", String.valueOf(System.currentTimeMillis() / 1000)));
		xml.put("sign", genPackageSign(signParams));
		for (int i = 0; i < signParams.size(); i++) {
			xml.put(signParams.get(i).getName(),signParams.get(i).getValue());
		}
		return removeElements(xml);
	}

	private static Map<String, String> removeElements(Map<String, String> xml) {
		xml.remove("appid");
		xml.remove("mch_id");
		xml.remove("nonce_str");
		xml.remove("trade_type");
		//xml.remove("partnerid");
		xml.remove("prepay_id");
		xml.remove("result_code");
		xml.remove("return_code");
		xml.remove("return_msg");
		return xml;
	}

	private static String genProductArgs(BigDecimal amount,String out_trade_no) {
		StringBuffer xml = new StringBuffer();
		
		String	nonceStr = genNonceStr();
		
		xml.append("</xml>");
		List<NameValuePair> packageParams = new LinkedList<NameValuePair>();
		packageParams.add(new BasicNameValuePair("appid", Constants.APP_ID_WX));
		packageParams.add(new BasicNameValuePair("body", "APP pay test"));
		packageParams.add(new BasicNameValuePair("mch_id", Constants.MCH_ID));
		packageParams.add(new BasicNameValuePair("nonce_str", nonceStr));
		packageParams.add(new BasicNameValuePair("notify_url", "填写服务器的支付回调路径"));
		packageParams.add(new BasicNameValuePair("out_trade_no",out_trade_no)); 
		packageParams.add(new BasicNameValuePair("spbill_create_ip","127.0.0.1"));
		packageParams.add(new BasicNameValuePair("total_fee", String.valueOf(amount.movePointRight(2))));
//		packageParams.add(new BasicNameValuePair("total_fee", "1"));
		packageParams.add(new BasicNameValuePair("trade_type", "APP"));
		
		String sign = genPackageSign(packageParams);
		packageParams.add(new BasicNameValuePair("sign", sign));


		String xmlstring =toXml(packageParams);
		return xmlstring;
	}
	
	public static String genNonceStr() {
		Random random = new Random();
		return MD5.getMessageDigest(String.valueOf(random.nextInt(10000)).getBytes());
	}
	
	public static String genPackageSign(List<NameValuePair> params) {
		StringBuilder sb = new StringBuilder();

		for (int i = 0; i < params.size(); i++) {
			sb.append(params.get(i).getName());
			sb.append('=');
			sb.append(params.get(i).getValue());
			sb.append('&');
		}
		sb.append("key=");
		sb.append(Constants.API_KEY);


		String packageSign = MD5.getMessageDigest(sb.toString().getBytes()).toUpperCase();
		return packageSign;
	}
	
	public static String toXml(List<NameValuePair> params) {
		StringBuilder sb = new StringBuilder();
		sb.append("<xml>");
		for (int i = 0; i < params.size(); i++) {
			sb.append("<"+params.get(i).getName()+">");


			sb.append(params.get(i).getValue());
			sb.append("</"+params.get(i).getName()+">");
		}
		sb.append("</xml>");

		return sb.toString();
	}
	
}

public class Alipay {
	
	public static Map<String,String> prePay(BigDecimal payAbleAmount,String out_trade_no){
		//String orderInfo = getOrderInfo("订单付款", "订单付款",out_trade_no,"0.01");
		String orderInfo = getOrderInfo("订单付款", "订单付款",out_trade_no,String.valueOf(payAbleAmount));
		
		String sign = sign(orderInfo);
		
		try {
			/**
			 * 仅需对sign 做URL编码
			 */
			sign = URLEncoder.encode(sign, "UTF-8");
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}

		/**
		 * 完整的符合支付宝参数规范的订单信息
		 */
		final String payInfo = orderInfo + "&sign=\"" + sign + "\"&" + getSignType();
		
		Map<String,String> map = new HashMap<String, String>();
		map.put("payInfo", payInfo);
		return map;
	}
	
	private static String getOrderInfo(String subject, String body,String out_trade_no,String price) {

		// 签约合作者身份ID
		String orderInfo = "partner=" + "\"" + Constants.PARTNER + "\"";

		// 签约卖家支付宝账号
		orderInfo += "&seller_id=" + "\"" + Constants.SELLER + "\"";

		// 商户网站唯一订单号
		orderInfo += "&out_trade_no=" + "\"" + out_trade_no + "\"";

		// 商品名称
		orderInfo += "&subject=" + "\"" + subject + "\"";

		// 商品详情
		orderInfo += "&body=" + "\"" + body + "\"";

		// 商品金额
		orderInfo += "&total_fee=" + "\"" + price + "\"";

		// 服务器异步通知页面路径
		orderInfo += "¬ify_url=" + "\"" + "填写服务器的支付回调路径" + "\"";
		

		// 服务接口名称, 固定值
		orderInfo += "&service=\"mobile.securitypay.pay\"";

		// 支付类型, 固定值
		orderInfo += "&payment_type=\"1\"";

		// 参数编码, 固定值
		orderInfo += "&_input_charset=\"utf-8\"";

		// 设置未付款交易的超时时间
		// 默认30分钟,一旦超时,该笔交易就会自动被关闭。
		// 取值范围:1m~15d。
		// m-分钟,h-小时,d-天,1c-当天(无论交易何时创建,都在0点关闭)。
		// 该参数数值不接受小数点,如1.5h,可转换为90m。
		orderInfo += "&it_b_pay=\"30m\"";

		// extern_token为经过快登授权获取到的alipay_open_id,带上此参数用户将使用授权的账户进行支付
		// orderInfo += "&extern_token=" + "\"" + extern_token + "\"";

		// 支付宝处理完请求后,当前页面跳转到商户指定页面的路径,可空
		orderInfo += "&return_url=\"m.alipay.com\"";

		// 调用银行卡支付,需配置此参数,参与签名, 固定值 (需要签约《无线银行卡快捷支付》才能使用)
		// orderInfo += "&paymethod=\"expressGateway\"";

		return orderInfo;
	}
	
	
	private static String sign(String content) {
		return SignUtils.sign(content, Constants.RSA_PRIVATE);
	}
	
	private static String getSignType() {
		return "sign_type=\"RSA\"";
	}
}



退款部分

支付宝

	String strResponse = null;
	AlipayTradeRefundResponse response = null;
        try {
            AlipayClient alipayClient = new DefaultAlipayClient(url,Constants.APPID_ALIPAY,Constants.RSA_PRIVATE,"json","utf-8",Constants.RSA_PUBLIC);
            AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
            
            RefundInfo alidata = new RefundInfo();
            alidata.setOut_trade_no(out_trade_no);
            alidata.setRefund_amount(refund_amount);
            
            request.setBizContent(JSON.toJSONString(alidata));
            
            response = alipayClient.sdkExecute(request);
            if (response.isSuccess()) {
            	strResponse="退款成功";
        	} else {
        		strResponse="退款失败";
        	}
            
            return strResponse;
        } catch (Exception e) {
        	strResponse="退款出错";
        }
        return strResponse;

微信

public class WXRefund {
	private static final String url = "https://api.mch.weixin.qq.com/secapi/pay/refund";
	
	/**
	 * 微信退款
	 * @param out_trade_no 商户订单号
	 * @param total_fee 总金额
	 * @param refund_fee 退款金额
	 * @return
	 */
	public static String doRefund(String out_trade_no,int total_fee,int refund_fee) {
		
		InputStream instream = null;
		KeyStore keyStore = null;
		CloseableHttpResponse response = null;
		CloseableHttpClient httpclient = null;
		StringBuilder text = new StringBuilder();
		String key = Constants.MCH_ID;
		try {
			/**
			* 注意PKCS12证书 是从微信商户平台-》账户设置-》 API安全 中下载的
			*/
			keyStore = KeyStore.getInstance("PKCS12");
			instream = WXRefund.class.getResourceAsStream("/apiclient_cert.p12");//P12文件
			
			
			/**
			* 此处要改
			*/
			keyStore.load(instream, key.toCharArray());// 这里写密码..默认是MCHID
			
			/**
			* 此处要改
			*/
			SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, key.toCharArray())// 这里也是写密码的
			.build();
			// Allow TLSv1 protocol only
			SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, new String[] { "TLSv1" }, null, SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
			httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
			
			//=======================证书配置完成========================
			
			
			HttpPost httpPost = new HttpPost(url);
			
			String xmlstring = getRefunArgs(out_trade_no,total_fee,refund_fee);
			
			
			
			httpPost.setEntity(new StringEntity(xmlstring));
			httpPost.setHeader("Accept", "application/json");
			httpPost.setHeader("Content-type", "application/json");
			
			response = httpclient.execute(httpPost);
			
			HttpEntity entity = response.getEntity();
			 
			if (entity != null) {
				BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(entity.getContent()));
				
				String str;
				while ((str = bufferedReader.readLine()) != null) {
					text.append(str);
				}
			}
			EntityUtils.consume(entity);
		}catch(Exception e){
			
		}finally {
			if(instream != null){
				try {
					instream.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			if(response != null){
				try {
					response.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			
			if(httpclient != null){
				try {
					httpclient.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		Map<String,String> map = WXPay.decodeXml(text.toString());
		String return_msg = map.get("return_msg");
		if ("OK".equals(return_msg) && "SUCCESS".equals(map.get("return_code"))) {
			return "退款成功";
		}
		return return_msg;
	}

	//设置请求参数的值
	private static String getRefunArgs(String out_trade_no,int total_fee,int refund_fee) {
		String nonce_str = WXPay.genNonceStr();
		List<NameValuePair> packageParams = new LinkedList<NameValuePair>();
		packageParams.add(new BasicNameValuePair("appid", Constants.APP_ID_WX));
		packageParams.add(new BasicNameValuePair("mch_id", Constants.MCH_ID));
		packageParams.add(new BasicNameValuePair("nonce_str", nonce_str));
		packageParams.add(new BasicNameValuePair("op_user_id", Constants.MCH_ID));
		packageParams.add(new BasicNameValuePair("out_refund_no",out_trade_no));
		packageParams.add(new BasicNameValuePair("out_trade_no",out_trade_no));
		packageParams.add(new BasicNameValuePair("refund_fee", String.valueOf(refund_fee)));
		packageParams.add(new BasicNameValuePair("total_fee", String.valueOf(total_fee)));
		
		String sign = WXPay.genPackageSign(packageParams);
		packageParams.add(new BasicNameValuePair("sign", sign));


		return WXPay.toXml(packageParams);
		
	}
	
}


点击下载支付,退款

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值