欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

uni-app+springmvc调用JSAPI完成H5微信公众号内支付

程序员文章站 2024-01-22 11:15:16
...

1.微信服务号商户的申请流程以及后台的开发配置略,按照提示来做就OK了,重点是开发流程

2.开发流程

流程图:

uni-app+springmvc调用JSAPI完成H5微信公众号内支付

时序图:

uni-app+springmvc调用JSAPI完成H5微信公众号内支付开发使用框架:H5端用uni-app框架实现,后台采用java语言,由springmvc框架实现

大致开发步骤如下:

第一步:从公众号的网页发起支付请求,以ajax的方式,发送到商户后台系统,并传递必要参数

第二步:商户后台系统准备好参数,以http post方式访问微信的API,调用其中的统一下单接口,这一步最关键的是要取回预支付id,另外配齐其他的参数

第三步:回到公众号的网页,调用jssdk及相应方法,完成支付

第四步:支付后回调函数、跳转,ajax请求商户后台系统,验证支付结果

2.1在后台准备好参数然后调起微信统一下单接口

为了阅读方便,这里首先标记一下输入和输出

2.2.1后台部分的输入输出

从H5传递给后台的参数包括:

1.支付金额(fee)

2.手机的IP地址(ipaddr)

后台调用微信统一下单接口成功后返回给H5的参数包括:

1.公众号的appId

2.时间戳

3.随机字符串nonce_str

注意:这个随机字符串不是调起与支付接口前,我们自己用方法生成的随机字符串,而是微信接口向我们返回的随机字符串!

4.packageStr,按照官方文档的规则拼接好就可以了

5.paySgin,签名

注意:这个paySign签名也是个雷,最开始摸索阶段的时候一直无法通过验证,因为不知道是需要二次加签的,惨痛的教训!

6.out_trade_no:支付的订单号

2.2.2获得openid的步骤:

微信官方API文档地址:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140842

第一步:用户同意授权,获取code

https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect

注意:

1. redirect_uri参数:授权后重定向的回调链接地址, 请使用 urlEncode 对链接进行处理

2. scope:用snsapi_base

第二步:通过code换取网页授权access_token(其实微信支付就没有必要获取access_token了,咱们只要其中openid,不是要用户信息,此步结果已经就含有咱们需要的openid了)

获取code后,请求以下链接获取access_token: https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code

上一步的code有了,对于此链接的参数就容易了。可是在页面上如何处理是个问题,我是在pay.jsp页面加载完成后将获取code当做参数传异步到后台,在后台中用http相关类发送get请求(可以自行网上查找)。返回的JSON结果为:

{ "access_token":"ACCESS_TOKEN",

"expires_in":7200,

"refresh_token":"REFRESH_TOKEN",

"openid":"OPENID",

"scope":"SCOPE"

}

以上返回的JSON我们只要拿到openid就可以了

2.2.3准备好其他参数:

拿到openid后,我们就可以开始在controller类中准备其他的参数了

那么调起预支付接口,必须的参数有:

1.appId 公众号的appId(已有)

2.mch_id 即商户id(从商户平台可以查询的到)

3.nonce_str 随机字符串

4.sign 签名

5.body 所支付的名称(从H5端传至后台,或者后台自定义名称)

6.out_trade_no 支付订单号

7.total_fee 支付金额(从H5端传至后台)

8.spbill_create_ip 设备的IP地址,一般指发起地址的手机的ip地址(从H5端传至后台)

9.notify_url 回调地址(就是你支付成功后所跳转的地址,从后台配置一下就行)

10.trade_type 支付类型(这里我们写:JSAPI)

11.openid 支付人在微信公众号内的唯一标识(2.2.1中已可以拿到)

11个参数,还差谁?out_trade_no,nonce_str,sign,这三个

首先out_trade_no是支付的订单号,这个我们以自己的逻辑来生成就可以了,但要保证唯一性且官方文档要求32位以内,这里我用的是按照时间精确到毫秒一级加上四位随机数字来生成的订单号

