java微信app支付-统一下单

估计大多数人和我一样吧,每次要使用腾讯的开发api,都有一种想上吊的感觉,尤其是微信支付和支付宝对比起来文档确实差距还是有点大的

关于微信支付的申请我就不多说了,网上有很多,我们直接来说一下微信支付

微信支付是以下步骤(官方文档说明 https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=8_3)

步骤1:用户在商户APP中选择商品,提交订单,选择微信支付。

步骤2:商户后台收到用户支付单,调用微信支付统一下单接口。参见【统一下单API】。

步骤3:统一下单接口返回正常的prepay_id,再按签名规范重新生成签名后,将数据传输给APP。参与签名的字段名为appId,partnerId,prepayId,nonceStr,timeStamp,package。注意:package的值格式为Sign=WXPay

      步骤3要注意千万不要按照他给的签名字段进行前面,我就被坑了一天

     appid
     partnerid
     prepayid
     package
     noncestr
     timestamp
     sign

   签名字段一定不要按照文档的驼峰写法,应该是全部小写,就像上面

步骤4:商户APP调起微信支付。api参见本章节【app端开发步骤说明

步骤5:商户后台接收支付通知。api参见【支付结果通知API

步骤6:商户后台查询支付结果。,api参见【查询订单API

接下来我们就开始讲解统一下单

请求URL地址:https://api.mch.weixin.qq.com/pay/unifiedorder

参数

字段名变量名必填类型示例值描述
应用IDappidString(32)wxd678efh567hg6787微信开放平台审核通过的应用APPID
商户号mch_idString(32)1230000109微信支付分配的商户号
设备号device_infoString(32)013467007045764终端设备号(门店号或收银设备ID),默认请传"WEB"
随机字符串nonce_strString(32)5K8264ILTKCH16CQ2502SI8ZNMTM67VS随机字符串,不长于32位。推荐随机数生成算法
签名signString(32)C380BEC2BFD727A4B6845133519F3AD6签名,详见签名生成算法
商品描述bodyString(128)Ipad mini  16G  白色商品或支付单简要描述
商品详情detailString(8192)Ipad mini  16G  白色商品名称明细列表
附加数据attachString(127)深圳分店附加数据,在查询API和支付通知中原样返回,该字段主要用于商户携带订单的自定义数据
商户订单号out_trade_noString(32)20150806125346商户系统内部的订单号,32个字符内、可包含字母, 其他说明见商户订单号
货币类型fee_typeString(16)CNY符合ISO 4217标准的三位字母代码,默认人民币:CNY,其他值列表详见货币类型
总金额total_feeInt888订单总金额,单位为分,详见支付金额
终端IPspbill_create_ipString(16)123.12.12.123用户端实际ip
交易起始时间time_startString(14)20091225091010订单生成时间,格式为yyyyMMddHHmmss,如2009年12月25日9点10分10秒表示为20091225091010。其他详见时间规则
交易结束时间time_expireString(14)20091227091010

订单失效时间,格式为yyyyMMddHHmmss,如2009年12月27日9点10分10秒表示为20091227091010。其他详见时间规则

注意:最短失效时间间隔必须大于5分钟
商品标记goods_tagString(32)WXG商品标记,代金券或立减优惠功能的参数,说明详见代金券或立减优惠
通知地址notify_urlString(256)http://www.weixin.qq.com/wxpay/pay.php接收微信支付异步通知回调地址,通知url必须为直接可访问的url,不能携带参数。
交易类型trade_typeString(16)APP支付类型
指定支付方式limit_payString(32)no_creditno_credit--指定不能使用信用卡支付
我们先上工具类吧

