1. 程式人生 > >微信支付程式碼

微信支付程式碼

前言: 微信支付在實際應用中很常見,前段時間剛好業務需求設計微信支付,那麼這裡做下總結,個人總結,有不當之處還請參考正規文件;下面 是具體後端程式碼 和 方法工具類

package api.iruhua.controller;


import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


import javax.servlet.http.HttpServletRequest;


import org.apache.commons.lang3.StringUtils;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;


import com.haierp.model.sale.OuterOrderWxPay;
import com.haierp.service.IOuterOrderWxPayService;
import com.haierp.util.WxPay.MessageUtil;
import com.haierp.util.WxPay.PayUtil;
import com.haierp.util.WxPay.PaymentPo;
import com.haierp.util.WxPay.UUIDHexGenerator;


import net.sf.json.JSONObject;


@Controller
@RequestMapping("/wx/pay")
public class WxPayController {
private String total_fee;//總金額
    private String body;//商品描述
    private String detail;//商品詳情    
    private String attach;//附加資料
    private String time_start;//交易起始時間
    private String time_expire;//交易結束時間 
    private String openid;//使用者標識
    
    @Autowired
private IOuterOrderWxPayService outerOrderWxPayService;
    
    @RequestMapping("/unifiedorder")
@ResponseBody
    public Object pay(HttpServletRequest request) throws UnsupportedEncodingException, DocumentException{
        body = new String(request.getParameter("body").getBytes("UTF-8"), "ISO-8859-1");
        String appid = "wx56e36d38aff90280";//小程式ID
        String mch_id = "1486720292";//商戶號
        String nonce_str = UUIDHexGenerator.generate();//隨機字串
        String today = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
        String code = PayUtil.createCode(8);
        String out_trade_no = mch_id+today+code;//商戶訂單號
        String spbill_create_ip = request.getRemoteAddr();//終端IP
        String notify_url = "http://www.weixin.qq.com/wxpay/pay.php";//通知地址
        String trade_type = "JSAPI";//交易型別  
        String openid=request.getParameter("openId");//使用者標識


        //封裝支付引數
        PaymentPo paymentPo = new PaymentPo();


        paymentPo.setAppid(appid);
        paymentPo.setMch_id(mch_id);
        paymentPo.setNonce_str(nonce_str);
        String newbody=new String(body.getBytes("ISO-8859-1"),"UTF-8");//以utf-8編碼放入paymentPo,微信支付要求字元編碼統一採用UTF-8字元編碼
        paymentPo.setBody(newbody);
        paymentPo.setOut_trade_no(out_trade_no);
        paymentPo.setTotal_fee(request.getParameter("total_fee"));
        paymentPo.setSpbill_create_ip(spbill_create_ip);
        paymentPo.setNotify_url(notify_url);
        paymentPo.setTrade_type(trade_type);
        paymentPo.setOpenid(openid);


        // 把請求引數打包成Map
        Map<String, String> sParaTemp = new HashMap<String, String>();
        sParaTemp.put("appid", paymentPo.getAppid());
        sParaTemp.put("mch_id", paymentPo.getMch_id());
        sParaTemp.put("nonce_str", paymentPo.getNonce_str());
        sParaTemp.put("body",  paymentPo.getBody());
        sParaTemp.put("out_trade_no", paymentPo.getOut_trade_no());
        sParaTemp.put("total_fee",paymentPo.getTotal_fee());
        sParaTemp.put("spbill_create_ip", paymentPo.getSpbill_create_ip());
        sParaTemp.put("notify_url",paymentPo.getNotify_url());
        sParaTemp.put("trade_type", paymentPo.getTrade_type());
        sParaTemp.put("openid", paymentPo.getOpenid());


        // 除去Map中的空值和簽名引數
        Map<String, String> sPara = PayUtil.paraFilter(sParaTemp);
        String prestr = PayUtil.createLinkString(sPara); // 把Map所有元素,按照“引數=引數值”的模式用“&”字元拼接成字串
        String key = "&key=Iruha2017Iruha2018Iruha2019Iruha"; // 商戶支付金鑰
        //MD5運算生成簽名
        String mysign = PayUtil.sign(prestr, key, "utf-8").toUpperCase();
        paymentPo.setSign(mysign);
        //打包要傳送的xml
        String respXml = MessageUtil.messageToXML(paymentPo);
        // 列印respXml發現,得到的xml中有“__”不對,應該替換成“_”
        respXml = respXml.replace("__", "_");
        String url = "https://api.mch.weixin.qq.com/pay/unifiedorder";//統一下單API介面連結
        String param = respXml;
        String result =PayUtil.httpRequest(url, "POST", param);
        // 將解析結果儲存在HashMap中
        Map<String, String> map = new HashMap<String, String>();
        InputStream in=new ByteArrayInputStream(result.getBytes());  
        // 讀取輸入流
        SAXReader reader = new SAXReader();
        Document document = reader.read(in);
        // 得到xml根元素
        Element root = document.getRootElement();
        // 得到根元素的所有子節點
        @SuppressWarnings("unchecked")
        List<Element> elementList = root.elements();
        for (Element element : elementList) {
            map.put(element.getName(), element.getText());
        }
        // 返回資訊
        String return_code = map.get("return_code");//返回狀態碼
        String return_msg = map.get("return_msg");//返回資訊
        JSONObject JsonObject=new JSONObject() ;
        //請求成功
        if(return_code=="SUCCESS"||return_code.equals(return_code)){
            // 業務結果
            String prepay_id = map.get("prepay_id");//返回的預付單資訊
            String nonceStr=UUIDHexGenerator.generate();
            JsonObject.put("nonceStr", nonceStr);
            JsonObject.put("package", "prepay_id="+prepay_id);
            Long timeStamp= System.currentTimeMillis()/1000;
            JsonObject.put("timeStamp", timeStamp+"");
            String stringSignTemp = "appId="+appid+"&nonceStr=" + nonceStr + "&package=prepay_id=" + prepay_id+ "&signType=MD5&timeStamp=" + timeStamp;
            //再次簽名
            String paySign=PayUtil.sign(stringSignTemp, "&key=Iruha2017Iruha2018Iruha2019Iruha", "utf-8").toUpperCase();
            JsonObject.put("paySign", paySign);
            //商戶單號
            JsonObject.put("outTradeNo", out_trade_no);
        }
        
        if(StringUtils.isNotBlank(request.getParameter("orderInfo"))) {
        OuterOrderWxPay outerOrderWxPay = new OuterOrderWxPay();
            outerOrderWxPay.setWxPayTradeNo(out_trade_no);
            outerOrderWxPay.setOrderInfo(request.getParameter("orderInfo"));
            outerOrderWxPay.setStatus(0);
            outerOrderWxPay.setOpenId(openid);
            outerOrderWxPay.setGmtCreate(new Date());
            outerOrderWxPay.setGmtModify(new Date());
            outerOrderWxPayService.insert(outerOrderWxPay);
        }
        return JsonObject;
    }
public String getTotal_fee() {
return total_fee;
}
public void setTotal_fee(String total_fee) {
this.total_fee = total_fee;
}
public String getBody() {
return body;
}
public void setBody(String body) {
this.body = body;
}
public String getDetail() {
return detail;
}
public void setDetail(String detail) {
this.detail = detail;
}
public String getAttach() {
return attach;
}
public void setAttach(String attach) {
this.attach = attach;
}
public String getTime_start() {
return time_start;
}
public void setTime_start(String time_start) {
this.time_start = time_start;
}
public String getTime_expire() {
return time_expire;
}
public void setTime_expire(String time_expire) {
this.time_expire = time_expire;
}
public String getOpenid() {
return openid;
}
public void setOpenid(String openid) {
this.openid = openid;
}

public static void main(String[] args) throws UnsupportedEncodingException, DocumentException {
String appid = "wx56e36d38aff90280";//小程式ID
        String mch_id = "1486720292";//商戶號
        String nonce_str = UUIDHexGenerator.generate();//隨機字串
        String out_trade_no = "14867202922017092214472206842118";
        
        //封裝支付引數
        PaymentPo paymentPo = new PaymentPo();
        paymentPo.setAppid(appid);
        paymentPo.setMch_id(mch_id);
        paymentPo.setNonce_str(nonce_str);
        paymentPo.setOut_trade_no(out_trade_no);
        
        // 把請求引數打包成Map
        Map<String, String> sParaTemp = new HashMap<String, String>();
        sParaTemp.put("appid", paymentPo.getAppid());
        sParaTemp.put("mch_id", paymentPo.getMch_id());
        sParaTemp.put("nonce_str", paymentPo.getNonce_str());
        sParaTemp.put("out_trade_no", paymentPo.getOut_trade_no());
        
        // 除去Map中的空值和簽名引數
        Map<String, String> sPara = PayUtil.paraFilter(sParaTemp);
        String prestr = PayUtil.createLinkString(sPara); // 把Map所有元素,按照“引數=引數值”的模式用“&”字元拼接成字串
        String key = "&key=Iruha2017Iruha2018Iruha2019Iruha"; // 商戶支付金鑰
        //MD5運算生成簽名
        String mysign = PayUtil.sign(prestr, key, "utf-8").toUpperCase();
        paymentPo.setSign(mysign);
        //打包要傳送的xml
        String respXml = MessageUtil.messageToXML(paymentPo);
     // 列印respXml發現,得到的xml中有“__”不對,應該替換成“_”
        respXml = respXml.replace("__", "_");
        String url = "https://api.mch.weixin.qq.com/pay/orderquery";//統一下單API介面連結
        String param = respXml;
        String result =PayUtil.httpRequest(url, "POST", param);
        if(result.contains("<trade_state><![CDATA[SUCCESS]]></trade_state>")) {
        System.out.println("成功");
        } else {
        System.out.println("失敗");
        }
}

}

