JAVA後端調用微信支付“統一下單”接口實現微信二維碼掃碼支付

       以前寫過一篇設置微信二維碼失效時間的博客,最近又要新增微信退款的功能,於是又重新整理了一下前面的微信二維碼掃碼支付功能,感覺整體的實現方式都能夠掌控了,於是將具體的源碼拿出來分享一下。

開發之前,一定要先閱讀這篇說明文檔:https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=6_3

此處使用的微信二維碼掃碼支付功能,調用的是微信提供的“統一下單”接口,參考的微信官方文檔是:https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=9_1  。

 

實現後的功能是這樣的:

      

 

這個功能涉及到三個接口:

接口一:"http://www.*.com/項目名/pay/toWxPay.do",該接口調用微信支付統一下單接口,生成微信二維碼並展示給用戶,也就是前面那張圖中,當用戶點擊微信支付圖片的時候,就要調用該接口。注意,我這個接口使用的是springMVC來控制頁面的跳轉的,所以調用者調用這個接口時,應該使用表單提交的方式,發送post請求。

接口二:"http://www.*.com/項目名/pay/wxQuery.do",該接口用於查詢當前訂單是否支付成功,前端需要定時調用這個接口(比如每隔1秒調用一次),支付成功則關閉這個二維碼頁面,還未支付則繼續調用這個接口。因爲我的網站提供了多種支付方式,所有我並沒有調用微信支付提供的訂單查詢接口https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=9_2
因爲不管訂單最終是用哪種方式支付的,這個二維碼最終都是要關閉,由此降低一個訂單被多次支付的風險。雖然訂單被重複支付後,可以申請退款,但是你退款的操作也要耗費資源,既然如此,爲什麼不一開始就降低這種風險呢。

接口三:"http://www.*.com/項目名/pay/wxRedirect.do",該接口是微信支付成功後的回調接口,就是用戶掃碼支付成功後,微信平臺確認收到了錢,他平臺那邊處理完之後(比如做雙方的扣款,轉賬,記錄流水等操作),就會把這個處理的結果告訴我們,那麼怎麼告訴呢,就是通過這個回調接口了。所以需要注意,這個回調接口不要做登錄攔截!!!

 

下面直接上代碼,首先是導入依賴的jar包: 

<!-- 微信支付開始-->
<!-- https://mvnrepository.com/artifact/com.google.zxing/core -->
<dependency>
    <groupId>com.google.zxing</groupId>
    <artifactId>core</artifactId>
    <version>3.1.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.jdom/jdom -->
<dependency>
    <groupId>org.jdom</groupId>
    <artifactId>jdom</artifactId>
    <version>1.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/xml-apis/xml-apis -->
<dependency>
    <groupId>xml-apis</groupId>
    <artifactId>xml-apis</artifactId>
    <version>1.0.b2</version>
</dependency>
<!-- 微信支付結束-->

 

然後是三個接口:

package wxpay;

import java.io.*;
import java.util.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;


@Controller
@RequestMapping("/pay")
public class PayController {
	
	private static final Logger logger = Logger.getLogger(PayController.class);

	/**
	 * 接口一:調用微信Native支付統一下單接口,生成微信二維碼
	 */
	@RequestMapping(value = "/toWxPay", method = RequestMethod.POST)
	public String toWxPay(String orderId,String userId,Double amount,Model model,
			HttpServletRequest request, HttpServletResponse response) throws Exception {
		
		String url="weixin";//默認是網頁端的請求,此時你的webapp目錄下需要一個weixin.jsp文件,這個頁面也是你展示二維碼的那個頁面
		try {

			if(StringUtils.isBlank(orderId)||StringUtils.isBlank(userId)||amount==null){
				model.addAttribute("errorMsg", "缺少必要參數");
				return url;
			}

			//個人核心業務隱身符,此處需要拿着orderId和userId爲查詢條件去數據庫查詢這個訂單是否存在,
			//判斷是否已經支付過了,同時還要攜帶這個金額是否已數據庫中記錄的商品實際金額一致
			//如果檢驗不通過,就不執行後面的操作

			//默認失效時間是訂單失效的時間,這個時間需要從你的數據庫查詢這個訂單的剩餘有效時間,此處暫時設置成30分鐘
			Long expireTime=30*60L;

			String key="WX_RD_CODE_"+orderId;
			Long ttl = RedisUtils.ttl(key);
			//如果二維碼還沒有失效,就使用沒有失效的二維碼
			if(ttl>10){
				model.addAttribute("codeUrl", RedisUtils.get(key));//二維碼的url
				model.addAttribute("expire", ttl.intValue());//二維碼有效期
				return url;
			}

      //因爲通常,一個網站接入微信支付,pc端接入的是微信Native支付,
      //微信公衆號端接入的是JSAPI支付,app接入的是微信app支付,此外還有H5支付。
      //開發時遇到同一個訂單號,如果開始使用二維碼支付,獲取二維碼後沒有掃碼,
      //二維碼依舊有效的時候,公衆號那邊發起JSAPI支付會失敗。
      //不可能同一個訂單使用不同的訂單號,這個本身就很矛盾,
      //所以還是訂單號後面追加標識用於區分,當然了支付回調接口在接收的時候
      //也要通過處理獲取真實的訂單號。
      String outTrandNo=orderId+"_NATIVE";

			//如果原來的二維碼失效了,就重新生成二維碼
			String codeUrl = GenerateQrCodeUtil.getCodeurl(request,expireTime,outTrandNo,userId,amount);

			//生成的圖片路徑
			logger.info("生成的圖片路徑:"+codeUrl);

			String webParentPath = new File(request.getSession().getServletContext().getRealPath("/")).getParent();// 當前WEB環境的上層目錄
			String xiangmuName = request.getContextPath();// 項目名稱
			String fileUrl = GenerateQrCodeUtil.encodeQrcode(codeUrl,response,
					webParentPath +xiangmuName+ "/img","wxImg/");//二維碼保存在/webapp/img/wxImg/ 文件夾下
			if(fileUrl != null){
				codeUrl="/img/"+fileUrl;
				model.addAttribute("codeUrl",codeUrl);//二維碼的url
				model.addAttribute("expire", ttl.intValue());//二維碼有效期

				//設置一個標誌,用來保存二維碼的路徑
				RedisUtils.set(key, codeUrl, expireTime.intValue());
			}

		} catch (Exception e) {
			logger.info("調用微信二維碼失敗:"+e.getMessage());
			throw e;
		}finally{
			//關閉保護
			RedisUtils.set(orderId, "1",60*60*24*50);
		}
		return url;
	}

	/**
	 * 接口二:查詢訂單是否支付成功
	 * 查詢付款是否成功,主要是跳轉到微信支付二維碼頁面之後,需要定時去查詢這個訂單是否已經支付成功,
	 * 訂單支付成功之後,前端需要及時關閉這個二維碼頁面。由於我這邊有多種支付方式,所有後臺並沒有調用
	 * 微信支付提供的訂單查詢接口,因爲不管訂單最終是用哪種方式支付的,這個二維碼最終都是要關閉的
	 */
	@RequestMapping(value = "wxQuery")
	@ResponseBody
	public Result wxQuery(HttpServletResponse response , String orderId) {
		response.setHeader("Access-Control-Allow-Origin", "*");

		Result result = new Result();
		try {

			if(StringUtils.isBlank(orderId)){
				result.setSuccess(false);
				result.setMsg("缺少必要參數");
				return result;
			}

			Long ttl = RedisUtils.ttl("PAY_" + orderId);

			//判斷是否付款成功,付款成功返回ture;未付款返回false
			result.setSuccess(ttl>1);

		} catch (Exception e) {
			result.setSuccess(false);
		}
		return result;
	}

