开始之前,先准备好:appid、商家号、商户密匙。

工具类:

MD5Util.java

 1 package com.yiexpress.core.utils.wechat;
 2
 3 import java.security.MessageDigest;
 4
 5 /**
 6  * MD5工具类
 7  */
 8 public class MD5Util {
 9     public final static String MD5(String s) {
10         char hexDigits[]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
11
12         try {
13             byte[] btInput = s.getBytes();
14
15             MessageDigest mdInst = MessageDigest.getInstance("MD5");
16
17             mdInst.update(btInput);
18
19             byte[] md = mdInst.digest();
20
21             int j = md.length;
22             char str[] = new char[j * 2];
23             int k = 0;
24             for (int i = 0; i < j; i++) {
25                 byte byte0 = md[i];
26                 str[k++] = hexDigits[byte0 >>> 4 & 0xf];
27                 str[k++] = hexDigits[byte0 & 0xf];
28             }
29             String md5Str = new String(str);
30             return md5Str;
31         } catch (Exception e) {
32             e.printStackTrace();
33             return null;
34         }
35     }
36 }  

SapUtils.java

  1 package com.yiexpress.core.utils;
  2 import java.lang.reflect.*;
  3 import java.util.List;
  4 import java.io.IOException;
  5 import java.io.StringWriter;
  6
  7 import org.dom4j.Document;
  8 import org.dom4j.DocumentHelper;
  9 import org.dom4j.Element;
 10 import org.dom4j.io.OutputFormat;
 11 import org.dom4j.io.XMLWriter;
 12 import org.slf4j.Logger;
 13 import org.slf4j.LoggerFactory;
 14 import org.springframework.util.StringUtils;
 15
 16
 17 public class SapUtils {
 18     private static final Logger logger = LoggerFactory.getLogger(SapUtils.class);
 19     /** 根据反射对javabean转成xml文件的格式
 20      * 以类名为第一标签,所有属性作为第二节点,并放入对应的值,如果属性为空 就不放入该熟悉
 21      * @param dto 传入的对象
 22      * @param operationName 操作名称
 23      * @return
 24      */
 25     public static String formatToXml(Object dto,String operationName){
 26         logger.info("解析当前类{}为指定的xml文档格式的数据",dto.getClass().getName());
 27         logger.info("当前的同步方法是,{}",operationName);
 28         String result = null;
 29         Field fields[]=dto.getClass().getDeclaredFields();//dto 是实体类名称
 30         //DocumentHelper提供了创建Document对象的方法
 31         Document document = DocumentHelper.createDocument();
 32
 33         //添加节点信息
 34          String className=dto.getClass().getName();
 35          // 操作的名称
 36         Element rootElement = document.addElement(operationName);
 37         try {
 38             Field.setAccessible(fields, true);
 39             for (int i = 0; i < fields.length; i++) {
 40                 //添加节点信息
 41                 if(!StringUtils.isEmpty(fields[i].get(dto))){
 42                     Class<?> type = fields[i].getType();
 43                     // 如果是list
 44                     if(type == List.class){
 45                         String listName = fields[i].getName();
 46                        createElement(rootElement, fields[i].get(dto),listName);
 47                     }
 48                     else{
 49                         Element element = rootElement.addElement(fields[i].getName());
 50                         element.setText((String) fields[i].get(dto));
 51                     }
 52                 }
 53             }
 54             // 设置XML文档格式
 55             OutputFormat outputFormat = OutputFormat.createPrettyPrint();
 56             // 设置XML编码方式,即是用指定的编码方式保存XML文档到字符串(String),这里也可以指定为GBK或是ISO8859-1
 57             outputFormat.setEncoding("UTF-8");
 58             // outputFormat.setSuppressDeclaration(true); //是否生产xml头
 59             outputFormat.setIndent(true); //设置是否缩进
 60             outputFormat.setIndent("    "); //以四个空格方式实现缩进
 61             outputFormat.setNewlines(true); //设置是否换行
 62             StringWriter stringWriter =null;
 63             // Writer fileWriter =null;
 64             // xmlWriter是用来把XML文档写入字符串的(工具)
 65             XMLWriter xmlWriter = null;
 66            try {
 67                    // stringWriter字符串是用来保存XML文档的
 68                 stringWriter = new StringWriter();
 69                 // fileWriter = new FileWriter("D:\\modu11le.xml");
 70                 // xmlWriter是用来把XML文档写入字符串的(工具)
 71                 xmlWriter = new XMLWriter(stringWriter, outputFormat);
 72                 // 把创建好的XML文档写入字符串
 73                 xmlWriter.write(document);
 74                 //fileWriter.write(stringWriter.toString());
 75                 result=stringWriter.toString();
 76             } catch (IOException e) {
 77                 logger.error("写入数据失败");
 78                 throw new RuntimeException("写入数据失败"+e);
 79             }finally{
 80                  try {
 81                      if(xmlWriter!=null){
 82                          xmlWriter.flush();
 83                          xmlWriter.close();
 84                      }
 85 /*                     if(fileWriter!=null){
 86                          fileWriter.flush();
 87                          fileWriter.close();
 88                      }*/
 89
 90                 } catch (IOException e) {
 91                     logger.error("关闭输出流出错");
 92                     throw new RuntimeException("关闭输出流出错"+e);
 93                 }
 94             }
 95         } catch (Exception e) {
 96             logger.error("添加xml的节点失败"+e);
 97         }
 98         logger.error("转换xml结束");
 99         return result;
100     }
101
102     /**
103      * 添加类中的list
104      * @param element
105      * @param object
106      * @param name
107      * @return
108      * @throws IllegalArgumentException
109      * @throws IllegalAccessException
110      */
111     public static Element createElement(Element element ,Object object,String name ) throws IllegalArgumentException, IllegalAccessException{
112         Element nameElement = element.addElement(name);
113         List info = (List)object;
114         for(int j= 0;j<info.size();j++){
115             // 添加row的标签
116             Element rowElement = nameElement.addElement("row");
117             // 添加 对象的熟悉
118             Field fields[]=info.get(j).getClass().getDeclaredFields();//dto 是实体类名称
119             Field.setAccessible(fields, true);
120             for (int i = 0; i < fields.length; i++) {
121                 //添加节点信息
122                 if(!StringUtils.isEmpty(fields[i].get(info.get(j)))){
123                         Element childElement = rowElement.addElement(fields[i].getName());
124                         childElement.setText((String) fields[i].get(info.get(j)));
125                 }
126             }
127         }
128         return element;
129     }
130 }

