JAVA 微信公共号支付

由于上一篇博客中写到openid已经获取到 下面我们需要做的是微信公众号的支付

首先要做的事情是还是去微信公众号去配置

登录微信公众号之后点击左侧列表---微信支付----将商户号记下 ----登陆微信商户平台去将商户的key拿到-----点击微信支付中的开发设置

(这个授权目录的地址不是服务的地址而是你支付页面的地址的上一级)

例:

比如我的支付页面地址是http://域名 /MountainTourism/tshd/tshd.html

那么授权目录这块就写http://域名/MountainTourism/tshd/

做之前最好看一下微信支付的API

https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_7&index=6

里面有参数的详解

下面直接贴代码 只贴核心的代码

WeChatController.java

	/**
	 * 微信支付
	 * @author:wuqiwei
	 * @param @param request
	 * @param @param response
	 * @param @return
	 * @param @throws ServletException
	 * @param @throws IOException
	 * @date:2017年4月5日上午10:45:42
	 */
	@RequestMapping(value = "/WeChatPay",produces="text/html;charset=UTF-8;", method = RequestMethod.GET)
	public String WeChatPay(final HttpServletRequest request,final HttpServletResponse response) throws ServletException, IOException {
		//网页授权后获取传递的参数
        String money = request.getParameter("money");//分为单位
        //金额转化为分为单位
//        float sessionmoney = Float.parseFloat(money);
//        String finalmoney = String.format("%.2f", sessionmoney);
//        finalmoney = finalmoney.replace(".", "");
//        System.out.println("money"+finalmoney);
		String openid = request.getParameter("openId");
//		System.out.println("openid"+openid);
          String outTradeNum = System.currentTimeMillis() + ""; // 商户订单号
          Map<String, String> wxPayParamMap = null;
          try {
              wxPayParamMap = WXJSPay.jsApiPay(openid, money, outTradeNum,UUID.randomUUID().toString()); // 测试金额为1分钱
          } catch (JDOMException e) {
              e.printStackTrace();
          }
          JSONObject json = JSONObject.fromObject(wxPayParamMap); 
          String result = json.toString();
          System.out.println(result);
          return result;
	}
WXJSPay.java

package com.htht.tourism.utils;

import java.io.IOException;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;

import org.jdom.JDOMException;


/**
 * 
 * 调起微信jsapi
 */
public final class WXJSPay {
    private WXJSPay() {
        throw new Error("工具类不能实例化!");
    }

    /**
     * 调起微信jsapi
     */
    @SuppressWarnings("rawtypes")
    public static Map jsApiPay(final String openid, final String totalFee, final String outTradeNum,
          final String callbackid) throws JDOMException, IOException {
        String noceStr = Sha1Util.getNonceStr(); // 随机字符串
        String timeStamp = Sha1Util.getTimeStamp(); // 时间戳
        // 接口package部分-内容----------------------------------------------------------
        TreeMap<String, String> contentMap = new TreeMap<String, String>();
        contentMap.put("appid", ConfigUtil.getProperty("WeChat","appid")); // 公众账号 ID
        contentMap.put("mch_id",ConfigUtil.getProperty("WeChat","mch_id")); // 商户号
        contentMap.put("nonce_str", noceStr); // 随机字符串
        contentMap.put("body", ConfigUtil.getProperty("WeChat","body")); // 商品描述
        contentMap.put("out_trade_no", outTradeNum); // 商户订单号
        contentMap.put("total_fee", totalFee); // 订单总金额
        contentMap.put("spbill_create_ip", ConfigUtil.getProperty("WeChat","spbill_create_ip")); // 订单生成的机器IP
        contentMap.put("notify_url",ConfigUtil.getProperty("WeChat","notify_url")); // 通知地址
                                                                                   // 不同类型的订单回调地址不一样,根据type来确定
        contentMap.put("trade_type", ConfigUtil.getProperty("WeChat","trade_type_js")); // 交易类型
        contentMap.put("attach", callbackid); // 订单数据预存的id
        contentMap.put("openid", openid); // 用户标识
        String wxpackage = WeiXinSignAndPackage.createPackage("UTF-8",contentMap);
        contentMap.put("sign", wxpackage);
        String result = WeiXinSignAndPackage.getPrepayId(contentMap); // 调用统一接口返回的值
        System.err.println(result);
        Map<String, String> map = XMLUtil.doXMLParse(result); // 调用统一接口返回的值转换为XML格式
        System.out.println(map);
        System.out.println("---------------------");
        SortedMap<Object, Object> wxPayParamMap = new TreeMap<Object, Object>();
        wxPayParamMap.put("appId",ConfigUtil.getProperty("WeChat","appid"));
        wxPayParamMap.put("timeStamp", timeStamp);
        wxPayParamMap.put("nonceStr", noceStr);
        wxPayParamMap.put("package", "prepay_id=" + map.get("prepay_id"));
        wxPayParamMap.put("signType",ConfigUtil.getProperty("WeChat","signType"));
        String paySign = WeiXinSignAndPackage.createPaySign("UTF-8",wxPayParamMap); // 支付得到的签名
        wxPayParamMap.put("paySign", paySign);
        wxPayParamMap.put("payMoney", totalFee); // 到前段显示使用,支付不需要此参数
        return wxPayParamMap;
    }