nonce_str是一个随机生成的字符串,也是要求32位以内,这里附上生成nonce_str的JAVA代码:

private static final String SYMBOLS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
private static final Random RANDOM = new SecureRandom();

/**
* 生成随机字符串,用于微信支付
* @return
*/
public static String generateNonceStr() {
    char[] nonceChars = new char[32];
    for (int index = 0; index < nonceChars.length; ++index) {
        nonceChars[index] = SYMBOLS.charAt(RANDOM.nextInt(SYMBOLS.length()));
    }
    return new String(nonceChars);
}

最后一个参数:sign,比较麻烦,如果你去翻官方文档,可能会晕的,我也是百度了好多前辈们的经验最终才闯关成功...

先看一下微信提供的java sdk里,生成签名的方法有哪些参数(最后我会附上sdk工具类代码文件WxAPIUtils.java):

String sign = "";
try {
    sign = WxAPIUtils.generateSignature(map, Commons.paySecret, WxAPIUtils.SignType.MD5);
} catch (Exception e1) {
    e1.printStackTrace();
}

1.Commons.paySecret是指商户的支付**,注意,并不是你公众号的那个appSecret,这个从商户平台的后台可以查的到

2.WxAPIUtils.SignType.MD5,SignType是一个枚举类型,我们固定用MD5就可以了

3.map,这个map比较痛苦,我们首先将其他的参数,都放到这个map里,然后将这个map传递给生成签名的方法,最终得到签名sign...,这里附上代码:

//将统一下单接口的必要参数,组装Map
final Map<String, String> map = new HashMap<String, String>();
map.put("appid", appId);
map.put("attach", "paytest");
map.put("body", body);
map.put("mch_id", mchId);
map.put("nonce_str", nonce_str);
map.put("notify_url", notify_url);
map.put("openid", openId);
map.put("out_trade_no", out_trade_no);
map.put("spbill_create_ip", spbill_create_ip);
map.put("total_fee", total_fee + "");
map.put("trade_type", trade_type);

上面代码,多了一个attach,我不确定有没有用,反正之前的测试,我没有加attach,测试是失败的,attach对应的值,你可以自定义

2.2.4调起微信预支付接口

好,现在sign也拿到了,依据接口规范,我们组装一个xml然后就可以调起预支付接口了:

String apiXml = "<xml>";
apiXml += "<appid>" + appId + "</appid>";
apiXml += "<attach>paytest</attach>";
apiXml += "<body>" + body + "</body>";
apiXml += "<mch_id>" + mchId + "</mch_id>";
apiXml += "<nonce_str>" + nonce_str + "</nonce_str>";
apiXml += "<notify_url>" + notify_url + "</notify_url>";
apiXml += "<openid>" + openId + "</openid>";
apiXml += "<out_trade_no>" + out_trade_no +"</out_trade_no>";
apiXml += "<spbill_create_ip>" + spbill_create_ip + "</spbill_create_ip>";
apiXml += "<total_fee>" + total_fee + "</total_fee>";
apiXml += "<trade_type>" + trade_type + "</trade_type>";
apiXml += "<sign>" + sign + "</sign>";
apiXml += "</xml>";
String unifiedorder_url = "https://api.mch.weixin.qq.com/pay/unifiedorder"; //预支付接口地址
String xmlStr = HttpUtils.sendPost(unifiedorder_url, apiXml);//sendPost方法稍后也会附上

uni-app+springmvc调用JSAPI完成H5微信公众号内支付

 

如果您看到了类似这样的xml返回,恭喜你,与支付调用成功了

这里的xmlStr就是微信预支付接口给你返回的东西了,我们需要将其转成xml,然后进行解读

Map wxBackMap = XmlConvertMapUtil.Dom2Map(xmlStr); //将微信接口返回的xml转成map

XmlConvertMapUtil.java最后我也会附上文件)

2.2.5准备参数,拼组JSON给H5端

1.nonceStr随机字符串,再次强调,这个是从微信接口返回的随机字符串,不是我们自己之前生成的那个