UnifiedOrderRequest.java

package com.yiexpress.core.utils.wechat;public class UnifiedOrderRequest {private String appid;// 公众账号ID  private String mch_id;//商户号   private String device_info; //设备号   否  private String nonce_str;//随机字符串      private String sign;//签名     private String sign_type;//签名类型   private String body;//商品描述       private String detail;//商品详情   private String attach;//附加数据    private String out_trade_no;//商户订单号   private String fee_type;//标价币种     private String total_fee;//标价金额  private String spbill_create_ip;//终端IP   private String time_start;//交易起始时间   private String time_expire;//交易结束时间  private String goods_tag;//订单优惠标记   private String notify_url;//通知地址     private String trade_type;//交易类型   private String product_id;//商品ID  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 getSign_type() {return sign_type;}public void setSign_type(String sign_type) {this.sign_type = sign_type;}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 getTotal_fee() {return total_fee;}public void setTotal_fee(String total_fee) {this.total_fee = total_fee;}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 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 getProduct_id() {return product_id;}public void setProduct_id(String product_id) {this.product_id = product_id;}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;}}

UnifiedOrderRespose.java

package com.yiexpress.core.utils.wechat;public class UnifiedOrderRespose {private String return_code;             //返回状态码  private String return_msg;              //返回信息  private String appid;                   //公众账号ID  private String mch_id;                  //商户号  private String device_info;             //设备号  private String nonce_str;               //随机字符串  private String sign;                    //签名  private String result_code;             //业务结果  private String err_code;                //错误代码  private String err_code_des;            //错误代码描述  private String trade_type;              //交易类型  private String prepay_id;               //预支付交易会话标识  private String code_url;                //二维码链接  public String getReturn_code() {return return_code;}public void setReturn_code(String return_code) {this.return_code = return_code;}public String getReturn_msg() {return return_msg;}public void setReturn_msg(String return_msg) {this.return_msg = return_msg;}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 getResult_code() {return result_code;}public void setResult_code(String result_code) {this.result_code = result_code;}public String getErr_code() {return err_code;}public void setErr_code(String err_code) {this.err_code = err_code;}public String getErr_code_des() {return err_code_des;}public void setErr_code_des(String err_code_des) {this.err_code_des = err_code_des;}public String getTrade_type() {return trade_type;}public void setTrade_type(String trade_type) {this.trade_type = trade_type;}public String getPrepay_id() {return prepay_id;}public void setPrepay_id(String prepay_id) {this.prepay_id = prepay_id;}public String getCode_url() {return code_url;}public void setCode_url(String code_url) {this.code_url = code_url;}
}

WXPayConstants.java

package com.yiexpress.core.utils.wechat;public class WXPayConstants {public enum SignType {  MD5, HMACSHA256  }  public static final String FAIL     = "FAIL";  public static final String SUCCESS  = "SUCCESS";  public static final String HMACSHA256 = "HMAC-SHA256";  public static final String MD5 = "MD5";  public static final String FIELD_SIGN = "sign";  public static final String FIELD_SIGN_TYPE = "sign_type";
}

WXPayUtil.java

package com.yiexpress.core.utils.wechat;import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.StringWriter;
import java.io.Writer;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.*;
import java.security.MessageDigest;  import org.w3c.dom.Node;
import org.w3c.dom.NodeList;  import com.yiexpress.core.utils.SapUtils;
import com.yiexpress.core.utils.XmlUtil;import com.yiexpress.core.utils.wechat.WXPayConstants.SignType;import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;  import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.input.SAXBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;  /** * 支付工具类 */
public class WXPayUtil {  private static Logger log = LoggerFactory.getLogger(WXPayUtil.class);  /** * 生成订单对象信息 * @param orderId 订单号 * @param appId 微信appId * @param mch_id 微信分配的商户ID * @param body  支付介绍主体 * @param price 支付价格(放大100倍) * @param spbill_create_ip 终端IP * @param notify_url  异步直接结果通知接口地址 * @param noncestr  * @return */  public static Map<String,Object> createOrderInfo(Map<String, String> requestMap,String shopKey) {    //生成订单对象    UnifiedOrderRequest unifiedOrderRequest = new UnifiedOrderRequest();    unifiedOrderRequest.setAppid(requestMap.get("appId"));//公众账号ID    unifiedOrderRequest.setBody(requestMap.get("body"));//商品描述    unifiedOrderRequest.setMch_id(requestMap.get("mch_id"));//商户号    unifiedOrderRequest.setNonce_str(requestMap.get("noncestr"));//随机字符串      unifiedOrderRequest.setNotify_url(requestMap.get("notify_url"));//通知地址    unifiedOrderRequest.setOpenid(requestMap.get("userWeixinOpenId"));  unifiedOrderRequest.setDetail(requestMap.get("detail"));//详情  unifiedOrderRequest.setOut_trade_no(requestMap.get("out_trade_no"));//商户订单号    unifiedOrderRequest.setSpbill_create_ip(requestMap.get("spbill_create_ip"));//终端IP    unifiedOrderRequest.setTotal_fee(requestMap.get("payMoney"));  //金额需要扩大100倍:1代表支付时是0.01    unifiedOrderRequest.setTrade_type("JSAPI");//JSAPI--公众号支付、NATIVE--原生扫码支付、APP--app支付  SortedMap<String, String> packageParams = new TreeMap<String, String>();    packageParams.put("appid", unifiedOrderRequest.getAppid());    packageParams.put("body", unifiedOrderRequest.getBody());    packageParams.put("mch_id", unifiedOrderRequest.getMch_id());    packageParams.put("nonce_str", unifiedOrderRequest.getNonce_str());    packageParams.put("notify_url", unifiedOrderRequest.getNotify_url());  packageParams.put("openid", unifiedOrderRequest.getOpenid());  packageParams.put("detail", unifiedOrderRequest.getDetail());  packageParams.put("out_trade_no", unifiedOrderRequest.getOut_trade_no());    packageParams.put("spbill_create_ip", unifiedOrderRequest.getSpbill_create_ip());    packageParams.put("total_fee", unifiedOrderRequest.getTotal_fee());    packageParams.put("trade_type", unifiedOrderRequest.getTrade_type());try {  unifiedOrderRequest.setSign(generateSignature(packageParams,shopKey));//签名  } catch (Exception e) {  e.printStackTrace();  }  //将订单对象转为xml格式    String orderstr=SapUtils.formatToXml(unifiedOrderRequest,"xml").replace("<?xml version=\"1.0\" encoding=\"UTF-8\"?>","");log.debug("封装好的统一下单请求数据:"+orderstr.replace("__", "_"));  Map<String,Object> responseMap = new HashMap<String,Object>();  responseMap.put("orderInfo_toString", orderstr.replace("__", "_"));  responseMap.put("unifiedOrderRequest",unifiedOrderRequest);  return responseMap;    }   public static void main(String[] args) {
//         UnifiedOrderRequest ut=new UnifiedOrderRequest();
//         ut.setAppid("wx1234156789");
//         ut.setBody("内容body");
//         ut.setMch_id("商户号");
//         ut.setNonce_str("随机字符串");
//         ut.setNotify_url("回调地址");
//         ut.setOpenid("openid");
//         ut.setDetail("详情");
//         ut.setOut_trade_no("订单号");
//         ut.setSpbill_create_ip("终端IP");
//         ut.setTotal_fee("金额");
//         ut.setTrade_type("调用类型JSAPI");
//         System.out.println("---"+SapUtils.formatToXml(ut,"xml")+"---");
//         UnifiedOrderRequest unifiedOrderRequest = new UnifiedOrderRequest();
//         unifiedOrderRequest.setAppid("dsfsdf");//公众账号ID
//         unifiedOrderRequest.setBody("sdfsdf");//商品描述
//         unifiedOrderRequest.setMch_id("sdfsd");//商户号
//         unifiedOrderRequest.setNonce_str("dfsd");//随机字符串
//         unifiedOrderRequest.setNotify_url("sdfdsf");//通知地址
//         unifiedOrderRequest.setOpenid("sdfsdf");
//
//         unifiedOrderRequest.setTrade_type("JSAPI");//JSAPI--公众号支付、NATIVE--原生扫码支付、APP--app支付
//
//         System.out.println("---"+SapUtils.formatToXml(unifiedOrderRequest,"xml").replace("<?xml version=\"1.0\" encoding=\"UTF-8\"?>","")+"---");
//         String str="<xml><appid>dsfsdf</appid><mch_id>sdfsd</mch_id><nonce_str>dfsd</nonce_str><body>sdfsdf</body><notify_url>sdfdsf</notify_url><trade_type>JSAPI</trade_type><openid>sdfsdf</openid></xml>";
//         UnifiedOrderRequest s=SapUtils.getBeanByxml(str,UnifiedOrderRequest.class);
//         System.out.println(s.getAppid()+"---"+s.getMch_id()+"--"+s.getFee_type());
}/**  * 生成签名  * @param appid_value  * @param mch_id_value  * @param productId  * @param nonce_str_value  * @param trade_type   * @param notify_url   * @param spbill_create_ip   * @param total_fee   * @param out_trade_no   * @return  */    private static String createSign(UnifiedOrderRequest unifiedOrderRequest,String shopKey) {    //根据规则创建可排序的map集合    SortedMap<String, String> packageParams = new TreeMap<String, String>();    packageParams.put("appid", unifiedOrderRequest.getAppid());    packageParams.put("body", unifiedOrderRequest.getBody());    packageParams.put("mch_id", unifiedOrderRequest.getMch_id());    packageParams.put("nonce_str", unifiedOrderRequest.getNonce_str());    packageParams.put("notify_url", unifiedOrderRequest.getNotify_url());    packageParams.put("out_trade_no", unifiedOrderRequest.getOut_trade_no());    packageParams.put("spbill_create_ip", unifiedOrderRequest.getSpbill_create_ip());    packageParams.put("trade_type", unifiedOrderRequest.getTrade_type());    packageParams.put("total_fee", unifiedOrderRequest.getTotal_fee());    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();    String v = (String) entry.getValue();    //为空不参与签名、参数名区分大小写    if (null != v && !"".equals(v) && !"sign".equals(k)  && !"key".equals(k)) {    sb.append(k + "=" + v + "&");    }    }    //第二步拼接key,key设置路径:微信商户平台(pay.weixin.qq.com)-->账户设置-->API安全-->密钥设置    sb.append("key="+shopKey);    String sign = MD5Util.MD5(sb.toString()).toUpperCase();//MD5加密    log.error("方式一生成的签名="+sign);  return sign;    }    //xml解析      public static SortedMap<String, String> doXMLParseWithSorted(String strxml) throws Exception {      strxml = strxml.replaceFirst("encoding=\".*\"", "encoding=\"UTF-8\"");      if(null == strxml || "".equals(strxml)) {      return null;      }      SortedMap<String,String> m = new TreeMap<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 = getChildrenText(children);      }      m.put(k, v);      }      //关闭流
          in.close();       return m;      }     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(getChildrenText(list));      }      sb.append(value);      sb.append("</" + name + ">");      }      }       return sb.toString();      }   /**  * 调统一下单API  * @param orderInfo  * @return  */    public static UnifiedOrderRespose httpOrder(String orderInfo,int index) {//统一下单接口地址 自动适应  1中国境内  2东南亚   3其他String[] urlList={"https://api.mch.weixin.qq.com/pay/unifiedorder","https://apihk.mch.weixin.qq.com/pay/unifiedorder","https://apius.mch.weixin.qq.com/pay/unifiedorder "};//String url = "https://api.mch.weixin.qq.com/pay/unifiedorder";    try {    HttpURLConnection conn = (HttpURLConnection) new URL(urlList[index]).openConnection();    //加入数据      conn.setRequestMethod("POST");      conn.setDoOutput(true);      BufferedOutputStream buffOutStr = new BufferedOutputStream(conn.getOutputStream());      buffOutStr.write(orderInfo.getBytes("UTF-8"));    buffOutStr.flush();      buffOutStr.close();      //获取输入流      BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream(), "UTF-8"));      String line = null;      StringBuffer sb = new StringBuffer();      while((line = reader.readLine())!= null){      sb.append(line);      }   //xml转对象UnifiedOrderRespose unifiedOrderRespose =XmlUtil.getBeanByxml(sb.toString(),UnifiedOrderRespose.class);    return unifiedOrderRespose;  } catch (Exception e) {    e.printStackTrace();    }    return null;    }/** * XML格式字符串转换为Map * * @param strXML XML字符串 * @return XML数据转换后的Map * @throws Exception */  public static Map<String, String> xmlToMap(String strXML) throws Exception {  try {  Map<String, String> data = new HashMap<String, String>();  DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();  DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();  InputStream stream = new ByteArrayInputStream(strXML.getBytes("UTF-8"));  org.w3c.dom.Document doc = documentBuilder.parse(stream);  doc.getDocumentElement().normalize();  NodeList nodeList = doc.getDocumentElement().getChildNodes();  for (int idx = 0; idx < nodeList.getLength(); ++idx) {  Node node = nodeList.item(idx);  if (node.getNodeType() == Node.ELEMENT_NODE) {  org.w3c.dom.Element element = (org.w3c.dom.Element) node;  data.put(element.getNodeName(), element.getTextContent());  }  }  try {  stream.close();  } catch (Exception ex) {  // do nothing
            }  return data;  } catch (Exception ex) {  WXPayUtil.getLogger().warn("Invalid XML, can not convert to map. Error message: {}. XML content: {}", ex.getMessage(), strXML);  throw ex;  }  }  /** * 将Map转换为XML格式的字符串 * * @param data Map类型数据 * @return XML格式的字符串 * @throws Exception */  public static String mapToXml(Map<String, String> data) throws Exception {  DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();  DocumentBuilder documentBuilder= documentBuilderFactory.newDocumentBuilder();  org.w3c.dom.Document document = documentBuilder.newDocument();  org.w3c.dom.Element root = document.createElement("xml");  document.appendChild(root);  for (String key: data.keySet()) {  String value = data.get(key);  if (value == null) {  value = "";  }  value = value.trim();  org.w3c.dom.Element filed = document.createElement(key);  filed.appendChild(document.createTextNode(value));  root.appendChild(filed);  }  TransformerFactory tf = TransformerFactory.newInstance();  Transformer transformer = tf.newTransformer();  DOMSource source = new DOMSource(document);  transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");  transformer.setOutputProperty(OutputKeys.INDENT, "yes");  StringWriter writer = new StringWriter();  StreamResult result = new StreamResult(writer);  transformer.transform(source, result);  String output = writer.getBuffer().toString(); //.replaceAll("\n|\r", "");  try {  writer.close();  }  catch (Exception ex) {  }  return output;  }  /** * 生成带有 sign 的 XML 格式字符串 * * @param data Map类型数据 * @param key API密钥 * @return 含有sign字段的XML */  public static String generateSignedXml(final Map<String, String> data, String key) throws Exception {  return generateSignedXml(data, key, SignType.MD5);  }  /** * 生成带有 sign 的 XML 格式字符串 * * @param data Map类型数据 * @param key API密钥 * @param signType 签名类型 * @return 含有sign字段的XML */  public static String generateSignedXml(final Map<String, String> data, String key, SignType signType) throws Exception {  String sign = generateSignature(data, key, signType);  data.put(WXPayConstants.FIELD_SIGN, sign);  return mapToXml(data);  }  /** * 判断签名是否正确 * * @param xmlStr XML格式数据 * @param key API密钥 * @return 签名是否正确 * @throws Exception */  public static boolean isSignatureValid(String xmlStr, String key) throws Exception {  Map<String, String> data = xmlToMap(xmlStr);  if (!data.containsKey(WXPayConstants.FIELD_SIGN) ) {  return false;  }  String sign = data.get(WXPayConstants.FIELD_SIGN);  return generateSignature(data, key).equals(sign);  }  /** * 判断签名是否正确,必须包含sign字段,否则返回false。使用MD5签名。 * * @param data Map类型数据 * @param key API密钥 * @return 签名是否正确 * @throws Exception */  public static boolean isSignatureValid(Map<String, String> data, String key) throws Exception {  return isSignatureValid(data, key, SignType.MD5);  }  /** * 判断签名是否正确,必须包含sign字段,否则返回false。 * * @param data Map类型数据 * @param key API密钥 * @param signType 签名方式 * @return 签名是否正确 * @throws Exception */  public static boolean isSignatureValid(Map<String, String> data, String key, SignType signType) throws Exception {  if (!data.containsKey(WXPayConstants.FIELD_SIGN) ) {  return false;  }  String sign = data.get(WXPayConstants.FIELD_SIGN);  return generateSignature(data, key, signType).equals(sign);  }  /** * 生成签名 * * @param data 待签名数据 * @param key API密钥 * @return 签名 */  public static String generateSignature(final Map<String, String> data, String key) throws Exception {  return generateSignature(data, key, SignType.MD5);  }  /** * 生成签名. 注意,若含有sign_type字段,必须和signType参数保持一致。 * * @param data 待签名数据 * @param key API密钥 * @param signType 签名方式 * @return 签名 */  public static String generateSignature(final Map<String, String> data, String key, SignType signType) throws Exception {  Set<String> keySet = data.keySet();  String[] keyArray = keySet.toArray(new String[keySet.size()]);  Arrays.sort(keyArray);  StringBuilder sb = new StringBuilder();  for (String k : keyArray) {  if (k.equals(WXPayConstants.FIELD_SIGN)) {  continue;  }  if (data.get(k).trim().length() > 0) // 参数值为空,则不参与签名  sb.append(k).append("=").append(data.get(k).trim()).append("&");  }  sb.append("key=").append(key);  if (SignType.MD5.equals(signType)) {  return MD5(sb.toString()).toUpperCase();  }  else if (SignType.HMACSHA256.equals(signType)) {  return HMACSHA256(sb.toString(), key);  }  else {  log.error("获取签名失败,失败原因:"+String.format("Invalid sign_type: %s", signType));  throw new Exception(String.format("Invalid sign_type: %s", signType));  }  }  /** * 获取随机字符串 Nonce Str * @return String 随机字符串 */  public static String generateNonceStr() {  return UUID.randomUUID().toString().replaceAll("-", "").substring(0, 32);  }  /**  * Map转xml数据  */    public static String GetMapToXML(Map<String,String> param){    StringBuffer sb = new StringBuffer();    sb.append("<xml>");    for (Map.Entry<String,String> entry : param.entrySet()) {     sb.append("<"+ entry.getKey() +">");    sb.append(entry.getValue());    sb.append("</"+ entry.getKey() +">");    }      sb.append("</xml>");    return sb.toString();    }    /** * 生成 MD5 * @param data 待处理数据 * @return MD5结果 */  public static String MD5(String data) throws Exception {  java.security.MessageDigest md = MessageDigest.getInstance("MD5");  byte[] array = md.digest(data.getBytes("UTF-8"));  StringBuilder sb = new StringBuilder();  for (byte item : array) {  sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3));  }  return sb.toString().toUpperCase();  }  /** * 生成 HMACSHA256 * @param data 待处理数据 * @param key 密钥 * @return 加密结果 * @throws Exception */  public static String HMACSHA256(String data, String key) throws Exception {  Mac sha256_HMAC = Mac.getInstance("HmacSHA256");  SecretKeySpec secret_key = new SecretKeySpec(key.getBytes("UTF-8"), "HmacSHA256");  sha256_HMAC.init(secret_key);  byte[] array = sha256_HMAC.doFinal(data.getBytes("UTF-8"));  StringBuilder sb = new StringBuilder();  for (byte item : array) {  sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3));  }  return sb.toString().toUpperCase();  }  /** * 日志 * @return */  public static Logger getLogger() {  Logger logger = LoggerFactory.getLogger("wxpay java sdk");  return logger;  }  /** * 获取当前时间戳,单位秒 * @return */  public static long getCurrentTimestamp() {  return System.currentTimeMillis()/1000;  }  /** * 获取当前时间戳,单位毫秒 * @return */  public static long getCurrentTimestampMs() {  return System.currentTimeMillis();  }  /** * 生成 uuid, 即用来标识一笔单,也用做 nonce_str * @return */  public static String generateUUID() {  return UUID.randomUUID().toString().replaceAll("-", "").substring(0, 32);  }  /**  * 支付签名  * @param timestamp  * @param noncestr  * @param packages  * @return  * @throws UnsupportedEncodingException   */    public static String paySign(String timestamp, String noncestr,String packages,String appId){    Map<String, String> paras = new HashMap<String, String>();    paras.put("appid", appId);    paras.put("timestamp", timestamp);    paras.put("noncestr", noncestr);    paras.put("package", packages);    paras.put("signType", "MD5");    StringBuffer sb = new StringBuffer();    Set es = paras.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 (null != v && !"".equals(v) && !"sign".equals(k)  && !"key".equals(k)) {    sb.append(k + "=" + v + "&");    }    }    String sign = MD5Util.MD5(sb.toString()).toUpperCase();//MD5加密    return sign;    }
}  