方法工具類:

package com.haierp.util.WxPay;


import java.net.InetAddress;


public class UUIDHexGenerator {
    private static String sep = "";


    private static final int IP;


    private static short counter = (short) 0;


    private static final int JVM = (int) (System.currentTimeMillis() >>> 8);


    private static UUIDHexGenerator uuidgen = new UUIDHexGenerator();


    static {
        int ipadd;
        try {
            ipadd = toInt(InetAddress.getLocalHost().getAddress());
        } catch (Exception e) {
            ipadd = 0;
        }
        IP = ipadd;
    }


    public static UUIDHexGenerator getInstance() {
        return uuidgen;
    }


    public static int toInt(byte[] bytes) {
        int result = 0;
        for (int i = 0; i < 4; i++) {
            result = (result << 8) - Byte.MIN_VALUE + (int) bytes[i];
        }
        return result;
    }


    protected static String format(int intval) {
        String formatted = Integer.toHexString(intval);
        StringBuffer buf = new StringBuffer("00000000");
        buf.replace(8 - formatted.length(), 8, formatted);
        return buf.toString();
    }


    protected static String format(short shortval) {
        String formatted = Integer.toHexString(shortval);
        StringBuffer buf = new StringBuffer("0000");
        buf.replace(4 - formatted.length(), 4, formatted);
        return buf.toString();
    }