String nonce_str_back = wxBackMap.get("nonce_str").toString(); //随机字符串

2.packageStr

String packageStr = "prepay_id=" + wxBackMap.get("prepay_id").toString();//前面一定要加prepay_id=

3.signType

String signType = "MD5"; //signType,默认值为MD5

4.二次签名paySign

final Map<String, String> mapAgain = new HashMap<String, String>();
mapAgain.put("appId", appId);
mapAgain.put("timeStamp", timestampStr);
mapAgain.put("nonceStr", nonce_str_back);
mapAgain.put("package", packageStr);
mapAgain.put("signType", signType);
String signResultBack = "";
try {
    signResultBack = WxAPIUtils.generateSignature(mapAgain, Commons.paySecret, WxAPIUtils.SignType.MD5);
} catch (Exception e1) {
    e1.printStackTrace();
}

OK,准备完毕,可以开始组装JSON了

WxPrePayVo wxPrePayVo = new WxPrePayVo();
wxPrePayVo.setAppId(appId);
wxPrePayVo.setTimeStamp(timestampStr);
wxPrePayVo.setNonceStr(nonce_str_back);
wxPrePayVo.setPackageStr(packageStr);
wxPrePayVo.setSignType(signType);
wxPrePayVo.setPaySign(signResultBack);
wxPrePayVo.setOutTradeNo(out_trade_no);
jsonContent = JSONObject.fromObject(wxPrePayVo).toString();
return jsonContent;

到此,后台调与预支付接口代码完毕,jsonContent返回给H5端

2.3前台H5端的代码(uni-app)

2.3.1引用微信jssdk以及其他的js工具

包括:微信jssdk,sohu获取ip地址的工具,以及自己写微信配置方法以及invoke方法的js文件

我这个jweixin-1.0.0.js版本比较老,引新一点的也没问题

在App.vue中加入代码:


var wxSdk = document.createElement('script');
wxSdk.type = 'text/javascript';
wxSdk.src = 'https://res.wx.qq.com/open/js/jweixin-1.0.0.js';
head.appendChild(wxSdk);

var ipadrTool = document.createElement('script');
ipadrTool.type = 'text/javascript';
ipadrTool.src = 'http://pv.sohu.com/cityjson?ie=utf-8';
head.appendChild(ipadrTool);

var mysdk = document.createElement('script');
mysdk.type = 'text/javascript';
mysdk.src = 'http://xxxx.com/js/myJssdk.js';
head.appendChild(mysdk);

H5端调用后台预支付接口以及收到返回值后的操作代码:

methods: {
    prepay() {
	this.ipaddr = returnCitySN.cip
	this.$http({
	url : 'http://xxxx.com/xxxx/interface/wxPrepay',
 	method: 'POST',
 	expressData: {
  	    userId: this.userId,
	    fee: this.money,
	    ipaddr: this.ipaddr,
	    payType: this.payType
	}
    }).then(res =>{
 	// console.log(res)
	this.appId = res.appId
	this.timeStamp = res.timeStamp
	this.nonceStr = res.nonceStr
	this.packageStr = res.packageStr
	this.paySign = res.paySign
	this.outTradeNo = res.outTradeNo
					
	uni.setStorage({
		key:'payInfo',
		data:{
			userId: this.userId,
			payType: this.payType,
			outTradeNo: this.outTradeNo
		},
	})
	    pay(this.timeStamp, this.nonceStr, this.packageStr, this.paySign)
            //这里的pay方法就在myJssdk.js中,是调用微信支付的核心方法
	})
    }
},

上面的pay方法调用微信jssdk执行支付 ,这个请看代码附件

参考链接:

1.https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1

2.https://blog.csdn.net/javaYouCome/article/details/79473743###

附录:

1.myJssdk.js:

function wxconfig(rs) {
	wx.config({
		debug: false,
		appId: '{你的公众号的appId}',
		timestamp: rs.timestamp,
		nonceStr: rs.nonceStr,
		signature: rs.signature,
		jsApiList: [
			'onMenuShareTimeline',
			'onMenuShareAppMessage',
			'onMenuShareQQ',
			'onMenuShareWeibo',
			'onMenuShareQZone',
			'chooseWXPay'
		]
	});
}

