微信支付(公众号支付)仅三个文件让你分分钟搞定

微信支付,说起来容易,做起来真不容易,网上资料很多,但是随着微信支付的更新,有用的不多,bug也很多,调试了好久,终于弄明白如何让微信支付调通。这里涉及前后端代码,从而更方便直接用。

首先微信支付,需要弄明白一些流程,从而快速了解。
1、由于是h5页面支付,需要跳转一个地址,获取openid,可以是单独一个index.html,里面只有一个跳转地址,或者也可以直接在微信公众号的子菜单中直接增加这个地址:

https://open.weixin.qq.com/connect/oauth2/authorize?appid=填写appid&redirect_uri=填写&response_type=code&scope=snsapi_base#wechat_redirect

这样跳转的时候就直接可以获取到openid,其中appid需要填写,redirect_uri需要填写,这个地址就是这个跳转地址成功后会获得一个code,然后传给这个地址,我是写到了后台的controller中,从而可以根据这个code,解析出openid。当然也可以单独一个页面,然后通过这个页面进入controller中,然后再跳转到支付页面。
2、由于是后台解析获得openid,所以从后台需要跳转到业务支付页面pay.html,在那里完成支付逻辑,代码后面统一上。
3、支付完成后调出支付窗口,完成支付,并跳到到支付通知地址。

核心流程是上面,但是关键的配置很多,一个不能少,准备工作如下:

1、微信公众号配置:公众号设置-》功能设置-》JS接口安全域名(请求controller的地址前缀),网页授权域名(可以是一级域名,在这个域名下请求的页面可以获得授权)
2、微信公众号配置:微信公众号-》基本设置-》APPID,APPSecert(用于获取openid的参数使用)
3、微信支付商户平台:产品中心-》开发配置-》JSAPI支付目录配置(用于支付页面在这个位置调起,本文是pay.html放在这个目录)
4、微信支付商户平台:账户中心-》API安全-》API证书(*.p12格式,用于代码配置证书用),API密钥(产生签名需要使用这个,会进行两次签名)

开始代码

1、下载最新版的微信官方java版本demo,地址为:

https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=11_1

由于WXPayConfig是抽象类,需要继承,同目录下新建一个类MyConfig,代码如下:

package com.wxpay.demo.sdk;
import com.wxpay.demo.sdk.WXPayConfig;
import java.io.*;

public class MyConfig extends WXPayConfig{
    
    private byte[] certData;

    public MyConfig() throws Exception {
        String certPath = "C:\\cert\\apiclient_cert.p12";//填写具体路径
        File file = new File(certPath);
        InputStream certStream = new FileInputStream(file);
        this.certData = new byte[(int) file.length()];
        certStream.read(this.certData);
        certStream.close();
    }

    public String getAppID() {
        return "wx***";//填写具体的公众号中的APPID
    }

    public String getMchID() {
        return "160***";//微信支付商户平台中的商户号
    }

    public String getKey() {
        return "d2ab1****";//微信公众号中的APPSecert
    }
    
    public String getAPIKey() {
        return "Ling****";//微信支付商户平台中的API密钥
    }

    public InputStream getCertStream() {
        ByteArrayInputStream certBis = new ByteArrayInputStream(this.certData);
        return certBis;
    }

    public int getHttpConnectTimeoutMs() {
        return 8000;
    }

    public int getHttpReadTimeoutMs() {
        return 10000;
    }

    @Override
    IWXPayDomain getWXPayDomain() {
        // TODO Auto-generated method stub
        IWXPayDomain iwxPayDomain = new IWXPayDomain() {
            
            public void report(String domain, long elapsedTimeMillis, Exception ex) {
        
            }
    
            public DomainInfo getDomain(WXPayConfig config) {
                return new IWXPayDomain.DomainInfo(WXPayConstants.DOMAIN_API, true);
            }
        };
        return iwxPayDomain;
    }
}

开始核心的后台java逻辑,涉及三个,一个是/wx/openid是开篇说的,重要:通过一个链接跳转后的回调地址,从而后台获得openid,然后跳转到自己的支付页面,第二是/wx/pay,就是支付页面需要ajax调用这个接口,从而在这个接口里面完成微信预支付的接口,获得prepay_id,然后返回给前端,前端再调起支付接口,成功后,进入第三步,/wx/notify,这个接口是成功后会调用这个接口,进行告诉微信成功,并调用自己的业务逻辑。

package com.wxpay.demo.controller;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.URL;
import java.net.URLConnection;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import com.wxpay.demo.sdk.MyConfig;
import com.wxpay.demo.sdk.WXPayConstants.SignType;
import com.wxpay.demo.sdk.WXPayUtil;

import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONObject;

import com.alibaba.fastjson.JSON;


@Controller
@RequestMapping("/wx")
public class InterfaceController {
    
    private String m_openid;
    private String m_prepayid;
    private String m_nonce_str;
    