    protected static int getJVM() {
        return JVM;
    }


    protected synchronized static short getCount() {
        if (counter < 0) {
            counter = 0;
        }
        return counter++;
    }


    protected static int getIP() {
        return IP;
    }


    protected static short getHiTime() {
        return (short) (System.currentTimeMillis() >>> 32);
    }


    protected static int getLoTime() {
        return (int) System.currentTimeMillis();
    }


    public static String generate() {
            return  new   StringBuffer(36).append(format(getIP())).append(sep).append(format(getJVM())).append(sep)
                .append(format(getHiTime())).append(sep).append(format(getLoTime())).append(sep)
                .append(format(getCount())).toString();
    }

}

package com.haierp.util.WxPay;


import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.SignatureException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


import com.wangzhixuan.commons.utils.DigestUtils;


public class PayUtil {
    /**
     * 簽名字串
     * @param text需要簽名的字串
     * @param key 金鑰
     * @param input_charset編碼格式
     * @return 簽名結果
     */
    public static String sign(String text, String key, String input_charset) {
        text = text + key;
        return DigestUtils.md5Hex(getContentBytes(text, input_charset));
    }


    /**
     * 簽名字串
     *  @param text需要簽名的字串
     * @param sign 簽名結果
     * @param key金鑰
     * @param input_charset 編碼格式
     * @return 簽名結果
     */
    public static boolean verify(String text, String sign, String key, String input_charset) {
        text = text + key;
        String mysign = DigestUtils.md5Hex(getContentBytes(text, input_charset));
        if (mysign.equals(sign)) {
            return true;
        } else {
            return false;
        }
    }


