java开发微信公众号支付

前端技术 2023/09/02 Java

最近做了微信公众号支付的开发,由于是第一次做也摸索了几天的时间,也只是达到了实现功能的水平,并没有太多考虑到性能问题,所以这篇文章比较适合初学者。

    微信公众号支付的总体其实很简单,大致就分为三步。第一步需要获取用户授权;第二步调用统一下单接口获取预支付id;第三步H5调起微信支付的内置的js。下面介绍具体每一步的开发流程。

一    首先要明确微信公众号支付属于网页版支付,所以相较于app的直接调取微信支付要多一步微信授权。也就是需要获取用户的openid。微信公众号使用的交易类型是JSAPI,所以统一下单接口的文档明确的写到

因此我们必须去获取openid,同时也可以处理一些我们需要的逻辑。获取用户授权有两种方式:1.scope=snsapi_base;2.scope=snsapi_userinfo.我使用的是snsapi_base

Scope为snsapi_base

https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx520c15f417810387&redirect_uri=http%3A%2F%2Fchong.qq.com%2Fphp%2Findex.php%3Fd%3D%26c%3DwxAdapter%26m%3DmobileDeal%26showwxpaytitle%3D1%26vb2ctag%3D4_2030_5_1194_60&response_type=code&scope=snsapi_base&state=123#wechat_redirect

Scope为snsapi_userinfo

https://open.weixin.qq.com/connect/oauth2/authorize?appid=wxf0e81c3bee622d60&redirect_uri=http%3A%2F%2Fnba.bluewebgame.com%2Foauth_response.php&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect

微信的官方文档也有对各个参数的详细说明,我就关键的参数仔细的说明一下。首先appid就不多说了就是你微信公众号的appid固定写死的,redirect_uri这个参数是最重要的,这个地址是访问你处理的接口地址。你可以在这个链接上拼接上你所需要的参数,一般你是要把订单的金额传到这个接口里的,访问这个链接的时候微信会给你code你需要用它去获取openid,记得要对其进行urlencode处理。state参数可以理解为扩展字段,其他的参数都是固定写法就不在多做介绍了。下面是获取openid的代码片段。