function pay(timeStamp, nonceStr, packageStr, paySign) {
    if (typeof WeixinJSBridge == "undefined"){
        if( document.addEventListener ){
            document.addEventListener('WeixinJSBridgeReady', onBridgeReady, false);
        }else if (document.attachEvent){
            document.attachEvent('WeixinJSBridgeReady', onBridgeReady); 
            document.attachEvent('onWeixinJSBridgeReady', onBridgeReady);
        }
    }else{
        onBridgeReady(timeStamp, nonceStr, packageStr, paySign);
    }
}

function onBridgeReady(timeStamp, nonceStr, packageStr, paySign) {
	WeixinJSBridge.invoke( 'getBrandWCPayRequest', {
		"appId": '{你的公众号的appId}',            //公众号名称,由商户传入     
	    "timeStamp": timeStamp,    //时间戳,自1970年以来的秒数     
	    "nonceStr": nonceStr,      //随机串     
	    "package": packageStr,     
	    "signType": 'MD5',         //微信签名方式:     
	    "paySign": paySign         //微信签名
		},function(res){      
      	
			if(res.err_msg == "get_brand_wcpay_request:ok" ) {
            
				console.log('支付成功');
				window.location.href = "http://xxxx.com/pages/pay/payback/"
			}else if(res.err_msg == "get_brand_wcpay_request:cancel"){
          	
				console.log('支付取消');
 
			}else if(res.err_msg == "get_brand_wcpay_request:fail"){
          	
				console.log('支付失败');
	
			WeixinJSBridge.call('closeWindow');
        
		} 
	});
	//使用以上方式判断前端返回,微信团队郑重提示:res.err_msg将在用户支付成功后返回ok,但并不保证它绝对可靠。
}

2.Controller 类的代码:

package com.xmtk.lawyerHelp.frontInterface;

import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import com.xmtk.lawyerHelp.payRecord.entity.WxPrePayVo;
import com.xmtk.lawyerHelp.utils.Commons;
import com.xmtk.lawyerHelp.utils.HttpUtils;
import com.xmtk.lawyerHelp.utils.StrUtils;
import com.xmtk.lawyerHelp.utils.WxAPIUtils;
import com.xmtk.lawyerHelp.utils.XmlConvertMapUtil;

import net.sf.json.JSONObject;