	/**
	 * 接口三:微信支付回調接口
	 * 注意!注意!注意!這個接口不要做權限攔截操作,要直接放行
	 */
	@RequestMapping(value = "wxRedirect")
	@ResponseBody
	public void wxRedirect(HttpServletRequest req, HttpServletResponse resp) throws Exception {
		logger.info("微信支付回調開始了");

		// 創建支付應答對象
		ResponseHandler resHandler = new ResponseHandler(req, resp);
		// 讀取參數
		InputStream inputStream = req.getInputStream();
		StringBuffer sb = new StringBuffer();
		BufferedReader in = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
		String s;
		while ((s = in.readLine()) != null) {
			sb.append(s);
		}
		in.close();
		inputStream.close();

		// 解析xml成map
		Map<String, String> m =XMLUtil.doXMLParse(sb.toString());

		// 過濾空 設置 TreeMap
		SortedMap<Object, Object> packageParams = new TreeMap<Object, Object>();
		Iterator<String> it = m.keySet().iterator();

		while (it.hasNext()) {
			String parameter = it.next();
			String parameterValue = m.get(parameter);

			String v = "";
			if (null != parameterValue) {
				v = parameterValue.trim();
			}
			packageParams.put(parameter, v);
		}

		// 判斷簽名是否正確
		if (!PayCommonUtil.isTenpaySign("UTF-8", packageParams, Constant.MCH_KEY)) {
			logger.info("回調後發現簽名失敗了...");
			return ;
		}

		if (!"SUCCESS".equals(packageParams.get("result_code"))) {
			// 錯誤時,返回結果未簽名,記錄retcode、retmsg看失敗詳情。
			logger.info("查詢驗證簽名失敗或業務錯誤");
			return;
		}

		// 到這裏,說明是支付成功了
		////////// 執行自己的業務邏輯////////////////

		// 通知id
		String mch_id = (String) packageParams.get("mch_id");
		String openid = (String) packageParams.get("openid");//付款方的openId
		String is_subscribe = (String) packageParams.get("is_subscribe");//是否關注公衆號
		String out_trade_no = (String) packageParams.get("out_trade_no"); // 自己網站定義的訂單號
		String attach = (String) packageParams.get("attach");//讀取附帶的參數
		String total_fee = (String) packageParams.get("total_fee");//支付金額
		String transaction_id = (String) packageParams.get("transaction_id");//微信那邊生成的流水號,注意需要保存

		logger.info("attach:" + attach + ",mch_id:" + mch_id + ",openid:" + openid + ",is_subscribe:" + is_subscribe + ",out_trade_no:" + out_trade_no + ",total_fee:" + total_fee + ",transaction_id:"+ transaction_id);

		//因爲前面已經有定義格式:網站的流水號_支付標識 
		out_trade_no=out_trade_no.split("_")[0];
		logger.info("真正的流水號是:"+out_trade_no);


		// ----------- 處理業務開始 --------------
		logger.info("處理業務邏輯開始。。。");

		// 處理數據庫邏輯,注意交易單不要重複處理,注意判斷返回金額

		try {

			//注意我們原來定義的參數形式是這樣的:orderId+","+userId+","+amount+",wxpay";
			String[] str = attach.split(",");
			if (str == null || str.length != 4) {
				logger.info("微信回調的attach參數錯誤,可能是非法請求");
				return;
			}

			String orderId = str[0];//自己網站定義的訂單號
			String userId = str[1];//這個訂單號對應的用戶userId
			double amount = Double.parseDouble(str[2]);//訂單金額
			String type = str[3];//用於標識此次微信支付是支付那種類型的金額,由自己定義;

			//執行到這裏,應該單獨往表中添加一條記錄,用於記錄微信付款成功了,注意這裏應該使用獨立的事務,
			// 防止後面的業務失敗時,導致整個事務回滾。
			// 主要是爲了將來排查錯誤使用,比如同一個訂單,但是前面2分鐘用戶已經使用支付寶支付了,現在用戶又用
			//微信支付了一遍,此時回調操作怎麼處理呢?所以類似的這個回調成功的記錄都必須要有,後面退款的時候可能需要用


			if ("wxpay".equals(type)) {
				logger.info("進入微信支付後續處理邏輯");

				//執行你自己的業務邏輯,比如設置訂單爲已支付,添加資金流水等
				//······

				//設置支付成功標誌,不管你用哪種支付方式,只要這個訂單支付成功了,就要設置這個標誌
				RedisUtils.set("PAY_"+orderId,"1",60*60*24*30);//設置有效期30天,具體時間看你自己的業務

			}

		} catch (Exception e) {

			logger.info("回調錯誤:"+ e.getMessage());
		}

		logger.info("商家流水號:" + out_trade_no);// 其他字段也可用類似方式獲取
		logger.info("FrontRcvResponse前臺接收報文返回結束");
		// ------------------------------
		// 處理業務完畢
		// ------------------------------
		// 通知微信.異步確認成功.必寫.不然會一直通知後臺.八次之後就認爲交易失敗了.
		String resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>"
				+ "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";
		resHandler.sendToCFT(resXml);
	}

}

Result.java實體類不分享,可以自己創建一個;

RedisUtils工具類看我的另一篇博客:Jedis常用工具類,包含一些具有事務的設置值的方法

 

WXUtil.java類

package wxpay;

import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.UUID;
import java.util.Map.Entry;
import net.sf.json.JSONException;
import net.sf.json.JSONObject;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


/**
 * 微信開發相關工具
 * 
 */
public class WXUtil {

	private static Logger log = LoggerFactory.getLogger(WXUtil.class);


	/**
	 * 把HashMap轉換成xml
	 * @param arr
	 * @return
	 * #time:下午5:32:36
	 *
	 */
	public static String ArrayToXml(SortedMap<String, String> arr) {
		String xml = "<xml>";
		Iterator<Entry<String, String>> iter = arr.entrySet().iterator();
		while (iter.hasNext()) {
			Entry<String, String> entry = iter.next();
			String key = entry.getKey();
			String val = entry.getValue();
			if ("attach".equalsIgnoreCase(key)||"body".equalsIgnoreCase(key)||"sign".equalsIgnoreCase(key)) {
				xml += "<" + key + ">" + val + "</" + key + ">";

			} else
				xml += "<" + key + "><![CDATA[" + val + "]]></" + key + ">";
		}

		xml += "</xml>";
		return xml;
	}