XmlUtil.java

  1 package com.yiexpress.core.utils;
  2 import java.io.StringReader;
  3 import java.lang.reflect.Field;
  4 import java.util.Date;
  5
  6
  7 import org.dom4j.Document;
  8 import org.dom4j.Element;
  9 import org.dom4j.io.SAXReader;
 10 import org.xml.sax.InputSource;
 11
 12 public class XmlUtil{
 13     /**
 14      * json 数据转换对象
 15      *
 16      * @param Element
 17      *            要转换的Element数据
 18      * @param pojo
 19      *            要转换的目标对象类型
 20      * @return 转换的目标对象
 21      * @throws Exception
 22      *             转换失败
 23      */
 24     @SuppressWarnings("rawtypes")
 25     public static Object fromXmlToBean(Element rootElt, Class pojo) throws Exception{
 26         // 首先得到pojo所定义的字段
 27         Field[] fields = pojo.getDeclaredFields();
 28         // 根据传入的Class动态生成pojo对象
 29         Object obj = pojo.newInstance();
 30         for (Field field : fields)
 31         {
 32             // 设置字段可访问(必须,否则报错)
 33             field.setAccessible(true);
 34             // 得到字段的属性名
 35             String name = field.getName();
 36             // 这一段的作用是如果字段在Element中不存在会抛出异常,如果出异常,则跳过。
 37             try
 38             {
 39                 rootElt.elementTextTrim(name);
 40             }
 41             catch (Exception ex)
 42             {
 43                 continue;
 44             }
 45             if (rootElt.elementTextTrim(name) != null && !"".equals(rootElt.elementTextTrim(name)))
 46             {
 47                 // 根据字段的类型将值转化为相应的类型,并设置到生成的对象中。
 48                 if (field.getType().equals(Long.class) || field.getType().equals(long.class))
 49                 {
 50                     field.set(obj, Long.parseLong(rootElt.elementTextTrim(name)));
 51                 }
 52                 else if (field.getType().equals(String.class))
 53                 {
 54                     field.set(obj, rootElt.elementTextTrim(name));
 55                 }
 56                 else if (field.getType().equals(Double.class) || field.getType().equals(double.class))
 57                 {
 58                     field.set(obj, Double.parseDouble(rootElt.elementTextTrim(name)));
 59                 }
 60                 else if (field.getType().equals(Integer.class) || field.getType().equals(int.class))
 61                 {
 62                     field.set(obj, Integer.parseInt(rootElt.elementTextTrim(name)));
 63                 }
 64                 else if (field.getType().equals(java.util.Date.class))
 65                 {
 66                     field.set(obj, Date.parse(rootElt.elementTextTrim(name)));
 67                 }
 68                 else
 69                 {
 70                     continue;
 71                 }
 72             }
 73         }
 74         return obj;
 75     }
 76
 77     /**
 78      * 把xml格式转化为指定对象
 79      *
 80      * @param xml
 81      * @return
 82      */
 83     @SuppressWarnings("unchecked")
 84     public static <T> T getBeanByxml(String xml, Class<T> valueType) {
 85         T person = null;
 86         InputSource in = new InputSource(new StringReader(xml));
 87         in.setEncoding("UTF-8");
 88         SAXReader reader = new SAXReader();
 89         Document document;
 90         try {
 91             document = reader.read(in);
 92             Element root = document.getRootElement();
 93             person = (T) XmlUtil.fromXmlToBean(root, valueType);
 94
 95         } catch (Exception e) {
 96             // TODO Auto-generated catch block
 97             e.printStackTrace();
 98             System.out.println("数据解析错误");
 99
100         }
101         return person;
102     }
103 }  