public class PayCommonUtil {
	//微信参数配置
	public static String API_KEY="";
	public static String APPID="";
	public static String MCH_ID="";
	//随机字符串生成
	public static String getRandomString(int length) { //length表示生成字符串的长度    
	       String base = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";       
	       Random random = new Random();       
	       StringBuffer sb = new StringBuffer();       
	       for (int i = 0; i < length; i++) {       
	           int number = random.nextInt(base.length());       
	           sb.append(base.charAt(number));       
	       }       
	       return sb.toString();       
	    }  
	//请求xml组装
	  public static String getRequestXml(SortedMap<String,Object> parameters){
	        StringBuffer sb = new StringBuffer();
	        sb.append("<xml>");
	        Set es = parameters.entrySet();
	        Iterator it = es.iterator();
	        while(it.hasNext()) {
	            Map.Entry entry = (Map.Entry)it.next();
	            String key = (String)entry.getKey();
	            String value = (String)entry.getValue();
	            if ("attach".equalsIgnoreCase(key)||"body".equalsIgnoreCase(key)||"sign".equalsIgnoreCase(key)) {
	                sb.append("<"+key+">"+"<![CDATA["+value+"]]></"+key+">");
	            }else {
	                sb.append("<"+key+">"+value+"</"+key+">");
	            }
	        }
	        sb.append("</xml>");
	        return sb.toString();
	    }
	  //生成签名
	  public static String createSign(String characterEncoding,SortedMap<String,Object> parameters){
	        StringBuffer sb = new StringBuffer();
	        Set es = parameters.entrySet();
	        Iterator it = es.iterator();
	        while(it.hasNext()) {
	            Map.Entry entry = (Map.Entry)it.next();
	            String k = (String)entry.getKey();
	            Object v = entry.getValue();
	            if(null != v && !"".equals(v)
	                    && !"sign".equals(k) && !"key".equals(k)) {
	                sb.append(k + "=" + v + "&");
	            }
	        }
	        sb.append("key=" + API_KEY);
	        String sign = MD5Util.MD5Encode(sb.toString(), characterEncoding).toUpperCase();
	        return sign;
	    }
	  //请求方法
	  public static String httpsRequest(String requestUrl, String requestMethod, String outputStr) {
	        try {
	           
	            URL url = new URL(requestUrl);
	            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
	          
	            conn.setDoOutput(true);
	            conn.setDoInput(true);
	            conn.setUseCaches(false);
	            // 设置请求方式(GET/POST)
	            conn.setRequestMethod(requestMethod);
	            conn.setRequestProperty("content-type", "application/x-www-form-urlencoded");
	            // 当outputStr不为null时向输出流写数据
	            if (null != outputStr) {
	                OutputStream outputStream = conn.getOutputStream();
	                // 注意编码格式
	                outputStream.write(outputStr.getBytes("UTF-8"));
	                outputStream.close();
	            }
	            // 从输入流读取返回内容
	            InputStream inputStream = conn.getInputStream();
	            InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");
	            BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
	            String str = null;
	            StringBuffer buffer = new StringBuffer();
	            while ((str = bufferedReader.readLine()) != null) {
	                buffer.append(str);
	            }
	            // 释放资源
	            bufferedReader.close();
	            inputStreamReader.close();
	            inputStream.close();
	            inputStream = null;
	            conn.disconnect();
	            return buffer.toString();
	        } catch (ConnectException ce) {
	            System.out.println("连接超时:{}"+ ce);
	        } catch (Exception e) {
	        	System.out.println("https请求异常:{}"+ e);
	        }
	        return null;
	    }
	  //退款的请求方法
	  public static String httpsRequest2(String requestUrl, String requestMethod, String outputStr) throws Exception {
	        KeyStore keyStore  = KeyStore.getInstance("PKCS12");
	        StringBuilder res = new StringBuilder("");
	        FileInputStream instream = new FileInputStream(new File("/home/apiclient_cert.p12"));
	        try {
	            keyStore.load(instream, "".toCharArray());
	        } finally {
	            instream.close();
	        }

	        // Trust own CA and all self-signed certs
	        SSLContext sslcontext = SSLContexts.custom()
	                .loadKeyMaterial(keyStore, "1313329201".toCharArray())
	                .build();
	        // Allow TLSv1 protocol only
	        SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
	                sslcontext,
	                new String[] { "TLSv1" },
	                null,
	                SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
	        CloseableHttpClient httpclient = HttpClients.custom()
	                .setSSLSocketFactory(sslsf)
	                .build();
	        try {

	        	HttpPost httpost = new HttpPost("https://api.mch.weixin.qq.com/secapi/pay/refund");
	            httpost.addHeader("Connection", "keep-alive");
	            httpost.addHeader("Accept", "*/*");
	            httpost.addHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
	            httpost.addHeader("Host", "api.mch.weixin.qq.com");
	            httpost.addHeader("X-Requested-With", "XMLHttpRequest");
	            httpost.addHeader("Cache-Control", "max-age=0");
	            httpost.addHeader("User-Agent", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0) ");
	        	 StringEntity entity2 = new StringEntity(outputStr ,Consts.UTF_8);
	        	 httpost.setEntity(entity2);
	            System.out.println("executing request" + httpost.getRequestLine());

	            CloseableHttpResponse response = httpclient.execute(httpost);
	           
	            try {
	                HttpEntity entity = response.getEntity();
	                
	                System.out.println("----------------------------------------");
	                System.out.println(response.getStatusLine());
	                if (entity != null) {
	                    System.out.println("Response content length: " + entity.getContentLength());
	                    BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(entity.getContent()));
	                    String text;res.append(text);
	                    while ((text = bufferedReader.readLine()) != null) {
                            res.append(text);
                            System.out.println(text);
	                    }
	                   
	                }
	                EntityUtils.consume(entity);
	            } finally {
	                response.close();
	            }
	        } finally {
	            httpclient.close();
	        }
			return  res.toString();
	        
	    }
	  //xml解析
	  public static Map doXMLParse(String strxml) throws JDOMException, IOException {
	        strxml = strxml.replaceFirst("encoding=\".*\"", "encoding=\"UTF-8\"");

	        if(null == strxml || "".equals(strxml)) {
	            return null;
	        }
	        
	        Map m = new HashMap();
	        
	        InputStream in = new ByteArrayInputStream(strxml.getBytes("UTF-8"));
	        SAXBuilder builder = new SAXBuilder();
	        Document doc = builder.build(in);
	        Element root = doc.getRootElement();
	        List list = root.getChildren();
	        Iterator it = list.iterator();
	        while(it.hasNext()) {
	            Element e = (Element) it.next();
	            String k = e.getName();
	            String v = "";
	            List children = e.getChildren();
	            if(children.isEmpty()) {
	                v = e.getTextNormalize();
	            } else {
	                v = getChildrenText(children);
	            }
	            
	            m.put(k, v);
	        }
	        
	        //关闭流
	        in.close();
	        
	        return m;
	    }
	  
	  public static String getChildrenText(List children) {
	        StringBuffer sb = new StringBuffer();
	        if(!children.isEmpty()) {
	            Iterator it = children.iterator();
	            while(it.hasNext()) {
	                Element e = (Element) it.next();
	                String name = e.getName();
	                String value = e.getTextNormalize();
	                List list = e.getChildren();
	                sb.append("<" + name + ">");
	                if(!list.isEmpty()) {
	                    sb.append(getChildrenText(list));
	                }
	                sb.append(value);
	                sb.append("</" + name + ">");
	            }
	        }
	        
	        return sb.toString();
	    }
	 
}

