Java后台----微信小程序调微信支付

1.申请商户号,设置api密钥.
2.在开发电脑上安装安全控件.
3.我所开发的业务逻辑是前端调用我提供的一个支付前的接口,Java后台先去查询订单相关内容,设置好参数(需要的参数可查看https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=9_1)后调用微信方统一下单接口(注意经常会报签名错误,请检查好自己生成的签名和微信的是否一致 https://pay.weixin.qq.com/wiki/tools/signverify/ 点击这个网址可以校验一下,微信生成的和自己生成的是否一致),统一下单接口返回成功后,用返回的参数再次签名,返回给小程序前端所需要的参数.代码如下:

public String userPay(Object object) {
		//开发者的订单信息
		OrderListVo orderListVo = new OrderListVo(;)
		//调统一下单接口
		Map unifiedOrderMap = unifiedOrder(orderListVo);
		//再次签名返回前端
		return signAgain(unifiedOrderMap);
	}
	
	/**
	 * 统一下单
	 * @param request
	 */
	public Map unifiedOrder(OrderListVo orderListVo) {
	     //统一下单url
		String url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
		SortedMap parameters = new TreeMap();
		//小程序的appid
		parameters.put("appid", WXPayConstants.AppID);
		// 此处传入openid(授权登录后获取的)
		parameters.put("openid", orderListVo.getOpenId());
		// 微信支付商户号
		parameters.put("mch_id", WXPayConstants.MCHID);
		// 随机字符串,用UUID生成
		String nonceStr = UniqueUtil.generateUUID();
		parameters.put("nonce_str", nonceStr);
		// 常量MD5
		parameters.put("sign_type", WXPayConstants.MD5);
		// 商品说明
		parameters.put("body", orderListVo.getGoodsName());
		// 商品详情
		parameters.put("detail", orderListVo.getGoodsDescribe());
		// 自定义订单号,不能超过32个字符
		parameters.put("out_trade_no", orderListVo.getOrderNo());
		// 标价金额:支付金额单位为【分】,参数值不能带小数
		//int price =  (int) (orderListVo.getPrice()*100);
		parameters.put("total_fee","1");
		// 终端IP:APP和网页支付提交用户端ip(存在反向代理,需获取用户真实ip)
		parameters.put("spbill_create_ip", "127.0.0.1");
		// 通知地址:此路径为接收微信支付结果通知的回调地址,通知url必须为外网可访问的url,不能携带参数
		parameters.put("notify_url", "www.baidu.com");
		// 交易类型:JSAPI 公众号支付   NATIVE 扫码支付   APP APP支付
		parameters.put("trade_type", "JSAPI");
		try {
			// 下单前签名(微信端会对其进行校验)
			parameters.put("sign", PayUtil.createSign("utf-8", parameters));
			// 将map转换为xml数据
			String xml = PayUtil.getRequestXml(parameters);
			// 发送post请求,返回xml数据
			String resp = PayUtil.httpsRequest(url, "POST", xml);
			Map unifiedOrderMap = XMLUtil.doXMLParse(resp);
			return unifiedOrderMap;
		} catch (Exception e) {
			logger.error("统一下单,失败", e);
			return null;
		}
	}
private String signAgain(Map unifiedOrderMap) {
		String returnCode = (String) unifiedOrderMap.get("return_code");
		String resultCode = (String) unifiedOrderMap.get("result_code");
		// 需要返回给页面的数据
		SortedMap returnMap = new TreeMap();
		try {
			if ("SUCCESS".equals(returnCode) && "SUCCESS".equals(resultCode)) {
				// 进行签名校验
				SortedMap map = new TreeMap();
				map.put("return_code", unifiedOrderMap.get("return_code"));
				map.put("return_msg", unifiedOrderMap.get("return_msg"));
				map.put("appid", unifiedOrderMap.get("appid"));
				map.put("mch_id", unifiedOrderMap.get("mch_id"));
				map.put("nonce_str", unifiedOrderMap.get("nonce_str"));
				map.put("result_code", unifiedOrderMap.get("result_code"));
				map.put("prepay_id", unifiedOrderMap.get("prepay_id"));
				map.put("trade_type", unifiedOrderMap.get("trade_type"));
				// 生成签名
				String mySign = PayCommonUtil.createSign("utf-8", map);
				// 微信返回的签名
				String wxSign = (String) unifiedOrderMap.get("sign");
				//签名校验
				if (mySign.equals(wxSign)) {
					returnMap.put("appId", unifiedOrderMap.get("appid"));
					returnMap.put("timeStamp", DatetimeUtil.getSecondTimestampTwo(new Date()) + "");
					returnMap.put("nonceStr", UniqueUtil.generateUUID());
					returnMap.put("package", "prepay_id=" + unifiedOrderMap.get("prepay_id"));
					returnMap.put("signType", WXPayConstants.MD5);
					// 此处生成的签名返回给页面作为参数
					returnMap.put("paySign",  PayUtil.createSign("utf-8", returnMap));
					return JSONObject.parseObject(JSONObject.toJSONString(returnMap)).toJSONString();
					// 签名校验成功,你可以在此处进行自己业务逻辑的处理
					// storeMap可以存储那些你需要存进数据库的信息,可以生成预支付订单
				}else {
					//logger.error("签名校验失败,下单返回信息为 --> {}"+ JSON.toJSONString(returnMap));
					// 签名校验失败,你可以在此处进行校验失败的业务逻辑
					return null;
				}
			}
		} catch (Exception e) {
			logger.error("用户支付,失败", e);
			return null;
		}
		return JSONObject.parseObject(JSONObject.toJSONString(returnMap)).toJSONString();
	}

所需要的工具类

package com.king.util;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.URL;
import java.security.MessageDigest;
import java.util.*;

import javax.net.ssl.HttpsURLConnection;
import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang.StringUtils;
import com.king.constants.WXPayConstants;

public class PayUtil {
	/**
	 * @Description:创建sign签名
	 * @param characterEncoding
	 *            编码格式
	 * @param map
	 *            请求参数
	 * @return
	 */
	public static String createSign(String characterEncoding, SortedMap 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();
			Object v = entry.getValue();
			if (null != v && !"".equals(v) && !"sign".equals(k) && !"key".equals(k))
			{
				sb.append(k + "=" + v + "&");
			}
		}
		sb.append("key=" + WXPayConstants.AppKey);
		String sign = md5Password(sb.toString());
		sign = sign.toUpperCase();
		return sign;
	}
	/**
	 * 生成32位md5码
	 *
	 * @param key
	 * @return
	 */
	public static String md5Password(String key) {
		char hexDigits[] = {
				'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
		};
		try {
			byte[] btInput = key.getBytes();
			// 获得MD5摘要算法的 MessageDigest 对象
			MessageDigest mdInst = MessageDigest.getInstance("MD5");
			// 使用指定的字节更新摘要
			mdInst.update(btInput);
			// 获得密文
			byte[] md = mdInst.digest();
			// 把密文转换成十六进制的字符串形式
			int j = md.length;
			char str[] = new char[j * 2];
			int k = 0;
			for (int i = 0; i < j; i++) {
				byte byte0 = md[i];
				str[k++] = hexDigits[byte0 >>> 4 & 0xf];
				str[k++] = hexDigits[byte0 & 0xf];
			}
			return new String(str);
		} catch (Exception e) {
			return null;
		}
	}

	/**
	 * @Description:将请求参数转换为xml格式的string
	 * @param map
	 *            请求参数
	 * @return
	 */
	public static String getRequestXml(SortedMap packageParams)
	{
		StringBuffer sb = new StringBuffer();
		sb.append(""); 
		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 ("attach".equalsIgnoreCase(k) || "body".equalsIgnoreCase(k))
			{
				sb.append("<" + k + ">" + "");
			} else
			{
				sb.append("<" + k + ">" + v + "");
			}
		}
		sb.append("");
		return sb.toString();
	}

	/**
	 * 发送https请求
	 * @param requestUrl 请求地址
	 * @param requestMethod 请求方式(GET、POST)
	 * @param data 提交的数据
	 * @return JSONObject(通过JSONObject.get(key)的方式获取json对象的属性值)
	 */
	public static String httpsRequest(String requestUrl, String requestMethod, String data) {
		InputStream inputStream = null;
		InputStreamReader inputStreamReader = null;
		BufferedReader bufferedReader = null;
		try {
			URL url = new URL(requestUrl);
			HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
			conn.setDoOutput(true);
			conn.setDoInput(true);
			conn.setUseCaches(false);
			// 设置请求方式(GET/POST)
			conn.setRequestMethod(requestMethod);
			conn.connect();
			// 当data不为null时向输出流写数据
			if (null != data) {
				// getOutputStream方法隐藏了connect()方法
				OutputStream outputStream = conn.getOutputStream();
				// 注意编码格式
				outputStream.write(data.getBytes("UTF-8"));
				outputStream.close();
			}
			// 从输入流读取返回内容
			inputStream = conn.getInputStream();
			inputStreamReader = new InputStreamReader(inputStream, "utf-8");
			bufferedReader = new BufferedReader(inputStreamReader);
			String str = null;
			StringBuffer buffer = new StringBuffer();
			while ((str = bufferedReader.readLine()) != null) {
				buffer.append(str);
			}
			conn.disconnect();
			return buffer.toString();
		} catch (Exception e) {
			return null;
		} finally {
			// 释放资源
			try {
				if(null != inputStream) {
					inputStream.close();
				}
				if(null != inputStreamReader) {
					inputStreamReader.close();
				}
				if(null != bufferedReader) {
					bufferedReader.close();
				}
			} catch (IOException e) {
			}
		}
	}

	/**
	 * 获取访问者IP
	 * 在一般情况下使用Request.getRemoteAddr()即可,但是经过nginx等反向代理软件后,这个方法会失效
	 * 本方法先从Header中获取X-Real-IP,如果不存在再从X-Forwarded-For获得第一个IP(用,分割),
	 * 如果还不存在则调用Request .getRemoteAddr()
	 * @param request
	 * @return
	 */
	public static String getIpAddr(HttpServletRequest request) {
		String ip = request.getHeader("X-Real-IP");
		if (!StringUtils.isBlank(ip) && !"unknown".equalsIgnoreCase(ip)) {
			return ip;
		}
		ip = request.getHeader("X-Forwarded-For");
		if (!StringUtils.isBlank(ip) && !"unknown".equalsIgnoreCase(ip)) {
			// 多次反向代理后会有多个IP值,第一个为真实IP。
			int index = ip.indexOf(',');
			if (index != -1) {
				return ip.substring(0, index);
			} else {
				return ip;
			}
		} else {
			return request.getRemoteAddr();
		}
	}
	public static void main(String[] args) {
		SortedMap parameters = new TreeMap();
		parameters.put("appid", "");
		// 此处传入openid
		parameters.put("openid", "");
		// 微信支付商户号
		parameters.put("mch_id","");
		System.out.println(createSign("utf-8", parameters));
		String xml = PayCommonUtil.getRequestXml(parameters);
		System.out.println(xml);
	}

}