获取预支付ID和签名的controller

package com.yiexpress.jerry.controller.ewe.wechat;import java.util.HashMap;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;import javax.servlet.http.HttpServletRequest;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;import com.yiexpress.core.utils.wechat.UnifiedOrderRequest;
import com.yiexpress.core.utils.wechat.UnifiedOrderRespose;
import com.yiexpress.core.utils.wechat.WXPayUtil;/** * 微信支付controller  */
@Controller
@RequestMapping(value = "/wxpay")
public class WXPayController{  private static final Logger LOGGER = LoggerFactory.getLogger(WXPayController.class);private String appId="公总号 appid";//公总号 appidprivate String mchId="商家号";//商家号private String apiKey="商户密匙";//商户密匙/** * 获取终端IP * @param request * @return */  public static String getIpAddr(HttpServletRequest request)  {    String ip  =  request.getHeader( " x-forwarded-for " );    if (ip == null || ip.length() == 0 || " unknown " .equalsIgnoreCase(ip))  {    ip = request.getHeader( " Proxy-Client-IP " );    }     if (ip  == null || ip.length() == 0 || " unknown " .equalsIgnoreCase(ip))  {    ip  =  request.getHeader( " WL-Proxy-Client-IP " );    }     if (ip  == null || ip.length() == 0 || " unknown " .equalsIgnoreCase(ip))  {    ip  =  request.getRemoteAddr();    }     return  ip;    }   /** * 支付初始化   返回预支付ID、签名等信息* @param payMoney * @return  map * result  -1*/  @RequestMapping("/toPayInit")  @ResponseBody  public Map<String,Object> toPay(HttpServletRequest request,@RequestParam(value="payMoney",required=true)float payMoney,@RequestParam(value="openId",required=true) String openId,@RequestParam(value="orderId",required=true)String orderId){  Map<String,Object> map = new HashMap<>();  //订单号 目前生产的随机数  后面放入指定系统唯一的单号  //判断单号是否存在String noncestr = WXPayUtil.generateNonceStr();  Map<String,String> requestMap = new HashMap<String, String>();  requestMap.put("appId",appId);  requestMap.put("userWeixinOpenId",openId);  //之前使用ETCA单号作为商户订单号,现在改为自动生成的账单号    2018-10-25 Peter//requestMap.put("out_trade_no",auShipmentBrief.getShipmentReference());  requestMap.put("out_trade_no","订单号");  requestMap.put("mch_id",mchId);  //计算金额   微信支付的金额的单位是分,例如:实际支付1.23元,传入参数就是123int money=0;try {money=(int)(payMoney*100);} catch (Exception e) {map.put("result",-1);map.put("msg","金额格式不正确");return map;}requestMap.put("payMoney",money+"");  requestMap.put("spbill_create_ip", getIpAddr(request));  requestMap.put("notify_url","回调地址");requestMap.put("noncestr", noncestr);  requestMap.put("body","微信下单账单支付");  requestMap.put("detail","散客下单账单支付"); Map<String,Object> requestInfo = WXPayUtil.createOrderInfo(requestMap,apiKey);  String orderInfo_toString = (String) requestInfo.get("orderInfo_toString");  LOGGER.debug("request 请求字符串:"+orderInfo_toString);//判断返回码        UnifiedOrderRespose orderResponse = WXPayUtil.httpOrder(orderInfo_toString,0);// 调用统一下单接口//判断超时的情况if(orderResponse==null || orderResponse.getReturn_code()==null || ("SUCCESS".equals(orderResponse.getReturn_code()) && (orderResponse.getErr_code()==null || "SYSTEMERROR".equals(orderResponse.getErr_code())))){orderResponse = WXPayUtil.httpOrder(orderInfo_toString,1);if(orderResponse==null || orderResponse.getReturn_code()==null || ("SUCCESS".equals(orderResponse.getReturn_code()) && (orderResponse.getErr_code()==null || "SYSTEMERROR".equals(orderResponse.getErr_code())))){orderResponse = WXPayUtil.httpOrder(orderInfo_toString,2);}}LOGGER.debug("response 返回字段:==》{}",orderResponse);//根据微信文档return_code 和result_code都为SUCCESS的时候才会返回code_url    if(null!=orderResponse  && "SUCCESS".equals(orderResponse.getReturn_code()) && "SUCCESS".equals(orderResponse.getResult_code())){    String timestamp = String.valueOf(WXPayUtil.getCurrentTimestamp());  map.put("timestamp",timestamp);  map.put("noncestr",noncestr);  UnifiedOrderRequest unifiedOrderRequest = (UnifiedOrderRequest) requestInfo.get("unifiedOrderRequest");  map.put("unifiedOrderRequest",unifiedOrderRequest);  SortedMap<String, String> packageParams = new TreeMap<String, String>();    packageParams.put("appId",appId);    packageParams.put("signType","MD5");    packageParams.put("nonceStr", noncestr);    packageParams.put("timeStamp", timestamp);    String packages = "prepay_id="+orderResponse.getPrepay_id();  packageParams.put("package",packages); String sign = null;try {  //生成签名sign = WXPayUtil.generateSignature(packageParams,apiKey); } catch (Exception e) {  map.put("result",-1);map.put("msg","支付签名信息异常");e.printStackTrace();  }if(sign!=null && !"".equals(sign)){ LOGGER.debug("------------支付签名:"+sign+"-------------------");map.put("paySign",sign);  map.put("result",1);map.put("appId",appId);}else{  map.put("result",-1); map.put("msg","支付签名信息异常");} map.put("prepay_id",orderResponse.getPrepay_id());  return map;    }else{ //不成功  if(orderResponse!=null){String text = "调用微信支付出错,返回状态码:"+orderResponse.getReturn_code()+",返回信息:"+orderResponse.getReturn_msg();  if(orderResponse.getErr_code()!=null && !"".equals(orderResponse.getErr_code())){  text = text +",错误码:"+orderResponse.getErr_code()+",错误描述:"+orderResponse.getErr_code_des();  }  LOGGER.error(text);}else{LOGGER.error("返回值   orderResponse对象为空");}map.put("result",-1);map.put("msg","支付环境异常,请稍后再试");return map;    }  }  }  

jsp代码

