微信支付代码的java封装

来源:互联网 发布:ecshop sql 编辑:程序博客网 时间:2024/06/05 04:36

最近的项目在处理前任留下的微信支付,应为没有进行封装,很难重用,所有自己花了点时间整理了一下,做成工具类和帮助类,方便别人不一定,但方便自己是肯定的。贴出来交流一下。

以下是一些代码,其中用到的一些包要自己去下载了。

package com.test.weixin.help;import java.util.Date;import java.util.HashMap;import java.util.Map;import java.util.TreeMap;import org.apache.log4j.Logger;import com.test.weixin.util.SignUtil;import com.test.weixin.util.UrlUtil;import com.test.weixin.util.XMLUtil;public class PayHelper {private static Logger log = org.apache.log4j.Logger.getLogger(PayHelper.class);/** * 统一下单请求地址 */public static final String UNIFIEDORDER_URL = "https://api.mch.weixin.qq.com/pay/unifiedorder";/** * tradeType 下单类型:JSAPI--公众号支付 */public static final String TRADE_TYPE_JSAPI = "JSAPI";/** * tradeType 下单类型:APP--app支付 */public static final String TRADE_TYPE_APP = "APP";/** * tradeType 下单类型NATIVE--原生扫码支付 */public static final String TRADE_TYPE_NATIVE = "NATIVE";private String appId = null;private String mchId = null;private String mchKey = null;public PayHelper(String appId, String mchId,String mchKey) {this.appId = appId;this.mchId = mchId;this.mchKey = mchKey;}/** * 公众号统一下单  * @param openId * @param fee * @param tradeNo * @param notifyUrl * @param ip * @param body * @param more 更多参数参见微信文档 * @return * @throws Exception */public String unifiedH5(String openId,int fee,String tradeNo,String notifyUrl,String ip,String body,Map<String,String> more)throws Exception{Map<String,String> map = new HashMap<String, String>();map.put("openid",openId);map.put("total_fee",String.valueOf(fee));map.put("out_trade_no",tradeNo);map.put("notify_url",notifyUrl);map.put("spbill_create_ip",ip);map.put("body",body);if(null!=more){map.putAll(more);}return unified(TRADE_TYPE_JSAPI,map);}/** * 根据预支付id 生成包含所有必须参数的map对象 * @param prepayId * @return * @throws Exception */public Map<String,String> getClientPrepayMap(String prepayId)throws Exception{Map<String,String> map = new HashMap<String,String>();map.put("appId",appId);map.put("timeStamp",String.valueOf(new Date().getTime()/1000));map.put("nonceStr",SignUtil.randomStr(16));map.put("package","prepay_id="+prepayId);map.put("signType","MD5");String sign = unifiedSign(map,mchKey,SignUtil.SIGN_TYPE_MD5);map.put("paySign",sign);return map;}/** * 统一下单签名 * @param map map只关心业务参数即可,随机字符串,sign签名后在方法内部加入map对象中 * @param key * @return 签名字符串 * @throws Exception */public String unifiedSign(Map<String,String> map,String key,String signType)throws Exception{TreeMap<String,String> treeMap = new TreeMap<String, String>(map);treeMap.remove("key");StringBuilder sb = new StringBuilder();for(Map.Entry<String,String> e:treeMap.entrySet()){String v = e.getValue();if(null==v||"null".equalsIgnoreCase(v)||"".equals(v)){continue;}sb.append("&").append(e.getKey()).append("=").append(e.getValue());}String data = sb.substring(1);if(null!=key){ data += "&key="+key;}log.debug("统一下单(使用"+signType+")签名字符串:"+data);String sign = SignUtil.sign(data,signType).toUpperCase();return sign;}/** * 统一下单,返回预支付id * @param tradeType 下单类型:JSAPI--公众号支付、NATIVE--原生扫码支付、APP--app支付, * @param payParas * @return * @throws Exception */private String unified(String tradeType,Map<String,String> payParas)throws Exception{String prepayId = "";Map<String,String> map = new HashMap<String, String>(payParas);map.put("appid",appId);map.put("mch_id",mchId);map.put("trade_type",tradeType);map.put("nonce_str",SignUtil.randomStr(16));String sign = unifiedSign(map,mchKey,SignUtil.SIGN_TYPE_MD5);map.put("sign",sign);String postXML = XMLUtil.getXML(map);String str = UrlUtil.urlPost(UNIFIEDORDER_URL,postXML);log.debug(tradeType+"请求预支付返回结果:"+str);Map<String,String> result =XMLUtil.parserXML(str);prepayId = result.get("prepay_id");if(null==prepayId){throw new Exception("获取预支付id失败");}return prepayId;}}

上面只是完成了公众号支付的方法 unifiedH5(),如果需要更多的支付,如:小程序,App或者微信原生支付,可以自行添加方法,在方法内部完成所需参数的封装后调私有方法unified,并指定正确的trade_type参数即可。



下面是几个用到的工具包,本人能力有限,参考了大量网上的代码。