统一下单

参数说明
sn订单号
totalAmount支付金额
description产品描述

public static Map<String, String> weixinPrePay(String sn,BigDecimal totalAmount,
			String description, HttpServletRequest request) {
		Setting setting = SettingUtils.get();
		SortedMap<String, Object> parameterMap = new TreeMap<String, Object>();
		parameterMap.put("appid", PayCommonUtil.APPID);
		parameterMap.put("mch_id", PayCommonUtil.MCH_ID);
		parameterMap.put("nonce_str", PayCommonUtil.getRandomString(32));
		parameterMap.put("body",
				StringUtils.abbreviate(description.replaceAll(
						"[^0-9a-zA-Z\\u4e00-\\u9fa5 ]", ""), 600));
		parameterMap.put("out_trade_no", sn);
		parameterMap.put("fee_type", "CNY");
		System.out.println("jiner");
		BigDecimal total = totalAmount.multiply(new BigDecimal(100));
		java.text.DecimalFormat df=new java.text.DecimalFormat("0");
		parameterMap.put("total_fee", df.format(total));
		System.out.println("jiner2");
		parameterMap.put("spbill_create_ip", request.getRemoteAddr());
		parameterMap.put("notify_url", "http://xxx.com");
		parameterMap.put("trade_type", "APP");
		System.out.println("");
		String sign = PayCommonUtil.createSign("UTF-8", parameterMap);
		System.out.println("jiner2");
		parameterMap.put("sign", sign);
		String requestXML = PayCommonUtil.getRequestXml(parameterMap);
		System.out.println(requestXML);
		String result = PayCommonUtil.httpsRequest(
				"https://api.mch.weixin.qq.com/pay/unifiedorder", "POST",
				requestXML);
		System.out.println(result);
		Map<String, String> map = null;
		try {
			map = PayCommonUtil.doXMLParse(result);
		} catch (JDOMException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return map;
	}

 
 

 

获取prepay_id,二次签名发送结果给app,此方法结合业务自己优化一下,这里只是举个例子

public static String createSignAgain(HttpServletRequest request)
			Map<String, String> map = weixinPrePay(payment.getSn(), payment.getAmount(),description,
				request);
		JSONObject jsonObject = new JSONObject();
		SortedMap<String, Object> parameterMap = new TreeMap<String, Object>();
		parameterMap.put("appid", PayCommonUtil.APPID);
		parameterMap.put("partnerid", PayCommonUtil.MCH_ID);
		parameterMap.put("prepayid", map.get("prepay_id"));
		parameterMap.put("package", "Sign=WXPay");
		parameterMap.put("noncestr", PayCommonUtil.getRandomString(32));
		parameterMap.put("timestamp", System.currentTimeMillis());
		String sign = PayCommonUtil.createSign("UTF-8", parameterMap);
		parameterMap.put("sign", sign);
		jsonObject.put("parameterMap",parameterMap);
		return jsonObject.toString();
	}


 到此统一下下单完成,关于app支付我就不说了,下一篇说一下支付结果通用通知 


  • 5
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 15
    评论