	/**
	 * @date 2016-5-5下午2:32:05
	 * @Description:將請求參數轉換爲xml格式的string
	 * @param parameters
	 *            請求參數
	 * @return
	 */
	@SuppressWarnings("rawtypes")
	public static String getRequestXml(SortedMap<Object, 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 k = (String) entry.getKey();
			String v = (String) entry.getValue();
			if ("attach".equalsIgnoreCase(k) || "body".equalsIgnoreCase(k)
					|| "sign".equalsIgnoreCase(k)) {
				sb.append("<" + k + ">" + "<![CDATA[" + v + "]]></" + k + ">");
			} else {
				sb.append("<" + k + ">" + v + "</" + k + ">");
			}
		}
		sb.append("</xml>");
		return sb.toString();
	}

	/**
	 * 根據內容類型判斷文件擴展名
	 * 
	 * @param contentType
	 *            內容類型
	 * @return
	 */
	public static String getFileExt(String contentType) {
		String fileExt = "";
		if ("image/jpeg".equals(contentType))
			fileExt = ".jpg";
		else if ("audio/mpeg".equals(contentType))
			fileExt = ".mp3";
		else if ("audio/amr".equals(contentType))
			fileExt = ".amr";
		else if ("video/mp4".equals(contentType))
			fileExt = ".mp4";
		else if ("video/mpeg4".equals(contentType))
			fileExt = ".mp4";
		return fileExt;
	}

	/**
	 * 獲取接口訪問憑證
	 * 
	 * @param appid
	 *            憑證
	 * @param appsecret
	 *            密鑰
	 * @return
	 */
	public static Token getToken(String appid, String appsecret) {
		Token token = null;
		String requestUrl = Constant.TOKEN_URL.replace("APPID", appid).replace(
				"APPSECRET", appsecret);
		// 發起GET請求獲取憑證
		JSONObject jsonObject = CommonUtil
				.httpsRequest(requestUrl, "GET", null);
		if (null != jsonObject) {
			try {
				token = new Token();
				token.setAccessToken(jsonObject.getString("access_token"));
				token.setExpiresIn(jsonObject.getInt("expires_in"));
			} catch (JSONException e) {
				token = null;
				// 獲取token失敗
				log.error("獲取token失敗 errcode:{} errmsg:{}",
						jsonObject.getInt("errcode"),
						jsonObject.getString("errmsg"));
			}
		}
		return token;
	}

	/**
	 * 獲取驗證簽名
	 * 
	 * @param map
	 * @return
	 */
	public static String createSign(Map<String, String> map) {
		SortedMap<String, String> packageParams = new TreeMap<String, String>();
		for (Map.Entry<String, String> m : map.entrySet()) {
			packageParams.put(m.getKey(), m.getValue().toString());
		}
		StringBuffer sb = new StringBuffer();
		Set<?> es = packageParams.entrySet();
		Iterator<?> it = es.iterator();
		while (it.hasNext()) {
			@SuppressWarnings("rawtypes")
			Map.Entry entry = (Map.Entry) it.next();
			String k = (String) entry.getKey();
			String v = (String) entry.getValue();
			if (!StringUtils.isEmpty(v) && !"sign".equals(k)
					&& !"key".equals(k)) {
				sb.append(k + "=" + v + "&");
			}
		}
		sb.append("key=" + Constant.MCH_KEY);
		String sign = CommonUtil.MD5Encode(sb.toString(), Constant.CHARSET)
				.toUpperCase();
		return sign;
	}

	/**
	 * 創建訂單號
	 * 
	 * @return
	 */
	public static String getOrderNo() {
		String order = Constant.MCH_ID
				+ new SimpleDateFormat("yyyyMMdd").format(new Date());
		Random r = new Random();
		for (int i = 0; i < 10; i++) {
			order += r.nextInt(9);
		}
		return order;
	}

	/**
	 * 拼接字符串成XML格式
	 * 
	 * @param map
	 * @return
	 */
	public static String createXML(Map<String, String> map) {
		String xml = "<xml>";
		Set<String> set = map.keySet();
		Iterator<String> i = set.iterator();
		while (i.hasNext()) {
			String str = i.next();
			xml += "<" + str + ">" + "<![CDATA[" + map.get(str) + "]]>" + "</"
					+ str + ">";
		}
		xml += "</xml>";
		return xml;
	}

	/**
	 * 獲取時間戳
	 * 
	 * @return
	 */
	public static String getTimestamp() {
		return CommonUtil.toString(System.currentTimeMillis());
	}

	public static String createTimestamp() {
		return Long.toString(System.currentTimeMillis() / 1000);
	}

	/**
	 * nonceStr生成簽名的隨機串
	 * 
	 * @return
	 */
	public static String getNoncestr() {
		return CommonUtil.buildRandom();
	}

	public static String createNoncestr() {
		return UUID.randomUUID().toString();
	}

	/**
	 * 獲取非網頁授權access_token
	 * 
	 * @param appid
	 * @param appsecret
	 * @return
	 */
	public static Token getAccessTokenNoAuth(String appid, String appsecret) {
		return getToken(appid, appsecret);
	}

	/**
	 * 校驗簽名
	 * 
	 * @param jsapi_ticket
	 * @param url
	 * @return
	 */
	public static Map<String, String> sign(String jsapi_ticket, String url) {
		Map<String, String> ret = new HashMap<String, String>();
		String nonce_str = createNoncestr();
		String timestamp = createTimestamp();
		String string1;
		String signature = "";
		// 注意這裏參數名必須全部小寫,且必須有序
		string1 = "jsapi_ticket=" + jsapi_ticket + "&noncestr=" + nonce_str
				+ "&timestamp=" + timestamp + "&url=" + url;
		System.out.println(string1);
		try {
			MessageDigest crypt = MessageDigest.getInstance("SHA-1");
			crypt.reset();
			crypt.update(string1.getBytes("UTF-8"));
			signature = CommonUtil.byteToHex(crypt.digest());
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		ret.put("url", url);
		ret.put("jsapi_ticket", jsapi_ticket);
		ret.put("nonceStr", nonce_str);
		ret.put("timestamp", timestamp);
		ret.put("signature", signature);
		return ret;
	}

	/**
	 * 校驗簽名
	 * 
	 * @param signature
	 *            微信加密簽名
	 * @param timestamp
	 *            時間戳
	 * @param nonce
	 *            隨機數
	 * @return
	 */
	public static boolean checkSignature(String signature, String timestamp,
			String nonce) {
		// 對token、timestamp和nonce按字典排序
		String[] paramArr = new String[] { Constant.TOKEN, timestamp, nonce };
		Arrays.sort(paramArr);
		// 將排序後的結果拼接成一個字符串
		String content = paramArr[0].concat(paramArr[1]).concat(paramArr[2]);
		String ciphertext = null;
		try {
			MessageDigest md = MessageDigest.getInstance("SHA-1");
			// 對接後的字符串進行sha1加密
			byte[] digest = md.digest(content.toString().getBytes());
			ciphertext = CommonUtil.byteToStr(digest);
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		}
		// 將sha1加密後的字符串與signature進行對比
		return ciphertext != null ? ciphertext.equals(signature.toUpperCase())
				: false;
	}

	/**
	 * 驗證簽名。
	 * 
	 * @param signature
	 * @param timestamp
	 * @param nonce
	 * @return
	 */
	public static String getSignature(String sKey) throws Exception {
		String ciphertext = null;
		MessageDigest md = MessageDigest.getInstance("SHA-1");
		byte[] digest = md.digest(sKey.toString().getBytes());
		ciphertext = CommonUtil.byteToStr(digest);
		return ciphertext.toLowerCase();
	}

	/**
	 * 獲得分享鏈接的簽名。
	 * 
	 * @param ticket
	 * @param nonceStr
	 * @param timeStamp
	 * @param url
	 * @return
	 * @throws Exception
	 */
	public static String getSignature(String ticket, String nonceStr,
			long timeStamp, String url) throws Exception {
		String sKey = "jsapi_ticket=" + ticket + "&noncestr=" + nonceStr
				+ "timestamp=" + timeStamp + "&url=" + url;
		return getSignature(sKey);
	}
}

 

Token.java類
package wxpay;

/**
 * 憑證
 */
public class Token {

	// 接口訪問憑證
	private String accessToken;

	// 憑證有效期,單位:秒
	private int expiresIn;

	public String getAccessToken() {
		return accessToken;
	}

	public void setAccessToken(String accessToken) {
		this.accessToken = accessToken;
	}

	public int getExpiresIn() {
		return expiresIn;
	}

	public void setExpiresIn(int expiresIn) {
		this.expiresIn = expiresIn;
	}
}

 

GenerateQrCodeUtil.java類:

package wxpay;

import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.InterfaceAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.security.MessageDigest;
import java.text.SimpleDateFormat;
import java.util.*;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.WriterException;
import com.google.zxing.common.BitMatrix;


public class GenerateQrCodeUtil {
	private static final Logger logger = Logger.getLogger(GenerateQrCodeUtil.class);

	private static final int WHITE = 0xFFFFFFFF;

	private static final int BLACK = 0xFF000000;

	private static BufferedImage toBufferedImage(BitMatrix matrix) {
		int width = matrix.getWidth();
		int height = matrix.getHeight();
		BufferedImage image = new BufferedImage(width, height,
				BufferedImage.TYPE_INT_RGB);
		for (int x = 0; x < width; x++) {
			for (int y = 0; y < height; y++) {
				image.setRGB(x, y, matrix.get(x, y) ? BLACK : WHITE);
			}
		}
		return image;
	}