package com.test.weixin.util;import java.security.MessageDigest;import java.util.Random;/** *  * @author Wayne.Lee * @date 2017/09/20 */public class SignUtil {public static final String SIGN_TYPE_MD5 = "MD5";public static final String SIGN_TYPE_SHA1 = "SHA-1";private static String[] keys =new String[]{"0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f"};public static String signSHA1(String data)throws Exception{return sign(data,SIGN_TYPE_SHA1);}public static String signMD5(String data)throws Exception{return sign(data,SIGN_TYPE_MD5);}/** * 返回指定长度的随机字符串 * @param length * @return */public static String randomStr(int length){    //随机字符串的随机字符库    String KeyString = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";    StringBuffer sb = new StringBuffer();    Random random = new Random();    int len = KeyString.length();    for (int i = 0; i < length; i++) {       sb.append(KeyString.charAt(random.nextInt(len)));    }    return sb.toString();}public static String sign(String data,String signName)throws Exception{//指定sha1算法      MessageDigest digest = MessageDigest.getInstance(signName);      digest.update(data.getBytes());      //获取字节数组      byte messageDigest[] = digest.digest();      // Create Hex String      StringBuilder hexString = new StringBuilder();      // 字节数组转换为 十六进制 数      for (int i = 0,len = messageDigest.length; i < len; i++) {         byte b = messageDigest[i];       String s = keys[b&0xF];       String p = keys[(b>>4)&0xF];       hexString.append(p).append(s);    }      return hexString.toString();}public static void main(String[] args)throws Exception {System.out.println(SignUtil.sign("123456","SHA-1"));System.out.println(SignUtil.sign("123456","MD5"));System.out.println(SignUtil.sign("123456","SHA-256"));System.out.println(SignUtil.sign("123456","SHA-512"));}}package com.test.weixin.util;import org.apache.commons.httpclient.HttpClient;import org.apache.commons.httpclient.methods.GetMethod;import org.apache.commons.httpclient.methods.PostMethod;public class UrlUtil {public static String urlGet(String url)throws Exception{ GetMethod get = new GetMethod(url);     HttpClient httpClient = new HttpClient();     get.getParams().setContentCharset("utf-8");     httpClient.executeMethod(get);        return get.getResponseBodyAsString();}public static String urlPost(String url,String postBody)throws Exception{ PostMethod post = new PostMethod(url);     HttpClient httpClient = new HttpClient();     post.getParams().setContentCharset("utf-8");     post.setRequestBody(postBody);     httpClient.executeMethod(post);        return post.getResponseBodyAsString();}}package com.test.weixin.util;import java.io.ByteArrayInputStream;import java.util.LinkedHashMap;import java.util.Map;import java.util.TreeMap;import javax.xml.parsers.DocumentBuilder;import javax.xml.parsers.DocumentBuilderFactory;import org.w3c.dom.Document;import org.w3c.dom.Element;import org.w3c.dom.Node;import org.w3c.dom.NodeList;/** * 微信支付工具类,处理xml数据 * @author Wayne.Lee * @date 2017/09/20 * */public class XMLUtil {        /**     * 根据参数xml转换为map对象,基于微信支付,不做深层处理     * @param xml     * @return     * @throws Exception     */    public static Map<String,String> parserXML(String xml)throws Exception{                DocumentBuilder doc = DocumentBuilderFactory.newInstance().newDocumentBuilder();                Document d = doc.parse(new ByteArrayInputStream(xml.getBytes()));        Element el = d.getDocumentElement();        NodeList list = el.getChildNodes();        Map<String,String> map = new LinkedHashMap<String,String>();        for(int i=0,len=list.getLength();i<len;i++){            Node n = list.item(i);            if(n.hasChildNodes()){                Node f = n.getFirstChild();                short ft =f.getNodeType();                            if(ft==Node.CDATA_SECTION_NODE||ft==Node.TEXT_NODE){                    map.put(n.getNodeName(),f.getNodeValue());                }            }        }                    return map;    }            /**     * 将map转换为xml数据,偷懒处理,全部数据都用<![CDATA[]]>包装     * @param map     * @return     * @throws Exception     */    public static String getXML(Map<String,String> map)throws Exception{        StringBuilder sb = new StringBuilder("<xml>");        for(Map.Entry<String,String> en:map.entrySet()){            String key = en.getKey();            sb.append("<"+key+"><![CDATA[");            sb.append(en.getValue());            sb.append("]]></"+key+">");        }        return sb.append("</xml>").toString();    }    }


在使用微信支付时,可以使用如下方式:

@RequestMapping("/pay")
    @ResponseBody
    public Map<String,String> pay(HttpServletRequest request){
        try{
            //此处通过request获取相应的参数
            //....................
            
            //"appId","mchId","mchKey"初始化支付对象
            PayHelper payHelper = new PayHelper("appId","mchId","mchKey");
            
            //公众号统一支付,获取预支付id
            String prepayId = payHelper.unifiedH5("openId",100,"tradeNo","notifyUrl","ip","body",new HashMap<String,String>());
            
            //生成包括签名的map对象到前端(json),有公众号中完成支付
            Map<String,String> json = payHelper.getClientPrepayMap(prepayId);
        
            return json;
            
        }catch(Exception e){
            Map<String,String> errorMap = new HashMap<String, String>();
            errorMap.put("errcode","-1");
            errorMap.put("msg","预支付失败");
            return errorMap;
        }
    }









原创粉丝点击