### 回答1: 以下是微信小程序统一下单Java后台代码示例: ``` import java.util.HashMap; import java.util.Map; import java.util.SortedMap; import java.util.TreeMap; import org.apache.commons.codec.digest.DigestUtils; public class WechatPay { // 微信支付接口地址 private static final String UNIFIED_ORDER_URL = "https://api.mch.weixin.qq.com/pay/unifiedorder"; // 微信支付商户号 private static final String MCH_ID = "your_mch_id"; // 微信支付密钥 private static final String KEY = "your_api_key"; /** * 统一下单方法 * * @param openid 用户openid * @param body 商品描述 * @param totalFee 订单总金额,单位为分 * @param spbillCreateIp 用户端实际ip * @param outTradeNo 商户订单号 * @param notifyUrl 支付结果通知地址 * @return 统一下单结果 * @throws Exception */ public static Map<String, String> unifiedOrder(String openid, String body, int totalFee, String spbillCreateIp, String outTradeNo, String notifyUrl) throws Exception { // 构造请求参数 SortedMap<String, String> parameters = new TreeMap<>(); parameters.put("appid", "your_app_id"); parameters.put("mch_id", MCH_ID); parameters.put("nonce_str", String.valueOf(System.currentTimeMillis())); parameters.put("body", body); parameters.put("out_trade_no", outTradeNo); parameters.put("total_fee", String.valueOf(totalFee)); parameters.put("spbill_create_ip", spbillCreateIp); parameters.put("notify_url", notifyUrl); parameters.put("trade_type", "JSAPI"); parameters.put("openid", openid); parameters.put("sign", sign(parameters)); // 发送请求 String xml = HttpUtil.post(UNIFIED_ORDER_URL, XmlUtil.toXml(parameters)); Map<String, String> result = XmlUtil.toMap(xml); // 验证返回结果 if (!"SUCCESS".equals(result.get("return_code"))) { throw new Exception(result.get("return_msg")); } if (!"SUCCESS".equals(result.get("result_code"))) { throw new Exception(result.get("err_code_des")); } return result; } /** * 生成签名 * * @param parameters 请求参数 * @return 签名字符串 */ private static String sign(SortedMap<String, String> parameters) { StringBuilder sb = new StringBuilder(); for (String key : parameters.keySet()) { String value = parameters.get(key); if (value != null && !"".equals(value) && !"sign".equals(key) && !"key".equals(key)) { sb.append(key).append("=").append(value).append("&"); } } sb.append("key=").append(KEY); return DigestUtils.md5Hex(sb.toString()).toUpperCase(); } } ``` 这段代码实现了微信小程序的统一下单功能,其中包括了生成签名、构造请求参数、发送请求、解析响应等功能。你需要将代码中的`your_app_id`、`your_mch_id`、`your_api_key`替换为自己的实际值,并引入Apache Commons Codec和HttpUtil、XmlUtil工具类。 ### 回答2: 微信小程序统一下单是指在用户使用微信小程序进行支付时,通过后台的Java代码来完成支付的过程。 要实现微信小程序统一下单,首先需要在代码中引入微信支付的SDK。然后,在后台的Java代码中,需要编写处理统一下单逻辑的方法。 在这个方法中,首先需要获取到用户传递过来的支付参数,包括小程序的ID、密钥、订单号、金额等信息。然后,通过调用微信支付SDK提供的统一下单接口,向微信支付平台发送请求。这个接口会返回一个预支付交易会话标识prepay_id。 接下来,需要将prepay_id返回给小程序端,小程序将根据prepay_id生成签名等信息,用于调起支付接口。同时,后台的Java代码还需要保存订单相关的信息,以便后续查询或退款等操作。 当用户确认支付并完成支付后,微信支付平台会向后台发送支付通知。后台的Java代码需要编写处理支付通知的方法,用于更新订单状态或处理其他业务逻辑。 需要注意的是,在进行统一下单时,要保证传递给微信支付平台的数据的准确性和安全性,以避免支付中出现问题。 总的来说,微信小程序统一下单的后台Java代码主要包括获取支付参数、调用微信支付SDK进行统一下单、处理支付通知等步骤。这样,就可以通过后台的Java代码实现微信小程序的支付功能。 ### 回答3: 微信小程序统一下单是指用户在微信小程序中发起支付请求,并将支付相关的参数传递给后台服务器进行处理。下面是一个简单的微信小程序统一下单的后台Java代码示例: ```java import java.util.Map; import java.util.SortedMap; import java.util.TreeMap; public class WechatPay { public static String unifiedOrder(String openid, String totalFee) { SortedMap<String, Object> params = new TreeMap<>(); params.put("appid", "your_appid"); params.put("mch_id", "your_mch_id"); params.put("nonce_str", WechatPayUtil.generateNonceStr()); params.put("body", "支付测试"); params.put("out_trade_no", WechatPayUtil.generateOutTradeNo()); params.put("total_fee", totalFee); params.put("spbill_create_ip", "your_client_ip"); params.put("notify_url", "your_notify_url"); params.put("trade_type", "JSAPI"); params.put("openid", openid); params.put("sign", WechatPayUtil.generateSign(params, "your_api_key")); String xmlParams = WechatPayUtil.mapToXml(params); String result = HttpUtil.sendPost("https://api.mch.weixin.qq.com/pay/unifiedorder", xmlParams); Map<String, Object> resultMap = WechatPayUtil.xmlToMap(result); return resultMap.get("prepay_id").toString(); } } ``` 上述代码中,WechatPay类的unifiedOrder方法接收openId和totalFee参数,并根据微信支付接口要求将相关参数进行组装,其中your_appid、your_mch_id、your_notify_url、your_api_key需要替换成真实的值。最后,通过HttpUtil类发送POST请求到https://api.mch.weixin.qq.com/pay/unifiedorder接口,获取返回结果,并从结果中解析出prepay_id,作为小程序发起支付的参数返回给前端。 这只是一个简单的示例,实际开发中还需要考虑异常处理、支付结果的回调通知等。希望对你有帮助!

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值