java实现微信小游戏支付流程

微信支付的整体流程图

在这里插入图片描述

微信小游戏支付,服务端主要开发的两个接口。

  1. getBalance()
    查询玩家的米大师的余额币的数量,客户端根据返回的米大师余额币判断是拉起支付,还是直接判定余额币充足,不用再次支付,可以直接请求服务端调用 pay接口,扣完玩家的米大师余额币。
  2. pay()
    用于扣除玩家的米大师余额币,服务端根据微信API返回的数据(错误码),判断是否扣除成功。

java主要实现的代码

  1. getBalance
	/**
	 * @param userId        玩家在游戏内的唯一标识
	 * @param appid         
	 * @param openid
	 * @param access_token  调用凭证
	 * @param pf            支付平台,android者windows
	 * @return
	 */
	public PayResult getBalance(Long userId, String appid, String openid, String access_token, String pf)
	{
		String unixTimestamp = Long.toString(System.currentTimeMillis()/1000L); //UNIX 时间戳,单位是秒
		String signTemp = "appid=" + appid + "&offer_id=" + offer_id + "&openid="+ openid
				 + "&pf=" + pf + "&ts=" + unixTimestamp + "&zone_id=" + zone_id 
					+ "&org_loc=" + getBalance_url_org_loc + "&method=POST"
					+ "&secret=" + midas_secret;
		String sig = HMACUtils.HMAC_SHA256(midas_secret, signTemp); //拿到签名
		
		JSONObject postBody = new JSONObject(7);
		postBody.put("openid", openid);
		postBody.put("appid", appid);
		postBody.put("offer_id", offer_id);
		postBody.put("ts", unixTimestamp);
		postBody.put("zone_id", zone_id);
		postBody.put("pf", pf);
		postBody.put("sig", sig);
		String bodyJson = postBody.toJSONString();
		StringEntity stringEntity = new StringEntity(bodyJson, "UTF-8");
		stringEntity.setContentEncoding("UTF-8");
		
		LoggerUtils.log(this.getClass(), userId, "payModel", "getBalance", "before", bodyJson, pf);
		
		String getBalance_url = "https://api.weixin.qq.com/" + getBalance_url_org_loc + "?access_token=" + access_token;
		HttpPost httpPost = new HttpPost(getBalance_url);
		httpPost.setEntity(stringEntity);
		httpPost.addHeader("Content-Type", "application/json");
		httpPost.addHeader("Accept", "application/json");
		
		CloseableHttpResponse response = null;
		try
		{
			response = HttpUtils.getHttpClient().execute(httpPost);
			String jsonStr = EntityUtils.toString(response.getEntity(), "utf-8");
			LoggerUtils.log(this.getClass(), userId, "payModel", "getBalance", "after", jsonStr, pf);
			JSONObject json = JSONObject.parseObject(jsonStr);
			return PayResult.createPayResult(json.get("errcode"), json.get("errmsg"), json.get("balance"));
		} 
		catch (Exception e)
		{
			LoggerUtils.error(this.getClass(), "getBalance", e, userId, pf);
			return PayResult.exception_payResult;
		}
		finally
		{
			HttpClientUtils.closeQuietly(response);
		}
	}
  1. pay:客户端已经支付完成,服务端请求API扣除该账户的米大师余额币
/**
	 * @param userId          玩家的唯一标识
	 * @param appid
	 * @param openid
	 * @param access_token    接口凭证
	 * @param amt             要扣除的数量
	 * @param pf              平台
	 * @param createPayId     用于生成唯一订单号(可以借助redis的自增实现,保证全局唯一)
	 * @return
	 */
	public PayResult pay(Long userId, String appid, String openid, String access_token, Integer amt, String pf, Long createPayId)
	{
		String bill_no = DateFormatUtils.format(System.currentTimeMillis(), "yyyyMMddHHmmss_") + createPayId; //订单号,全局唯一
		
		String unixTimestamp = Long.toString(System.currentTimeMillis()/1000L); //UNIX 时间戳,单位是秒
		String signTemp = "amt=" +amt + "&appid=" + appid + "&bill_no=" + bill_no +  "&offer_id=" + offer_id 
				+ "&openid="+ openid + "&pf=" + pf + "&ts=" + unixTimestamp + "&zone_id=" + zone_id
				+ "&org_loc=" + pay_url_org_loc + "&method=POST&secret=" + midas_secret;
		String sig = HMACUtils.HMAC_SHA256(midas_secret, signTemp); //拿到签名
		
		JSONObject postBody = new JSONObject(9);
		postBody.put("openid", openid);
		postBody.put("appid", appid);
		postBody.put("offer_id", offer_id);
		postBody.put("ts", unixTimestamp);
		postBody.put("zone_id", zone_id);
		postBody.put("pf", pf);
		postBody.put("amt", amt);
		postBody.put("bill_no", bill_no);
		postBody.put("sig", sig);
		String bodyJson = postBody.toJSONString();
		StringEntity stringEntity = new StringEntity(bodyJson, "UTF-8");
		stringEntity.setContentEncoding("UTF-8");
		
		LoggerUtils.log(this.getClass(), userId, "payModel", "pay", "before", amt, bill_no, bodyJson, pf);
		
		String pay_url = "https://api.weixin.qq.com/" + pay_url_org_loc + "?access_token=" + access_token;
		HttpPost httpPost = new HttpPost(pay_url);
		httpPost.setEntity(stringEntity);
		httpPost.addHeader("Content-Type", "application/json");
		httpPost.addHeader("Accept", "application/json");
		
		CloseableHttpResponse response = null;
		try
		{
			response = HttpUtils.getHttpClient().execute(httpPost);
			String jsonStr = EntityUtils.toString(response.getEntity(), "utf-8");
			JSONObject json = JSONObject.parseObject(jsonStr);
			return PayResult.createPayResult(json.get("errcode"), json.get("errmsg"), json.get("balance"), json.get("bill_no"));
		} 
		catch (IOException e)
		{
			LoggerUtils.error(this.getClass(), "pay", e, amt, bill_no, pf);
			return PayResult.exception_payResult;
		}
		finally
		{
			HttpClientUtils.closeQuietly(response);
		}
	}