	public static String encodeQrcode(String content, HttpServletResponse response,String webParentPath,String fileDir) {
		response.setCharacterEncoding("utf-8");
		if (StringUtils.isBlank(content))
			return null;
		MultiFormatWriter multiFormatWriter = new MultiFormatWriter();
		Map<EncodeHintType, String> hints = new HashMap<EncodeHintType, String>();
		hints.put(EncodeHintType.CHARACTER_SET, "UTF-8"); // �����ַ��������
		BitMatrix bitMatrix = null;
		String fileUrl = null;
		try {
			bitMatrix = multiFormatWriter.encode(content,
					BarcodeFormat.QR_CODE, 300, 300, hints);
			BufferedImage image = toBufferedImage(bitMatrix);
			
			if(fileDir != null){
				FileOutputStream fos = null;
				try {
					File f = new File(webParentPath+File.separator+fileDir);
					if (!f.exists()) {
						f.mkdir();
					}
					fileUrl = fileDir+UUID.randomUUID().toString()+".png";
					fos = new FileOutputStream(webParentPath+File.separator+fileUrl);
					ImageIO.write(image, "png", fos);
				} catch (IOException e) {
					e.printStackTrace();
				} finally {
					if(fos != null){
						try {
							fos.close();
						} catch (IOException e) {
							e.printStackTrace();
						}
					}
				}
			}else{
				try {
					ImageIO.write(image, "png", response.getOutputStream());
				} catch (IOException e) {
					e.printStackTrace();
				}
			}

		} catch (WriterException e1) {
			e1.printStackTrace();
		}
		return fileUrl;
	}

	static String getOrderExpireTime(Long expire){
		SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
		Date now = new Date();
		Date afterDate = new Date(now .getTime() + expire);
		return sdf.format(afterDate );
	}

	public static String getCodeurl( HttpServletRequest request,long time, String orderId,
									 String userId,Double amount) {

		String attach = orderId+","+userId+","+amount+",wxpay";//附加數據,在查詢API和支付通知中原樣返回,可作爲自定義參數使用。
		String totalFee = getMoney(amount+"");//訂單總金額,單位爲分,詳見支付金額
		String spbill_create_ip = request.getRemoteAddr();//支持IPV4和IPV6兩種格式的IP地址。用戶的客戶端IP
		String notify_url = "https://www.域名.cn/項目名/pay/wxRedirect";//異步接收微信支付結果通知的回調地址,通知url必須爲外網可訪問的url,不能攜帶參數。
		String trade_type = "NATIVE";//交易類型
		String app_id= Constant.APP_ID;//微信支付分配的公衆賬號ID(企業號corpid即爲此appId)
		String app_secret=Constant.APP_SECRET;//微信公衆號的appsecret
		String mch_id = Constant.MCH_ID;//微信支付分配的商戶號
		String mch_key=Constant.MCH_KEY;
		String nonce_str = WXUtil.createNoncestr().substring(1, 32);//隨機字符串,長度要求在32位以內。
		String body = "平臺-運費";//商品簡單描述,該字段請按照規範傳遞,具體請見參數規定
		String expireTime=getOrderExpireTime(time*1000);//設置二維碼超時失效時間
		String out_trade_no = orderId;//你自己平臺生成的訂單號,要求32個字符內,只能是數字、大小寫字母_-|* 且在同一個商戶號下唯一

		SortedMap<String, String> packageParams = new TreeMap<String, String>();
		packageParams.put("appid", app_id);
		packageParams.put("mch_id", mch_id);
		packageParams.put("nonce_str", nonce_str);
		packageParams.put("body", body);
		packageParams.put("attach", attach);
		packageParams.put("out_trade_no", out_trade_no);
		packageParams.put("total_fee", totalFee);
		packageParams.put("spbill_create_ip", spbill_create_ip);
		packageParams.put("notify_url", notify_url);
		packageParams.put("trade_type", trade_type);
		packageParams.put("time_expire", expireTime);//設置二維碼超時失效時間

		String sign = WXUtil.createSign(packageParams);
	    logger.info("生成的簽名是:"+sign);
	    packageParams.put("sign", sign);

	    String xml =WXUtil.ArrayToXml(packageParams);
	    logger.info("map轉換成xml的結果:"+xml);

		String createOrderURL = "https://api.mch.weixin.qq.com/pay/unifiedorder";
		return GetWxOrderno.getCodeUrl(createOrderURL, xml);
	}

	public static String getMoney(String amount) {
		if (amount == null) {
			return "";
		}
		String currency = amount.replaceAll("\\$|\\¥|\\,", ""); 
																
		int index = currency.indexOf(".");
		int length = currency.length();
		Long amLong = 0l;
		if (index == -1) {
			amLong = Long.valueOf(currency + "00");
		} else if (length - index >= 3) {
			amLong = Long.valueOf((currency.substring(0, index + 3)).replace(
					".", ""));
		} else if (length - index == 2) {
			amLong = Long.valueOf((currency.substring(0, index + 2)).replace(
					".", "") + 0);
		} else {
			amLong = Long.valueOf((currency.substring(0, index + 1)).replace(
					".", "") + "00");
		}
		return amLong.toString();
	}

	public String localIp() {
		String ip = null;
		Enumeration<?> allNetInterfaces;
		try {
			allNetInterfaces = NetworkInterface.getNetworkInterfaces();
			while (allNetInterfaces.hasMoreElements()) {
				NetworkInterface netInterface = (NetworkInterface) allNetInterfaces
						.nextElement();
				List<InterfaceAddress> InterfaceAddress = netInterface
						.getInterfaceAddresses();
				for (InterfaceAddress add : InterfaceAddress) {
					InetAddress Ip = add.getAddress();
					if (Ip != null && Ip instanceof Inet4Address) {
						ip = Ip.getHostAddress();
					}
				}
			}
		} catch (SocketException e) {
			e.printStackTrace();
		}
		return ip;
	}

	@SuppressWarnings("rawtypes")
	public static String createSign(SortedMap<String, String> packageParams) {
		StringBuffer sb = new StringBuffer();
		Set es = packageParams.entrySet();
		Iterator it = es.iterator();
		while (it.hasNext()) {
			Map.Entry entry = (Map.Entry) it.next();
			String k = (String) entry.getKey();
			String v = (String) entry.getValue();
			if (null != v && !"".equals(v) && !"sign".equals(k)
					&& !"key".equals(k)) {
				sb.append(k + "=" + v + "&");
			}
		}

		sb.append("key=" +Constant.MCH_KEY);
		String sign = MD5Encode(sb.toString(), "GBK")
				.toUpperCase();
		return sign;
	}
	

	private static String byteArrayToHexString(byte b[]) {
		StringBuffer resultSb = new StringBuffer();
		for (int i = 0; i < b.length; i++)
			resultSb.append(byteToHexString(b[i]));

		return resultSb.toString();
	}

	private static String byteToHexString(byte b) {
		int n = b;
		if (n < 0)
			n += 256;
		int d1 = n / 16;
		int d2 = n % 16;
		return hexDigits[d1] + hexDigits[d2];
	}

	public static String MD5Encode(String origin, String charsetname) {
		String resultString = null;
		try {
			resultString = new String(origin);
			MessageDigest md = MessageDigest.getInstance("MD5");
			if (charsetname == null || "".equals(charsetname))
				resultString = byteArrayToHexString(md.digest(resultString
						.getBytes()));
			else
				resultString = byteArrayToHexString(md.digest(resultString
						.getBytes(charsetname)));
		} catch (Exception exception) {
		}
		return resultString;
	}

	private static final String hexDigits[] = { "0", "1", "2", "3", "4", "5",
			"6", "7", "8", "9", "a", "b", "c", "d", "e", "f" };
}

 

GetWxOrderno.java類

package wxpay;

import java.io.StringReader;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.params.ClientPNames;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
import org.apache.log4j.Logger;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.input.SAXBuilder;
import org.xml.sax.InputSource;

public class GetWxOrderno {

	private static Logger logger = Logger.getLogger(GetWxOrderno.class);

