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 = "**********"; // 微信公众号id
	private static String SECRET = "**********"; // 微信公众号密钥id
	private 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;
	@Autowired
	private 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());
	//获取用户的openid
	public 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请求获取openIdStr
		String openIdStr = HttpRequest.sendGet(getopenid_url, param);
		JSONObject json = JSONObject.parseObject(openIdStr);// 转成Json格式
		String openId = json.getString("openid");// 获取openId
		log.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 = "";// 预支付id
			if (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 {
	@Autowired
	private Order o;
	@Autowired
	private SessionFactory sessionfactory;
	private final Log log = LogFactory.getLog(getClass());
	@Transactional
	public 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转map
			log.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();
                }
            } catch (Exception e2) {
                e2.printStackTrace();
            }
        }
        return result;
    }
 
    /**
     * 向指定 URL 发送POST方法的请求
     * 
     * @param url
     *            发送请求的 URL
     * @param param
     *            请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
     * @return 所代表远程资源的响应结果
     */
    public static 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",
  
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值