 1 <script type="text/javascript">
 2
 3 //点击支付按钮 开始支付
 4 function toPay(){
 5
 6     //初步判断数据
 7     var openId=$("#openId").val();
 8     var payMoney=$("#payMoney").val();
 9     $.ajax({
10         url : "${pageContext.request.contextPath}/toPayInit",
11         type:"POST",
12         dataType : 'json',
13         data:{
14             payMoney:payMoney,
15             openId:openId,
16             orderId:"订单号"
17         },
18         success : function(result) {
19             if(result.result==1){
20                 var paySign = result.paySign;
21                 var prepay_id = result.prepay_id;
22                 var nonceStr = result.noncestr;
23                 var timestamp = result.timestamp;
24                 var unifiedOrderRequest = result.unifiedOrderRequest;
25                 var spbill_create_ip = unifiedOrderRequest.spbill_create_ip;
26                 var detail = unifiedOrderRequest.detail;
27                 var out_trade_no = unifiedOrderRequest.out_trade_no;
28                 var appId=result.appId;
29                 onBridgeReady(paySign,prepay_id,nonceStr,timestamp,appId);
30             }else{
31                 alert("失败");
32             }
33         },
34         error : function(data, status, e) { // 服务器响应失败时的处理函数
35             alert("数据异常,支付失败", 'error');
36         }
37     });
38 }
39
40 //调起公众号支付
41 function onBridgeReady(paySign,prepay_id,nonceStr,timestamp,appId){
42    WeixinJSBridge.invoke(
43        'getBrandWCPayRequest', {
44            "appId":appId,     //appid
45            "timeStamp":timestamp,
46            "nonceStr":nonceStr, //随机串
47            "package":"prepay_id="+prepay_id,
48            "signType":"MD5",
49            "paySign":paySign //微信签名
50        },
51        function(res){
52             // 使用以上方式判断前端返回,微信团队郑重提示:res.err_msg将在用户支付成功后返回    ok,但并不保证它绝对可靠。
53            if(res.err_msg == "get_brand_wcpay_request:ok" ) {
54                alert("支付完成", 'success');
55            }else if(res.err_msg == "get_brand_wcpay_request:cancel" ) {
56                alert("取消支付", 'success');
57
58            }else if(res.err_msg == "get_brand_wcpay_request:fail"){
59                alert("支付失败", 'success');
60
61            }
62        }
63    );
64 }
65 </script>

定义微信支付成功回调接口APIAupostController.java