	public static DefaultHttpClient httpclient;
	static {
		httpclient = new DefaultHttpClient();
		httpclient = (DefaultHttpClient) HttpClientConnectionManager
				.getSSLInstance(httpclient);
	}
	public static String getPayNo(String url, String xmlParam) {
		DefaultHttpClient client = new DefaultHttpClient();
		client.getParams().setParameter(ClientPNames.ALLOW_CIRCULAR_REDIRECTS,
				true);
		HttpPost httpost = HttpClientConnectionManager.getPostMethod(url);
		String prepay_id = "";
		try {
			httpost.setEntity(new StringEntity(xmlParam, "UTF-8"));
			HttpResponse response = httpclient.execute(httpost);
			String jsonStr = EntityUtils.toString(response.getEntity(), "UTF-8");
			Map<String, String> map = parseXmlToMap(jsonStr);
			prepay_id = map.get("prepay_id");
		} catch (Exception e) {
			e.printStackTrace();
		}
		return prepay_id;
	}

	public static Map<String, String> getReturnUrl(String url, String xmlParam) {
		Map<String, String> map = new HashMap<>();
		DefaultHttpClient client = new DefaultHttpClient();
		client.getParams().setParameter(ClientPNames.ALLOW_CIRCULAR_REDIRECTS, true);
		HttpPost httpost = HttpClientConnectionManager.getPostMethod(url);

		try {
			httpost.setEntity(new StringEntity(xmlParam, "UTF-8"));
			HttpResponse response = httpclient.execute(httpost);
			String jsonStr = EntityUtils.toString(response.getEntity(), "UTF-8");
			map = parseXmlToMap(jsonStr);

		} catch (Exception e) {
			e.printStackTrace();
		}
		return map;
	}

	public static String getCodeUrl(String url, String xmlParam) {
		DefaultHttpClient client = new DefaultHttpClient();
		client.getParams().setParameter(ClientPNames.ALLOW_CIRCULAR_REDIRECTS,
				true);
		HttpPost httpost = HttpClientConnectionManager.getPostMethod(url);
		String code_url = "";
		try {
			httpost.setEntity(new StringEntity(xmlParam, "UTF-8"));
			HttpResponse response = httpclient.execute(httpost);
			String jsonStr = EntityUtils.toString(response.getEntity(), "UTF-8");
			Map<String, String> map = parseXmlToMap(jsonStr);
			code_url = map.get("code_url");
		} catch (Exception e) {
			e.printStackTrace();
		}
		return code_url;
	}

	public static String getOrderQuery(String url, String xmlParam) {
		DefaultHttpClient client = new DefaultHttpClient();
		client.getParams().setParameter(ClientPNames.ALLOW_CIRCULAR_REDIRECTS,
				true);
		HttpPost httpost = HttpClientConnectionManager.getPostMethod(url);
		String success = "";
		try {
			httpost.setEntity(new StringEntity(xmlParam, "UTF-8"));
			HttpResponse response = httpclient.execute(httpost);
			String jsonStr = EntityUtils.toString(response.getEntity(), "UTF-8");
			Map<String, String> map = parseXmlToMap(jsonStr);
			success = map.get("return_code");
		} catch (Exception e) {
			e.printStackTrace();
		}
		return success;
	}
	
	public static Map<String, String> parseXmlToMap(String xml)
			throws Exception {
		if (StringUtils.isBlank(xml)) {
			return null;
		}
		Map<String, String> m = new HashMap<String, String>();

		StringReader read = new StringReader(xml);
		// 創建新的輸入源SAX 解析器將使用 InputSource 對象來確定如何讀取 XML 輸入
		InputSource source = new InputSource(read);

		// 創建一個新的SAXBuilder
		SAXBuilder sb = new SAXBuilder();
		// 通過輸入源構造一個Document
		Document doc;
		doc = (Document) sb.build(source);

		Element root = doc.getRootElement();// 指向根節點
		List<Element> list = root.getChildren();

		if(list==null||list.size()<1){
			return null;
		}

		for (Element element : list) {
			logger.info("key是:" + element.getName() + ",值是:" + element.getText());
			m.put(element.getName(),element.getText());
		}

		return m;
	}

}

HttpClientConnectionManager.java

package wxpay;

import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.impl.client.DefaultHttpClient;

@SuppressWarnings("deprecation")
public class HttpClientConnectionManager {

	/**
	 * ��ȡSSL��֤��HttpClient
	 * 
	 * @param httpClient
	 * @return
	 */
	public static HttpClient getSSLInstance(HttpClient httpClient) {
		ClientConnectionManager ccm = httpClient.getConnectionManager();
		SchemeRegistry sr = ccm.getSchemeRegistry();
		sr.register(new Scheme("https", MySSLSocketFactory.getInstance(), 443));
		httpClient = new DefaultHttpClient(ccm, httpClient.getParams());
		return httpClient;
	}

	/**
	 * ģ�������post�ύ
	 * 
	 * @param url
	 * @return
	 */
	public static HttpPost getPostMethod(String url) {
		HttpPost pmethod = new HttpPost(url); // ������Ӧͷ��Ϣ
		pmethod.addHeader("Connection", "keep-alive");
		pmethod.addHeader("Accept", "*/*");
		pmethod.addHeader("Content-Type",
				"application/x-www-form-urlencoded; charset=UTF-8");
		pmethod.addHeader("Host", "api.mch.weixin.qq.com");
		pmethod.addHeader("X-Requested-With", "XMLHttpRequest");
		pmethod.addHeader("Cache-Control", "max-age=0");
		pmethod.addHeader("User-Agent",
				"Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0) ");
		return pmethod;
	}

	/**
	 * ģ�������GET�ύ
	 * 
	 * @param url
	 * @return
	 */
	public static HttpGet getGetMethod(String url) {
		HttpGet pmethod = new HttpGet(url);
		// ������Ӧͷ��Ϣ
		pmethod.addHeader("Connection", "keep-alive");
		pmethod.addHeader("Cache-Control", "max-age=0");
		pmethod.addHeader("User-Agent",
				"Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0) ");
		pmethod.addHeader("Accept",
				"text/html,application/xhtml+xml,application/xml;q=0.9,*/;q=0.8");
		return pmethod;
	}
}

 

MD5Util.java

package wxpay;

import java.security.MessageDigest;

public class MD5Util {

	private static String byteArrayToHexString(byte b[]) {
		StringBuffer resultSb = new StringBuffer();
		for (int i = 0; i < b.length; i++)
			resultSb.append(byteToHexString(b[i]));

		return resultSb.toString();
	}

	private static String byteToHexString(byte b) {
		int n = b;
		if (n < 0)
			n += 256;
		int d1 = n / 16;
		int d2 = n % 16;
		return hexDigits[d1] + hexDigits[d2];
	}

	public static String MD5Encode(String origin, String charsetname) {
		String resultString = null;
		try {
			resultString = new String(origin);
			MessageDigest md = MessageDigest.getInstance("MD5");
			if (charsetname == null || "".equals(charsetname))
				resultString = byteArrayToHexString(md.digest(resultString
						.getBytes()));
			else
				resultString = byteArrayToHexString(md.digest(resultString
						.getBytes(charsetname)));
		} catch (Exception exception) {
		}
		return resultString;
	}

	private static final String hexDigits[] = { "0", "1", "2", "3", "4", "5",
			"6", "7", "8", "9", "a", "b", "c", "d", "e", "f" };

}

 

MySSLSocketFactory.java

package wxpay;

import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;

import org.apache.http.conn.ssl.SSLSocketFactory;

@SuppressWarnings("deprecation")
public class MySSLSocketFactory extends SSLSocketFactory {
	static {
		mySSLSocketFactory = new MySSLSocketFactory(createSContext());
	}
	private static MySSLSocketFactory mySSLSocketFactory = null;

	private static SSLContext createSContext() {
		SSLContext sslcontext = null;
		try {
			sslcontext = SSLContext.getInstance("SSL");
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		}
		try {
			sslcontext.init(null,
					new TrustManager[] { new MyX509TrustManager() }, null);
		} catch (KeyManagementException e) {
			e.printStackTrace();
			return null;
		}
		return sslcontext;
	}

	private MySSLSocketFactory(SSLContext sslContext) {
		super(sslContext);
		this.setHostnameVerifier(ALLOW_ALL_HOSTNAME_VERIFIER);
	}

