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("\n|\r", "");
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();
}

}

转载于:https://www.cnblogs.com/yangxiaomei/p/9018790.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值