微信支付客户端调用Java API接口付款(验签、Xml封装、订单生成)

一、工具类

1、生成订单

package com.utils;

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

public class WxOrderUtils {

    public static String getOrderNo() {
        SimpleDateFormat simpleDateFormat;
        simpleDateFormat = new SimpleDateFormat("yyyyMMddHHmmss");
        Date date = new Date();
        String str = simpleDateFormat.format(date);
        Random random = new Random();
        int rannum = (int) (random.nextDouble() *5);// 获取5位随机数
        return str + rannum;// 当前时间 + 系统5随机生成位数
    }

    public static void main(String[] args) {
        String fileName = getOrderNo();
        System.out.println(fileName);// 8835920140307
    }
}

2、Sign签名

package com.pay.wx.utils;

import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;

import com.utils.MD5Utils;

import net.sf.json.JSONObject;

public class WXSignUtils {
	public final static String pack = "Sign=WXPay";

	public static String unifiedorderMapToSign(String appid, String mch_id, String nonce_str, String body, String detail, String attach, String out_trade_no, int total_fee, String time_start, String time_expire, String notify_url, String spbill_create_ip) {
		// 参数:开始生成签名
		SortedMap<Object, Object> parameters = new TreeMap<Object, Object>();
		parameters.put("appid", appid);
		parameters.put("mch_id", mch_id);
		parameters.put("nonce_str", nonce_str);
		parameters.put("body", body);
		parameters.put("detail", detail);
		parameters.put("attach", attach);
		parameters.put("out_trade_no", out_trade_no);
		parameters.put("total_fee", total_fee);
		parameters.put("time_start", time_start);
		parameters.put("time_expire", time_expire);
		parameters.put("notify_url", notify_url);
		parameters.put("trade_type", "APP");
		parameters.put("spbill_create_ip", spbill_create_ip);
		String sign = createSign(parameters);
		return sign;
	}
	@SuppressWarnings("rawtypes")
	public static String createSign(SortedMap<Object, Object> parameters) {
		StringBuffer sb = new StringBuffer();
		Set es = parameters.entrySet();// 所有参与传参的参数按照accsii排序(升序)
		Iterator it = es.iterator();
		while (it.hasNext()) {
			Map.Entry entry = (Map.Entry) it.next();
			String k = (String) entry.getKey();
			Object v = entry.getValue();
			if (null != v && !"".equals(v) && !"sign".equals(k) && !"key".equals(k)) {
				sb.append(k + "=" + v + "&");
			}
		}
		sb.append("key=" + wechat_pay_secret_key);//微信secret key
		System.out.println("字符串拼接后是:" + sb.toString());
		String sign = MD5Utils.MD5(sb.toString()).toUpperCase();
		return sign;
	}
}

3、XML参数封装

package com.utils;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;

import javax.net.ssl.HttpsURLConnection;

import com.pay.wx.Unifiedorder;

/**
 * post提交xml格式的参数
 * 
 * @author iYjrg_xiebin
 * @date 2016年10月25日下午3:33:38
 */
public class HttpXmlUtils {

