欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

完整微信小程序支付代码+支付工具

程序员文章站 2022-07-13 17:08:39
...

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 com.haierp.util.PropertiesUtils;
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 = PropertiesUtils.getProperties().getProperty("wx.sale.appId");//小程序ID
    String mch_id = "1505845591";//商户号
    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 = PropertiesUtils.getProperties().getProperty("wx.sale.appId");//小程序ID
    String mch_id = "1505845591";//商户号
    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.model.sale;

import java.io.Serializable;
import java.util.Date;

import com.baomidou.mybatisplus.annotations.IdType;
import com.baomidou.mybatisplus.annotations.TableField;
import com.baomidou.mybatisplus.annotations.TableId;
import com.baomidou.mybatisplus.annotations.TableName;

@TableName(“outer_order_wx_pay”)
public class OuterOrderWxPay implements Serializable {
@TableId(type = IdType.AUTO)
private Long id;

@TableField(value = "wx_pay_trade_no")
private String wxPayTradeNo; // 微信支付商户订单号

@TableField(value = "order_info")
private String orderInfo;//订单明细

private Integer status;// 订单状态

@TableField(value = "open_id")
private String openId;//订单明细

@TableField(value = "gmt_create")
private Date gmtCreate;

@TableField(value = "gmt_modify")
private Date gmtModify;

public Long getId() {
    return id;
}
public void setId(Long id) {
    this.id = id;
}
public Integer getStatus() {
    return status;
}
public void setStatus(Integer status) {
    this.status = status;
}
public String getWxPayTradeNo() {
    return wxPayTradeNo;
}
public void setWxPayTradeNo(String wxPayTradeNo) {
    this.wxPayTradeNo = wxPayTradeNo;
}
public String getOrderInfo() {
    return orderInfo;
}
public void setOrderInfo(String orderInfo) {
    this.orderInfo = orderInfo;
}
public String getOpenId() {
    return openId;
}
public void setOpenId(String openId) {
    this.openId = openId;
}
public Date getGmtCreate() {
    return gmtCreate;
}
public void setGmtCreate(Date gmtCreate) {
    this.gmtCreate = gmtCreate;
}
public Date getGmtModify() {
    return gmtModify;
}
public void setGmtModify(Date gmtModify) {
    this.gmtModify = gmtModify;
}

}

// 微信支付信息工具类

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);
}

}

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;

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.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();
}

}