千家信息网

如何使用java实现微信支付的公众号支付

发表于:2026-11-01 作者:千家信息网编辑
千家信息网最后更新 2026年11月01日,小编给大家分享一下如何使用java实现微信支付的公众号支付,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!最近两周实现了调用微信接口使用微信进行支付的需求,包含公众号支付及扫码支付两种
千家信息网最后更新 2026年11月01日如何使用java实现微信支付的公众号支付

小编给大家分享一下如何使用java实现微信支付的公众号支付,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!

最近两周实现了调用微信接口使用微信进行支付的需求,包含公众号支付及扫码支付两种方式,由于微信文档写的较为简略,现将调用微信接口进行支付流程进行记录及分享。

本文旨在对公众号支付的实现流程进行介绍,即微信用户从公众号中点击链接进入商品h6页面,选择商品后点击支付按钮后弹出微信支付页面、输入支付密码、支付成功后跳转到全部商品页面的整个过程。微信扫码支付请参看后续文章。

1、首先,商户需申请微信公众号、微信商户号及微信支付权限。开发过程中需参照公众号及商户平台提供如下参数:

① appid:公众号id,登录微信公众号-开发-基本配置中获得; ② mch_id:收款商家商户号; ③ APP_SECRET:第三方唯一凭证密码; ④ key:收款商户后台进行配置,登录微信商户平台-账户设置-安全设置-api安全,设置32位key值。

2、登录微信公众号,进行开发相关设置:

① 获取用户基本信息(主要是openid)权限配置:微信公众平台-开发-接口权限-网页授权-网页授权域名(不接受IP地址,需通过ICP备案验证,不带http):

② 支付测试目录及测试白名单设置:微信公众平台-微信支付-开发配置,测试授权目录具体到最后一级。

3、获取用户openid,OpenID是公众号一对一对应用户身份的标识:

① 微信网页授权获取用户信息文档:https://developers.weixin.qq.com/miniprogram/dev/wxcloud/guide/functions/userinfo.html。根据文档拼装url,引导用户在微信上点击该链接,获取用户openid等基本信息;

② 引导用户点击url(例如公众号推送该链接),形式如下: https://open.weixin.qq.com/connect/oauth3/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect

各个参数需替换,含义如下: REDIRECT_URI:重定向URL,可为商品列表页面或商品页面,用户授权成功即转到该URL指向页面 scope:snsapi_base和snsapi_userinfo两种,snsapi_base为用户静默授权,snsapi_userinfo需要用户进行授权确认,可以获得更多用户信息。本文选择后者 state:重定向后会带上此参数

③ 用户授权后,重定向的页面获得code参数(若用户禁止授权,则重定向后不会带上code参数,仅会带上state参数redirect_uri?state=STATE ),官方对于code参数的说明如下:

code作为换取access_token的票据,每次用户授权带上的code将不一样,code只能使用一次,5分钟未被使用自动过期。

重定向页面对应controller中通过String code = getPara("code");获取code参数。

④ contoller中同时利用WxPayUtil中方法,调用微信接口,获取当前用户openid,将该openid存入session:

setSessionAttr("openid", (WxPayUtil.getOpenIdByCode(code)).get("openid"));

4、用户选择商品点击付款,在商家提供h6页面确认支付对应controller中,进行统一下单,获得prepay_id(这里需要注意,订单金额转换成以分为单位)。统一下单的官方文档地址为:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1

//统一下单,返回xml,用return_code判断统一下单结果,获取prepay_id等预支付成功信息String prePayInfoXml = WxPayUtil.unifiedOrder("WxPay", userOrder.getStr("orderNo"), (entity.getBigDecimal("orderMoney").multiply(new BigDecimal(100))).intValue(), WxPayUtil.getIpAddr(getRequest()), getSessionAttr("openid").toString());//生成包含prepay_id的map,map传入前端map = WxPayUtil.getPayMap(prePayInfoXml);//将订单号放入map,用以支付后处理map.put("orderNo",userOrder.getStr("orderNo"));

