公司做公众号时需要接入微信支付,个人根据网上的demo摸索着完成了公司公众号的支付和退款功能。现也将代码分享出来,希望对需要朋友有帮助。
一.提交支付的toPay.jsp页面代码:

<%String basePath = request.getScheme() + "://"+ request.getServerName() + request.getContextPath()+ "/";
%>
<html>
<body>....<div class="zdx3"><button onclick="pay()">共需支付${sumPrice }元&nbsp;&nbsp;确认支付</button></div>
</body>
</html> <script>function pay() {var url="<%=basePath%>wechat/pay?money=${sumPrice}"; //注意此处的basePath是没有端口号的域名地址。如果包含:80,在提交给微信时有可能会提示 “redirect_uri参数错误” 。//money为订单需要支付的金额//state中存放的为商品订单号var weixinUrl="https://open.weixin.qq.com/connect/oauth2/authorize?appid=${appId}&redirect_uri="+encodeURI(url)+"&response_type=code&scope=snsapi_userinfo&state=${orderId}#wechat_redirect";window.location.href=encodeURI(weixinUrl);}</script>

二.后台处理支付功能代码
(包含两部分:
1.处理支付信息,通过微信接口生成订单号,返回支付页面
2.提供一个微信支付完成后的回调接口)
第1部分代码:

/*** 用户提交支付,获取微信支付订单接口*/
@RequestMapping(value="/pay")
public ModelAndView pay(HttpServletRequest request,HttpServletResponse response){ModelAndView mv = new ModelAndView();String GZHID = "wxfd7c065eee11112222";// 微信公众号idString GZHSecret = "b5b3a627f5d1f8888888888888";// 微信公众号密钥idString SHHID = "111111111";// 财付通商户号String SHHKEY = "mmmmmmmmmmmmmmm";// 商户号对应的密钥/*------1.获取参数信息------- *///商户订单号String out_trade_no= request.getParameter("state"); //价格String money = request.getParameter("money");//金额转化为分为单位String finalmoney = WeChat.getMoney(money);//获取用户的codeString code = request.getParameter("code");/*------2.根据code获取微信用户的openId和access_token------- *///注: 如果后台程序之前已经得到了用户的openId 可以不需要这一步,直接从存放openId的位置或session中获取就可以。//toPay.jsp页面中提交的url路径也就不需要再经过微信重定向。写成:http://localhost:8080/项目名/wechat/pay?money=${sumPrice}&state=${orderId}String openid=null;try {List<Object> list = accessToken(code);openid=list.get(1).toString();} catch (IOException e) {logger.error("根据code获取微信用户的openId出现错误", e);mv.setViewName("error");return mv;}/*------3.生成预支付订单需要的的package数据------- *///随机数 String nonce_str= MD5.getMessageDigest(String.valueOf(new Random().nextInt(10000)).getBytes());//订单生成的机器 IPString spbill_create_ip = request.getRemoteAddr();//交易类型 :jsapi代表微信公众号支付String trade_type = "JSAPI";//这里notify_url是 微信处理完支付后的回调的应用系统接口url。String notify_url ="http://69a6a38e.ngrok.natapp.cn/heyi-console/wechat/weixinNotify";SortedMap<String, String> packageParams = new TreeMap<String, String>();packageParams.put("appid",  GZHID);  packageParams.put("mch_id",  SHHID);  packageParams.put("nonce_str", nonce_str);  packageParams.put("body", "费用");  packageParams.put("out_trade_no", out_trade_no);  packageParams.put("total_fee", finalmoney);  packageParams.put("spbill_create_ip", spbill_create_ip);  packageParams.put("notify_url", notify_url);  packageParams.put("trade_type", trade_type); packageParams.put("openid", openid); /*------4.根据package数据生成预支付订单号的签名sign------- */RequestHandler reqHandler = new RequestHandler(request, response);reqHandler.init( GZHID,  GZHSecret,  SHHKEY);String sign = reqHandler.createSign(packageParams);/*------5.生成需要提交给统一支付接口https://api.mch.weixin.qq.com/pay/unifiedorder 的xml数据-------*/String xml="<xml>"+"<appid>"+ GZHID+"</appid>"+"<mch_id>"+ SHHID+"</mch_id>"+"<nonce_str>"+nonce_str+"</nonce_str>"+"<sign>"+sign+"</sign>"+"<body><![CDATA["+"费用"+"]]></body>"+"<out_trade_no>"+out_trade_no+"</out_trade_no>"+"<total_fee>"+finalmoney+"</total_fee>"+"<spbill_create_ip>"+spbill_create_ip+"</spbill_create_ip>"+"<notify_url>"+notify_url+"</notify_url>"+"<trade_type>"+trade_type+"</trade_type>"+"<openid>"+openid+"</openid>"+"</xml>";/*------6.调用统一支付接口https://api.mch.weixin.qq.com/pay/unifiedorder 生产预支付订单----------*/String createOrderURL = "https://api.mch.weixin.qq.com/pay/unifiedorder";String prepay_id="";try {prepay_id = GetWxOrderno.getPayNo(createOrderURL, xml);if(prepay_id.equals("")){mv.addObject("ErrorMsg", "支付错误");mv.setViewName("error");return mv;}} catch (Exception e) {logger.error("统一支付接口获取预支付订单出错", e);mv.setViewName("error");return mv;}/*将prepay_id存到库中*/PageData p = new PageData();p.put("shopId", out_trade_no);p.put("prePayId", prepay_id);activityService.updatePrePayId(p);/*------7.将预支付订单的id和其他信息生成签名并一起返回到jsp页面 ------- */nonce_str= MD5.getMessageDigest(String.valueOf(new Random().nextInt(10000)).getBytes());SortedMap<String, String> finalpackage = new TreeMap<String, String>();String timestamp = String.valueOf(System.currentTimeMillis() / 1000);String packages = "prepay_id="+prepay_id;finalpackage.put("appId",  GZHID);  finalpackage.put("timeStamp", timestamp);  finalpackage.put("nonceStr", nonce_str);  finalpackage.put("package", packages);  finalpackage.put("signType", "MD5");String finalsign = reqHandler.createSign(finalpackage);mv.addObject("appid",  GZHID);mv.addObject("timeStamp", timestamp);mv.addObject("nonceStr", nonce_str);mv.addObject("packageValue", packages);mv.addObject("paySign", finalsign);mv.addObject("success","ok");mv.setViewName("wechat/pay");return mv;
}

第2部分代码:

/*** 提交支付后的微信异步返回接口*/
@RequestMapping(value="/weixinNotify")
public void weixinNotify(HttpServletRequest request, HttpServletResponse response){String out_trade_no=null;String return_code =null;try {InputStream inStream = request.getInputStream();ByteArrayOutputStream outSteam = new ByteArrayOutputStream();byte[] buffer = new byte[1024];int len = 0;while ((len = inStream.read(buffer)) != -1) {outSteam.write(buffer, 0, len);}outSteam.close();inStream.close();String resultStr  = new String(outSteam.toByteArray(),"utf-8");logger.info("支付成功的回调:"+resultStr);Map<String, Object> resultMap = parseXmlToList(resultStr);String result_code = (String) resultMap.get("result_code");String is_subscribe = (String) resultMap.get("is_subscribe");String transaction_id = (String) resultMap.get("transaction_id");String sign = (String) resultMap.get("sign");String time_end = (String) resultMap.get("time_end");String bank_type = (String) resultMap.get("bank_type");out_trade_no = (String) resultMap.get("out_trade_no");return_code = (String) resultMap.get("return_code");request.setAttribute("out_trade_no", out_trade_no);//通知微信.异步确认成功.必写.不然微信会一直通知后台.八次之后就认为交易失败了.response.getWriter().write(RequestHandler.setXML("SUCCESS", ""));}  catch (Exception e) {logger.error("微信回调接口出现错误:",e);try {response.getWriter().write(RequestHandler.setXML("FAIL", "error"));} catch (IOException e1) {e1.printStackTrace();}} if(return_code.equals("SUCCESS")){//支付成功的业务逻辑}else{//支付失败的业务逻辑}
}

三.微信app中具体支付的jsp页面

<html>
<head>
<script src="js/jquery-1.8.2.min.js" type="text/javascript"></script>
</head>
<body onload="javascript:pay();"><script type="text/javascript">function pay(){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();}       }function onBridgeReady(){WeixinJSBridge.invoke('getBrandWCPayRequest', {"appId" : "${appid}",     //公众号名称,由商户传入     "timeStamp": "${timeStamp}",         //时间戳,自1970年以来的秒数     "nonceStr" : "${nonceStr}", //随机串     "package" : "${packageValue}",     "signType" : "MD5",         //微信签名方式:     "paySign" : "${paySign}"    //微信签名 },function(res){if(res.err_msg == "get_brand_wcpay_request:ok"){  alert("微信支付成功!");}else if(res.err_msg == "get_brand_wcpay_request:cancel"){  alert("用户取消支付!");}else{  alert("支付失败!");}  }); }</script>
</body>
</html>

其他需要用到的相关类和方法:

金额 元转分:

   /*** 元转换成分* @param money* @return*/public static String getMoney(String amount) {if(amount==null){return "";}// 金额转化为分为单位String currency =  amount.replaceAll("\\$|\\¥|\\,", "");  //处理包含, ¥ 或者$的金额  int index = currency.indexOf(".");  int length = currency.length();  Long amLong = 0l;  if(index == -1){  amLong = Long.valueOf(currency+"00");  }else if(length - index >= 3){  amLong = Long.valueOf((currency.substring(0, index+3)).replace(".", ""));  }else if(length - index == 2){  amLong = Long.valueOf((currency.substring(0, index+2)).replace(".", "")+0);  }else{  amLong = Long.valueOf((currency.substring(0, index+1)).replace(".", "")+"00");  }  return amLong.toString(); }

通过微信用户code获取用户的openId:

    /*** 通过微信用户的code换取网页授权access_token* @return* @throws IOException* @throws*/public List<Object> accessToken(String code) throws IOException {List<Object> list = new ArrayList<Object>();String url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid="+ WeChat.HYGZHID + "&secret=" + WeChat.HYGZHSecret+ "&code=" + code + "&grant_type=authorization_code";HttpClient client = new DefaultHttpClient();HttpPost post = new HttpPost(url);HttpResponse res = client.execute(post);if (res.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {HttpEntity entity = res.getEntity();String str = org.apache.http.util.EntityUtils.toString(entity, "utf-8");ObjectMapper mapper=new com.fasterxml.jackson.databind.ObjectMapper.ObjectMapper();Map<String,Object> jsonOb=mapper.readValue(str, Map.class);list.add(jsonOb.get("access_token"));list.add(jsonOb.get("openid"));}return list;}

MD5提取摘要:

/*** MD5加密*/
public class MD5 {private MD5() {}/*** 对传入的数据提取摘要* @param buffer* @return*/public final static String getMessageDigest(byte[] buffer) {char hexDigits[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };try {MessageDigest mdTemp = MessageDigest.getInstance("MD5");mdTemp.update(buffer);byte[] md = mdTemp.digest();int j = md.length;char str[] = new char[j * 2];int k = 0;for (int i = 0; i < j; i++) {byte byte0 = md[i];str[k++] = hexDigits[byte0 >>> 4 & 0xf];str[k++] = hexDigits[byte0 & 0xf];}return new String(str);} catch (Exception e) {return null;}}
}

解析微信回调的xml数据:

 /*** description: 解析微信通知xml* * @param xml* @return* @author ex_yangxiaoyi* @see*/@SuppressWarnings({ "unused", "rawtypes", "unchecked" })private static Map parseXmlToList(String xml) {Map retMap = new HashMap();try {StringReader read = new StringReader(xml);// 创建新的输入源SAX 解析器将使用 InputSource 对象来确定如何读取 XML 输入InputSource source = new InputSource(read);// 创建一个新的SAXBuilderSAXBuilder sb = new org.jdom.input.SAXBuilder.SAXBuilder();// 通过输入源构造一个DocumentDocument doc = (Document) sb.build(source);Element root = doc.getRootElement();// 指向根节点List<Element> es = root.getChildren();if (es != null && es.size() != 0) {for (Element element : es) {retMap.put(element.getName(), element.getValue());}}} catch (Exception e) {e.printStackTrace();}return retMap;}

java文件和需要用到的工具类,我都放到csdn的下载中了。
地址:https://download.csdn.net/download/aofavx/10606894 (免积分)。
如果有不对或者少文件的地方,请留言。我给大家补正。

微信公众号支付详细步骤(整理)相关推荐

  1. 微信公众号支付开发步骤Java(超详细)

    做为一个刚刚做完微信公众号的小白,我不得不吐槽一下微信给的官方文档,里面那坑一个接一个,我这是跳进去再爬出来,一下给做了四天,本来技术就不够好,还被文档带的跑偏跑偏...我在这给大家整理一份超级详细的 ...

  2. java微信公众号支付退款_java 微信公众号支付 详细教程【站长吐血整理】

    maven或者gradle 项目记得引用第三方开放的sdk工具类,微信支付的,很全 微信开发者第三方sdk库资料:weixin-popular compile group: 'com.github.w ...

  3. 如何实现开发一个企业认证开发版微信服务号的详细步骤

    题目:企业如何实现开发一个企业开发版微信公众号的详细步骤?(以PHP为例进行开发) 先附上一张流程图: 一.首先在微信公众平台官网进行注册登录,打款认证,微信公众平台小程序注册与认证详细过程看链接: ...

  4. 微信支付整理 (微信公众号支付)

    由于本人愚钝,在最初接触微信支付时遇到很多坑.在第一次将微信支付调试成功之后在网上炫耀般的留了一个qq(24xxxx)号,以便帮助到更多的人.由此便接触到了大概100多号人的qq询问,期间也拒绝了很多 ...

  5. 微信公众号支付JSAPI 详细记录

    刚刚调试通微信公众号支付,写个博客记录一下. jsapi必要的几个参数 微信公众号的账户密码,微信商户账号密码. 登陆微信公众号,左下角开发-基本配置,查看APPID 1.公众APPID(已经得到) ...

  6. 微信公众号迁移丨如何迁移微信公众号 最详细公众号迁移流程和方法

    微信公众号迁移丨如何迁移微信公众号 最详细微信公众号迁移流程和方法 微信公众号如何迁移?微信公众号迁移公证书需要准备哪些资料? 怎么迁移微信公众号! 教你迁移微信公众号_迁移完成后,原账号就注销了,无 ...

  7. JAVA微信支付(微信公众号支付JSAPI)

    JAVA开发微信支付-公众号支付/微信浏览器支付(JSAPI) 写本篇博客其一是因为最近做的项目在用这个功能,通过本篇博客进行一个全局的梳理,其二呢,也就是想趁着思路清晰,把心得记录下来,分享给大家, ...

  8. 微信公众号支付前端部分流程

    上周公司安排了微信公众号支付开发任务,经过快一周的不断填坑,终于把支付搞定,现在把遇到的问题和开发步骤记录一下,方便遇到同样问题的老铁们节省一些时间,少入些坑,先说一下本文不包含的内容,因为这些并不难 ...

  9. yii2嵌入微信公众号支付

    序言 随着微信被越来越多的人使用,微信商城成为如今的热门.每一个商城都需要有自己的支付方式,微信商城也不例外.微信公众号支付就是微信商城的一种支付方式,微信支付随着微信的推广使用也被广泛应用.今天我主 ...

最新文章

  1. Windows下Anaconda2(Python2)和Anaconda3(Python3)的共存
  2. 解析烧录固件失败_化虚为实,示人本相!FLIR热像仪双型号双版本上手解析
  3. 使用MessageFormat格式化数字,日期
  4. linux边看系统信息,Linux查看系统信息大全[备忘]
  5. 聊聊ES7与ES8特性
  6. ViewResult()和ActionResult()之间的区别
  7. MATLAB r2016a 配置 VLFeat 库教程(超详细,一看必会)
  8. 简述java内存模型
  9. 解压.tar.bz2文件命令
  10. 天翼对讲机写频软件_手台对讲机应该怎么选?
  11. 华为自带时钟天气下载_华为天气时钟农历插件,求华为自带的天气时钟
  12. 「Activiti精品 悟纤出品」Activiti7 Getting Started-摸石头过河 - 第323篇
  13. Linux操作系统优化
  14. PHP反序列化-__wakeup()方法漏洞(CVE-2016-7124)
  15. 红米2怎么升android l,红米2的1G内存少装app够用?怎样让1G内存的安卓手机多装app而不卡?...
  16. 数字化运营管控是如何提升管理透明及效率的!
  17. oracle function
  18. 微信PC版重磅更新!2个困扰多年的大麻烦,这次终于解决了
  19. [Datawhale-李宏毅机器学习-39期]-005-网络设计技巧
  20. TypeError:object of type 'type' has no len()的一种可能原因

热门文章

  1. 原生js获取本地ip地址(自己用)
  2. 元宇宙产业委常务副主任委员甘华鸣:狭义元宇宙9大技术:一种基于狭义元宇宙体系结构的观点
  3. html中百分比都支持吗,響應式設計中百分比%的問題_html/css_WEB-ITnose
  4. 很火的华为太空表网站源码
  5. QML如何实现背景透明
  6. CSS【Text(文本)+Fonts(字体)】
  7. Eclipse在导入项目时显示 “Invalid Project Description”时的处理方法
  8. jenkins构建:ERROR: Error fetching remote repo ‘origin‘(hudson.plugins.git.GitException/does not point)
  9. Watir数据驱动 - Excel
  10. 白杨SEO:从5118站长工具备案内参发现百度SEO批量建站优化玩法