JAVA -- 微信公众号支付(JSAPI)

相信 百度上有好多 写这种支付的 一大堆 有的可能 并不是那么容易懂 。我也是 在自己摸索并结合网上教程 获得一些经验 ,趁着记忆犹新把它写出来 也方便 大家 或者 以后我自己会用到

我简单的 把 一大堆东西简化了 把他们整合写在了一个类里面。下面开始:
(微信 配置的那些东西 相信大家都知道 ,在这里就不多说了 忽略配置)

第一: 了解支付的接口链接和参数信息
官方文档 : https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1
接口链接 URL地址:https://api.mch.weixin.qq.com/pay/unifiedorder
官方文档有好多参数 我们只需要其中有用到的就好
需要的参数 :
appid--------------------微信支付分配的公众账号ID(企业号corpid即为此appId)
mch_id------------------微信支付分配的商户号
openid-------------------此参数为微信用户在商户对应appid下的唯一标识
body----------------------商品简单描述
nonce_str---------------随机字符串,长度要求在32位以内。
out_trade_no----------商户系统内部订单号,要求32个字符内,只能是数字、大小写字母_-|* 且在同一个商户号下唯一
spbill_create_ip-------APP和网页支付提交用户端ip
total_fee----------------订单总金额,单位为分
trade_type-------------JSAPI -JSAPI支付
notify_url---------------异步接收微信支付结果通知的回调地址,通知url必须为外网可访问的url,不能携带参数。
sign----------------------通过签名算法计算得出的签名值

上面就是我们需要的参数
第二、获取openid
获取openid 要先让用户授权得到code再用code去换取
获取code的接口链接:https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=redirectUri&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect"

注意: redirect_uri参数:授权后重定向的回调链接地址, 请使用 urlEncode 对链接进行处理。
处理方法 :java.net.URLEncoder.encode(url, “UTF-8”);

用code换取openid
接口链接:https://api.weixin.qq.com/sns/oauth2/access_token?appid=appid&secret=appsecret&code=code&grant_type=authorization_code

这里我用了一个OpenIdUtil类方便以后直接调用

public class OpenIdUtil
{
	/**
	 * 获取微信用户信息
	 * @param code 微信端的CODE
	 * @param classify 用户标示
	 * @return
	 */
	public static String oauth2GetOpenid(String code) {
		String appid = "替换自己的";
		String appsecret = "替换自己的";
		//授权(必填)
		String grant_type = "authorization_code";
		//URL
		String requestUrl = "https://api.weixin.qq.com/sns/oauth2/access_token";
		//请求参数
		String params = "appid=" + appid + "&secret=" + appsecret + "&code=" + code + "&grant_type=" + grant_type;
		//发送请求
		String data = HttpSendUtil.sendGet(requestUrl, params);
		//解析相应内容(转换成json对象)
		JSONObject  json = JSONObject.fromObject(data);
		//用户的唯一标识(openid)
		String openId = String.valueOf(json.get("openid"));
		return openId;
	}
}

我在这里吧http请求工具类 也贴出来 这样 大家就不用再去到处找了
HttpSendUtil类