@Controller
@RequestMapping("/interface")
public class interfaceController2 {
	@RequestMapping(value = "/wxPrepay", method = RequestMethod.POST, 
			produces = "application/json;charset=UTF-8")
	public @ResponseBody String wxPrepay(@RequestBody String jsonStr, HttpServletRequest request) {
		String jsonContent = "{\"data\":\"none\"}"; 
		JSONObject jo = JSONObject.fromObject(jsonStr);
		String userId = jo.getString("userId");
		String openId = "";
		if(StrUtils.isNotEmptyStr(userId)) {  //用户的微信openid,事先已在用户表里保存过
			openId = tabUserService.getTabUserById(Integer.parseInt(userId)).getWxOpenId();
		}
		//统一下单:必须参数准备
		String appId = Commons.appId;  //appId
		String mchId = Commons.mch_id;  //商户号
		String nonce_str = WxAPIUtils.generateNonceStr();  //随机字符串
		
		String body = "lawyerMember";//商品描述
		String out_trade_no = WxAPIUtils.getOrderNo();  //商户订单号
		Integer total_fee = Integer.parseInt(jo.getString("fee"));  //支付金额(单位为分)
		String spbill_create_ip = jo.getString("ipaddr");  //设备的IP地址
		String notify_url = Commons.notify_url;
		String trade_type = "JSAPI";  //交易类型
		
		//将统一下单接口的必要参数,组装Map
		final Map<String, String> map = new HashMap<String, String>();
		map.put("appid", appId);
		map.put("attach", "paytest");
		map.put("body", body);
		map.put("mch_id", mchId);
		map.put("nonce_str", nonce_str);
		map.put("notify_url", notify_url);
		map.put("openid", openId);
		map.put("out_trade_no", out_trade_no);
		map.put("spbill_create_ip", spbill_create_ip);
		map.put("total_fee", total_fee + "");
		map.put("trade_type", trade_type);
		
		String sign = "";
		try {
			sign = WxAPIUtils.generateSignature(map, Commons.paySecret, WxAPIUtils.SignType.MD5);
		} catch (Exception e1) {
			e1.printStackTrace();
		}  //签名
		//将获得的签名也put进map
		map.put("sign", sign);
		
		//Map转XML
		String apiXml = "<xml>";
		apiXml += "<appid>" + appId + "</appid>";
		apiXml += "<attach>paytest</attach>";
		apiXml += "<body>" + body + "</body>";
		apiXml += "<mch_id>" + mchId + "</mch_id>";
		apiXml += "<nonce_str>" + nonce_str + "</nonce_str>";
		apiXml += "<notify_url>" + notify_url + "</notify_url>";
		apiXml += "<openid>" + openId + "</openid>";
		apiXml += "<out_trade_no>" + out_trade_no +"</out_trade_no>";
		apiXml += "<spbill_create_ip>" + spbill_create_ip + "</spbill_create_ip>";
		apiXml += "<total_fee>" + total_fee + "</total_fee>";
		apiXml += "<trade_type>" + trade_type + "</trade_type>";
		apiXml += "<sign>" + sign + "</sign>";
		apiXml += "</xml>";
		
//		System.out.println("调用前XML:" + apiXml);
		String unifiedorder_url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
		String xmlStr = HttpUtils.sendPost(unifiedorder_url, apiXml);//发送post请求"统一下单接口"返回预支付id:prepay_id
		Long tstp = System.currentTimeMillis() / 1000;
		String timestampStr = tstp.toString();  //时间戳
//		System.out.println("统一下单返回:" + xmlStr);
		Map wxBackMap = XmlConvertMapUtil.Dom2Map(xmlStr);  //将微信接口返回的xml转成map
		
		String nonce_str_back = wxBackMap.get("nonce_str").toString();  //随机字符串
		//package,API说明的参数是package,由于package是JAVA的关键字,故更改命名传回前端再做处理
		String packageStr = "prepay_id=" + wxBackMap.get("prepay_id").toString();
		String signType = "MD5";   //signType,默认值为MD5
//		String signResultBack = wxBackMap.get("sign").toString();
		
		//二次签名
		final Map<String, String> mapAgain = new HashMap<String, String>();
		mapAgain.put("appId", appId);
		mapAgain.put("timeStamp", timestampStr);
		mapAgain.put("nonceStr", nonce_str_back);
		mapAgain.put("package", packageStr);
		mapAgain.put("signType", signType);
		String signResultBack = "";
		try {
			signResultBack = WxAPIUtils.generateSignature(mapAgain, Commons.paySecret, WxAPIUtils.SignType.MD5);
		} catch (Exception e1) {
			e1.printStackTrace();
		} 
		
		//将准备返回给前台的Vo对象赋值,准备组装json
		WxPrePayVo wxPrePayVo = new WxPrePayVo();
		wxPrePayVo.setAppId(appId);
		wxPrePayVo.setTimeStamp(timestampStr);
		wxPrePayVo.setNonceStr(nonce_str_back);
		wxPrePayVo.setPackageStr(packageStr);
		wxPrePayVo.setSignType(signType);
		wxPrePayVo.setPaySign(signResultBack);
		wxPrePayVo.setOutTradeNo(out_trade_no);
//		wxPrePayVo.setPayType(payType);
		jsonContent = JSONObject.fromObject(wxPrePayVo).toString();
		return jsonContent;
	}
}

3.XmlConvertMapUtil.java

package com.xmtk.lawyerHelp.utils;

import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;