    /**
     * @param content
     * @param charset
     * @return
     * @throws SignatureException
     * @throws UnsupportedEncodingException
     */
    public static byte[] getContentBytes(String content, String charset) {
        if (charset == null || "".equals(charset)) {
            return content.getBytes();
        }
        try {
            return content.getBytes(charset);
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException("MD5簽名過程中出現錯誤,指定的編碼集不對,您目前指定的編碼集是:" + charset);
        }
    }


    /**
     * 生成6位或10位隨機數 param codeLength(多少位)
     * @return
     */
    public static String createCode(int codeLength) {
        String code = "";
        for (int i = 0; i < codeLength; i++) {
            code += (int) (Math.random() * 9);
        }
        return code;
    }


    private static boolean isValidChar(char ch) {
        if ((ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z'))
            return true;
        if ((ch >= 0x4e00 && ch <= 0x7fff) || (ch >= 0x8000 && ch <= 0x952f))
            return true;// 簡體中文漢字編碼
        return false;
    }


    /**
     * 除去陣列中的空值和簽名引數
     * @param sArray 簽名引數組
     * @return 去掉空值與簽名引數後的新簽名引數組
     */
    public static Map<String, String> paraFilter(Map<String, String> sArray) {
        Map<String, String> result = new HashMap<String, String>();
        if (sArray == null || sArray.size() <= 0) {
            return result;
        }
        for (String key : sArray.keySet()) {
            String value = sArray.get(key);
            if (value == null || value.equals("") || key.equalsIgnoreCase("sign")
                    || key.equalsIgnoreCase("sign_type")) {
                continue;
            }
            result.put(key, value);
        }
        return result;
    }


    /**
     * 把陣列所有元素排序,並按照“引數=引數值”的模式用“&”字元拼接成字串
     * @param params 需要排序並參與字元拼接的引數組
     * @return 拼接後字串
     */
    public static String createLinkString(Map<String, String> params) {
        List<String> keys = new ArrayList<String>(params.keySet());
        Collections.sort(keys);


        String prestr = "";


        for (int i = 0; i < keys.size(); i++) {
            String key = keys.get(i);
            String value = params.get(key);
            if (i == keys.size() - 1) {// 拼接時,不包括最後一個&字元
                prestr = prestr + key + "=" + value;
            } else {
                prestr = prestr + key + "=" + value + "&";
            }
        }
        return prestr;
    }
    /**
     * 
     * @param requestUrl請求地址
     * @param requestMethod請求方法
     * @param outputStr引數
     */
    public static String httpRequest(String requestUrl,String requestMethod,String outputStr){
        // 建立SSLContext
        StringBuffer buffer=null;
        try{
        URL url = new URL(requestUrl);
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        conn.setRequestMethod(requestMethod);
        conn.setDoOutput(true);
        conn.setDoInput(true);
        conn.connect();


        //往伺服器端寫內容
        if(null !=outputStr){
            OutputStream os=conn.getOutputStream();
            os.write(outputStr.getBytes("utf-8"));
            os.close();
        }
        // 讀取伺服器端返回的內容
        InputStream is = conn.getInputStream();
        InputStreamReader isr = new InputStreamReader(is, "utf-8");
        BufferedReader br = new BufferedReader(isr);
        buffer = new StringBuffer();
        String line = null;
        while ((line = br.readLine()) != null) {
                      buffer.append(line);
        }
        }catch(Exception e){
            e.printStackTrace();
        }
        return buffer.toString();
        }   
    public static String urlEncodeUTF8(String source){
        String result=source;
        try {
            result=java.net.URLEncoder.encode(source, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return result;
    }

}

package com.haierp.util.WxPay;

/**微信支付dto類**/
public class PaymentPo {
    private String appid;//小程式ID
    private String mch_id;//商戶號
    private String device_info;//裝置號
    private String nonce_str;//隨機字串
    private String sign;//簽名
    private String body;//商品描述  
    private String detail;//商品詳情    
    private String attach;//附加資料
    private String out_trade_no;//商戶訂單號
    private String fee_type;//貨幣型別
    private String spbill_create_ip;//終端IP
    private String time_start;//交易起始時間
    private String time_expire;//交易結束時間 
    private String goods_tag;//商品標記
    private String total_fee;//總金額
    private String notify_url;//通知地址    
    private String trade_type;//交易型別    
    private String limit_pay;//指定支付方式
    private String openid;//使用者標識
public String getAppid() {
return appid;
}
public void setAppid(String appid) {
this.appid = appid;
}
public String getMch_id() {
return mch_id;
}
public void setMch_id(String mch_id) {
this.mch_id = mch_id;
}
public String getDevice_info() {
return device_info;
}
public void setDevice_info(String device_info) {
this.device_info = device_info;
}
public String getNonce_str() {
return nonce_str;
}
public void setNonce_str(String nonce_str) {
this.nonce_str = nonce_str;
}
public String getSign() {
return sign;
}
public void setSign(String sign) {
this.sign = sign;
}
public String getBody() {
return body;
}
public void setBody(String body) {
this.body = body;
}
public String getDetail() {
return detail;
}
public void setDetail(String detail) {
this.detail = detail;
}
public String getAttach() {
return attach;
}
public void setAttach(String attach) {
this.attach = attach;
}
public String getOut_trade_no() {
return out_trade_no;
}
public void setOut_trade_no(String out_trade_no) {
this.out_trade_no = out_trade_no;
}
public String getFee_type() {
return fee_type;
}
public void setFee_type(String fee_type) {
this.fee_type = fee_type;
}
public String getSpbill_create_ip() {
return spbill_create_ip;
}
public void setSpbill_create_ip(String spbill_create_ip) {
this.spbill_create_ip = spbill_create_ip;
}
public String getTime_start() {
return time_start;
}
public void setTime_start(String time_start) {
this.time_start = time_start;
}
public String getTime_expire() {
return time_expire;
}
public void setTime_expire(String time_expire) {
this.time_expire = time_expire;
}
public String getGoods_tag() {
return goods_tag;
}
public void setGoods_tag(String goods_tag) {
this.goods_tag = goods_tag;
}
public String getTotal_fee() {
return total_fee;
}
public void setTotal_fee(String total_fee) {
this.total_fee = total_fee;
}
public String getNotify_url() {
return notify_url;
}
public void setNotify_url(String notify_url) {
this.notify_url = notify_url;
}
public String getTrade_type() {
return trade_type;
}
public void setTrade_type(String trade_type) {
this.trade_type = trade_type;
}
public String getLimit_pay() {
return limit_pay;
}
public void setLimit_pay(String limit_pay) {
this.limit_pay = limit_pay;
}
public String getOpenid() {
return openid;
}
public void setOpenid(String openid) {
this.openid = openid;
}
    
    
}

package com.haierp.util.WxPay;


import java.io.IOException;
import java.io.Writer;
import java.util.HashMap;
import java.util.List;


import javax.servlet.http.HttpServletRequest;


import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;


import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.core.util.QuickWriter;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
import com.thoughtworks.xstream.io.xml.PrettyPrintWriter;
import com.thoughtworks.xstream.io.xml.XppDriver;

/*資訊流整合工具類*/

public class MessageUtil {


    public static HashMap<String,String> parseXML(HttpServletRequest request) throws Exception, IOException{
        HashMap<String,String> map=new HashMap<String,String>();
        // 通過IO獲得Document
        SAXReader reader = new SAXReader();
        Document doc = reader.read(request.getInputStream());


        //得到xml的根節點
        Element root=doc.getRootElement();
        recursiveParseXML(root,map);
        return map;
    }
    private static void recursiveParseXML(Element root,HashMap<String,String> map){
        //得到根節點的子節點列表
        List<Element> elementList=root.elements();
        //判斷有沒有子元素列表
        if(elementList.size()==0){
            map.put(root.getName(), root.getTextTrim());
        }
        else{
            //遍歷
            for(Element e:elementList){
                recursiveParseXML(e,map);
            }
        }
    }
    private static XStream xstream = new XStream(new XppDriver() {
        public HierarchicalStreamWriter createWriter(Writer out) {
            return new PrettyPrintWriter(out) {
                // 對所有xml節點都增加CDATA標記
                boolean cdata = true;


                public void startNode(String name, Class clazz) {
                    super.startNode(name, clazz);
                }


                protected void writeText(QuickWriter writer, String text) {
                    if (cdata) {
                        writer.write("<![CDATA[");
                        writer.write(text);
                        writer.write("]]>");
                    } else {
                        writer.write(text);
                    }
                }
            };
        }
    });


    public static String messageToXML(PaymentPo paymentPo){
        xstream.alias("xml",PaymentPo.class);
        return xstream.toXML(paymentPo);
    }

}