java实现公众号微信支付功能,走了很多弯路,决定把代码全部贴出来,警示萌新

本文主要是介绍java实现公众号微信支付功能,走了很多弯路,决定把代码全部贴出来,警示萌新,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

公众号实现微信支付的前提条件

1、是认证的服务号,开通了微信支付功能

不能是订阅号,不能没有认证,不能没有开通微信支付功能

2、获取公众号的appid与秘钥

3、开通了微信商户平台,微信商户平台开通了JSAPI支付

4、把商户平台与这个服务号关联起来,在商户平台里面产品中心里面,有关联设置;然后再服务号里面同意就可以了

5、获取商户平台的商户号与秘钥!

无论是商户开发平台的私钥还是服务号的秘钥,要重设的,这个东西不会存储在平台里面!


微信支付的第一步、获取openid

看这个更具体  https://blog.csdn.net/tian_jiangnan/article/details/105724200

微信支付第二步、在商户开发平台设置支付目录

前提:你的域名备案了,域名解析了

设置支付目录的例子

我的域名是www.jianshu.com

我的javaweb项目,我的项目名称是gold

我设置的支付目录是www.jianshu.com/gold  记得保存


 在微信公众号里面设置ip白名单,没错就是把你的服务器公网ip地址写上去,然后保存


现在就呈上我实现微信支付的整个流程吧!

设置公众号菜单,我添加了一个菜单在线支付


这个在线支付绑定的网页是www.jianshu.com/gold/index.jsp

在这个首页Index.jsp里面有一个在线支付的按钮,这个按钮的链接是

	<a href="https://open.weixin.qq.com/connect/oauth2/authorize?
appid=wx99*************68&redirect_uri=http%3a%2f%2fwww.jianshu.com%2fgold%2fpay.jsp&response_type=code&
scope=snsapi_base#wechat_redirect"><button type="button" class="btn btn-info" style="margin-left:40%;">在线登记</button></a></div>

注意redirect_uri路径要进行编码

当我们进入这个pay.jsp页面的时候,页面路径会自动添加上code参数信息

pay.jsp页面


<input type="text" code="${param.code}" id="code" 
<button type="button" class="btn btn-default" onclick="pay()">微信支付</button>

对于${param.code}不用感觉惊慌,不需要引入任何文件,就可以获取路径中的code参数

当我们点击微信支付按钮的时候,执行如下操作

pay方法是进行统一下单处理,而后面的onBridgeReady() 是执行支付成功以后的操作