public class XmlConvertMapUtil {
	public static Map<String,String> Dom2Map(String xml) {
		Map<String,String> map = new HashMap<String, String>();
		Document doc = null;
		try {
			doc = DocumentHelper.parseText(xml);
		} catch (DocumentException e) {
			e.printStackTrace();
		}
		if(doc ==null)
			return map;
		Element root = doc.getRootElement();
	  for (Iterator iterator = root.elementIterator(); iterator.hasNext();) {
		 Element e = (Element) iterator.next();
		 map.put(e.getName(), e.getText());
	  }
	  return map;
	}
	
	public static byte[] callMapToXML(Map map) {
//		System.out.println("将Map转成Xml, Map:" + map.toString());
		StringBuffer sb = new StringBuffer();
		sb.append("<xml>");
//		sb.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?><xml>");
		mapToXMLTest2(map, sb);
		sb.append("</xml>");
//		System.out.println("将Map转成Xml, Xml:" + sb.toString());
		try {
			return sb.toString().getBytes("UTF-8");
		} catch (Exception e) {
			System.out.println(e);
		}
		return null;
	}
	
	private static void mapToXMLTest2(Map map, StringBuffer sb) {
		Set set = map.keySet();
		for (Iterator it = set.iterator(); it.hasNext();) {
			String key = (String) it.next();
			Object value = map.get(key);
			if (null == value)
				value = "";
			if (value.getClass().getName().equals("java.util.ArrayList")) {
				ArrayList list = (ArrayList) map.get(key);
				sb.append("<" + key + ">");
				for (int i = 0; i < list.size(); i++) {
					HashMap hm = (HashMap) list.get(i);
					mapToXMLTest2(hm, sb);
				}
				sb.append("</" + key + ">");
			} else {
				if (value instanceof HashMap) {
					sb.append("<" + key + ">");
					mapToXMLTest2((HashMap) value, sb);
					sb.append("</" + key + ">");
				} else {
					sb.append("<" + key + ">" + value + "</" + key + ">");
				}
			}
		}
	}
	
	public static void main(String[] args) {
		Map<String, String> map = new HashMap<String, String>();
		map.put("key1", "value1");
		map.put("key2", "value2");
		map.put("key3", "value3");
		try {
			String c = new String(callMapToXML(map), "UTF-8");
			System.out.println(c);
			Map mapback = Dom2Map(c);
			System.out.println(mapback.get("key1"));
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		
	}
}

4.WxAPIUtils.java

package com.xmtk.lawyerHelp.utils;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

public class WxAPIUtils {
	
	public enum SignType {
        MD5, HMACSHA256
    }
	
	private static final String SYMBOLS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";

    private static final Random RANDOM = new SecureRandom();
	/**
	 * 生成随机字符串,用于微信支付
	 * @return
	 */
	public static String generateNonceStr() {
        char[] nonceChars = new char[32];
        for (int index = 0; index < nonceChars.length; ++index) {
            nonceChars[index] = SYMBOLS.charAt(RANDOM.nextInt(SYMBOLS.length()));
        }
        return new String(nonceChars);
    }
	
	/**
	 * 生成商户订单号(21位长度,微信文档规定订单号不得超过32位)
	 * @return
	 */
	public static String getOrderNo(){
	    SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS");
	    Date date = new Date();
	    return sdf.format(date) + getRandomStringByLength(4);
	}
	
	public static String getRandomStringByLength(int length) {
	    String base = "0123456789";
	    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();
	}
	