    /**
     * 测试主函数
     */
    public static void main(final String[] args) {
    	String outTradeNum = System.currentTimeMillis() + ""; // 商户订单号
    	System.out.println(outTradeNum);
        try {
            jsApiPay("wx561844b33b2fd788", "1000", "12313", "id");
        } catch (JDOMException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
WeiXinSignAndPackage.java(创建支付包Package、创建支付签名paysign)

package com.htht.tourism.utils;

import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;

/**
 * 
 * 创建支付包Package
 *
 */
public final class WeiXinSignAndPackage {
    private WeiXinSignAndPackage() {
        throw new Error("工具类不能实例化!");
    }

    /**
     * 创建支付包Package
     * 
     * @param treeMap
     * @return
     */
    public static String createPackage(String characterEncoding, SortedMap<String, String> parameters) {
//        String string1 = originalString(treeMap);
//        String stringSignTemp = string1 + "key=" + ConfigUtil.getProperty("WeChat","paternerKey");
//        String sign = MD5Util.md5Encode(stringSignTemp, ConfigUtil.getProperty("WeChat","input_charset")).toUpperCase();
//        return sign;
    	 StringBuffer sb = new StringBuffer();
         Set es = parameters.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=" + ConfigUtil.getProperty("WeChat","paternerKey"));
         String sign = MD5Util.md5Encode(sb.toString(), characterEncoding).toUpperCase();
         return sign;
    }

    /**
     * 创建支付签名paysign
     * 
     * @param wxpackage
     * @return
     */
    public static String createPaySign(String characterEncoding, SortedMap<Object, Object> parameters) {
//        String string1 = originalString(param);
//        String stringSignTemp = string1 + "key=" + ConfigUtil.getProperty("WeChat","paternerKey");
//        System.out.println("签名调试输出:" + stringSignTemp);
//        String paysign = MD5Util.md5Encode(stringSignTemp, ConfigUtil.getProperty("WeChat","input_charset")).toUpperCase();
//        return paysign;
    	 StringBuffer sb = new StringBuffer();
         Set es = parameters.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=" + ConfigUtil.getProperty("WeChat","paternerKey"));
         String sign = MD5Util.md5Encode(sb.toString(), characterEncoding).toUpperCase();
         return sign;
    }

    /**
     * wxpackage组装原始串
     * 
     * @param treeMap
     * @return
     */
    private static String originalString(final TreeMap<String, String> treeMap) {
        Set<Entry<String, String>> entry = treeMap.entrySet();
        StringBuffer sb = new StringBuffer();
        for (Entry<String, String> obj : entry) {
            String k = obj.getKey();
            String v = obj.getValue();
            if (v == null && "".equals(v)) {
                continue;
            }
            sb.append(k + "=" + v + "&");
        }
        return sb.toString();
    }

    /**
     * 原url
     */
    @SuppressWarnings("unused")
    private static String originalURLString(final TreeMap<String, String> treeMap) {
        Set<Entry<String, String>> entry = treeMap.entrySet();
        StringBuffer sb = new StringBuffer();
        try {
            for (Entry<String, String> obj : entry) {
                String k = obj.getKey();
                String v = obj.getValue();
                if (v == null && "".equals(v)) {
                    continue;
                }
                sb.append(k.toLowerCase() + "=" + URLEncoder.encode(v,ConfigUtil.getProperty("WeChat","input_charset")) + "&");
            }
        } catch (Exception e) {
        }
        return sb.toString();
    }

    /**
     * 创建微信支付订单号
     * 
     * @return
     */
    public static String getOutTradeNo() {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddhhmmss");
        String body = String.valueOf((int) (Math.random() * ConstantNumbers.NUMBER_100000000));
        String outTradeNo = "WXP" + sdf.format(new Date()) + body;
        System.out.println("创建支付订单号:" + outTradeNo);
        return outTradeNo;
    }

    /**
     * 创建格式为yyyyMMddHHmmss的当前时间串
     * 
     * @return
     */
    public static String getNowTime() {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
        return sdf.format(new Date());
    }

    /**
     * 是否财付通签名,规则是:按参数名称a-z排序,遇到空值的参数不参加签名。
     */
    public static synchronized boolean isValidSign(final TreeMap<String, String> treeMap) {
        Set<Entry<String, String>> entry = treeMap.entrySet();
        StringBuffer sb = new StringBuffer();
        String signback = null;
        String inputCharset = null;
        for (Entry<String, String> obj : entry) {
            String k = obj.getKey();
            String v = obj.getValue();
            if (v == null && "".equals(v)) {
                continue;
            }
            if (k.equals("sign")) {
                signback = v;
                continue;
            }
            sb.append(k.toLowerCase() + "=" + v + "&");
        }
        String string1 = sb.toString();
        String stringSignTemp = string1 + "key=" + ConfigUtil.getProperty("WeChat","paternerKey");//商户支付密钥
        System.out.println("程序计算签名串:" + stringSignTemp);
        String sign = MD5Util.md5Encode(stringSignTemp, inputCharset).toUpperCase();
        System.out.println("程序计算财付通签名:" + sign);
        System.out.println("系统返回签名:" + signback);
        if (sign.equals(signback)) {
            System.out.println("DeBug财付通签名比对结果:TRUE");
            return true;
        } else {
            System.out.println("DeBug财付通签名比对结果:FALSE");
            return false;
        }
    }

    /**
     * 判断微信签名
     * 
     * @param treeMap
     * @return
     */
    public static synchronized boolean isWXSign(final TreeMap<String, String> treeMap) {
        Set<Entry<String, String>> entry = treeMap.entrySet();
        StringBuffer sb = new StringBuffer();
        String appSignature = null;
        for (Entry<String, String> obj : entry) {
            String k = obj.getKey();
            String v = obj.getValue();
            if (v == null && "".equals(v)) {
                continue;
            }
            if (k.equals("AppSignature")) {
                appSignature = v;
                continue;
            }
            if (k.equals("SignMethod")) {
                continue;
            }
            sb.append(k.toLowerCase() + "=" + v + "&");
        }
        String paysign = sb.toString();
        paysign = paysign.substring(0, paysign.length() - 1);
        System.out.println("\n\n程序计算微信签名串:" + paysign);
        paysign = Sha1Util.getSha1(paysign);
        System.out.println("程序计算微信签名结果:" + paysign);
        System.out.println("微信返回签名结果:" + appSignature);
        if (paysign.equals(appSignature)) {
            System.out.println("DeBug微信签名比对结果:TRUE");
            return true;
        } else {
            System.out.println("DeBug微信签名比对结果:FALSE");
            return false;
        }
    }

    /**
     * map转换
     */
    public static TreeMap<String, String> mapToTreeMap(final Map<Object, Object> map) {
        TreeMap<String, String> treeMap = new TreeMap<String, String>();
        Set<Entry<Object, Object>> entry = map.entrySet();
        for (Entry<Object, Object> key : entry) {
            treeMap.put(key.getKey().toString(), ((String[]) key.getValue())[0].toString());
        }
        return treeMap;
    }

    /**
     *map转换
     */
    public static TreeMap<String, String> strmapToTreeMap(final Map<String, String> map) {
        TreeMap<String, String> treeMap = new TreeMap<String, String>();
        Set<Entry<String, String>> entry = map.entrySet();
        for (Entry<String, String> key : entry) {
            treeMap.put(key.getKey().toString(), key.getValue().toString());
        }
        return treeMap;
    }

    /**
     * 获取PrepayId
     */
    public static String getPrepayId(final TreeMap<String, String> payParamMap) {
        String result = HttpTool.sendPost(ConfigUtil.getProperty("WeChat","prepay_id_url"), payParamMap, ConfigUtil.getProperty("WeChat","input_charset"));
        return result;
    }
}

xml工具类

XMLUtil.java

package com.htht.tourism.utils;
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 java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;

import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;

/**
 * xml工具类
 *
 */
public final class XMLUtil {

    private XMLUtil() {
        throw new Error("工具类不能实例化!");
    }

    /**
     * 解析request流对象InputStream 解析xml,返回第一级元素键值对。如果第一级元素有子节点,则此节点的值是子节点的xml数据。
     */
    @SuppressWarnings("all")
    public static Map<String, String> doXMLParse(final HttpServletRequest request) throws JDOMException, IOException {
        Map<String, String> m = new HashMap<String, String>();
        SAXBuilder builder = new SAXBuilder();
        ServletInputStream in = request.getInputStream();
        Document doc = builder.build(in);
        Element root = doc.getRootElement();
        List<Object> list = root.getChildren();
        Iterator<Object> 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;
    }

    /**
     * 解析String类型的xml流对象InputStream
     * 解析xml,返回第一级元素键值对。如果第一级元素有子节点,则此节点的值是子节点的xml数据。
     */
    @SuppressWarnings("all")
    public static Map<String, String> doXMLParse(final String strxml) throws JDOMException, IOException {
        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
     */
    @SuppressWarnings("all")
    private static String getChildrenText(final 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();
    }

    /**
     * 将请求参数转换为xml格式的string
     * 通知微信.异步确认成功.必写.不然会一直通知后台.八次之后就认为交易失败了.
     * 
     */
    @SuppressWarnings("all")
    public static String getRequestXml(final SortedMap<String, String> 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();
    }

    /**
     * main
     */
    public static void main(final String[] arg) {
        SortedMap<String, String> sm = new TreeMap<String, String>();
        sm.put("SUCCESS", "OK");
        String ss = getRequestXml(sm);
        System.out.println(ss);
    }

}
Sha1Util.java('api说明: 'createSHA1Sign创建签名SHA1 'getSha1()Sha1签名)

package com.htht.tourism.utils;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;

/**
 * 请求校验工具类
 * 
 * @author 简爱微萌
 * @Email zyw205@gmial.com
 * 
 */
public class SignUtil {
    // 与接口配置信息中的Token要一致
    private static String token = "htht2xsly";

    /**
     * 验证签名
     * 
     * @param signature
     * @param timestamp
     * @param nonce
     * @return
     */
    public static boolean checkSignature(String signature, String timestamp,
            String nonce) {
        String[] arr = new String[] { token, timestamp, nonce };
        // 将token、timestamp、nonce三个参数进行字典序排序
        //Arrays.sort(arr);
        sort(arr);
        StringBuilder content = new StringBuilder();
        for (int i = 0; i < arr.length; i++) {
            content.append(arr[i]);
        }
        MessageDigest md = null;
        String tmpStr = null;

        try {
            md = MessageDigest.getInstance("SHA-1");
            // 将三个参数字符串拼接成一个字符串进行sha1加密
            byte[] digest = md.digest(content.toString().getBytes());
            tmpStr = byteToStr(digest);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }

        content = null;
        // 将sha1加密后的字符串可与signature对比,标识该请求来源于微信
        return tmpStr != null ? tmpStr.equals(signature.toUpperCase()) : false;
    }

    /**
     * 将字节数组转换为十六进制字符串
     * 
     * @param byteArray
     * @return
     */
    private static String byteToStr(byte[] byteArray) {
        String strDigest = "";
        for (int i = 0; i < byteArray.length; i++) {
            strDigest += byteToHexStr(byteArray[i]);
        }
        return strDigest;
    }

    /**
     * 将字节转换为十六进制字符串
     * 
     * @param mByte
     * @return
     */
    private static String byteToHexStr(byte mByte) {
        char[] Digit = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A',
                'B', 'C', 'D', 'E', 'F' };
        char[] tempArr = new char[2];
        tempArr[0] = Digit[(mByte >>> 4) & 0X0F];
        tempArr[1] = Digit[mByte & 0X0F];

        String s = new String(tempArr);
        return s;
    }

    public static void sort(String a[]) {
        for (int i = 0; i < a.length - 1; i++) {
            for (int j = i + 1; j < a.length; j++) {
                if (a[j].compareTo(a[i]) < 0) {
                    String temp = a[i];
                    a[i] = a[j];
                    a[j] = temp;
                }
            }
        }
    }
}
回调方法

WeChatController.java

 /**
     * 支付回调
     * 
     * @throws IOException
     * @throws JDOMException
     */
    @RequestMapping(value = "callback", method = RequestMethod.POST)
    public void callback(final HttpServletRequest request, final HttpServletResponse response) throws JDOMException {
        try {
            InputStream inStream = request.getInputStream();
            ByteArrayOutputStream outSteam = new ByteArrayOutputStream();
            byte[] buffer = new byte[1024];
            int len = 0;
            while ((len = inStream.read(buffer)) != -1) {
                outSteam.write(buffer, 0, len);
            }
            outSteam.close();
            inStream.close();
            String resultStr = new String(outSteam.toByteArray(), "utf-8");
            Map<String, String> resultMap = XMLUtil.doXMLParse(resultStr);
            String outTradeNo = resultMap.get("out_trade_no");
            String transactionId = resultMap.get("transaction_id"); // 微信支付订单号
            // String sign = resultMap.get("sign");
            String returnCode = resultMap.get("return_code"); // 签名验证
            String openid = resultMap.get("openid"); // 用户标识
            if (returnCode.equals("SUCCESS")) {
                SortedMap<String, String> sm = new TreeMap<String, String>();
                sm.put("return_code", "SUCCESS"); // 告诉微信服务器,我收到信息了,不要在调用回调action了,
                sm.put("return_msg", "OK");
                String backString = XMLUtil.getRequestXml(sm);
                response.getWriter().write(backString); // 通知微信.异步确认成功.必写.不然会一直通知后台.八次之后就认为交易失败了.
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
以上代码就是Java后台的核心代码 将程序中的appid 及商户id等一些信息 换成你们自己的信息就可以

前端的代码就不贴了 微信官网有看一下就知道了

总结:由于我也是第一次做,写这篇文章是想记录一下自己的工作成果,和分享给一下也是新手的朋友们可以有一些帮助,最后希望有好的见解朋友可以留言讨论,大家一起学习进步。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值