5、前端获得上一步中的map后,调用微信支付JSAPI,前端js代码如下所示:

6、用户完成支付,后台等待微信支付回调,进行支付成功后操作:

① 用户输入密码完成支付。后台回调地址(统一下单中设定的notify_url)接收微信支付结果,对支付结果进行判断并进行对应操作:

public void notify(){ System.out.print("微信支付回调获取数据开始"); HttpServletRequest request = getRequest(); String resXml = WxPayUtil.getNotifyResult(request); //向微信输出处理结果,如果成功(SUCCESS),微信就不会继续调用了,否则微信会连续调用8次 renderText(resXml, "text/xml");}

相关工具及常量类如下:

① WxPayUtil类(支付工具类):

public class WxPayUtil { private static Logger logger = Logger.getLogger(WxPayUtil.class); /** * 根据code获取openid * @param code * @return * @throws IOException */ public static Map getOpenIdByCode(String code) throws IOException { //请求该链接获取access_token HttpPost httppost = new HttpPost("https://api.weixin.qq.com/sns/oauth3/access_token"); //组装请求参数 String reqEntityStr = "appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code"; reqEntityStr = reqEntityStr.replace("APPID", WxPayConstants.APPID); reqEntityStr = reqEntityStr.replace("SECRET", WxPayConstants.APP_SECRET); reqEntityStr = reqEntityStr.replace("CODE", code); StringEntity reqEntity = new StringEntity(reqEntityStr); //设置参数 httppost.setEntity(reqEntity); //设置浏览器 CloseableHttpClient httpclient = HttpClients.createDefault(); //发起请求 CloseableHttpResponse response = httpclient.execute(httppost); //获得请求内容 String strResult = EntityUtils.toString(response.getEntity(), Charset.forName("utf-8")); //获取openid JSONObject jsonObject = new JSONObject(strResult); Map map = new HashMap(); map.put("openid",jsonObject.get("openid")); map.put("access_token",jsonObject.get("access_token")); map.put("refresh_token",jsonObject.get("refresh_token")); return map; } /** * 统一下单 * @param body * @param out_trade_no * @param total_fee * @param IP * @param notify_url * @param openid * @return * @throws IOException */ public static String unifiedOrder(String body,String out_trade_no,Integer total_fee,String IP,String openid)throws IOException { //设置访问路径 HttpPost httppost = new HttpPost("https://api.mch.weixin.qq.com/pay/unifiedorder"); String nonce_str = getNonceStr().toUpperCase();//随机 //组装请求参数,按照ASCII排序 String sign = "appid=" + WxPayConstants.APPID + "&body=" + body + "&mch_id=" + WxPayConstants.MCH_ID + "&nonce_str=" + nonce_str + "¬ify_url=" + WxPayConstants.NOTIFY_URL + "&openid=" + openid + "&out_trade_no=" + out_trade_no + "&spbill_create_ip=" + IP + "&total_fee=" + total_fee.toString() + "&trade_type=" + WxPayConstants.TRADE_TYPE_JS + "&key=" + WxPayConstants.KEY;//这个字段是用于之后MD5加密的,字段要按照ascii码顺序排序 sign = ToolMD5.MD5Encode(sign,"").toUpperCase(); //组装包含openid用于请求统一下单返回结果的XML StringBuilder sb = new StringBuilder(""); sb.append(""); setXmlKV(sb,"appid",WxPayConstants.APPID); setXmlKV(sb,"body",body); setXmlKV(sb,"mch_id",WxPayConstants.MCH_ID); setXmlKV(sb,"nonce_str",nonce_str); setXmlKV(sb,"notify_url",WxPayConstants.NOTIFY_URL); setXmlKV(sb,"openid",openid); setXmlKV(sb,"out_trade_no",out_trade_no); setXmlKV(sb,"spbill_create_ip",IP); setXmlKV(sb,"total_fee",total_fee.toString()); setXmlKV(sb,"trade_type",WxPayConstants.TRADE_TYPE_JS); setXmlKV(sb,"sign",sign); sb.append(""); System.out.println("统一下单请求:" + sb); StringEntity reqEntity = new StringEntity(new String (sb.toString().getBytes("UTF-8"),"ISO8859-1"));//这个处理是为了防止传中文的时候出现签名错误 httppost.setEntity(reqEntity); CloseableHttpClient httpclient = HttpClients.createDefault(); CloseableHttpResponse response = httpclient.execute(httppost); String strResult = EntityUtils.toString(response.getEntity(), Charset.forName("utf-8")); System.out.println("统一下单返回xml:" + strResult); return strResult; } /** * 根据统一下单返回预支付订单的id和其他信息生成签名并拼装为map(调用微信支付) * @param prePayInfoXml * @return */ public static Map getPayMap(String prePayInfoXml){ Map map = new HashMap(); String prepay_id = getXmlPara(prePayInfoXml,"prepay_id");//统一下单返回xml中prepay_id String timeStamp = String.valueOf((System.currentTimeMillis()/1000));//1970年到现在的秒数 String nonceStr = getNonceStr().toUpperCase();//随机数据字符串 String packageStr = "prepay_id=" + prepay_id; String signType = "MD5"; String paySign = "appId=" + WxPayConstants.APPID + "&nonceStr=" + nonceStr + "&package=prepay_id=" + prepay_id + "&signType=" + signType + "&timeStamp=" + timeStamp + "&key="+ WxPayConstants.KEY;//注意这里的参数要根据ASCII码 排序 paySign = ToolMD5.MD5Encode(paySign,"").toUpperCase();//将数据MD5加密 map.put("appId",WxPayConstants.APPID); map.put("timeStamp",timeStamp); map.put("nonceStr",nonceStr); map.put("packageStr",packageStr); map.put("signType",signType); map.put("paySign",paySign); map.put("prepay_id",prepay_id); return map; } /** * 修改订单状态,获取微信回调结果 * @param request * @return */ public static String getNotifyResult(HttpServletRequest request){ String inputLine; String notifyXml = ""; String resXml = ""; try { while ((inputLine = request.getReader().readLine()) != null){ notifyXml += inputLine; } request.getReader().close(); } catch (Exception e) { logger.debug("xml获取失败:" + e); e.printStackTrace(); } System.out.println("接收到的xml:" + notifyXml); logger.debug("收到微信异步回调:"); logger.debug(notifyXml); if(ToolString.isEmpty(notifyXml)){ logger.debug("xml为空:"); } String appid = getXmlPara(notifyXml,"appid");; String bank_type = getXmlPara(notifyXml,"bank_type"); String cash_fee = getXmlPara(notifyXml,"cash_fee"); String fee_type = getXmlPara(notifyXml,"fee_type"); String is_subscribe = getXmlPara(notifyXml,"is_subscribe"); String mch_id = getXmlPara(notifyXml,"mch_id"); String nonce_str = getXmlPara(notifyXml,"nonce_str"); String openid = getXmlPara(notifyXml,"openid"); String out_trade_no = getXmlPara(notifyXml,"out_trade_no"); String result_code = getXmlPara(notifyXml,"result_code"); String return_code = getXmlPara(notifyXml,"return_code"); String sign = getXmlPara(notifyXml,"sign"); String time_end = getXmlPara(notifyXml,"time_end"); String total_fee = getXmlPara(notifyXml,"total_fee"); String trade_type = getXmlPara(notifyXml,"trade_type"); String transaction_id = getXmlPara(notifyXml,"transaction_id"); //根据返回xml计算本地签名 String localSign = "appid=" + appid + "&bank_type=" + bank_type + "&cash_fee=" + cash_fee + "&fee_type=" + fee_type + "&is_subscribe=" + is_subscribe + "&mch_id=" + mch_id + "&nonce_str=" + nonce_str + "&openid=" + openid + "&out_trade_no=" + out_trade_no + "&result_code=" + result_code + "&return_code=" + return_code + "&time_end=" + time_end + "&total_fee=" + total_fee + "&trade_type=" + trade_type + "&transaction_id=" + transaction_id + "&key=" + WxPayConstants.KEY;//注意这里的参数要根据ASCII码 排序 localSign = ToolMD5.MD5Encode(localSign,"").toUpperCase();//将数据MD5加密 System.out.println("本地签名是:" + localSign); logger.debug("本地签名是:" + localSign); logger.debug("微信支付签名是:" + sign); //本地计算签名与微信返回签名不同||返回结果为不成功 if(!sign.equals(localSign) || !"SUCCESS".equals(result_code) || !"SUCCESS".equals(return_code)){ System.out.println("验证签名失败或返回错误结果码"); logger.error("验证签名失败或返回错误结果码"); resXml = "" + "" + "" + " "; }else{ System.out.println("支付成功"); logger.debug("公众号支付成功,out_trade_no(订单号)为:" + out_trade_no); resXml = "" + "" + "" + " "; } return resXml; } /** * 获取32位随机字符串 * @return */ public static String getNonceStr(){ String str = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; StringBuilder sb = new StringBuilder(); Random rd = new Random(); for(int i = 0 ; i < 32 ; i ++ ){ sb.append(str.charAt(rd.nextInt(str.length()))); } return sb.toString(); } /** * 插入XML标签 * @param sb * @param Key * @param value * @return */ public static StringBuilder setXmlKV(StringBuilder sb,String Key,String value){ sb.append("<"); sb.append(Key); sb.append(">"); sb.append(value); sb.append(""); return sb; } /** * 解析XML 获得名称为para的参数值 * @param xml * @param para * @return */ public static String getXmlPara(String xml,String para){ int start = xml.indexOf("<"+para+">"); int end = xml.indexOf(""); if(start < 0 && end < 0){ return null; } return xml.substring(start + ("<"+para+">").length(),end).replace("",""); } /** * 获取ip地址 * @param request * @return */ public static String getIpAddr(HttpServletRequest request) { InetAddress addr = null; try { addr = InetAddress.getLocalHost(); } catch (UnknownHostException e) { return request.getRemoteAddr(); } byte[] ipAddr = addr.getAddress(); String ipAddrStr = ""; for (int i = 0; i < ipAddr.length; i++) { if (i > 0) { ipAddrStr += "."; } ipAddrStr += ipAddr[i] & 0xFF; } return ipAddrStr; }}

② 常量类(根据商户信息进行设置):

public class WxPayConstants { //第三方用户唯一ID public static String APPID = ""; //第三方用户唯一凭证密码 public static String APP_SECRET = ""; //商户ID public static String MCH_ID = ""; //微信商户平台-账户设置-安全设置-api安全,配置32位key public static String KEY = ""; //交易类型 public static String TRADE_TYPE_JS = "JSAPI"; //微信支付回调url public static String NOTIFY_URL = "";}

看完了这篇文章,相信你对"如何使用java实现微信支付的公众号支付"有了一定的了解,如果想了解更多相关知识,欢迎关注行业资讯频道,感谢各位的阅读!

支付 用户 公众 参数 统一 商户 成功 结果 页面 信息 商品 平台 订单 开发 配置 安全 地址 密码 接口 文档 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 什么是科技互联网 华服互联网科技靠谱吗 伟宏互联网科技 互联网科技工作委员会副主任毛军 互联网 科技公司 互联网络科技有限公司 睿民互联网科技 科技互联网创业计划书 金融科技和互联网金融 互联网公司会议桌创意科技软装饰 成都玖崟互联网科技有限公司乐商圈怎么样 科技与互联网的利与弊 承德科技产业互联网发展 互联网金融中的现代科技 互联网科技和法律行业 锡山区互联网智能科技产品供应 中国新注册互联网科技 万物互联网智能科技 互联网科技创新方面的资料 小牛互联网科技有限公司地址 科技互联网 广州大一互联网络科技有限公司 中关村互联网科技集团 链环科技传统企业怎么转型互联网 乌鲁木齐新华智原互联网科技学校 工业互联网山东科技大学 互联网科技快讯热点 上海同邻互联网科技有限公司规模 互联网领先科技活动 小牛互联网科技有限公司地址
0