	/**
	 * 开始post提交参数到接口 并接受返回
	 * 
	 * @param url
	 * @param xml
	 * @param method
	 * @param contentType
	 * @return
	 */
	public static String xmlHttpProxy(String url, String xml, String method, String contentType) {
		InputStream is = null;
		OutputStreamWriter os = null;

		try {
			URL _url = new URL(url);
			HttpURLConnection conn = (HttpURLConnection) _url.openConnection();
			conn.setDoInput(true);
			conn.setDoOutput(true);
			conn.setRequestProperty("Content-type", "text/xml");
			conn.setRequestProperty("Pragma:", "no-cache");
			conn.setRequestProperty("Cache-Control", "no-cache");
			conn.setRequestMethod("POST");
			os = new OutputStreamWriter(conn.getOutputStream());
			os.write(new String(xml.getBytes(contentType)));
			os.flush();

			// 返回值
			is = conn.getInputStream();
			return getContent(is, "utf-8");
		} catch (MalformedURLException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				if (os != null) {
					os.close();
				}
				if (is != null) {
					is.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return null;
	}

	/**
	 * 解析返回的值
	 * 
	 * @param is
	 * @param charset
	 * @return
	 */
	public static String getContent(InputStream is, String charset) {
		String pageString = null;
		InputStreamReader isr = null;
		BufferedReader br = null;
		StringBuffer sb = null;
		try {
			isr = new InputStreamReader(is, charset);
			br = new BufferedReader(isr);
			sb = new StringBuffer();
			String line = null;
			while ((line = br.readLine()) != null) {
				sb.append(line + "\n");
			}
			pageString = sb.toString();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				if (is != null) {
					is.close();
				}
				if (isr != null) {
					isr.close();
				}
				if (br != null) {
					br.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
			sb = null;
		}
		return pageString;
	}

	/**
	 * 构造xml参数
	 * 
	 * @param xml
	 * @return
	 */
	public static String xmlInfoUnifiedorder(Unifiedorder unifiedorder) {
		// 构造xml参数的时候,至少又是个必传参数
		/*
		 * <xml> <appid>wx2421b1c4370ec43b</appid> <attach>支付测试</attach>
		 * <body>JSAPI支付测试</body> <mch_id>10000100</mch_id>
		 * <nonce_str>1add1a30ac87aa2db72f57a2375d8fec</nonce_str>
		 * <notify_url>http://wxpay.weixin.qq.com/pub_v2/pay/notify.v2.php</
		 * notify_url> <openid>oUpF8uMuAJO_M2pxb1Q9zNjWeS6o</openid>
		 * <out_trade_no>1415659990</out_trade_no>
		 * <spbill_create_ip>14.23.150.211</spbill_create_ip>
		 * <total_fee>1</total_fee> <trade_type>JSAPI</trade_type>
		 * <sign>0CB01533B8C1EF103065174F50BCA001</sign> </xml>
		 */

		if (unifiedorder != null) {
			StringBuffer bf = new StringBuffer();
			bf.append("<xml>");

			bf.append("<appid><![CDATA[");
			bf.append(unifiedorder.getAppid());
			bf.append("]]></appid>");

			bf.append("<mch_id><![CDATA[");
			bf.append(unifiedorder.getMch_id());
			bf.append("]]></mch_id>");

			bf.append("<nonce_str><![CDATA[");
			bf.append(unifiedorder.getNonce_str());
			bf.append("]]></nonce_str>");

			bf.append("<sign><![CDATA[");
			bf.append(unifiedorder.getSign());
			bf.append("]]></sign>");

			bf.append("<body><![CDATA[");
			bf.append(unifiedorder.getBody());
			bf.append("]]></body>");

			bf.append("<detail><![CDATA[");
			bf.append(unifiedorder.getDetail());
			bf.append("]]></detail>");

			bf.append("<attach><![CDATA[");
			bf.append(unifiedorder.getAttach());
			bf.append("]]></attach>");

			bf.append("<out_trade_no><![CDATA[");
			bf.append(unifiedorder.getOut_trade_no());
			bf.append("]]></out_trade_no>");

			bf.append("<total_fee><![CDATA[");
			bf.append(unifiedorder.getTotal_fee());
			bf.append("]]></total_fee>");

			bf.append("<spbill_create_ip><![CDATA[");
			bf.append(unifiedorder.getSpbill_create_ip());
			bf.append("]]></spbill_create_ip>");

			bf.append("<time_start><![CDATA[");
			bf.append(unifiedorder.getTime_start());
			bf.append("]]></time_start>");

			bf.append("<time_expire><![CDATA[");
			bf.append(unifiedorder.getTime_expire());
			bf.append("]]></time_expire>");

			bf.append("<notify_url><![CDATA[");
			bf.append(unifiedorder.getNotify_url());
			bf.append("]]></notify_url>");

			bf.append("<trade_type><![CDATA[");
			bf.append(unifiedorder.getTrade_type());
			bf.append("]]></trade_type>");

			bf.append("</xml>");
			return bf.toString();
		}

		return "";
	}

	/**
	 * post请求并得到返回结果
	 * 
	 * @param requestUrl
	 * @param requestMethod
	 * @param output
	 * @return
	 */
	public static String httpsRequest(String requestUrl, String requestMethod, String output) {
		try {
			URL url = new URL(requestUrl);
			HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
			connection.setDoOutput(true);
			connection.setDoInput(true);
			connection.setUseCaches(false);
			connection.setRequestMethod(requestMethod);
			if (null != output) {
				OutputStream outputStream = connection.getOutputStream();
				outputStream.write(output.getBytes("UTF-8"));
				outputStream.close();
			}
			// 从输入流读取返回内容
			InputStream inputStream = connection.getInputStream();
			InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");
			BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
			String str = null;
			StringBuffer buffer = new StringBuffer();
			while ((str = bufferedReader.readLine()) != null) {
				buffer.append(str);
			}
			bufferedReader.close();
			inputStreamReader.close();
			inputStream.close();
			inputStream = null;
			connection.disconnect();
			return buffer.toString();
		} catch (Exception ex) {
			ex.printStackTrace();
		}

		return "";
	}

}

4、setPay 请求参数封装

package com.pay.wx.utils;

import java.util.SortedMap;
import java.util.TreeMap;

import com.utils.WXSignUtils;

import net.sf.json.JSONObject;

public class PayUtils {
	public final static String pack = "Sign=WXPay";

	public static JSONObject setPayMap(String appid, String mch_id, String prepay_id, String nonce_str, String dateline) {
		// 参数:开始生成签名
		SortedMap<Object, Object> par = new TreeMap<Object, Object>();
		par.put("appid", appid);
		par.put("partnerid", mch_id);
		par.put("prepayid", prepay_id);
		par.put("package", pack);
		par.put("noncestr", nonce_str);
		par.put("timestamp", dateline);
		String signnew = WXSignUtils.createSign(par);
		par.put("sign", signnew);
		par.put("package", pack);
		par.remove("package");
		JSONObject js = JSONObject.fromObject(par);
		return js;
	}
}


 

一、付款

1、后台接口参数封装(APP打开微信支付SDK参数)

package com.service.impl;

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

import net.sf.json.JSONObject;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import com.model.PayCustomerDetail;
import com.model.PayUnifiedOrder;
import com.pay.wx.Unifiedorder;
import com.pay.wx.utils.PayUtils;
import com.utils.BeanUtilsExtends;
import com.utils.HttpXmlUtils;
import com.utils.JSONUtils;
import com.utils.RandomUtils;
import com.utils.TimeUtils;
import com.utils.WxOrderUtils;

@Service
public class PayServiceImpl implements PayService {
	private final Logger logger = LoggerFactory.getLogger(PayBoServiceImpl.class);

	public Map<String, Object> orderPay(Map<String, Object> paramMap) throws Exception {
		Map<String, Object> map = new HashMap<String, Object>();
		map.put("state", "0");// 创建订单状态,0=失败,1=成功
		map.put("msg", "支付交易失败,请稍后再试");

		String custid = "1";
		String body = "购买商品";
		String total_price = "100"; // 订单总金额,单位为分,详见支付金额
		String detail = "购买商品,价格" + total_price + "元";
		String attach = ""; // 附加数据,在查询API和支付通知中原样返回,该字段主要用于商户携带订单的自定义数据
		String out_trade_no = WxOrderUtils.getOrderNo(); // 商户系统内部的订单号,32个字符内、可包含字母,其他说明见商户订单号
		String appid = appID;// 微信开放平台审核通过的应用APPID
		String mch_id = wechat_pay_merchant_no;// 微信开放平台审核通过的应用merchant_no
		String nonce_str = RandomUtils.randomUserName(16);
		String spbill_create_ip = "127.0.0.1";
		double totalfee = Double.parseDouble(total_price);// // 单位是分,即是0.01元
		int total_fee = (int) (totalfee * 100);
		String time_start = TimeUtils.timeStart();
		String time_expire = TimeUtils.timeExpire();
		String notify_url = callback_order_pay;// 同步回调地址

		String sign = PayUtils.unifiedorderMapToSign(appid, mch_id, nonce_str, body, detail, attach, out_trade_no, total_fee, time_start, time_expire, notify_url, spbill_create_ip);
		// 拼装支付订单信息
		Unifiedorder unifiedorder = new Unifiedorder();
		unifiedorder.setAppid(appid);
		unifiedorder.setMch_id(mch_id);
		unifiedorder.setNonce_str(nonce_str);
		unifiedorder.setSign(sign);
		unifiedorder.setBody(body);
		unifiedorder.setDetail(detail);
		unifiedorder.setAttach(attach);
		unifiedorder.setOut_trade_no(out_trade_no);
		unifiedorder.setTotal_fee(total_fee);
		unifiedorder.setSpbill_create_ip(spbill_create_ip);
		unifiedorder.setTime_start(time_start);
		unifiedorder.setTime_expire(time_expire);
		unifiedorder.setNotify_url(notify_url);
		unifiedorder.setTrade_type(PayUtils.trade_type);
		String xmlInfo = HttpXmlUtils.xmlInfoUnifiedorder(unifiedorder);// 构造xml参数
		PayUnifiedOrder payUnifiedOrder = new PayUnifiedOrder();
		BeanUtilsExtends.copyProperties(payUnifiedOrder, unifiedorder);
		payUnifiedOrder.setUpdatetime(new Date());
		payUnifiedOrder.setCustomerid(custid);
		payUnifiedOrder.setState(1);
		payUnifiedOrder.setOrderstatus(0);
		payUnifiedOrder.setPayUnifiedOrderXml(xmlInfo);
		payUnifiedOrderService.savePayUnifiedOrder(payUnifiedOrder);// 订单信息保存

		PayCustomerDetail payCustomerDetail = new PayCustomerDetail();
		payCustomerDetail.setTitle(body);
		payCustomerDetail.setContent(detail);
		payCustomerDetail.setAmount(totalfee);
		payCustomerDetail.setPoundage(0.0);
		payCustomerDetail.setCustomerid(custid);
		payCustomerDetail.setTradestatus(0); // 交易状态 : 0=初始化,1=成功,2=失败
		payCustomerDetail.setIp(spbill_create_ip);
		payCustomerDetail.setCreatetime(new Date());
		payCustomerDetail.setUpdatetime(new Date());
		payCustomerDetail.setOuttradeno(out_trade_no);
		payCustomerDetail.setState(1);
		payCustomerDetailService.savePayCustomerDetail(payCustomerDetail);// 订单详细信息记录

		String method = "POST";
		String weixinPost = HttpXmlUtils.httpsRequest("https://api.mch.weixin.qq.com/pay/unifiedorder", method, xmlInfo).toString();
		logger.info("=============================start============================");
		logger.info(weixinPost);
		logger.info("=============================end==============================");
		String json = JSONUtils.xml2json(weixinPost);
		if (StringUtils.isNotBlank(json)) {
			// 参数:开始生成签名
			JSONObject jsonObject = JSONUtils.getJsonObjectFromJsonString(json);
			String prepay_id = jsonObject.getString("prepay_id");
			// 时间戳
			String dateline = String.valueOf(new Date().getTime());// mysq时间戳只有10位要做处理
			dateline = dateline.substring(0, 10);
			payUnifiedOrder.setPack(PayUtils.pack);
			payUnifiedOrder.setSetpay_timestamp(dateline);
			payUnifiedOrder.setPrepayid(prepay_id);
			payUnifiedOrder.setSetPayXml(weixinPost);
			payUnifiedOrderService.savePayUnifiedOrder(payUnifiedOrder); // 存储回调信息

			JSONObject js = PayUtils.setPayMap(appid, mch_id, prepay_id, nonce_str, dateline);
			map.put("setpay", js);// 返回支付参数,app客户端使用里面的值用来调用支付
			map.put("state", "1");// 创建订单状态,0=失败,1=成功
			map.put("msg", "支付申请创建成功");
			return map;
		} else {
			payUnifiedOrder.setSetPayXml(weixinPost);
			payUnifiedOrderService.savePayUnifiedOrder(payUnifiedOrder);// 存储回调信息
		}
		return map;
	}
}

2、APP客户端使用API返回参数打开微信支付SDK

后台返回值参数:

{
	"setpay": {
		"appid": "wxfa234123412897843",
		"noncestr": "11232323112205947",
		"package_": "Sign=WXPay",
		"partnerid": "150523232351",
		"prepayid": "wx123232323230a3404882531",
		"sign": "87E12411D457944452352352536C4",
		"timestamp": "1528902743"
	},
	"state": "1",
	"msg": "支付申请创建成功"
}

3、微信支付成功后,微信回调API服务端,处理业务,更新订单状态

package com.service.impl;

import java.io.InputStream;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

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

import net.sf.json.JSONObject;

import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.model.PayCustomerDetail;
import com.model.PayUnifiedOrder;
import com.service.PayCustomerDetailService;
import com.service.PayUnifiedOrderService;

@Service
public class PayCallbackServiceImpl {
	private final Logger logger = LoggerFactory.getLogger(PayCallbackServiceImpl.class);

	@Autowired
	private PayUnifiedOrderService payUnifiedOrderService;
	@Autowired
	private PayCustomerDetailService payCustomerDetailService;

	@SuppressWarnings("unchecked")
	public void callbackVipOrderPay(HttpServletRequest request, HttpServletResponse response) throws Exception {
		String msg = "error";
		// 解析结果存储在HashMap
		Map<String, String> map = new HashMap<String, String>();
		InputStream inputStream = request.getInputStream();
		// 读取输入流
		SAXReader reader = new SAXReader();
		Document document = reader.read(inputStream);
		// 得到xml根元素
		Element root = document.getRootElement();
		// 得到根元素的所有子节点
		List<Element> elementList = root.elements();
		// 遍历所有子节点
		for (Element e : elementList) {
			map.put(e.getName(), e.getText());
		}
		JSONObject json = JSONObject.fromObject(map);
		System.out.println("===消息通知的结果:" + json.toString() + "==========================");
		String outTradeNo = map.get("out_trade_no");
		PayUnifiedOrder payUnifiedOrder = payUnifiedOrderService.findPayUnifiedOrderByOut_trade_no(outTradeNo);
		if (payUnifiedOrder == null) {
			logger.info("支付回调根据订单号查询支付信息失败,为空");
			// 释放资源
			inputStream.close();
			inputStream = null;
			// 不返回结果,微信会重新调用,总调用5次
			return;
		}
		PayCustomerDetail payCustomerDetail = payCustomerDetailService.findPayCustomerDetailByOut_trade_no(outTradeNo);
		if (payCustomerDetail == null) {
			logger.info("回调根据订单号查询用户明细失败,为空");
			// 释放资源
			inputStream.close();
			inputStream = null;
			// 不返回结果,微信会重新调用,总调用5次
			return;
		}
		payUnifiedOrder.setSetPayCallBackXml(json.toString());// 请求支付回调XML
		payUnifiedOrder.setResult_code(map.get("return_code"));// 业务结果
		payUnifiedOrder.setUpdatetime(new Date());

		payCustomerDetail.setUpdatetime(new Date());
		payCustomerDetail.setReachtime(new Date());
		// 判断是否支付成功
		if (map.get("return_code").equals("SUCCESS")) {
			if (payUnifiedOrder != null && payUnifiedOrder.getOrderstatus().intValue() != 0) {
				logger.info("订单已处理,无需重复处理");
				inputStream.close();
				inputStream = null;
				msg = "success";
				response.setContentType("text/xml");
				response.getWriter().println(msg);// 返回结果,微信不会重新调用
				return;
			}
			payUnifiedOrder.setOrderstatus(1);// 交易状态 : 0=初始化,1=成功,2=失败
			payUnifiedOrder.setOpenid(map.get("openid"));// 用户标识
			payUnifiedOrder.setBank_type(map.get("bank_type"));// 付款银行
			payUnifiedOrder.setTransaction_id(map.get("transaction_id"));// 微信支付订单号
			payUnifiedOrder.setTime_end(map.get("time_end"));// 支付完成时间
			payUnifiedOrderService.savePayUnifiedOrder(payUnifiedOrder);

			payCustomerDetail.setTradestatus(1);// 交易状态 : 0=初始化,1=成功,2=失败
			payCustomerDetailService.savePayCustomerDetail(payCustomerDetail);
			// 释放资源
			inputStream.close();
			inputStream = null;
			logger.info("支付成功,outTradeNo={}", outTradeNo);
			msg = "success";
			response.setContentType("text/xml");
			response.getWriter().println(msg);// 返回结果,微信不会重新调用
			return;
		} else if (map.get("return_code").equals("FAIL")) {
			payUnifiedOrder.setOrderstatus(2);
			payUnifiedOrder.setErr_code(map.get("err_code"));// 错误代码
			payUnifiedOrder.setErr_code_des(map.get("err_code_des"));// 错误代码描述
			payUnifiedOrderService.savePayUnifiedOrder(payUnifiedOrder);

			payCustomerDetail.setTradestatus(2);// 交易状态 : 0=初始化,1=成功,2=失败
			payCustomerDetailService.savePayCustomerDetail(payCustomerDetail);
			logger.error("支付失败,outTradeNo={}", outTradeNo);
			// 释放资源
			inputStream.close();
			inputStream = null;
			response.setContentType("text/xml");
			response.getWriter().println(msg);// 返回结果,微信不会重新调用
			return;
		}
		// 释放资源
		inputStream.close();
		inputStream = null;
		response.setContentType("text/xml");
		response.getWriter().println(msg);
		return;
	}
}

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值