	/**
     * 生成签名. 注意,若含有sign_type字段,必须和signType参数保持一致。
     *
     * @param data 待签名数据
     * @param key API**
     * @param signType 签名方式
     * @return 签名
     */
    public static String generateSignature(final Map<String, String> data, String key, SignType signType) throws Exception {
        Set<String> keySet = data.keySet();
        String[] keyArray = keySet.toArray(new String[keySet.size()]);
        Arrays.sort(keyArray);
        StringBuilder sb = new StringBuilder();
        for (String k : keyArray) {
            if (k.equals("sign")) {
                continue;
            }
            if (data.get(k).trim().length() > 0) // 参数值为空,则不参与签名
                sb.append(k).append("=").append(data.get(k).trim()).append("&");
        }
        sb.append("key=").append(key);
        if (SignType.MD5.equals(signType)) {
            return MD5(sb.toString()).toUpperCase();
        }
        else if (SignType.HMACSHA256.equals(signType)) {
            return HMACSHA256(sb.toString(), key);
        }
        else {
            throw new Exception(String.format("Invalid sign_type: %s", signType));
        }
    }
    
    public static String MD5(String s) {
    	char hexArray[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
    	try {
			MessageDigest mdInst = MessageDigest.getInstance("MD5");
			mdInst.update(s.getBytes("UTF-8"));
			byte[] rawBit = mdInst.digest();
			String outputMD5 = " ";
			for(int i = 0; i<16; i++){
				outputMD5 = outputMD5 + hexArray[rawBit[i]>>>4& 0x0f];
				outputMD5 = outputMD5 + hexArray[rawBit[i]& 0x0f];
			}
			return outputMD5.trim();
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
    	return null;
    }
	
    /**
     * 生成 MD5
     *
     * @param data 待处理数据
     * @return MD5结果
     */
    public static String MD5_bak(String data) throws Exception {
        java.security.MessageDigest md = MessageDigest.getInstance("MD5");
        byte[] array = md.digest(data.getBytes("UTF-8"));
        StringBuilder sb = new StringBuilder();
        for (byte item : array) {
            sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3));
        }
        return sb.toString().toUpperCase();
    }
    
    /**
     * 生成 HMACSHA256
     * @param data 待处理数据
     * @param key **
     * @return 加密结果
     * @throws Exception
     */
    public static String HMACSHA256(String data, String key) throws Exception {
        Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
        SecretKeySpec secret_key = new SecretKeySpec(key.getBytes("UTF-8"), "HmacSHA256");
        sha256_HMAC.init(secret_key);
        byte[] array = sha256_HMAC.doFinal(data.getBytes("UTF-8"));
        StringBuilder sb = new StringBuilder();
        for (byte item : array) {
            sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3));
        }
        return sb.toString().toUpperCase();
    }
    
	public static void main(String args[]) {
//		String orderNo = getOrderNo();
//		System.out.println(orderNo);
	}
}

 5.sendPost方法:

/**
             * 向指定 URL 发送POST方法的请求
     * 
     * @param url
             *   发送请求的 URL
     * @param param
             *   请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
     * @return 所代表远程资源的响应结果
     */
    public static String sendPost(String url, String param) {
        PrintWriter out = null;
        BufferedReader in = null;
        String result = "";
        try {
            URL realUrl = new URL(url);
            // 打开和URL之间的连接
            URLConnection conn = realUrl.openConnection();
            // 设置通用的请求属性
            conn.setRequestProperty("accept", "*/*");
            conn.setRequestProperty("connection", "Keep-Alive");
            conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
                    
            // 发送POST请求必须设置如下两行
            conn.setDoOutput(true);
            conn.setDoInput(true);
            // 获取URLConnection对象对应的输出流
            out = new PrintWriter(new OutputStreamWriter(conn.getOutputStream(), "UTF-8"));	
            // 发送请求参数
            out.print(param);
            // flush输出流的缓冲
            out.flush();
            // 定义BufferedReader输入流来读取URL的响应
            in = new BufferedReader(
                    new InputStreamReader(conn.getInputStream(),"UTF-8"));
            String line;
            while ((line = in.readLine()) != null) {
                result += line;
            }
        } catch (Exception e) {
            System.out.println("发送 POST 请求出现异常!"+e);
            e.printStackTrace();
        }
        //使用finally块来关闭输出流、输入流
        finally{
            try{
                if(out!=null){
                    out.close();
                }
                if(in!=null){
                    in.close();
                }
            }
            catch(IOException ex){
                ex.printStackTrace();
            }
        }
        return result;
    }