	public static MySSLSocketFactory getInstance() {
		if (mySSLSocketFactory != null) {
			return mySSLSocketFactory;
		} else {
			return mySSLSocketFactory = new MySSLSocketFactory(createSContext());
		}
	}
}

 

MyX509TrustManager.java

package wxpay;

import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

import javax.net.ssl.X509TrustManager;

public class MyX509TrustManager implements X509TrustManager {

	// ���ͻ���֤��
	@Override
	public void checkClientTrusted(X509Certificate[] chain, String authType)
			throws CertificateException {
	}

	// ����������֤��
	@Override
	public void checkServerTrusted(X509Certificate[] chain, String authType)
			throws CertificateException {
	}

	// ���������ε�X509֤������
	@Override
	public X509Certificate[] getAcceptedIssuers() {
		return null;
	}
}

 

PayCommonUtil.java

package wxpay;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;

public class PayCommonUtil {
	/** 
     * 是否簽名正確,規則是:按參數名稱a-z排序,遇到空值的參數不參加簽名。 
     * @return boolean 
     */  
    @SuppressWarnings("rawtypes")
	public static boolean isTenpaySign(String characterEncoding, SortedMap<Object, Object> packageParams, String API_KEY) {  
        StringBuffer sb = new StringBuffer();  
        Set<?> es = packageParams.entrySet();  
        Iterator<?> it = es.iterator();  
        while(it.hasNext()) {  
            Map.Entry entry = (Map.Entry)it.next();  
            String k = (String)entry.getKey();  
            String v = (String)entry.getValue();  
            if(!"sign".equals(k) && null != v && !"".equals(v)) {  
                sb.append(k + "=" + v + "&");  
            }  
        }  
          
        sb.append("key=" + API_KEY);  
          
        //算出摘要  
        String mysign = MD5Util.MD5Encode(sb.toString(), characterEncoding).toLowerCase();  
        String tenpaySign = ((String)packageParams.get("sign")).toLowerCase();  
          
        //System.out.println(tenpaySign + "    " + mysign);  
        return tenpaySign.equals(mysign);  
    }  
  
    /** 
     * @author 
     * @date 2016-4-22 
     * @Description:sign簽名 
     * @param characterEncoding 
     *            編碼格式 
     *            請求參數
     * @return 
     */  
    @SuppressWarnings("rawtypes")
	public static String createSign(String characterEncoding, SortedMap<Object, Object> packageParams, String API_KEY) {  
        StringBuffer sb = new StringBuffer();  
        Set<?> es = packageParams.entrySet();  
        Iterator<?> it = es.iterator();  
        while (it.hasNext()) {  
            Map.Entry entry = (Map.Entry) it.next();  
            String k = (String) entry.getKey();  
            String v = (String) 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;  
    }  
  
    /** 
     * @author 
     * @date 2016-4-22 
     * @Description:將請求參數轉換爲xml格式的string 
     * @param parameters 
     *            請求參數 
     * @return 
     */  
    @SuppressWarnings("rawtypes")
	public static String getRequestXml(SortedMap<Object, 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 k = (String) entry.getKey();  
            String v = (String) entry.getValue();  
            if ("attach".equalsIgnoreCase(k) || "body".equalsIgnoreCase(k) || "sign".equalsIgnoreCase(k)) {  
                sb.append("<" + k + ">" + "<![CDATA[" + v + "]]></" + k + ">");  
            } else {  
                sb.append("<" + k + ">" + v + "</" + k + ">");  
            }  
        }  
        sb.append("</xml>");  
        return sb.toString();  
    }  
  
    /** 
     * 取出一個指定長度大小的隨機正整數. 
     *  
     * @param length 
     *            int 設定所取出隨機數的長度。length小於11 
     * @return int 返回生成的隨機數。 
     */  
    public static int buildRandom(int length) {  
        int num = 1;  
        double random = Math.random();  
        if (random < 0.1) {  
            random = random + 0.1;  
        }  
        for (int i = 0; i < length; i++) {  
            num = num * 10;  
        }  
        return (int) ((random * num));  
    }  
  
    /** 
     * 獲取當前時間 yyyyMMddHHmmss 
     *  
     * @return String 
     */  
    public static String getCurrTime() {  
        Date now = new Date();  
        SimpleDateFormat outFormat = new SimpleDateFormat("yyyyMMddHHmmss");  
        String s = outFormat.format(now);  
        return s;  
    }  

}  

 

RequestHandler.java  

package wxpay;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;


public class RequestHandler {

	private String tokenUrl;
	private String gateUrl;
	private String notifyUrl;
	private String appid;
	private String appkey;
	private String partnerkey;
	private String appsecret;
	private String Token;
	private String charset;
	private String last_errcode;
	protected HttpServletRequest request;
	protected HttpServletResponse response;
	private String key;
	private SortedMap<String, String> parameters;
	private String debugInfo;
	
	public void init(String app_id, String app_secret, String partner_key) {
		this.last_errcode = "0";
		this.Token = "token_";
		this.debugInfo = "";
		this.appid = app_id;
		this.partnerkey = partner_key;
		this.appsecret = app_secret;
		this.key = partner_key;
	}

	public RequestHandler(HttpServletRequest request,
			HttpServletResponse response) {
		this.request = request;
		this.response = response;
		notifyUrl = "https://gw.tenpay.com/gateway/simpleverifynotifyid.xml";
		this.gateUrl = "https://gw.tenpay.com/gateway/pay.htm";
		this.key = "";
		this.parameters = new TreeMap<String, String>();
		this.debugInfo = "";
	}

	public void init() {
	}
	public void init(String app_id, String app_secret, String app_key,
			String partner_key) {
		this.last_errcode = "0";
		this.Token = "token_";
		this.debugInfo = "";
		this.appkey = app_key;
		this.appid = app_id;
		this.partnerkey = partner_key;
		this.appsecret = app_secret;
	}

	public String getGateUrl() {
		return gateUrl;
	}

	public void setGateUrl(String gateUrl) {
		this.gateUrl = gateUrl;
	}

	public String getKey() {
		return key;
	}

	public void setKey(String key) {
		this.key = key;
	}

	public String getParameter(String parameter) {
		String s = this.parameters.get(parameter);
		return (null == s) ? "" : s;
	}
	public void setParameter(String parameter, String parameterValue) {
		String v = "";
		if (null != parameterValue) {
			v = parameterValue.trim();
		}
		this.parameters.put(parameter, v);
	}

	public SortedMap<String, String> getAllParameters() {
		return this.parameters;
	}

	public String getDebugInfo() {
		return debugInfo;
	}

	public String getRequestURL() throws UnsupportedEncodingException {

		this.createSign();

		StringBuffer sb = new StringBuffer();
		String enc = TenpayUtil.getCharacterEncoding(this.request,
				this.response);
		Set<?> es = this.parameters.entrySet();
		Iterator<?> it = es.iterator();
		while (it.hasNext()) {
			Map.Entry entry = (Map.Entry) it.next();
			String k = (String) entry.getKey();
			String v = (String) entry.getValue();

			if (!"spbill_create_ip".equals(k)) {
				sb.append(k + "=" + URLEncoder.encode(v, enc) + "&");
			} else {
				sb.append(k + "=" + v.replace("\\.", "%2E") + "&");
			}
		}

		// ȥ�����һ��&
		String reqPars = sb.substring(0, sb.lastIndexOf("&"));

		return this.getGateUrl() + "?" + reqPars;

	}

	public void doSend() throws UnsupportedEncodingException, IOException {
		this.response.sendRedirect(this.getRequestURL());
	}