//获取openId
            HttpClientUtil util = HttpClientUtil.getInstance();
            Map<String, String> map = new HashMap<String, String>();
            map.put(\"appid\", WxPayConfig.APPID);
            map.put(\"secret\", WxPayConfig.APPSECRET);
            map.put(\"code\", code);
            map.put(\"grant_type\", WxPayConfig.GRANT_TYPE);
            String returnStr = util.doPostRetString(\"https://api.weixin.qq.com/sns/oauth2/access_token\", null,map);
            logger.info(\"returnStr:[\" + returnStr + \"]\");
            AccessToken at = JSON.parseObject(returnStr, AccessToken.class);

AccessToken.java

public class AccessToken {
   
  private String access_token;
  private String expires_in;
  private String refresh_token;
  private String openid;
  private String scope;
  private String unionid;
   
  public String getAccess_token() {
    return access_token;
  }
  public void setAccess_token(String access_token) {
    this.access_token = access_token;
  }
  public String getExpires_in() {
    return expires_in;
  }
  public void setExpires_in(String expires_in) {
    this.expires_in = expires_in;
  }
  public String getRefresh_token() {
    return refresh_token;
  }
  public void setRefresh_token(String refresh_token) {
    this.refresh_token = refresh_token;
  }
  public String getOpenid() {
    return openid;
  }
  public void setOpenid(String openid) {
    this.openid = openid;
  }
  public String getScope() {
    return scope;
  }
  public void setScope(String scope) {
    this.scope = scope;
  }
  public String getUnionid() {
    return unionid;
  }
  public void setUnionid(String unionid) {
    this.unionid = unionid;
  }
  @Override
  public String toString() {
    return \"AccessToken [access_token=\" + access_token + \", expires_in=\"
        + expires_in + \", refresh_token=\" + refresh_token + \", openid=\"
        + openid + \", scope=\" + scope + \", unionid=\" + unionid + \"]\";
  }
   
   
 
}

二    我们获取了openid后,就可以进行下一步的统一下单的开发了。微信上统一下单接口的文档写的比较详细了,具体的参数含义我就不多做介绍了。下面直接贴最直观的代码,特别提醒的是一定要注意签名的正确。签名所使用的key并不是AppSecret而是你申请时自己定义的商户key。

//统一下单
 
            WxPaySendData data = new WxPaySendData();
            data.setAppid(WxPayConfig.APPID);
            data.setAttach(\"微信支付\");
            data.setBody(\"微信公众号支付\");
            data.setMch_id(WxPayConfig.MCHID);
            data.setNonce_str(nonceStr);
            data.setNotify_url(WxPayConfig.NOTIFY_URL);
            data.setOut_trade_no(tradeNo);
            data.setTotal_fee((int)(fee*100));//单位:分
            data.setTrade_type(\"JSAPI\");
            data.setSpbill_create_ip(ip);
            data.setOpenid(at.getOpenid());
            String returnXml = UnifiedorderService.unifiedOrder(data,WxPayConfig.KEY);
            WxPayReturnData reData = new WxPayReturnData();
            XStream xs1 = new XStream(new DomDriver());
            xs1.alias(\"xml\", WxPayReturnData.class);
            reData = (WxPayReturnData) xs1.fromXML(returnXml);

UnifiedorderService.java

public class UnifiedorderService {
   
  private final static Logger logger = LoggerFactory.getLogger(UnifiedorderService.class);
   
  public static String unifiedOrder(WxPaySendData data,String key){
    //统一下单支付
    String returnXml = null;
    try {
      //生成sign签名
      SortedMap<Object,Object> parameters = new TreeMap<Object,Object>();
      parameters.put(\"appid\", data.getAppid()); 
      parameters.put(\"attach\", data.getAttach());
      parameters.put(\"body\", data.getBody());
      parameters.put(\"mch_id\", data.getMch_id());
      parameters.put(\"nonce_str\", data.getNonce_str());
      parameters.put(\"notify_url\", data.getNotify_url());
      parameters.put(\"out_trade_no\", data.getOut_trade_no());
      parameters.put(\"total_fee\", data.getTotal_fee());
      parameters.put(\"trade_type\", data.getTrade_type());
      parameters.put(\"spbill_create_ip\", data.getSpbill_create_ip());
      parameters.put(\"openid\", data.getOpenid());
      parameters.put(\"device_info\", data.getDevice_info());
      logger.info(\"SIGN:\"+WxSign.createSign(parameters,key));
      data.setSign(WxSign.createSign(parameters,key));
      XStream xs = new XStream(new DomDriver(\"UTF-8\",new XmlFriendlyNameCoder(\"-_\", \"_\")));
      xs.alias(\"xml\", WxPaySendData.class);
      String xml = xs.toXML(data);
      logger.info(\"统一下单xml为:\\n\" + xml);
      HttpClientUtil util = HttpClientUtil.getInstance();
      returnXml = util.doPostForString(\"https://api.mch.weixin.qq.com/pay/unifiedorder\", null, xml);
      logger.info(\"返回结果:\" + returnXml);
    } catch (Exception e) {
      e.printStackTrace();
    } 
    return returnXml;
  }
   
}

WxSign

public class WxSign {
   
   
  private static String characterEncoding = \"UTF-8\";
 
  @SuppressWarnings(\"rawtypes\")
  public static String createSign(SortedMap<Object,Object> parameters,String key){ 
    StringBuffer sb = new StringBuffer(); 
    Set es = parameters.entrySet();//所有参与传参的参数按照accsii排序(升序) 
    Iterator it = es.iterator(); 
    while(it.hasNext()) { 
      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 = MD5Util.MD5Encode(sb.toString(), characterEncoding).toUpperCase(); 
    return sign; 
  }
   
  public static String getNonceStr() {
    Random random = new Random();
    return MD5Util.MD5Encode(String.valueOf(random.nextInt(10000)), \"UTF-8\");
  }
 
  public static String getTimeStamp() {
    return String.valueOf(System.currentTimeMillis() / 1000);
  }
 
}

最后要提一下的是NOTIFY_URL回调地址,接收微信支付异步通知回调地址。

三    通过上面的操作我们获得了预支付交易会话标识prepay_id,这样我们就可以进行最后一步的操作了。使用H5调起支付api。

//H5调起支付
              attr.addAttribute(\"appId\", reData.getAppid());
              attr.addAttribute(\"timeStamp\", WxSign.getTimeStamp());
              attr.addAttribute(\"nonceStr\", reData.getNonce_str());
              attr.addAttribute(\"package\", \"prepay_id=\"+reData.getPrepay_id());
              attr.addAttribute(\"signType\", \"MD5\");
              SortedMap<Object,Object> signMap = new TreeMap<Object,Object>();
              signMap.put(\"appId\", reData.getAppid()); 
              signMap.put(\"timeStamp\", WxSign.getTimeStamp());
              signMap.put(\"nonceStr\", reData.getNonce_str());
              signMap.put(\"package\", \"prepay_id=\"+reData.getPrepay_id());
              signMap.put(\"signType\", \"MD5\");
              logger.info(\"PaySIGN:\"+WxSign.createSign(signMap,WxPayConfig.KEY));
              attr.addAttribute(\"paySign\", WxSign.createSign(signMap,WxPayConfig.KEY));

将需要的参数传给页面后,使用微信提供方法调起支付。

<script>
  function getUrlParam(name) {
    //构造一个含有目标参数的正则表达式对象 
    var reg = new RegExp(\"(^|&)\" + name + \"=([^&]*)(&|$)\");
    //匹配目标参数 
    var r = window.location.search.substr(1).match(reg);
    //返回参数值 
    if (r != null)
      return unescape(r[2]);
    return null;
  }
 
  function onBridgeReady() {
    var appId = getUrlParam(\'appId\');
    var timeStamp = getUrlParam(\'timeStamp\');
    var nonceStr = getUrlParam(\'nonceStr\');
    var Package = getUrlParam(\'package\');
    var signType = getUrlParam(\'signType\');
    var paySign = getUrlParam(\'paySign\');
    WeixinJSBridge.invoke(\'getBrandWCPayRequest\', {
      \"appId\" : appId,//\"wx2421b1c4370ec43b\", //公众号名称,由商户传入   
      \"timeStamp\" : timeStamp,//\"1395712654\", //时间戳,自1970年以来的秒数   
      \"nonceStr\" : nonceStr,//\"e61463f8efa94090b1f366cccfbbb444\", //随机串   
      \"package\" : Package,//\"prepay_id=u802345jgfjsdfgsdg888\",
      \"signType\" : signType,//\"MD5\", //微信签名方式:   
      \"paySign\" : paySign,//\"70EA570631E4BB79628FBCA90534C63FF7FADD89\" //微信签名 
    }, function(res) { // 使用以上方式判断前端返回,微信团队郑重提示:res.err_msg将在用户支付成功后返回  ok,但并不保证它绝对可靠。  
      //alert(res.err_msg);
      if (res.err_msg == \"get_brand_wcpay_request:ok\") {
        alert(\"支付成功\");
      }
      if (res.err_msg == \"get_brand_wcpay_request:cancel\") {
        alert(\"交易取消\");
      }
      if (res.err_msg == \"get_brand_wcpay_request:fail\") {
        alert(\"支付失败\");
      }
    });
  }
 
  function callPay() {
    if (typeof WeixinJSBridge == \"undefined\") {
      if (document.addEventListener) {
        document.addEventListener(\'WeixinJSBridgeReady\', onBridgeReady,
            false);
      } else if (document.attachEvent) {
        document.attachEvent(\'WeixinJSBridgeReady\', onBridgeReady);
        document.attachEvent(\'onWeixinJSBridgeReady\', onBridgeReady);
      }
    } else {
      onBridgeReady();
    }
  }
</script>

在返回结果的地方可以自定义一些自己的返回页面。

    总结:由于我也是第一次做,写这篇文章是想记录一下自己的工作成果,和分享给一下也是新手的朋友们可以有一些帮助,最后希望有好的见解朋友可以留言讨论,大家一起学习进步。

以上就是关于java开发微信公众支付的所有内容了,希望大家能够喜欢。

本文地址:https://www.stayed.cn/item/4989

转载请注明出处。

本站部分内容来源于网络,如侵犯到您的权益,请 联系我

我的博客

人生若只如初见,何事秋风悲画扇。