 1 package com.yiexpress.api.controller.ewe.aupost;
 2
 3 import java.util.HashMap;
 4 import java.util.Map;
 5
 6 import javax.annotation.Resource;
 7 import javax.servlet.ServletInputStream;
 8 import javax.servlet.http.HttpServletRequest;
 9 import javax.servlet.http.HttpServletResponse;
10
11 import org.apache.commons.collections.MapUtils;
12 import org.slf4j.Logger;
13 import org.slf4j.LoggerFactory;
14 import org.springframework.beans.factory.annotation.Value;
15 import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
16 import org.springframework.stereotype.Controller;
17 import org.springframework.web.bind.annotation.RequestMapping;
18 import org.springframework.web.bind.annotation.ResponseBody;
19
20 import com.yiexpress.core.utils.wechat.WXPayUtil;
21 @Controller
22 @RequestMapping("/api")
23 public class APIAupostController {
24
25     private static final Logger LOGGER=LoggerFactory.getLogger(APIAupostController.class);
26
27
28     @Resource(name = "jacksonBean")
29     private MappingJackson2HttpMessageConverter jackson;
31     private String apiKey="商户密匙";//商户密匙
32
33      /**
34          * 异步回调接口
35          * @param request
36          * @param response
37          * @throws Exception
38          */
39         @RequestMapping(value="/paymentNotice",produces="text/html;charset=utf-8")
40         @ResponseBody
41         public String WeixinParentNotifyPage(HttpServletRequest request,HttpServletResponse response) throws Exception{
42             ServletInputStream instream = request.getInputStream();
43             StringBuffer sb = new StringBuffer();
44             int len = -1;
45             byte[] buffer = new byte[1024];
46             while((len = instream.read(buffer)) != -1){
47                 sb.append(new String(buffer,0,len));
48             }
49             instream.close();
50             Map<String,String> map = WXPayUtil.xmlToMap(sb.toString());//接受微信的回调的通知参数
51             Map<String,String> return_data = new HashMap<String,String>();
52             //判断签名是否正确
53             if(WXPayUtil.isSignatureValid(map,apiKey)){
54                 if(map.get("return_code").toString().equals("FAIL")){
55                     return_data.put("return_code", "FAIL");
56                     return_data.put("return_msg", map.get("return_msg"));
57                 }else {
58                     String return_code=MapUtils.getString(map,"return_code");
59                     String result_code=MapUtils.getString(map,"result_code");
60                     if(return_code!=null && "SUCCESS".equals(return_code) && result_code!=null && "SUCCESS".equals(result_code)){
61                         String out_trade_no =MapUtils.getString(map,"out_trade_no");//系统订单号
62                         //支付成功,可以自定义新逻辑
63
64                     }
65                 }
66             }else{
67                 return_data.put("return_code", "FAIL");
68                 return_data.put("return_msg", "签名错误");
69             }
70             String xml = WXPayUtil.GetMapToXML(return_data);
71             LOGGER.error("支付通知回调结果:"+xml);
72             return xml;
73         }
74
75 }

完工!

转载于:https://www.cnblogs.com/hanfengyeqiao/p/10616607.html

java微信公众号支付示例相关推荐