解析XML解析工具(需要引入jar包)
pom文件加入


		jdom
		jdom
		1.0

package com.king.util;

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

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

/**
 * 解析微信XML字符穿
 */
public class XMLUtil {
    
	/**
	 * 解析xml,返回第一级元素键值对。如果第一级元素有子节点,则此节点的值是子节点的xml数据。
	 */
	@SuppressWarnings({ "rawtypes", "unchecked" })
	public static Map doXMLParse(String strxml) {
		
		Map m = new HashMap();
		
		try {
			strxml = strxml.replaceFirst("encoding=\".*\"", "encoding=\"UTF-8\"");

			if(null == strxml || "".equals(strxml)) {
				return null;
			}
			
			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();
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		} catch (JDOMException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		return m;
	}
	
	/**
	 * 获取子结点的xml
	 * @param children
	 * @return String
	 */
	@SuppressWarnings("rawtypes")
	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("");
			}
		}
		
		return sb.toString();
	}
	
    /**
     * 微信支付将请求参数转换为xml格式的String
     * 
     * @param parameters
     * @return
     */
    @SuppressWarnings("rawtypes")
    public static String getRequestXmlQuery(SortedMap paramMap) {
        StringBuffer sb = new StringBuffer();
        sb.append("");
        Set set = paramMap.entrySet();
        Iterator it = set.iterator();
        while (it.hasNext()) {
            Map.Entry entry = (Map.Entry) it.next();
            String key = (String) entry.getKey();
            String value = (String) entry.getValue();
            sb.append("<" + key + ">" + "");
        }
        sb.append("");
        return sb.toString();
    }
	
    /**
     * 微信支付将请求参数转换为xml格式的String
     * 
     * @param parameters
     * @return
     */
    @SuppressWarnings("rawtypes")
    public static String getRequestXml(SortedMap paramMap) {
        StringBuffer sb = new StringBuffer();
        sb.append("");
        Set set = paramMap.entrySet();
        Iterator it = set.iterator();
        while (it.hasNext()) {
            Map.Entry entry = (Map.Entry) it.next();
            String key = (String) entry.getKey();
            String value = (String) entry.getValue();
            if ("attach".equalsIgnoreCase(key) || "body".equalsIgnoreCase(key) || "sign".equalsIgnoreCase(key)) {
                sb.append("<" + key + ">" + "");
            } else {
                sb.append("<" + key + ">" + value + "");
            }
        }
        sb.append("");
        return sb.toString();
    }
	
}

以上就是支付前的内容,返回给前端需要的五个参数,前端调用微信支付,回调成功后,调用后台接口修改数据库支付状态.

内容可能有所欠缺,后续发现会修改

你可能感兴趣的:(java)