public class HttpSendUtil 
{
	 /**
     * 向指定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;
            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.setRequestProperty("Content-Type", "text/xml");
            // 建立实际的连接
            connection.connect();
            // 定义 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",
                    "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
            conn.setRequestProperty("Content-Type", "text/xml");
            // 发送POST请求必须设置如下两行
            conn.setDoOutput(true);
            conn.setDoInput(true);
            // 获取URLConnection对象对应的输出流
            out = new PrintWriter(conn.getOutputStream());
            // 发送请求参数
            out.print(param);
            // flush输出流的缓冲
            out.flush();
            // 定义BufferedReader输入流来读取URL的响应
            in = new BufferedReader(
                    new InputStreamReader(conn.getInputStream() ));
            String line;
            while ((line = in.readLine()) != null) {
                result += line;
            }
        } catch (Exception e) {
            System.out.println("发送 POST 请求出现异常!"+e);
            e.printStackTrace();
        }
        //使用finally块来关闭输出流、输入流
        finally{
            try{
                if(out!=null){
                    out.close();
                }
                if(in!=null){
                    in.close();
                }
            }
            catch(IOException ex){
                ex.printStackTrace();
            }
        }
        return result;
    }    
}

好了 据需回到 上面 openid获取到了 那我们就开始发送数据了
统一下单 的 接口链接 : https://api.mch.weixin.qq.com/pay/unifiedorder

@RestController
@RequestMapping("/weChatPayController")
@SuppressWarnings({"rawtypes","unchecked"})
public class WeChatPayController {
	/**
	 * 支付
	 * @author LSJ
	 * @return
	 */
	@RequestMapping( value = "orderPay" , method =  RequestMethod.GET )
	public Map orderPay( HttpServletRequest request, HttpServletResponse response )
	{
		String out_trade_no = "";//随机生成32个字符内  (唯一)
		try {
			//拼接统一下单地址参数
			Map<String, String> paraMap = new HashMap<String, String>();
			//获取请求ip地址
			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", "描述");  
			paraMap.put("mch_id", "自己的商户ID");  
			paraMap.put("nonce_str", WXPayUtil.generateNonceStr());//随机字符串
			paraMap.put("openid", openId);
			paraMap.put("out_trade_no",out_trade_no );//订单号
			paraMap.put("spbill_create_ip", ip);  //用户IP  上面已获取
			paraMap.put("total_fee", "1");//支付金额  (单位分)  
			paraMap.put("trade_type", "JSAPI");  //支付类型 
			paraMap.put("notify_url", "自己的回调地址");// 此路径是微信服务器调用支付结果通知路径
			//利用WXPayUtil工具类生成签名
			String sign = WXPayUtil.generateSignature(paraMap, "商户密匙");
			paraMap.put("sign", sign);
			String xml = WXPayUtil.mapToXml(paraMap);//利用WXPayUtil工具类将所有参数(map)转xml格式
			String xmlStr = HttpSendUtil.sendPost( WeChatConstant.WX_UNIFIED_ORDER_URL , xml);//发送post请求"统一下单接口"返回预支付id:prepay_id
			//以下内容是返回前端页面的json数据
			String prepay_id = "";//预支付id
			if (xmlStr.indexOf("SUCCESS") != -1) {  
				Map<String, String> map = WXPayUtil.xmlToMap(xmlStr);  
				prepay_id = (String) map.get("prepay_id");  
				//package会用到prepay_id  值的格式例如:”prepay_id= wx2018…250…9981…666”
			}
			Map<String, String> payMap = new HashMap<String, String>();
			payMap.put("timeStamp", WXPayUtil.getCurrentTimestamp()+""); //时间戳
			payMap.put("nonceStr", WXPayUtil.generateNonceStr());  //随机字符串
			payMap.put("signType", "MD5");  //签名类型
			payMap.put("package", "prepay_id=" + prepay_id);    
			String paySign = WXPayUtil.generateSignature(payMap, "商户密匙");  
			payMap.put("paySign", paySign);
			return  payMap;
		} catch (Exception e) 
		{
			System.err.println(e);
		}
	}
}

前端 部分 我就不写出来

以下是我支付成功的回调地址

/**
	 * 支付成功后的回调
	 * @author LSJ
	 * @param request
	 * @param response
	 * @throws IOException
	 */
	@RequestMapping( value = "payCallBack" )
	public void payCallBack( HttpServletRequest request,HttpServletResponse response ) throws IOException
	{
		Map<String,Object> resultMap = null;

		try {
			System.err.println("支付结果回调...");
			//利用WXPayUtil工具类里的方法将XML读取出来
			String xmlStr = CommonUtil.parseInputStream(request.getInputStream());
			//并转换成MAP    这样就可以拿到xml里想要的数据了
			resultMap = CommonUtil.parseXML(xmlStr);
		} catch (KeyManagementException | NoSuchAlgorithmException | NoSuchProviderException | IOException e) {
			resultMap = Maps.newHashMap();
			resultMap.put("return_code", "FAIL");
			resultMap.put("return_msg","服务器报错");
		}
		response.getWriter().write(CommonUtil.getXmlWithMap(resultMap));
		response.getWriter().flush();
	}

===========上面就是 Java 微信公众号的支付方法 , 写的 不好 大神勿喷
对了 WXPayUtil 工具类 是jar包 是可以用maven仓库获取的

如果有什么不对的地方 或不懂得地方 请大家提出来

我的微信AiMyHear

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值