zoukankan      html  css  js  c++  java
  • JAVA-微信公众号支付详细步骤

    当时公司告诉我做微信公众号支付的需求,个人根据微信支付官网以及网上的demo来做完成支付功能。微信公众号支付分为以下步骤:

    第一步配置

    1.公司需注册微信公众号支付,提供给后台开发人员以下字段:

      appid:微信公众号id==登陆微信公众号后台-开发-基本配置

      secret:微信公众号密钥id

      mch_id:微信支付商户号==登陆微信支付后台,即可看到

      key:商户号对应的密钥

    2.设置支付目录:(具体步骤如微信支付官网:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_3) 需在商户平台设置授权域名:xx.xxx.cn (注:这个域名相当于Java项目运行时的ip:端口号) 另外在商户平台设置支付目录:http://域名//项目名

    3.测试环境:测试必须在服务器上测试,可以根据微信公众平台文档下载“微信开发者工具”如:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1455784140

                   首先:公司公众号登录管理后台,邀请开发者微信号为好友,同时开发者的微信要确认。

                    然后:在微信开发者工具上测试看测试条件是否满足:

                   (1)用开发者微信登录微信开发者工具。

                   (2)在浏览器上浏览获取code的链接: https://open.weixin.qq.com/connect/oauth2/authorize? appid=wxxxxxxxxxxxxxxx&redirect_uri=http://域名/项目名/获取openid的接口名&response_type=code&scope=snsapi_base&state=STATE#wechat_redirect ,若环境成功,浏览器上会自动跳到重定向(redirect_uri)的地址上,并自带code和state的值如:http://域名/项目名/获取openid的接口名&code=06jjjjjxxxxxxxxxxxxxxF1q2wmF1b6jmx&state=STATE 这时开发者的测试环境成功。注:redirect_uri地址可以进行urlEncode编码也可以不进行编码。

    第二步(后台开发代码编写)

    1.获取openid的接口:

    要获取openid先获取code,而code值需在前端获取,前端浏览获取code的微信链接:https://open.weixin.qq.com/connect/oauth2/authorize?

    前端代码:index.jsp如下:

    <html>
    <head>
    <meta charset="UTF-8">
    <meta name="x5-orientation" content="portrait">
    <link rel="stylesheet" href="/flowsweb/css/weui.min.css">
    <title>微信公众号支付测试</title>
    </head>
    <body>
    <div class="container" id="container">
    <a href=" https://open.weixin.qq.com/connect/oauth2/authorize? appid=wxxxxxxxxxxxxxxx&redirect_uri=http://域名/项目名/获取openid的接口名&response_type=code&scope=snsapi_base&state=STATE#wechat_redirect " class="weui-btn weui-btn_primary" style="font-size:40px; 100px;">
    立即支付
    </a>
    </div>
    </body>
    </html>

    获取openid接口代码:

    public class wxPayOpenId

    {

    public static Log LOG = LogFactory.getLog(wxPayOpenId.class);

    private static String APPID = "wxxxxxxxxxxxxxxxxxxxx51"; //微信公众号id

    private static String SECRET = "2xxxxxxxxxxxxxxxxxc"; //微信公众号密钥id

    private static String MCHID = "1xxxxxxxxx"; //微信支付商户号

    private static String KEY = "xxxxxxxxxxxxxxxxxxxxx"; //商户号对应的密钥

    // private static String CODEURL = "https://open.weixin.qq.com/connect/oauth2/authorize?"; //前端获取code的微信链接

    private static String OPENIDURL = "https://api.weixin.qq.com/sns/oauth2/access_token?"; //获取微信openid的链接

    private static String UNURL = "https://api.mch.weixin.qq.com/pay/unifiedorder"; //微信统一下单链接

    private static String TRADETYPE="JSAPI";//jsapi代表公众号支付

             public String execute(Context context) throws BPException {

                   HttpServletRequest request = (HttpServletRequest) context.getRequest();

                    //获取用户的code

                    String code = (String) context.getValue("code"); // 从前端请求获取code, 针对你的框架 String code = request.getParameter("code");

                    System.out.println("得到用户code值");

                    System.out.println(code);

                     //获取openid

                    String openId=getOpenId(code); //要把openid放在缓存里,因为“微信统一下单接口”需要用openid

                    context.setValue("openId", String.valueOf(openId));

                   return "0";

             }

               // 获取openId

             public String getOpenId(String code) {

                    System.out.println("此时code不为空");

                    String openIdUrl = OPENIDURL + "appid=" + APPID + "&secret=" + SECRET + "&code=" + code + "&grant_type=authorization_code";

                  try {

                            HttpRequest request = HttpRequest.post(openIdUrl).contentType("application/json;charset=utf-8");

                           String res = request.body();

                           if (res != null) {

                                    JSONObject obj = JSON.parseObject(res);

                                     System.out.println("输出调用获取openid链接的值~~~~~~~");

                                     System.out.println(obj);

                                     String access_token=obj.getString("access_token");

                                     System.out.println("输出access_token的值~~~~~~~");

                                     System.out.println(access_token);

                                     return obj.getString("openid");

                           }

                          return null;

                  }catch (Exception e) {

                    return null;

                     } 

                return null;

           }

    }

    2.微信统一下单接口:

    import java.io.IOException;

    import java.io.OutputStream;

    import java.io.UnsupportedEncodingException;

    import java.math.BigDecimal;

    import java.security.MessageDigest;

    import java.util.Iterator;

    import java.util.Map;

    import java.util.Random;

    import java.util.Set;

    import java.util.SortedMap;

    import java.util.TreeMap;

    import javax.servlet.http.HttpServletRequest;

    import javax.servlet.http.HttpServletResponse;

    import com.alibaba.fastjson.JSON;

    import com.alibaba.fastjson.JSONObject;

    import com.blade.kit.http.HttpRequest;

    import org.dom4j.*;

    import org.dom4j.io.SAXReader;

    import sun.util.logging.resources.logging;

    import org.apache.commons.logging.Log;

    import org.apache.commons.logging.LogFactory;

    import org.apache.http.HttpResponse;

    public class wxPayHttp{

    private static String APPID = "wxxxxxxxxxxxxxxxxxxxx51"; //微信公众号id

    private static String SECRET = "2xxxxxxxxxxxxxxxxxc"; //微信公众号密钥id

    private static String MCHID = "1xxxxxxxxx"; //微信支付商户号

    private static String KEY = "xxxxxxxxxxxxxxxxxxxxx"; //商户号对应的密钥

    // private static String CODEURL = "https://open.weixin.qq.com/connect/oauth2/authorize?"; //前端获取code的微信链接

    private static String OPENIDURL = "https://api.weixin.qq.com/sns/oauth2/access_token?"; //获取openid的链接

    private static String UNURL = "https://api.mch.weixin.qq.com/pay/unifiedorder"; //微信统一下单链接

    private static String TRADETYPE="JSAPI";//jsapi代表公众号支付

    public String execute(Context context) throws BPException {

                             HttpServletRequest request = (HttpServletRequest) context.getRequest();

                             String money=(String) context.getValue("money");

                            String body=(String) context.getValue("body");

                            String openid=(String) context.getValue("openid"); //openid要从缓存中获取

                           String xml=getxml(openid,money,body,request);

                           System.out.println("输出进行签名的数据xml:~~~~~~~~~~~~~~~");

                           System.out.println(xml);

                           String resxml=unifiedorder(xml);//解析xml字符串,取出preparepayid

                           System.out.println("输出调用微信统一下单所返回的数据resxml:~~~~~~~~~~~~~~~~~~");

                          System.out.println(resxml); try {

                          Map<String, String> resultMap=WXPayUtil.xmlToMap(resxml); //WXPayUtil类将在下面展示出来

                          String return_code=resultMap.get("return_code");

                         if ("SUCCESS".equalsIgnoreCase(return_code)) {

                         String prepay_id= resultMap.get("prepay_id");

                         System.out.println("输出prepay_id的值");

                         System.out.println(prepay_id);

                         String nonce_str= System.currentTimeMillis()+""+((int)(Math.random()*90000)+10000);//随机生成18位数字

                         SortedMap<Object, Object> finalpackage = new TreeMap<Object, Object>();

                         String timestamp = String.valueOf(System.currentTimeMillis() / 1000); //时间戳

                        String packages = "prepay_id="+prepay_id; finalpackage.put("appId", APPID);

                       finalpackage.put("timeStamp", timestamp);

                       finalpackage.put("nonceStr", nonce_str);

                       finalpackage.put("package", packages);

                       finalpackage.put("signType", "MD5");

                       String finalsign=WXPayUtil.creatSign(finalpackage,KEY); //进行签名

                       CollList data=(CollList)context.get("data");

                       Entity entity= new Entity(); //把如下数据放在集合data里传给前端

                       entity.addElement("appId", APPID);

                       entity.addElement("timeStamp",timestamp);

                       entity.addElement("nonceStr", nonce_str);

                       entity.addElement("package",packages );

                       entity.addElement("paySign",finalsign );

                       entity.addElement("signType","MD5");

                        //entity.addElement("success","ok" );

                       data.addEntity(entity);

                       } else {

                               return "-1";

                      }

                } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); return "-1"; }

                    return "0";

                 }

              //组装统一下订单参数并进行签名

             public static String getxml(String openid,String money,String body,HttpServletRequest request){

                          System.out.println("对订单参数进行签名+++++++++");

                         String returnXml = null;

                         try {

                                     String nonce_str= System.currentTimeMillis()+""+((int)(Math.random()*90000)+10000);//随机生成18位数字

                                     String notify_url="http://域名/项目名/回调时的接口名";//微信处理完统一订单后回调的接口url

                                     String out_trade_no =WXPayUtil.getCurrTime()+WXPayUtil.getRandomString2(5); //商户订单号

                                     int total_fee=(int)(Double.parseDouble(money)*100); //注意费用total_fee一定要是int型,微信支付官网规定的

                                     SortedMap<Object,Object> parameters = new TreeMap<Object,Object>();

                                    parameters.put("appid", APPID);

                                    parameters.put("mch_id", MCHID);

                                    parameters.put("nonce_str", nonce_str);

                                    //parameters.put("attach", "微信支付");

                                   parameters.put("body", body);

                                   parameters.put("out_trade_no", out_trade_no);

                                   parameters.put("total_fee", total_fee); //注意费用total_fee一定要是int型,微信支付官网规定的

                                   parameters.put("spbill_create_ip", request.getRemoteAddr());//获取订单生成的机器IP

                                   parameters.put("notify_url", notify_url);

                                   parameters.put("trade_type",TRADETYPE );

                                   parameters.put("openid", openid);

                                    //parameters.put("device_info", "WEB");

                                   String sign=WXPayUtil.creatSign(parameters,KEY);

                                    returnXml="<xml>"+
                                                       "<appid>"+ APPID+"</appid>"+
                                                       "<mch_id>"+ MCHID+"</mch_id>"+
                                                       "<nonce_str>"+nonce_str+"</nonce_str>"+
                                                       "<sign>"+sign+"</sign>"+
                  "<body>"+body+"</body>"+
                  "<out_trade_no>"+out_trade_no+"</out_trade_no>"+
                  "<total_fee>"+total_fee+"</total_fee>"+
                  "<spbill_create_ip>"+request.getRemoteAddr()+"</spbill_create_ip>"+
                  "<notify_url>"+notify_url+"</notify_url>"+
                  "<trade_type>"+TRADETYPE+"</trade_type>"+
                  "<openid>"+openid+"</openid>"+
                  "</xml>";

                  return returnXml;

         } catch (Exception e) { return returnXml; }

    }

      //调用微信统一下单接口

      public static String unifiedorder(String xml){

                    System.out.println("调用微信统一下单接口+++++++++unifiedorder");

        String returnxml=null;

        try {

          HttpRequest request = HttpRequest.post(UNURL).contentType( "application/json;charset=utf-8").send(xml);

          returnxml=request.body();

          System.out.println("微信统一下单接口返回值");

          System.out.println(returnxml);

          return returnxml;

        } catch (Exception e) { return returnxml;}

      }

    }

    3.微信回调的接口:

    public class wxNotify

    {    HttpServletRequest request = (HttpServletRequest) context.getRequest();

      try{
          boolean flag=false;
          ServletInputStream is=null;
          InputStreamReader isr = null;
          BufferedReader br=null;

          try {
              is = request.getInputStream();
              isr = new InputStreamReader(is);
              br =new BufferedReader(isr);
              StringBuilder stb = new StringBuilder();
              String s = "";
              //String return_msg=(String) context.getValue("return_msg");
              String return_code = "";
              while ((s = br.readLine()) != null) {
                  stb.append(s);
              }
             Document document = DocumentHelper.parseText(stb.toString());

          List<Element> returnCodeList = document.selectNodes("//return_code");
          for (Element element : returnCodeList) {
            return_code = element.getText();
          }
          if(return_code.equals("SUCCESS"))
          {
            List<Element> prepayIdList=document.selectNodes("//out_trade_no");
            String out_trade_no = "";//订单ID
            for (Element element : prepayIdList) {
                out_trade_no = element.getText();
            }
            if(StringUtils.isNotBlank(out_trade_no)){
              flag=true;
            }
          }

        }catch (Exception e) {

          e.printStackTrace();
        }finally{
            try {
                if (is != null) {
                  is.close();
                }
                if (isr != null) {
                    isr.close();
                }
                if (br != null) {
                      br.close();
                }
            } catch (IOException e) {
                flag = true;
                      }
        }
          if (flag) {
            context.setValue("return_code", "SUCCESS");
            context.setValue("return_msg", "OK");
            System.out.println("通知微信支付结果成功!!!!!!!");
            // return "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>";
            } else {
              context.setValue("return_code", "FAIL");
              context.setValue("return_msg", "return_code_err");
              // return "<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[return_code_err]]></return_msg></xml>";
              System.out.println("通知微信支付结果失败!!!!!!!!!");
            }

      } catch (NumberFormatException e) {
            e.printStackTrace();
            return "-1";
      }
    return "0";
    }

    }

    注意:公用的类  WXPayUtil .java

    import java.io.ByteArrayInputStream;
    import java.io.InputStream;
    import java.io.StringWriter;
    import java.text.SimpleDateFormat;
    import java.util.*;
    import java.security.MessageDigest;

    import org.w3c.dom.Node;
    import org.w3c.dom.NodeList;
    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.slf4j.Logger;
    import org.slf4j.LoggerFactory;

    public class WXPayUtil {

    /**
    * 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(" | ", "");
    try {
    writer.close();
    }
    catch (Exception ex) {
    }
    return output;
    }
    /**
    * 日志
    * @return
    */
    public static Logger getLogger() {
    Logger logger = LoggerFactory.getLogger("wxpay java sdk");
    return logger;
    }
    /**
    * md5加密
    * @param str
    * @return
    */
    public static String md5(String str) {
    try {
    MessageDigest md = MessageDigest.getInstance("MD5");
    md.update(str.getBytes());
    byte b[] = md.digest();
    int i;
    StringBuffer buf = new StringBuffer("");
    for (int offset = 0; offset < b.length; offset++) {
    i = b[offset];
    if (i < 0) {
    i += 256;
    }
    if (i < 16) {
    buf.append("0");
    }
    buf.append(Integer.toHexString(i));
    }
    str = buf.toString();
    } catch (Exception e) {
    e.printStackTrace();
    }
    return str;
    }
    /**
    * 签名算法
    * @param str
    * @return
    */
    public static String creatSign(SortedMap<Object, Object> parameters,String Key){
    StringBuffer sb = new StringBuffer();
    Set es = parameters.entrySet();
    Iterator<?> it = es.iterator();
    while (it.hasNext()) {
    @SuppressWarnings("rawtypes")
    Map.Entry entry = (Map.Entry) it.next();
    String k = (String) entry.getKey();
    Object v = entry.getValue();
    if (null != v && !"".equals(v) && !"sign".equals(k)
    && !"key".equals(k)) {
    sb.append(k + "=" + v + "&");}
    }
    sb.append("key="+Key);
    String sign =md5(sb.toString())
    .toUpperCase();

    return sign;

    }
    //自动生成out_trade_no
    public static String getCurrTime(){
    Date now=new Date();
    SimpleDateFormat outFormat=new SimpleDateFormat("yyyyMMddHHmmss");
    String s=outFormat.format(now);
    return s;
    }

    //产生任一位数随机数
    public static String getRandomString2(int length){
    //产生随机数
    Random random=new Random();
    StringBuffer sb=new StringBuffer();
    //循环length次
    for(int i=0; i<length; i++){
    //产生0-2个随机数,既与a-z,A-Z,0-9三种可能
    int number=random.nextInt(3);
    long result=0;
    switch(number){
    //如果number产生的是数字0;
    case 0:
    //产生A-Z的ASCII码
    result=Math.round(Math.random()*25+65);
    //将ASCII码转换成字符
    sb.append(String.valueOf((char)result));
    break;
    case 1:
    //产生a-z的ASCII码
    result=Math.round(Math.random()*25+97);
    sb.append(String.valueOf((char)result));
    break;
    case 2:
    //产生0-9的数字
    sb.append(String.valueOf
    (new Random().nextInt(10)));
    break;
    }
    }
    return sb.toString();
    }

    }

  • 相关阅读:
    MAC下cocos2dx环境搭建
    eclipse混淆打包出错
    eclipseme升级
    MyEclipse 10 中增加插件
    j2me图片处理大全
    关于svn使用
    NFS相关
    BMP文件格式图解
    UDA1341TS
    OpenOCD初始化脚本(uboot)
  • 原文地址:https://www.cnblogs.com/yangxiaomei/p/9018790.html
Copyright © 2011-2022 走看看