  1. java微信公众号支付开发平台_微信公众号支付demo,微信公众号支付Java DEMO

    1.5.4微信验证的控制方法: /** * 微信验证 * 请填写接口配置信息,此信息需要你有自己的服务器资源,填写的URL需要正确响应微信发送的Token验证 * 验证服务器地址的有效性 * 开发者提 ...

  2. 微信openid绑定java,微信公众号支付(一)如何获取用户openId

    一.获取apikey,appsecret与商户号 注册公众号.商户号 二.获取用户的OpenId 1.设置[授权回调页面域名] 官方解释:用户在网页授权页同意授权给公众号后,微信会将授权数据传给一个回 ...

  3. java微信公众号支付开发平台_Java微信公众平台开发之公众号支付(微信内H5调起支付)...

    官方文档 准备工作:已通过微信认证的公众号,必须通过ICP备案域名(否则会报支付失败) 借鉴了很多大神的文章,在此先谢过了 整个支付流程,看懂就很好写了 一.设置支付目录 在微信公众平台设置您的公众号 ...

  4. java微信公众号支付退款_java 微信公众号支付 详细教程【站长吐血整理】

    maven或者gradle 项目记得引用第三方开放的sdk工具类,微信支付的,很全 微信开发者第三方sdk库资料:weixin-popular compile group: 'com.github.w ...

  5. 从零开始实现JAVA微信公众号支付

      突然发现好久没写博客了,这几年在学校待的真是越来越懒了.最近在公司实习,boss让做微信端的开发,以前一直在做PC浏览器端开发,所以说算是从零开始.期间遇到了无数的坑,在这里记录一下.一方面让自己 ...

  6. 微信公众号页面支付接口java,[Java教程]微信公众号支付(三):页面调用微信支付JS并完成支付...

    [Java教程]微信公众号支付(三):页面调用微信支付JS并完成支付 0 2015-09-15 15:00:30 一.调用微信的JS文件 1.首先要绑定[JS接口安全域名],"公众号设置&q ...

  7. java开发微信公众号支付

    这篇文章主要给大家结合微信支付接口开发的实践,从获取用户授权到各主要接口的使用方法等方面介绍微信支付的关键点技术,有需要的小伙伴可以参考下 最近做了微信公众号支付的开发,由于是第一次做也摸索了几天的时 ...

  8. 微信公众号支付java前后端分离开发

    微信公众号支付java前后端分离开发 微信公众号支付java前后端分离开发 我们开发的是基于河北银行的支付,支付宝微信都做了,这里就介绍一下微信公众号支付,这个公众号支付需要配置的东西太多了,官方文档 ...

  9. java微信公众号JSAPI支付以及所遇到的坑

    java微信公众号JSAPI支付以及所遇到的坑 上周做了个支付宝微信扫码支付,今天总结一下.微信相比支付宝要麻烦许多 由于涉及到代理商,没办法,让我写个详细的申请流程,懵逼啊. 笔记地址 http:/ ...

  10. java版微信公众号支付

    前言 今天是2020-4-1愚人节,好久没写博客了,今天准备写一篇微信公众号支付,刚好公司给了我账户,让我有参数测试,由于以前对于支付是小白,所以把这个功能打通花了2天,一天8小时,首先看官网文档,其 ...

最新文章

  1. QN8027性能调试
  2. Nginx访问VM虚拟机CentOS 7系统与本地Windows系统共享目录403
  3. Linux-进程内存占用情况
  4. 计算机桌面游戏开发,桌面游戏菜单怎么做
  5. java final修饰属性_Java final关键字用来修饰类、方法、属性
  6. CentOS 7 gedit编辑器中文乱码解决方法
  7. c++代码整洁之道pdf_别再问如何用python提取PDF内容了
  8. 容器编排技术 -- Kubernetes是什么?
  9. 三菱mode bus tcp通讯_绍兴三菱MR-J4-70B
  10. Android 开源项目及库汇总
  11. jQuery WeUI学习笔记二
  12. 中国省份数据字典表---自用
  13. LINUX网卡地址配置
  14. 嵌入式C语言学习笔记附图
  15. 雷军语录:感谢“批评”让小米理性成长
  16. 第58章 热力学、热量和你
  17. 图解AODV协议(demo)
  18. vue3 腾讯地图输入地址或拖动标记获取经纬度
  19. LED灯泡数据传输速率最高1GB/秒!未来它可是要取代WIFI
  20. 南大通用数据库-Gbase-8a-学习-34-gcdump(导出数据库对象定义)

热门文章

  1. ExtJS学习------Ext.define的继承extend,用javascript实现相似Ext的继承
  2. linux-资料汇集
  3. Python实现Excel与XML之间的转换
  4. SqlServer存储过程基础
  5. iconfont-矢量图标字体的运用
  6. 一段和别人的对话,没事写出来(杂项)
  7. 招聘 | 浙大杨杰课题组-博士后与科研助理-医学AI/NLP
  8. 清华ACL'22 | 一文读懂刘知远所在实验室18篇论文详情
  9. 学术之路如何走好?过来人的10条建议!
  10. 哈工大学习笔记 | 图文并茂详解隐马尔可夫模型