其余重要的方法接口

  • 发送http请求,使用http连接池,减少频繁创建性能开销。(保证线程安全)
public class HttpUtils
{
	 private static PoolingHttpClientConnectionManager poolConnManager = null;
	 private static CloseableHttpClient httpClient; //线程安全,支持所有的线程使用它发送http请求
	 
	 static
	 {
         try
		{
        	SSLContextBuilder builder = new SSLContextBuilder();
			builder.loadTrustMaterial(null, new TrustSelfSignedStrategy());
			SSLConnectionSocketFactory ssls = new SSLConnectionSocketFactory(builder.build());
				
			Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder
					.<ConnectionSocketFactory>create()
					.register("http", PlainConnectionSocketFactory.getSocketFactory())
					.register("https", ssls)
					.build();
			 
			 poolConnManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
			 poolConnManager.setMaxTotal(640);
			 poolConnManager.setDefaultMaxPerRoute(320);
			 
			 httpClient = getConnection();
			 
		} catch (NoSuchAlgorithmException e)
		{
			e.printStackTrace();
		} catch (KeyStoreException e)
		{
			e.printStackTrace();
		} catch (KeyManagementException e)
		{
			e.printStackTrace();
		}
	 }
	
	 private static CloseableHttpClient getConnection()
	 {
        RequestConfig config = RequestConfig
        		.custom()
        		.setConnectTimeout(5000)
        		.setSocketTimeout(5000)
        		.setConnectionRequestTimeout(5000)
        		.build();
        
        CloseableHttpClient httpClient = HttpClients
        		.custom()
                .setConnectionManager(poolConnManager) // 设置连接池管理
                .setDefaultRequestConfig(config)
                .setRetryHandler(new DefaultHttpRequestRetryHandler(3, false)) // 设置重试次数
                .build();
        return httpClient;
	 }

	public static CloseableHttpClient getHttpClient()
	{
		return httpClient;
	}
}
  • 微信API参数对应的加密方法
public class HMACUtils
{
	public static String HMAC_SHA256(String key, String message)
	{
		String res = "";
		try
		{
			Mac instance = Mac.getInstance("HmacSHA256");
			SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(), "HmacSHA256");
			instance.init(secretKeySpec);
			byte[] doFinal = instance.doFinal(message.getBytes());
			res = byteArrayToHexString(doFinal);
		} 
		catch (Exception e)
		{
			e.printStackTrace();
		}
		return res;
	}
	
	
	  /**
     * 将加密后的字节数组转换成字符串
     *
     * @param b 字节数组
     * @return 字符串
     */
    private static String byteArrayToHexString(byte[] b) {
        StringBuilder hs = new StringBuilder();
        String stmp;
        for (int n = 0; b!=null && n < b.length; n++) {
            stmp = Integer.toHexString(b[n] & 0XFF);
            if (stmp.length() == 1)
                hs.append('0');
            hs.append(stmp);
        }
        return hs.toString().toUpperCase();
    }
}

  • getBalance和pay返回的实体类的定义
public class PayResult
{
	private Boolean exception;
	private Object errcode; //错误代码
	private Object errmsg; //作物提示信息
	private Object balance; //余额币的数目
	private Object bill_no; //订单号
	
	public final static WolfPayResult exception_payResult = new WolfPayResult(true);
	
	public boolean isException()
	{
		if(null != exception && exception)
			return true;
		else
			return false;
	}
	
	public static WolfPayResult createPayResult(Object errcode, Object errmsg, Object balance, Object bill_no)
	{
		WolfPayResult payResult = new WolfPayResult();
		payResult.setErrcode(errcode);
		payResult.setErrmsg(errmsg);
		payResult.setBalance(balance);
		payResult.setBill_no(bill_no);
		return payResult;
	}
	
	public static WolfPayResult createPayResult(Object errcode, Object errmsg, Object balance)
	{
		WolfPayResult payResult = new WolfPayResult();
		payResult.setErrcode(errcode);
		payResult.setErrmsg(errmsg);
		payResult.setBalance(balance);
		return payResult;
	}
	
	public WolfPayResult()
	{
	}
	public WolfPayResult(Boolean exception)
	{
		this.exception = exception;
	}
	
	get,set........
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值