	protected void createSign() {
		StringBuffer sb = new StringBuffer();
		Set<?> es = this.parameters.entrySet();
		Iterator<?> it = es.iterator();
		while (it.hasNext()) {
			Map.Entry entry = (Map.Entry) it.next();
			String k = (String) entry.getKey();
			String v = (String) entry.getValue();
			if (null != v && !"".equals(v) && !"sign".equals(k)
					&& !"key".equals(k)) {
				sb.append(k + "=" + v + "&");
			}
		}
		sb.append("key=" + this.getKey());

		String enc = TenpayUtil.getCharacterEncoding(this.request,
				this.response);
		String sign = MD5Util.MD5Encode(sb.toString(), enc).toUpperCase();

		this.setParameter("sign", sign);

		// debug��Ϣ
		this.setDebugInfo(sb.toString() + " => sign:" + sign);

	}
	protected void setDebugInfo(String debugInfo) {
		this.debugInfo = debugInfo;
	}

	protected HttpServletRequest getHttpServletRequest() {
		return this.request;
	}

	protected HttpServletResponse getHttpServletResponse() {
		return this.response;
	}

	public String getTokenUrl() {
		return tokenUrl;
	}

	public void setTokenUrl(String tokenUrl) {
		this.tokenUrl = tokenUrl;
	}

	public String getNotifyUrl() {
		return notifyUrl;
	}

	public void setNotifyUrl(String notifyUrl) {
		this.notifyUrl = notifyUrl;
	}

	public String getAppid() {
		return appid;
	}

	public void setAppid(String appid) {
		this.appid = appid;
	}

	public String getAppkey() {
		return appkey;
	}

	public void setAppkey(String appkey) {
		this.appkey = appkey;
	}

	public String getPartnerkey() {
		return partnerkey;
	}

	public void setPartnerkey(String partnerkey) {
		this.partnerkey = partnerkey;
	}

	public String getAppsecret() {
		return appsecret;
	}

	public void setAppsecret(String appsecret) {
		this.appsecret = appsecret;
	}

	public String getToken() {
		return Token;
	}

	public void setToken(String token) {
		Token = token;
	}

	public String getCharset() {
		return charset;
	}

	public void setCharset(String charset) {
		this.charset = charset;
	}

	public String getLast_errcode() {
		return last_errcode;
	}

	public void setLast_errcode(String last_errcode) {
		this.last_errcode = last_errcode;
	}

	public HttpServletRequest getRequest() {
		return request;
	}

	public void setRequest(HttpServletRequest request) {
		this.request = request;
	}

	public HttpServletResponse getResponse() {
		return response;
	}

	public void setResponse(HttpServletResponse response) {
		this.response = response;
	}

	public SortedMap<String, String> getParameters() {
		return parameters;
	}

	public void setParameters(SortedMap<String, String> parameters) {
		this.parameters = parameters;
	}

	public String getLasterrCode() {
		return last_errcode;
	}

	public void setAppKey(String key) {
		this.appkey = key;
	}

	public String UrlEncode(String src) throws UnsupportedEncodingException {
		return URLEncoder.encode(src, this.charset).replace("+", "%20");
	}

	public String genPackage(SortedMap<String, String> packageParams)
			throws UnsupportedEncodingException {
		String sign = createSign(packageParams);

		StringBuffer sb = new StringBuffer();
		Set es = packageParams.entrySet();
		Iterator it = es.iterator();
		while (it.hasNext()) {
			Map.Entry entry = (Map.Entry) it.next();
			String k = (String) entry.getKey();
			String v = (String) entry.getValue();
			sb.append(k + "=" + UrlEncode(v) + "&");
		}

		// ȥ�����һ��&
		String packageValue = sb.append("sign=" + sign).toString();
		System.out.println("packageValue=" + packageValue);
		return packageValue;
	}

	/**
	 * ����md5ժҪ,������:���������a-z����,������ֵ�IJ���μ�ǩ��
	 */
	@SuppressWarnings("rawtypes")
	public String createSign(SortedMap<String, String> packageParams) {
		StringBuffer sb = new StringBuffer();
		Set es = packageParams.entrySet();
		Iterator it = es.iterator();
		while (it.hasNext()) {
			Map.Entry entry = (Map.Entry) it.next();
			String k = (String) entry.getKey();
			String v = (String) entry.getValue();
			if (null != v && !"".equals(v) && !"sign".equals(k)
					&& !"key".equals(k)) {
				sb.append(k + "=" + v + "&");
			}
		}
		sb.append("key=" + Constant.MCH_KEY);
		System.out.println("md5 sb:" + sb);
		String sign = MD5Util.MD5Encode(sb.toString(), this.charset)
				.toUpperCase();

		return sign;

	}

	/**
	 * ����packageǩ��
	 */
	@SuppressWarnings("rawtypes")
	public boolean createMd5Sign(String signParams) {
		StringBuffer sb = new StringBuffer();
		Set es = this.parameters.entrySet();
		Iterator it = es.iterator();
		while (it.hasNext()) {
			Map.Entry entry = (Map.Entry) it.next();
			String k = (String) entry.getKey();
			String v = (String) entry.getValue();
			if (!"sign".equals(k) && null != v && !"".equals(v)) {
				sb.append(k + "=" + v + "&");
			}
		}

		// ���ժҪ
		String enc = TenpayUtil.getCharacterEncoding(this.request,
				this.response);
		String sign = MD5Util.MD5Encode(sb.toString(), enc).toLowerCase();

		String tenpaySign = this.getParameter("sign").toLowerCase();

		// debug��Ϣ
		this.setDebugInfo(sb.toString() + " => sign:" + sign + " tenpaySign:"
				+ tenpaySign);

		return tenpaySign.equals(sign);
	}

	// ���XML
	@SuppressWarnings("rawtypes")
	public String parseXML() {
		StringBuffer sb = new StringBuffer();
		sb.append("<xml>");
		Set es = this.parameters.entrySet();
		Iterator it = es.iterator();
		while (it.hasNext()) {
			Map.Entry entry = (Map.Entry) it.next();
			String k = (String) entry.getKey();
			String v = (String) entry.getValue();
			if (null != v && !"".equals(v) && !"appkey".equals(k)) {

				sb.append("<" + k + ">" + getParameter(k) + "</" + k + ">\n");
			}
		}
		sb.append("</xml>");
		return sb.toString();
	}

	public static String setXML(String return_code, String return_msg) {
		return "<xml><return_code><![CDATA[" + return_code
				+ "]]></return_code><return_msg><![CDATA[" + return_msg
				+ "]]></return_msg></xml>";
	}
}

 

ResponseHandler.java

package wxpay;

import java.io.IOException;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;


/**
 * Ӧ������
 * Ӧ������̳д��࣬��дisTenpaySign�������ɡ�
 * @author miklchen
 *
 */
public class ResponseHandler { 
	
	/** ��Կ */
	private String key;
	
	/** Ӧ��IJ��� */
	private SortedMap<String, String> parameters; 
	
	/** debug��Ϣ */
	private String debugInfo;
	
	private HttpServletRequest request;
	
	private HttpServletResponse response;
	
	private String uriEncoding;
	
	/**
	 * ���캯��
	 * 
	 * @param request
	 * @param response
	 */
	public ResponseHandler(HttpServletRequest request,
			HttpServletResponse response)  {
		this.request = request;
		this.response = response;

		this.key = "";
		this.parameters = new TreeMap<String, String>();
		this.debugInfo = "";
		
		this.uriEncoding = "";

		Map<?, ?> m = this.request.getParameterMap();
		Iterator<?> it = m.keySet().iterator();
		while (it.hasNext()) {
			String k = (String) it.next();
			String v = ((String[]) m.get(k))[0];			
			this.setParameter(k, v);
		}

	}
	
	/**
	*��ȡ��Կ
	*/
	public String getKey() {
		return key;
	}

	/**
	*������Կ
	*/
	public void setKey(String key) {
		this.key = key;
	}

	/**
	 * ��ȡ����ֵ
	 * @param parameter �������
	 * @return String 
	 */
	public String getParameter(String parameter) {
		String s = this.parameters.get(parameter); 
		return (null == s) ? "" : s;
	}
	
	/**
	 * ���ò���ֵ
	 * @param parameter �������
	 * @param parameterValue ����ֵ
	 */
	public void setParameter(String parameter, String parameterValue) {
		String v = "";
		if(null != parameterValue) {
			v = parameterValue.trim();
		}
		this.parameters.put(parameter, v);
	}
	