    //http中请求接口
    public String sendPost(String url, String param) {
        PrintWriter out = null;
        BufferedReader in = null;
        String result = "";
        try {
            URL realUrl = new URL(url);
            // 打开和URL之间的连接
            URLConnection conn = realUrl.openConnection();
            // 设置通用的请求属性
            conn.setRequestProperty("accept", "*/*");
            conn.setRequestProperty("connection", "Keep-Alive");
            conn.setRequestProperty("user-agent",
                    "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
            // 发送POST请求必须设置如下两行
            conn.setDoOutput(true);
            conn.setDoInput(true);
            // 获取URLConnection对象对应的输出流
            //out = new PrintWriter(conn.getOutputStream());
            // 获取URLConnection对象对应的输出流(进行编码)
            out = new PrintWriter(new OutputStreamWriter(conn.getOutputStream(),"UTF-8"));
 
 
            // 发送请求参数
            out.print(param);
            // flush输出流的缓冲
            out.flush();
            // 定义BufferedReader输入流来读取URL的响应
            in = new BufferedReader(new InputStreamReader(
                    conn.getInputStream(), "utf-8"));
            String line;
            while ((line = in.readLine()) != null) {
                result += line;
            }
 
        } catch (Exception e) {
            System.out.println("发送 POST 请求出现异常!" + e);
            e.printStackTrace();
        }
        // 使用finally块来关闭输出流、输入流
        finally {
            try {
                if (out != null) {
                    out.close();
                }
                if (in != null) {
                    in.close();
                }
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
        return result;
    }

    
    @RequestMapping("/openid")
    public void wet(HttpServletRequest request,HttpServletResponse response) throws Exception{
        
        MyConfig myconfig = new MyConfig();
        
        String json1 = "";
        String code = request.getParameter("code");
        String httpurl = "https://api.weixin.qq.com/sns/oauth2/access_token?"+"appid="+myconfig.getAppID()+"&secret="+myconfig.getKey()+"&code="+code+"&grant_type=authorization_code";//
        

        //网页授权获取用户信息时用于获取access_token以及openid的请求路径 https://api.weixin.qq.com/sns/oauth2/access_token?
         try {
             json1 = HttpUtil.get(httpurl);
             JSONObject jsonToken = new JSONObject(json1);
             m_openid = jsonToken.getStr("openid");
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
         
         response.sendRedirect("https://**/pay.html");//需要填写自己的支付页面路径
    }
    
    @RequestMapping("/pay")
    public void pay(HttpServletRequest request, HttpServletResponse response)
            throws Exception {
        
        MyConfig myconfig = new MyConfig();
        
        request.setCharacterEncoding("UTF-8");
        
        //网页授权后获取传递的参数
        String money = request.getParameter("money");//分为单位
        String ip = request.getParameter("ip");
        int intMoney = Integer.parseInt(money); 
        
        //用于获取随机数
        String strReq = WXPayUtil.generateNonceStr();//10位序列号,可以自行调整
        
        
        String orderNo=myconfig.getAppID()+Long.toString(WXPayUtil.getCurrentTimestamp());//随机生成了一个订单号

        Map data = new HashMap();
        data.put("appid", myconfig.getAppID());
        data.put("body", "商品名称");//填写自己的商品名称
        data.put("mch_id", myconfig.getMchID());
        data.put("nonce_str",strReq);
        data.put("notify_url", "需要填写回调地址");//如:https://**/wx/notify
        data.put("out_trade_no", orderNo);
        data.put("openid",m_openid);
        data.put("spbill_create_ip", ip);
        data.put("total_fee", money);
        data.put("trade_type", "JSAPI");  // 
   

        try {
            String sign = WXPayUtil.generateSignature(data, myconfig.getAPIKey(),SignType.MD5);
             
            data.put("sign", sign);
            String xml = WXPayUtil.mapToXml(data);
            String wxUnifiedorderUrl = "https://api.mch.weixin.qq.com/pay/unifiedorder";
            String xmlStr = sendPost(wxUnifiedorderUrl, xml);
            
            Map map = WXPayUtil.xmlToMap(xmlStr);
            if (xmlStr.indexOf("SUCCESS") != -1) {
                m_prepayid = (String) map.get("prepay_id");
                m_nonce_str = (String) map.get("nonce_str");
            }

            System.out.println("---rush wxpay/pay,m_prepayid="+m_prepayid+",nonce_str="+m_nonce_str);
            
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }


        Map json = new HashMap();
        json.put("appId", myconfig.getAppID());
        json.put("timeStamp", WXPayUtil.getCurrentTimestamp() + "");
        json.put("nonceStr", m_nonce_str);//需要用第一签名返回的值
        //json.put("nonceStr", WXPayUtil.generateNonceStr());
        json.put("package", "prepay_id=" + m_prepayid);     
        json.put("signType", "MD5");
        try {
            String sign = WXPayUtil.generateSignature(json, myconfig.getAPIKey(),SignType.MD5);
            json.put("paySign", sign);
        }catch(Exception e){
            e.printStackTrace();
        }
        
        String s = JSON.toJSONString(json);
        response.setCharacterEncoding("utf-8");
        response.setHeader("Access-Control-Allow-Origin", "*");
        response.setContentType("application/json; charset=utf-8");//返回的格式必须设置为application/json
        response.getWriter().write(s);//写入到返回结果中
        System.out.println("---rush wxpay/pay,json="+json);

        }
        
    @RequestMapping("/notify")
    public void notify(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
         System.out.println("--rush wxpay/notify--------------------"); 

        response.getWriter()
        .write("");
       // response.sendRedirect("https://***/payover.html");//可以进入自己的后续业务处理

    }
    
    
}

其中涉及的pay.html核心代码如下:





    
    支付   
    
    
     




如果不出意外,这三个文件弄好,就可以调起微信支付了,恭喜成功哦。。。

当然,由于微信支付需要https,java代码工程别忘记引入域名的证书配置,tomcat下也需要配置ssl。

你可能感兴趣的:(微信支付(公众号支付)仅三个文件让你分分钟搞定)