Java微信支付之服务号支付实现

网上的java微信支付sdk和Demo基本上是水的,看着头疼所以我决心自己开始写Java微信支付之公众号支付,多的不说见下面源码,为了方便使用我分别用了两个Servlet,一个是统一下单UnifiedorderServlet,一个是支付回调PayCallBackServlet,你们可以自己封装。

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

一是统一下单UnifiedorderServlet:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Random;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.http.ParseException;
import org.apache.http.client.ClientProtocolException;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONML;
import org.json.JSONObject;

public class UnifiedorderServlet extends HttpServlet {

	private static final long serialVersionUID = 1L;
	private static final String appid = "";// 找微信
	private static final String mch_id = "";// 找微信
	public static final String api_key = "";// 找微信
	private static final String trade_type = "JSAPI";// 写死

	public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		response.setContentType("text/html; charset=utf-8");
		PrintWriter out = response.getWriter();
		JSONObject jso = new JSONObject();
		double money = 0.01;
		String openId = "", out_trade_no = "", body = "测试", ip = "";
		try {
			out.print(execute(out_trade_no, body, openId, money, ip, jso).toString());
		} catch (JSONException e) {
			e.printStackTrace();
		}
		out.flush();
		out.close();
	}

	/**
	 * 微信服务号统一下单支付
	 * 
	 * @param out_trade_no
	 *            订单号
	 * @param body
	 *            标题
	 * @param openId
	 *            用户的openId
	 * @param money
	 *            支付金额
	 * @param ip
	 *            客户端ip
	 * @param request
	 *            HttpServletRequest
	 * @return
	 * @throws JSONException
	 */
	public JSONObject execute(String out_trade_no, String body, String openId, double money, String ip, JSONObject jso) throws JSONException {

		StringBuilder xml = new StringBuilder();
		String notify_url = "http://test.com/payCallBack";// 支付回调地址

		String prepay_id = "", sign = "", charset = "UTF-8", nonce_str = "";
		try {
			String weixinMoney = new java.text.DecimalFormat("#").format(money * 100);// 微信是以分为单位的所以要乘以100
			nonce_str = getRandomString(32);
			xml.append("appid=").append(appid).append("&body=").append(new String(body.getBytes(charset), charset));// 处理中文
			xml.append("&mch_id=").append(mch_id).append("&nonce_str=").append(nonce_str);
			xml.append("¬ify_url=").append(notify_url).append("&openid=").append(openId);
			xml.append("&out_trade_no=").append(out_trade_no).append("&spbill_create_ip=").append(ip);
			xml.append("&total_fee=").append(weixinMoney).append("&trade_type=").append(trade_type).append("&key=").append(api_key);
			sign = MD5Purity(xml.toString());
			// System.out.println(xml);
			xml.delete(0, xml.length());
			xml.append("<xml>");
			xml.append("   <appid>").append(appid).append("</appid>");
			xml.append("   <body>").append(body).append("</body>");
			xml.append("   <mch_id>").append(mch_id).append("</mch_id>");
			xml.append("   <nonce_str>").append(nonce_str).append("</nonce_str>");
			xml.append("   <openid>").append(openId).append("</openid>");
			xml.append("   <notify_url>").append(notify_url).append("</notify_url>");
			xml.append("   <out_trade_no>").append(out_trade_no).append("</out_trade_no>");
			xml.append("   <spbill_create_ip>").append(ip).append("</spbill_create_ip>");
			xml.append("   <total_fee>").append(weixinMoney).append("</total_fee>");
			xml.append("   <trade_type>").append(trade_type).append("</trade_type>");
			xml.append("   <sign>").append(sign).append("</sign>");
			xml.append("</xml>");
			HttpURLConnection conn = (HttpURLConnection) new URL("https://api.mch.weixin.qq.com/pay/unifiedorder").openConnection();
			conn.setDoOutput(true);
			conn.setRequestMethod("POST");
			conn.setRequestProperty("Content-Type", "text/xml");
			conn.setRequestProperty("Charset", charset);
			OutputStream os = conn.getOutputStream();
			os.write(xml.toString().getBytes(charset));
			xml.delete(0, xml.length());
			os.close();
			int responseCode = conn.getResponseCode();
			InputStreamReader in = null;
			BufferedReader br = null;
			if (responseCode == 200) {
				in = new InputStreamReader(conn.getInputStream(), charset);
				br = new BufferedReader(in);
				String retData = null;
				while ((retData = br.readLine()) != null)
					xml.append(retData);
				JSONArray childNodes = JSONML.toJSONObject(xml.toString()).getJSONArray("childNodes");
				int len = childNodes.length() - 1;
				for (int i = len; i > -1; i--) {
					JSONObject js = childNodes.getJSONObject(i);
					if (js.get("tagName").equals("prepay_id")) {
						prepay_id = js.getJSONArray("childNodes").getString(0);
						break;
					}
				}
			}
			if (in != null)
				in.close();
			if (br != null)
				br.close();
			conn.disconnect();
			// ----------------------------------给h5返回的数据
			String timeStamp = System.currentTimeMillis() + "";
			timeStamp = timeStamp.substring(0, 10);// 微信只要精确到秒
			nonce_str = getRandomString(32);
			jso.put("appId", appid);
			jso.put("nonceStr", nonce_str);
			jso.put("package", "prepay_id=" + prepay_id);
			jso.put("signType", "MD5");
			jso.put("timeStamp", timeStamp);
			xml.delete(0, xml.length());
			xml.append("appId=").append(appid);
			xml.append("&nonceStr=").append(nonce_str);
			xml.append("&package=").append(jso.getString("package"));
			xml.append("&signType=").append(jso.getString("signType"));
			xml.append("&timeStamp=").append(timeStamp);
			xml.append("&key=").append(api_key);
			sign = MD5Purity(new String(xml.toString().getBytes(charset), charset));
			jso.put("paySign", sign);
			//返回的数据主要用在这地方 https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_7&index=6
			// ----------------------------------给h5返回的数据
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		} catch (ParseException e) {
			e.printStackTrace();
		} catch (ClientProtocolException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return jso;
	}

	/**
	 * MD5
	 * 
	 * @param plainText
	 * @return
	 */
	public String MD5Purity(String plainText) {
		try {
			MessageDigest md = MessageDigest.getInstance("MD5");
			md.update(plainText.getBytes("utf-8"));
			byte b[] = md.digest();
			int i;
			StringBuffer buf = new StringBuffer("");
			for (int offset = 0; offset < b.length; offset++) {
				i = b[offset];
				if (i < 0)
					i += 256;
				if (i < 16)
					buf.append("0");
				buf.append(Integer.toHexString(i));
			}
			plainText = buf.toString();
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		return plainText.toUpperCase();
	}

	/**
	 * 生成一个随机字符串
	 * 
	 * @param length
	 *            表示生成字符串的长度
	 * @return
	 */
	private String getRandomString(int length) {
		String base = "abcdefghijklmnopqrstuvwxyz0123456789";
		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();
	}
}


二是支付回调PayCallBackServlet:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONML;
import org.json.JSONObject;

public class PayCallBackServlet extends HttpServlet {

	public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		response.setContentType("text/html; charset=utf-8");
		PrintWriter out = response.getWriter();
		out.print(doWxServer(request));
		out.flush();
		out.close();
	}

	/**
	 * 处理微信回调
	 * 
	 * @param request
	 * @return
	 * @throws ServletException
	 * @throws IOException
	 */
	public String doWxServer(HttpServletRequest request) {
		System.out.println("微信服务号支付回调");
		String inputLine;
		StringBuilder notityXml = new StringBuilder();
		BufferedReader bufferedReader = null;
		try {
			bufferedReader = request.getReader();
			while ((inputLine = bufferedReader.readLine()) != null)
				notityXml.append(inputLine);
			if (bufferedReader != null)
				bufferedReader.close();
			if (notityXml.length() < 10) {
				return "fail";
			}
			String appid = "", total_fee = "", bank_type = "", cash_fee = "", fee_type = "", is_subscribe = "", mch_id = "", nonce_str = "";
			String out_trade_no = "", transaction_id = "", openid = "", sign = "", result_code = "", return_code = "", time_end = "", trade_type = "";
			JSONArray result = JSONML.toJSONObject(notityXml.toString()).getJSONArray("childNodes");
			int len = result.length();
			for (int i = 0; i < len; i++) {
				JSONObject js = result.getJSONObject(i);
				Object tagName = js.get("tagName");
				if (tagName.equals("appid")) {
					appid = js.getJSONArray("childNodes").getString(0);
				} else if (tagName.equals("bank_type")) {
					bank_type = js.getJSONArray("childNodes").getString(0);
				} else if (tagName.equals("cash_fee")) {
					cash_fee = js.getJSONArray("childNodes").getString(0);
				} else if (tagName.equals("fee_type")) {
					fee_type = js.getJSONArray("childNodes").getString(0);
				} else if (tagName.equals("is_subscribe")) {
					is_subscribe = js.getJSONArray("childNodes").getString(0);
				} else if (tagName.equals("mch_id")) {
					mch_id = js.getJSONArray("childNodes").getString(0);
				} else if (tagName.equals("nonce_str")) {
					nonce_str = js.getJSONArray("childNodes").getString(0);
				} else if (tagName.equals("openid")) {
					openid = js.getJSONArray("childNodes").getString(0);
				} else if (tagName.equals("out_trade_no")) {
					out_trade_no = js.getJSONArray("childNodes").getString(0);
				} else if (tagName.equals("result_code")) {
					result_code = js.getJSONArray("childNodes").getString(0);
				} else if (tagName.equals("return_code")) {
					return_code = js.getJSONArray("childNodes").getString(0);
				} else if (tagName.equals("time_end")) {
					time_end = js.getJSONArray("childNodes").getString(0);
				} else if (tagName.equals("total_fee")) {
					total_fee = js.getJSONArray("childNodes").getInt(0) + "";
				} else if (tagName.equals("trade_type")) {
					trade_type = js.getJSONArray("childNodes").getString(0);
				} else if (tagName.equals("transaction_id")) {
					transaction_id = js.getJSONArray("childNodes").getString(0);
				} else if (tagName.equals("sign")) {
					sign = js.getJSONArray("childNodes").getString(0);
				}
			}
			StringBuilder str = new StringBuilder();
			str.append("appid=").append(appid).append("&bank_type=").append(bank_type).append("&cash_fee=").append(cash_fee).append("&fee_type=");
			str.append(fee_type).append("&is_subscribe=").append(is_subscribe).append("&mch_id=").append(mch_id).append("&nonce_str=");
			str.append(nonce_str).append("&openid=").append(openid).append("&out_trade_no=").append(out_trade_no).append("&result_code=").append(result_code)
					.append("&return_code=").append(return_code).append("&time_end=").append(time_end).append("&total_fee=").append(total_fee);
			str.append("&trade_type=").append(trade_type).append("&transaction_id=").append(transaction_id).append("&key=").append(UnifiedorderServlet.api_key);
			if (!MD5Purity(str.toString()).equals(sign)) {// 验证签名
				System.out.println("微信服务号支付回调签名异常sign=" + sign);
				System.out.println(str);
				System.out.println(result);
				return "fail";
			}
			total_fee = new java.text.DecimalFormat("#0.00").format(Double.parseDouble(total_fee) / 100);// 支付金额以分为单位
			return "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>";//成功后给微信返回数据
		} catch (JSONException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return "fail";
	}

	/**
	 * MD5
	 * 
	 * @param plainText
	 * @return
	 */
	public String MD5Purity(String plainText) {
		try {
			MessageDigest md = MessageDigest.getInstance("MD5");
			md.update(plainText.getBytes("utf-8"));
			byte b[] = md.digest();
			int i;
			StringBuffer buf = new StringBuffer("");
			for (int offset = 0; offset < b.length; offset++) {
				i = b[offset];
				if (i < 0)
					i += 256;
				if (i < 16)
					buf.append("0");
				buf.append(Integer.toHexString(i));
			}
			plainText = buf.toString();
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		return plainText.toUpperCase();
	}
}


大功告成有么么哒。

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值