function pay() {var recode = $("#code").attr("code");console.log("code信息:", recode);if (!recode) {//如果没有获取到code就中断return;}var url = "http://www.jianshu.com/gold/pay.do";$.ajax({url : url, //请求后台dataType : "json",data : {//money : 0.01,mycode : recode},success : function(result) {var log = eval(result);console.log("返回订单信息:", log);appId = log[0].appId;timeStamp = log[0].timeStamp;nonceStr = log[0].nonceStr;packages = log[0].package;signType = log[0].signType;paySign = log[0].paySign;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();}},//success});//ajax},//pay//单独的方法function onBridgeReady() {WeixinJSBridge.invoke('getBrandWCPayRequest', {"appId" : appId, //公众号名称,由商户传入     "timeStamp" : timeStamp, //时间戳,自1970年以来的秒数     "nonceStr" : nonceStr, //随机串     "package" : packages,"signType" : signType, //微信签名方式:     "paySign" : paySign//微信签名 }, function(res) {if (res.err_msg == "get_brand_wcpay_request:ok") {var url ="";var data={};var url = "http://www.jianshu.com/gold/insert.do";$.ajax({url : url, //请求后台dataType : "json",data :data,success : function(result) {console.log("返回订单信息:");},//success});//ajax//支付成功后跳转的页面} else if (res.err_msg == "get_brand_wcpay_request:cancel") {console.log('支付取消');} else if (res.err_msg == "get_brand_wcpay_request:fail") {console.log('支付失败');WeixinJSBridge.call('closeWindow');} //使用以上方式判断前端返回,微信团队郑重提示:res.err_msg将在用户支付成功后返回ok,但并不保证它绝对可靠。});}//单独的方法

点击pay按钮,会跳转到后台    var url = "http://www.jianshu.com/gold/pay.do";

我们看看这个方法里面的代码吧

package cn.com.pay;
import java.io.IOException;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import net.sf.json.JSONArray;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.struts2.ServletActionContext;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import com.alibaba.fastjson.JSONObject;
import cn.com.sdk.WXPayUtil;
@Repository(value = "pay")
public class Pay {private static String APPID = "**********"; // 微信公众号idprivate static String SECRET = "**********"; // 微信公众号密钥idprivate static String MCHID = "**********"; // 微信支付商户号private static String KEY = "**********"; // 商户号对应的密钥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代表公众号支付private String mycode;private String money;@Autowiredprivate SessionFactory sessionfactory;public String getMycode() {return mycode;}public void setMycode(String mycode) {this.mycode = mycode;}public String getMoney() {return money;}public void setMoney(String money) {this.money = money;}private final Log log = LogFactory.getLog(getClass());//获取用户的openidpublic String getOpenid(){String getopenid_url = "https://api.weixin.qq.com/sns/oauth2/access_token";String param = "appid=" + APPID + "&secret=" + SECRET + "&code="+ mycode + "&grant_type=authorization_code";// 向微信服务器发送get请求获取openIdStrString openIdStr = HttpRequest.sendGet(getopenid_url, param);JSONObject json = JSONObject.parseObject(openIdStr);// 转成Json格式String openId = json.getString("openid");// 获取openIdlog.info("该用户的openid是                             "+openId);return openId;}public String paymoney() {Map<String, String> paraMap = new HashMap<String, String>();log.info("mycode信息             "+mycode);int m=Integer.parseInt(money);money=Integer.toString(m*100);log.info("支付的金额是             "+money);openid=getOpenid();try {		// 获取请求ip地址HttpServletRequest request = ServletActionContext.getRequest();String ip = request.getHeader("x-forwarded-for");if (ip == null || ip.length() == 0|| "unknown".equalsIgnoreCase(ip)) {ip = request.getHeader("Proxy-Client-IP");}if (ip == null || ip.length() == 0|| "unknown".equalsIgnoreCase(ip)) {ip = request.getHeader("WL-Proxy-Client-IP");}if (ip == null || ip.length() == 0|| "unknown".equalsIgnoreCase(ip)) {ip = request.getRemoteAddr();}if (ip.indexOf(",") != -1) {String[] ips = ip.split(",");ip = ips[0].trim();}paraMap.put("appid", APPID);paraMap.put("body", "online");//这里写中文会乱码,会导致签名不正确paraMap.put("mch_id", MCHID);paraMap.put("nonce_str", WXPayUtil.generateNonceStr());paraMap.put("openid", openid);// 随机生成一个订单号paraMap.put("out_trade_no", getOrderIdByTime());// 订单号System.out.println("订单号是");System.out.println(getOrderIdByTime());log.info("订单号是            "+getOrderIdByTime());paraMap.put("spbill_create_ip", ip);paraMap.put("total_fee", money);paraMap.put("trade_type", "JSAPI");// 此路径是微信服务器调用支付结果通知路径paraMap.put("notify_url", "http://www.jiancs.com/gold/backs.do");String sign = WXPayUtil.generateSignature(paraMap, KEY);log.info("签名如下:            "+sign);paraMap.put("sign", sign);String xml = WXPayUtil.mapToXml(paraMap);// 将所有参数(map)转xml格式log.info("xml如下:        "+xml);String unifiedorder_url = "https://api.mch.weixin.qq.com/pay/unifiedorder";String xmlStr = HttpRequest.sendPost(unifiedorder_url, xml);// 发送post请求"统一下单接口"返回预支付id:prepay_id// 以下内容是返回前端页面的json数据log.info("调了统一接口的xmlStr如下:        "+xmlStr);String prepay_id = "";// 预支付idif (xmlStr.indexOf("SUCCESS") != -1) {Map<String, String> map = WXPayUtil.xmlToMap(xmlStr);prepay_id = (String) map.get("prepay_id");}log.info("此时获取到的prepay_id如下:        "+prepay_id);Map<String, String> payMap = new HashMap<String, String>();payMap.put("appId", APPID);payMap.put("timeStamp", WXPayUtil.getCurrentTimestamp() + "");payMap.put("nonceStr", WXPayUtil.generateNonceStr());payMap.put("signType", "MD5");payMap.put("package", "prepay_id=" + prepay_id);log.info("prepay_id如下:        "+"prepay_id=" + prepay_id);String paySign = WXPayUtil.generateSignature(payMap, KEY);log.info("paySign如下:        "+paySign);payMap.put("paySign", paySign);payMap.put("openid", openid);// 把payMap给前台HttpServletResponse response = ServletActionContext.getResponse();response.setCharacterEncoding("utf-8");try {JSONArray re = JSONArray.fromObject(payMap);String result = re.toString();PrintWriter writer = response.getWriter();writer.write(result);// 返回json数组writer.flush();writer.close();} catch (IOException e) {e.printStackTrace();}return null;} catch (Exception e) {e.printStackTrace();}return null;}// 随机订单号public static String getOrderIdByTime() {SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");String newDate = sdf.format(new Date());String result = "";Random random = new Random();for (int i = 0; i < 3; i++) {result += random.nextInt(10);}return newDate + result;}
}

 

 支付成功以后的回掉类与方法

package cn.com.pay;
import java.io.InputStream;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.struts2.ServletActionContext;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;import cn.com.bean.Order;
import cn.com.sdk.WXPayUtil;@Repository(value="wxPayController")
public class WxPayController {@Autowiredprivate Order o;@Autowiredprivate SessionFactory sessionfactory;private final Log log = LogFactory.getLog(getClass());@Transactionalpublic String callBack(){System.out.println("微信支付成功,微信发送的callback信息,请注意修改订单信息");log.info("微信支付成功,微信发送的callback信息,请注意修改订单信息");	HttpServletRequest request = ServletActionContext.getRequest();HttpServletResponse response = ServletActionContext.getResponse();InputStream is = null;try {is = request.getInputStream();//获取请求的流信息(这里是微信发的xml格式所有只能使用流来读)String xml = WXPayUtil.inputStream2String(is, "UTF-8");Map<String, String> notifyMap = WXPayUtil.xmlToMap(xml);//将微信发的xml转maplog.info("回调成功的代xml"+xml);			if(notifyMap.get("return_code").equals("SUCCESS")){  if(notifyMap.get("result_code").equals("SUCCESS")){  String ordersSn = notifyMap.get("out_trade_no");//商户订单号 String amountpaid = notifyMap.get("total_fee");//实际支付的订单金额:单位 分BigDecimal amountPay = (new BigDecimal(amountpaid).divide(new BigDecimal("100"))).setScale(2);//将分转换成元-实际支付金额:元SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//设置日期格式String time=df.format(new Date());// new Date()为获取当前系统时间/*以下是自己的业务处理------仅做参考* 更新order对应字段/已支付金额/状态码*///获取当前时间o.setMoney(amountPay+"");o.setOut_trade_no(ordersSn);o.setDate(time);//存储到数据库里面Session session = sessionfactory.openSession();session.save(o);session.close();//存储到数据库里面 }  }//告诉微信服务器收到信息了,不要在调用回调action了========这里很重要回复微信服务器信息用流发送一个xml即可response.getWriter().write("<xml><return_code><![CDATA[SUCCESS]]></return_code></xml>");  is.close();} catch (Exception e) {e.printStackTrace();}return null;}
}

 其实实现微信支付的主要是一些公众号官方提供的类

HttpRequest.java

package cn.com.pay;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.URL;
import java.net.URLConnection;
import java.util.List;
import java.util.Map;public class HttpRequest {/*** 向指定URL发送GET方法的请求* * @param url*            发送请求的URL* @param param*            请求参数,请求参数应该是 name1=value1&name2=value2 的形式。* @return URL 所代表远程资源的响应结果*/public static String sendGet(String url, String param) {String result = "";BufferedReader in = null;try {String urlNameString = url + "?" + param;System.out.println(urlNameString);URL realUrl = new URL(urlNameString);// 打开和URL之间的连接URLConnection connection = realUrl.openConnection();// 设置通用的请求属性connection.setRequestProperty("accept", "*/*");connection.setRequestProperty("connection", "Keep-Alive");connection.setRequestProperty("user-agent","Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");// 建立实际的连接connection.connect();// 获取所有响应头字段Map<String, List<String>> map = connection.getHeaderFields();// 遍历所有的响应头字段for (String key : map.keySet()) {System.out.println(key + "--->" + map.get(key));}// 定义 BufferedReader输入流来读取URL的响应in = new BufferedReader(new InputStreamReader(connection.getInputStream()));String line;while ((line = in.readLine()) != null) {result += line;}} catch (Exception e) {System.out.println("发送GET请求出现异常!" + e);e.printStackTrace();}// 使用finally块来关闭输入流finally {try {if (in != null) {in.close();}} c

这篇关于java实现公众号微信支付功能,走了很多弯路,决定把代码全部贴出来,警示萌新的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/882804

相关文章

C++对象布局及多态实现探索之内存布局(整理的很多链接)

本文通过观察对象的内存布局,跟踪函数调用的汇编代码。分析了C++对象内存的布局情况,虚函数的执行方式,以及虚继承,等等 文章链接:http://dev.yesky.com/254/2191254.shtml      论C/C++函数间动态内存的传递 (2005-07-30)   当你涉及到C/C++的核心编程的时候,你会无止境地与内存管理打交道。 文章链接:http://dev.yesky

问题:第一次世界大战的起止时间是 #其他#学习方法#微信

问题:第一次世界大战的起止时间是 A.1913 ~1918 年 B.1913 ~1918 年 C.1914 ~1918 年 D.1914 ~1919 年 参考答案如图所示

Java五子棋之坐标校正

上篇针对了Java项目中的解构思维,在这篇内容中我们不妨从整体项目中拆解拿出一个非常重要的五子棋逻辑实现:坐标校正,我们如何使漫无目的鼠标点击变得有序化和可控化呢? 目录 一、从鼠标监听到获取坐标 1.MouseListener和MouseAdapter 2.mousePressed方法 二、坐标校正的具体实现方法 1.关于fillOval方法 2.坐标获取 3.坐标转换 4.坐

[职场] 护理专业简历怎么写 #经验分享#微信

护理专业简历怎么写   很多想成为一名护理方面的从业者,但是又不知道应该怎么制作一份简历,现在这里分享了一份护理方面的简历模板供大家参考。   蓝山山   年龄:24   号码:12345678910   地址:上海市 邮箱:jianli@jianli.com   教育背景   时间:2011-09到2015-06   学校:蓝山大学   专业:护理学   学历:本科

Spring Cloud:构建分布式系统的利器

引言 在当今的云计算和微服务架构时代,构建高效、可靠的分布式系统成为软件开发的重要任务。Spring Cloud 提供了一套完整的解决方案,帮助开发者快速构建分布式系统中的一些常见模式(例如配置管理、服务发现、断路器等)。本文将探讨 Spring Cloud 的定义、核心组件、应用场景以及未来的发展趋势。 什么是 Spring Cloud Spring Cloud 是一个基于 Spring

Javascript高级程序设计(第四版)--学习记录之变量、内存

原始值与引用值 原始值:简单的数据即基础数据类型,按值访问。 引用值:由多个值构成的对象即复杂数据类型,按引用访问。 动态属性 对于引用值而言,可以随时添加、修改和删除其属性和方法。 let person = new Object();person.name = 'Jason';person.age = 42;console.log(person.name,person.age);//'J

java8的新特性之一(Java Lambda表达式)

1:Java8的新特性 Lambda 表达式: 允许以更简洁的方式表示匿名函数(或称为闭包)。可以将Lambda表达式作为参数传递给方法或赋值给函数式接口类型的变量。 Stream API: 提供了一种处理集合数据的流式处理方式,支持函数式编程风格。 允许以声明性方式处理数据集合(如List、Set等)。提供了一系列操作,如map、filter、reduce等,以支持复杂的查询和转

大学湖北中医药大学法医学试题及答案,分享几个实用搜题和学习工具 #微信#学习方法#职场发展

今天分享拥有拍照搜题、文字搜题、语音搜题、多重搜题等搜题模式,可以快速查找问题解析,加深对题目答案的理解。 1.快练题 这是一个网站 找题的网站海量题库,在线搜题,快速刷题~为您提供百万优质题库,直接搜索题库名称,支持多种刷题模式:顺序练习、语音听题、本地搜题、顺序阅读、模拟考试、组卷考试、赶快下载吧! 2.彩虹搜题 这是个老公众号了 支持手写输入,截图搜题,详细步骤,解题必备

uniapp接入微信小程序原生代码配置方案(优化版)

uniapp项目需要把微信小程序原生语法的功能代码嵌套过来,无需把原生代码转换为uniapp,可以配置拷贝的方式集成过来 1、拷贝代码包到src目录 2、vue.config.js中配置原生代码包直接拷贝到编译目录中 3、pages.json中配置分包目录,原生入口组件的路径 4、manifest.json中配置分包,使用原生组件 5、需要把原生代码包里的页面修改成组件的方

Java面试八股之怎么通过Java程序判断JVM是32位还是64位

怎么通过Java程序判断JVM是32位还是64位 可以通过Java程序内部检查系统属性来判断当前运行的JVM是32位还是64位。以下是一个简单的方法: public class JvmBitCheck {public static void main(String[] args) {String arch = System.getProperty("os.arch");String dataM