	/**
	 * �������еIJ���
	 * @return SortedMap
	 */
	public SortedMap<String, String> getAllParameters() {
		return this.parameters;
	}
	
	/**
	 * �Ƿ�Ƹ�ͨǩ��,������:���������a-z����,������ֵ�IJ���μ�ǩ��
	 * @return boolean
	 */
	@SuppressWarnings("rawtypes")
	public boolean isTenpaySign() {
		StringBuffer sb = new StringBuffer();
		Set<?> es = this.parameters.entrySet();
		Iterator<?> it = es.iterator();
		while(it.hasNext()) {
			Map.Entry entry = (Map.Entry)it.next();
			String k = (String)entry.getKey();
			String v = (String)entry.getValue();
			if(!"sign".equals(k) && null != v && !"".equals(v)) {
				sb.append(k + "=" + v + "&");
			}
		}
		
		sb.append("key=" + this.getKey());
		
		//���ժҪ
		String enc = TenpayUtil.getCharacterEncoding(this.request, this.response);
		String sign = MD5Util.MD5Encode(sb.toString(), enc).toLowerCase();
		
		String tenpaySign = this.getParameter("sign").toLowerCase();
		
		//debug��Ϣ
		this.setDebugInfo(sb.toString() + " => sign:" + sign +
				" tenpaySign:" + tenpaySign);
		
		return tenpaySign.equals(sign);
	}
	
	/**
	 * ���ش������Ƹ�ͨ��������
	 * @param msg: Success or fail��
	 * @throws IOException 
	 */
	public void sendToCFT(String msg) throws IOException {
		String strHtml = msg;
		PrintWriter out = this.getHttpServletResponse().getWriter();
		out.println(strHtml);
		out.flush();
		out.close();

	}
	
	/**
	 * ��ȡuri����
	 * @return String
	 */
	public String getUriEncoding() {
		return uriEncoding;
	}

	/**
	 * ����uri����
	 * @param uriEncoding
	 * @throws UnsupportedEncodingException
	 */
	public void setUriEncoding(String uriEncoding)
			throws UnsupportedEncodingException {
		if (!"".equals(uriEncoding.trim())) {
			this.uriEncoding = uriEncoding;

			// ����ת��
			String enc = TenpayUtil.getCharacterEncoding(request, response);
			Iterator<String> it = this.parameters.keySet().iterator();
			while (it.hasNext()) {
				String k = it.next();
				String v = this.getParameter(k);
				v = new String(v.getBytes(uriEncoding.trim()), enc);
				this.setParameter(k, v);
			}
		}
	}

	/**
	*��ȡdebug��Ϣ
	*/
	public String getDebugInfo() {
		return debugInfo;
	}
	
	/**
	*����debug��Ϣ
	*/
	protected void setDebugInfo(String debugInfo) {
		this.debugInfo = debugInfo;
	}
	
	protected HttpServletRequest getHttpServletRequest() {
		return this.request;
	}
	
	protected HttpServletResponse getHttpServletResponse() {
		return this.response;
	}
}

 

TenpayUtil.java

package wxpay;

import java.text.SimpleDateFormat;
import java.util.Date;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;


public class TenpayUtil {
	
	/**
	 * �Ѷ���ת�����ַ�
	 * @param obj
	 * @return String ת�����ַ�,������Ϊnull,�?ؿ��ַ�.
	 */
	public static String toString(Object obj) {
		if(obj == null)
			return "";
		
		return obj.toString();
	}
	
	/**
	 * �Ѷ���ת��Ϊint��ֵ.
	 * 
	 * @param obj
	 *            �����ֵĶ���.
	 * @return int ת�������ֵ,�Բ���ת���Ķ��?�0��
	 */
	public static int toInt(Object obj) {
		int a = 0;
		try {
			if (obj != null)
				a = Integer.parseInt(obj.toString());
		} catch (Exception e) {

		}
		return a;
	}
	
	/**
	 * ��ȡ��ǰʱ�� yyyyMMddHHmmss
	 * @return String
	 */ 
	public static String getCurrTime() {
		Date now = new Date();
		SimpleDateFormat outFormat = new SimpleDateFormat("yyyyMMddHHmmss");
		String s = outFormat.format(now);
		return s;
	}
	
	/**
	 * ��ȡ��ǰ���� yyyyMMdd
	 * @param date
	 * @return String
	 */
	public static String formatDate(Date date) {
		SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMdd");
		String strDate = formatter.format(date);
		return strDate;
	}
	
	/**
	 * ȡ��һ��ָ�����ȴ�С�����������.
	 * 
	 * @param length
	 *            int �趨��ȡ�������ij��ȡ�lengthС��11
	 * @return int ������ɵ������
	 */
	public static int buildRandom(int length) {
		int num = 1;
		double random = Math.random();
		if (random < 0.1) {
			random = random + 0.1;
		}
		for (int i = 0; i < length; i++) {
			num = num * 10;
		}
		return (int) ((random * num));
	}
	
	/**
	 * ��ȡ�����ַ�
	 * @param request
	 * @param response
	 * @return String
	 */
	public static String getCharacterEncoding(HttpServletRequest request,
			HttpServletResponse response) {
		
		if(null == request || null == response) {
			return "gbk";
		}
		
		String enc = request.getCharacterEncoding();
		if(null == enc || "".equals(enc)) {
			enc = response.getCharacterEncoding();
		}
		
		if(null == enc || "".equals(enc)) {
			enc = "gbk";
		}
		
		return enc;
	}
	
	/**
	 * ��ȡunixʱ�䣬��1970-01-01 00:00:00��ʼ������
	 * @param date
	 * @return long
	 */
	public static long getUnixTime(Date date) {
		if( null == date ) {
			return 0;
		}
		
		return date.getTime()/1000;
	}
		
	/**
	 * ʱ��ת�����ַ�
	 * @param date ʱ��
	 * @param formatType ��ʽ������
	 * @return String
	 */
	public static String date2String(Date date, String formatType) {
		SimpleDateFormat sdf = new SimpleDateFormat(formatType);
		return sdf.format(date);
	}

}

 

XMLUtil.java

package wxpay;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;

public class XMLUtil {

	/**
	 * ����xml,���ص�һ��Ԫ�ؼ�ֵ�ԡ�����һ��Ԫ�����ӽڵ㣬��˽ڵ��ֵ���ӽڵ��xml��ݡ�
	 * 
	 * @param strxml
	 * @return
	 * @throws JDOMException
	 * @throws IOException
	 */
	public static Map<String, String> doXMLParse(String strxml)
			throws JDOMException, IOException {
		strxml = strxml.replaceFirst("encoding=\".*\"", "encoding=\"UTF-8\"");
		if (null == strxml || "".equals(strxml)) {
			return null;
		}
		Map<String, String> m = new HashMap<String, String>();
		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 = XMLUtil.getChildrenText(children);
			}
			m.put(k, v);
		}
		// �ر���
		in.close();
		return m;
	}

	/**
	 * ��ȡ�ӽ���xml
	 * 
	 * @param children
	 * @return String
	 */
	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(XMLUtil.getChildrenText(list));
				}
				sb.append(value);
				sb.append("</" + name + ">");
			}
		}
		return sb.toString();
	}
}

Constant.java

package wxpay;

public class Constant {

	public static final String MCH_ID = "替換成你的商戶號";// 微信支付商戶號

	public static final String MCH_KEY ="替換成你的商戶密鑰";

	// 第三方用戶唯一憑證
	public final static String APP_ID = "替換成你的appid";

	// 第三方用戶唯一憑證密鑰
	public final static String APP_SECRET = "替換成你的app_secretd";

	
}

       

       將上面的所有.java文件放在同一個包裏,導入依賴的jar包就可以了。

展示二維碼的方式如下:

 <img src="${pageContext.request.contextPath}${codeUrl}" width="100%" height="100%" />

至於具體的頁面不分享,這個由你的前端自己寫就可以了。

 

至此,分享結束,希望能對諸位有所幫助。

 

 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章