import java.util.*; | |
import com.qq.open.OpenApiV3; | |
import com.qq.open.ErrorCode; | |
import com.qq.open.OpensnsException; | |
/** | |
* OpenAPI V3 SDK 示例代码 | |
* | |
* @version 3.0.0 | |
* @since jdk1.5 | |
* @author open.qq.com | |
* @copyright © 2012, Tencent Corporation. All rights reserved. | |
* @History: | |
* 3.0.0 | nemozhang | 2012-03-21 12:01:05 | initialization | |
* | |
*/ | |
public class TestOpenApiV3 | |
{ | |
public static void main(String args[]) | |
{ | |
// 应用基本信息 | |
String appid = "100703005"; | |
String appkey = "a7516cd28bfbfb6738d762a2a86f9741"; | |
// 用户的OpenID/OpenKey | |
String openid = "1BCB34776C647F98B0B01061D9E128ED"; | |
String openkey = "C572333371923B241795D333946E1279"; | |
// OpenAPI的服务器IP | |
// 最新的API服务器地址请参考wiki文档: http://wiki.open.qq.com/wiki/API3.0%E6%96%87%E6%A1%A3 | |
String serverName = "119.147.19.43"; | |
// 所要访问的平台, pf的其他取值参考wiki文档: http://wiki.open.qq.com/wiki/API3.0%E6%96%87%E6%A1%A3 | |
String pf = "qzone"; | |
OpenApiV3 sdk = new OpenApiV3(appid, appkey); | |
sdk.setServerName(serverName); | |
System.out.println("===========test GetUserInfo==========="); | |
testGetUserInfo(sdk, openid, openkey, pf); | |
} | |
/** | |
* 测试调用UserInfo接口 | |
* | |
*/ | |
public static void testGetUserInfo(OpenApiV3 sdk, String openid, String openkey, String pf) | |
{ | |
// 指定OpenApi Cgi名字 | |
String scriptName = "/v3/user/get_info"; | |
// 指定HTTP请求协议类型 | |
String protocol = "http"; | |
// 填充URL请求参数 | |
HashMap<String,String> params = new HashMap<String, String>(); | |
params.put("openid", openid); | |
params.put("openkey", openkey); | |
params.put("pf", pf); | |
try | |
{ | |
String resp = sdk.api(scriptName, params, protocol); | |
System.out.println(resp); | |
} | |
catch (OpensnsException e) | |
{ | |
System.out.printf("Request Failed. code:%d, msg:%s\n", e.getErrorCode(), e.getMessage()); | |
e.printStackTrace(); | |
} | |
} | |
}
|
腾讯开放平台的接入是非常麻烦的, open.qq.com,腾讯开放平台的文档很多很杂,社交功能的api接口也很多还有。我现在只接了他的登录跟支付。
一、登录。
登录相对来讲还是比较简单的,首先前端sdk要正确接入获取access_token 跟 openid ,然后需要一个https 方式的get请求来取得进一步的信息。
url :https://graph.qq.com/user/get_simple_userinfo?oauth_consumer_key=%s&access_token=%s&openid=%s&clientip=&oauth_version=2.a&scope=all
填写好自己应用的所有内容。https协议的java实现
- import java.io.BufferedReader;
- import java.io.DataOutputStream;
- import java.io.IOException;
- import java.io.InputStreamReader;
- import java.net.HttpURLConnection;
- import java.net.URL;
- import java.util.Map;
- import java.util.Map.Entry;
- import javax.net.ssl.HostnameVerifier;
- import javax.net.ssl.HttpsURLConnection;
- import javax.net.ssl.SSLSession;
- import org.apache.http.HttpEntity;
- import org.apache.http.HttpResponse;
- import org.apache.http.client.ClientProtocolException;
- import org.apache.http.client.methods.HttpPost;
- import org.apache.http.entity.ByteArrayEntity;
- import org.apache.http.impl.client.DefaultHttpClient;
- import org.apache.http.params.HttpConnectionParams;
- import org.apache.http.params.HttpParams;
- import org.slf4j.Logger;
- import org.slf4j.LoggerFactory;
- public class MyhttpService {
- private int read_time_out = 10000;
- private Logger logger = LoggerFactory.getLogger(MyhttpService.class);
- public MyhttpService() {
- super();
- }
- public MyhttpService(int time_out) {
- read_time_out = time_out;
- }
- public String doPost(String url, Map<String,String> params){
- StringBuilder postData = new StringBuilder();
- for(Entry<String,String> entry:params.entrySet()){
- if(postData.length()!=0){
- postData.append("&");
- }
- postData.append(entry.getKey()).append("=").append(entry.getValue());
- }
- return service(false, url, postData.toString(), "POST", null);
- }
- public String doPost(String url, Map<String,String> params,Map<String,String> headers){
- StringBuilder postData = new StringBuilder();
- for(Entry<String,String> entry:params.entrySet()){
- if(postData.length()!=0){
- postData.append("&");
- }
- postData.append(entry.getKey()).append("=").append(entry.getValue());
- }
- return service(false, url, postData.toString(), "POST", headers);
- }
- public String doPost(String url,String body){
- return service(false, url, body, "POST", null);
- }
- public String doPost(String url, String postData, Map<String,String> headers){
- return service(false, url, postData, "POST", headers);
- }
- public String doGet(String url, Map<String,String> headers){
- return service(false, url, null, "GET", headers);
- }
- public String doGet(String url){
- return service(false, url, null, "GET", null);
- }
- public String doHttpsPost(String url, String postData) {
- return service(true, url, postData, "POST",null);
- }
- public String doHttpsPost(String url, Map<String,String> params){
- return doHttpsPost(url,params,null);
- }
- public String doHttpsPost(String url, Map<String,String> params,Map<String,String> headers){
- StringBuilder postData = new StringBuilder();
- for(Entry<String,String> entry:params.entrySet()){
- if(postData.length()!=0){
- postData.append("&");
- }
- postData.append(entry.getKey()).append("=").append(entry.getValue());
- }
- return service(true, url, postData.toString(), "POST", headers);
- }
- public String doHttpsGet(String url) {
- return service(true, url, null, "GET",null);
- }
- private String service(boolean isHttps, String url, String postData, String method, Map<String,String> headers){
- HttpURLConnection conn = null;
- try {
- boolean doOutput = postData != null && postData.equals("");
- conn = isHttps ? createHttpsConn(url, method, doOutput) : createHttpConn(url, method, doOutput);
- fillProperties(conn, headers);
- if(doOutput) writeMsg(conn, postData);
- String msg = readMsg(conn);
- logger.debug(msg);
- return msg;
- } catch (Exception ex) {
- logger.error(ex.getMessage(), ex);
- } finally {
- if (conn != null) {
- conn.disconnect();
- conn = null;
- }
- }
- return null;
- }
- private HttpURLConnection createHttpConn(String url, String method, boolean doOutput) throws IOException {
- URL dataUrl = new URL(url);
- HttpURLConnection conn = (HttpURLConnection) dataUrl.openConnection();
- conn.setReadTimeout(read_time_out);
- conn.setRequestMethod(method);
- conn.setDoOutput(doOutput);
- conn.setDoInput(true);
- return conn;
- }
- public static void main(String[] args) {
- // System.out.println(DigestUtils.md5DigestAsHex("19a98d31-4652-4b94-b7cd-129e8ddaliji11899CNY68appstoreQY7road-16-WAN-0668ddddSHEN-2535-7ROAD-shenqug-lovedede77".getBytes()));
- }
- private String readMsg(HttpURLConnection conn) throws IOException {
- return readMsg(conn, "UTF-8");
- }
- private String readMsg(HttpURLConnection conn, String charSet) throws IOException {
- BufferedReader reader = null;
- try{
- reader = new BufferedReader(new InputStreamReader(conn.getInputStream(), charSet));
- StringBuilder sb = new StringBuilder();
- String line = null;
- while ((line = reader.readLine()) != null) {
- sb.append(line);
- }
- return sb.toString();
- } finally {
- if(reader != null){
- reader.close();
- }
- }
- }
- private void writeMsg(HttpURLConnection conn, String postData) throws IOException {
- DataOutputStream dos = new DataOutputStream(conn.getOutputStream());
- dos.write(postData.getBytes());
- dos.flush();
- dos.close();
- }
- private void fillProperties(HttpURLConnection conn, Map<String,String> params) {
- if(params == null||params.isEmpty()){
- return;
- }
- for (Entry<String,String> entry: params.entrySet()) {
- conn.addRequestProperty(entry.getKey(), entry.getValue());
- }
- }
- public String httpsPost(String url, String postData) {
- HttpURLConnection conn = null;
- try {
- boolean doOutput = (postData != null && postData.equals(""));//!Strings.isNullOrEmpty(postData);
- conn = createHttpsConn(url, "POST", doOutput);
- if (doOutput)
- writeMsg(conn, postData);
- return readMsg(conn);
- } catch (Exception ex) {
- // ingore
- // just print out
- logger.error(ex.getMessage(), ex);
- } finally {
- if (conn != null) {
- conn.disconnect();
- conn = null;
- }
- }
- return null;
- }
- private HttpURLConnection createHttpsConn(String url, String method, boolean doOutput) throws Exception {
- HostnameVerifier hv = new HostnameVerifier() {
- public boolean verify(String urlHostName, SSLSession session) {
- return true;
- }
- };
- HttpsURLConnection.setDefaultHostnameVerifier(hv);
- trustAllHttpsCertificates();
- URL dataUrl = new URL(url);
- HttpURLConnection conn = (HttpURLConnection) dataUrl.openConnection();
- conn.setReadTimeout(read_time_out);
- conn.setRequestMethod(method);
- conn.setDoOutput(doOutput);
- conn.setDoInput(true);
- return conn;
- }
- private static void trustAllHttpsCertificates() throws Exception {
- // Create a trust manager that does not validate certificate chains:
- javax.net.ssl.TrustManager[] trustAllCerts = new javax.net.ssl.TrustManager[1];
- javax.net.ssl.TrustManager tm = new miTM();
- trustAllCerts[0] = tm;
- javax.net.ssl.SSLContext sc = javax.net.ssl.SSLContext.getInstance("SSL");
- sc.init(null, trustAllCerts, null);
- javax.net.ssl.HttpsURLConnection.setDefaultSSLSocketFactory(
- sc.getSocketFactory());
- }
- public static class miTM implements javax.net.ssl.TrustManager, javax.net.ssl.X509TrustManager {
- public java.security.cert.X509Certificate[] getAcceptedIssuers() {
- return null;
- }
- public boolean isServerTrusted(
- java.security.cert.X509Certificate[] certs) {
- return true;
- }
- public boolean isClientTrusted(
- java.security.cert.X509Certificate[] certs) {
- return true;
- }
- public void checkServerTrusted(
- java.security.cert.X509Certificate[] certs, String authType) throws
- java.security.cert.CertificateException {
- return;
- }
- public void checkClientTrusted(
- java.security.cert.X509Certificate[] certs, String authType) throws
- java.security.cert.CertificateException {
- return;
- }
- }
- /**
- * 执行一个HTTP POST请求,返回请求响应的内容
- * @param url 请求的URL地址
- * @param params 请求的查询参数,可以为null
- * @return 返回请求响应的内容
- */
- public static String doPostforUC(String url, String body) {
- StringBuffer stringBuffer = new StringBuffer();
- HttpEntity entity = null;
- BufferedReader in = null;
- HttpResponse response = null;
- try {
- DefaultHttpClient httpclient = new DefaultHttpClient();
- HttpParams params = httpclient.getParams();
- HttpConnectionParams.setConnectionTimeout(params, 20000);
- HttpConnectionParams.setSoTimeout(params, 20000);
- HttpPost httppost = new HttpPost(url);
- httppost.setHeader("Content-Type", "application/x-www-form-urlencoded");
- httppost.setEntity(new ByteArrayEntity(body.getBytes("UTF-8")));
- response = httpclient.execute(httppost);
- entity = response.getEntity();
- in = new BufferedReader(new InputStreamReader(entity.getContent(),"UTF-8"));
- String ln;
- while ((ln = in.readLine()) != null) {
- stringBuffer.append(ln);
- stringBuffer.append("\r\n");
- }
- httpclient.getConnectionManager().shutdown();
- } catch (ClientProtocolException e) {
- e.printStackTrace();
- } catch (IOException e1) {
- e1.printStackTrace();
- } catch (IllegalStateException e2) {
- e2.printStackTrace();
- } catch (Exception e) {
- e.printStackTrace();
- } finally {
- if (null != in) {
- try {
- in.close();
- in = null;
- } catch (IOException e3) {
- e3.printStackTrace();
- }
- }
- }
- return stringBuffer.toString();
- }
- }
内容的返回是json格式的,可以从里面找自己需要的内容来解析
- JSONParser jsonParser = new JSONParser(JSONParser.DEFAULT_PERMISSIVE_MODE);
- JSONObject obj;
- obj = (JSONObject) jsonParser.parse(doHttpsGet);
- String code = String.valueOf(obj.get("ret"));
- if(code.equals("0")){
- String nickName = String.valueOf(obj.get("nickname"));
后面就是自己服务器的逻辑了。登录相对来讲还是很简单的。
二、支付
1、腾讯的支付接口不知道是新开发的,还是涉及太多,总之非常乱,他们的开放平台的wiki上面有,四个服务,应用接入,移动接入,网站接入,腾讯云接入。因为我们是移动游戏所以,应该按照移动接入来接,但是实际上还要涉及应用接入这边的文档。只看一边的文档会发现少很多东西。按照文档接入出现问题。正题。
我手中的文档是 移动接入的sdk下载里面的
,腾讯的支付有两种:第一种是由腾讯来管理我们的支付,举例就是玩家充值的元宝在腾讯服务器上面,这个蛋疼的地方是,以后你所有的元宝操作都要跟腾讯交互,增加、扣除、赠送等等都要写协议去腾讯云处理。所以我们用了另外一种模式,道具购买模式。道具购买模式是直接花q点或者q币购买我们的道具,这个道具就是元宝。
2、这里有一个问题是,sdk里面自带的文档跟wiki上面的不一致,调用的接口也不是一个
这个对我们的影响在于后面的发货接口。发货接口的文档又再wiki上面,所以后面我们回到wiki的时候发现两份文档对不上。sdk文档包括腾讯托管跟我们自己管理元宝两种,第一种因为接口多,所以大部分是将第一种方式的。
3、道具购买服务器需要实现两个接口。购买道具下订单接口。购买结束回调接口。
下单接口需要客户端在登录时候取得 paytoken openkey pf pfkey 然后按照文档以 http 方式连接开放api就可以了。
- //qq直接购买道具下单界面
- public String qq_buy_items(String appid,String sessionId ,String openid,String pay_token,String openkey ,String amount,String pf,String pfkey){
- String appkey = PlatformUtil.QQ_APPKEY;
- String apiaddress = "119.147.19.43";//qq测试地址
- // String apiaddress = "openapi.tencentyun.com";//qq正式
- //pf = "qq_m_qq-10000144-android-10000144-1111";
- //pfkey = "pfkey";
- OpenApiV3 openApiV3 = new OpenApiV3(appid, appkey, apiaddress);
- String zoneid="1";
- Map<String,String> params = new HashMap<String, String>();
- params.put("openid", openid);
- params.put("openkey", openkey);
- params.put("pf", pf);
- params.put("pfkey",pfkey);
- params.put("ts", String.valueOf(System.currentTimeMillis()/1000));
- params.put("pay_token", pay_token);
- params.put("zoneid", zoneid);
- params.put("appmode", "1");
- params.put("appid", appid);
- int iamount = SCUtils.calcScCount(amount+".0");
- String payitem = String.format("100*1*%s",String.valueOf(iamount));
- String goodsmeta = "元宝*元宝";
- String goodsurl = "http://dragon.dl.hoolaigames.com/other/CH.png";
- String app_metadata = String.format("%s-%s-",sessionId,String.valueOf(amount));
- params.put("payitem", payitem);
- params.put("goodsmeta", goodsmeta);
- params.put("goodsurl", goodsurl);
- params.put("app_metadata",app_metadata); //这个在最终透传时候会增加腾讯的内容,*qdqd*qq 告诉我们是用什么方式支付的
- // params.put("qq_m_qq",String.format("%s,%s,%s", appid,openid,openkey) );
- try {
- Map<String,String> cookies = new HashMap<String, String>();
- cookies.put("session_id", SnsSigCheck.encodeUrl("openid"));
- cookies.put("session_type", SnsSigCheck.encodeUrl("kp_actoken"));
- cookies.put("org_loc ",SnsSigCheck.encodeUrl("/mpay/buy_goods_m"));
- String api = openApiV3.api("/mpay/buy_goods_m", params,null ,"http");
- return api;
- } catch (OpensnsException e) {
- log.error("openApiV3.api invoke failed",e);
- return "error";
- }
- }
其中的 OpenApiV3 其实可以从开放平台下载,是 http://wiki.open.qq.com/wiki/SDK%E4%B8%8B%E8%BD%BD 里面其实是一些验证以及http的访问。实际接入时候可以下载一个最新的看看。返回值也是一个json
- JSONParser jsonParser = new JSONParser(JSONParser.DEFAULT_PERMISSIVE_MODE);
- JSONObject obj;
- obj = (JSONObject) jsonParser.parse(payurl);
- int ret = (Integer) obj.get("ret");
- String msg = (String) obj.get("msg");
- String token_id = (String) obj.get("token");
- String url_params = (String) obj.get("url_params");
关于返回值里面参数,文档跟实际的返回有些出入,不一致,token 文档中写的是token_id 但实际返回的是token,这个可以实际debug看下再接收参数。得到的这些值需要发送给前端的sdk,前端的sdk会用这个返回的url 处理剩下的逻辑。
4、支付回调。客户端拿到刚才的url 会回传给腾讯,然后腾讯会调用我们在后台配置的回调接口,来通知支付结果,同时我们也要处理道具发放逻辑。这里有一个非常困难的问题 https协议的证书问题。 腾讯的证书最变态的一点是绑定ip地址,当然也是为了安全考虑。腾讯的后台我没有登录,但是应该是配置回调的ip地址,填写回调url 然后腾讯会生成一个绑定ip地址的证书,你需要安装这个证书在那台服务器上面,
发货URL用来给腾讯计费后台回调。用户付费成功后,腾讯计费后台将回调该URL给用户发货。在9001端口后可以是一个cgi或者php的路径。
hosting应用on CVM(即应用部署在腾讯CVM服务器上):
-发货URL只需HTTP协议即可,不需要使用SSL安全协议。
-必须使用9001端口(内网端口,需开发者主动启用,用apache iis或nginx做一个web监听,端口改成9001)。
hosting应用on CEE_V2(即应用部署在腾讯CEE_V2服务器上):
-发货URL只需HTTP协议即可,不需要使用SSL安全协议。
-必须使用9001端口(内网端口,需开发者主动启用,用apache iis或nginx做一个web监听,端口改成9001)。
-路径必须以ceecloudpay开头,即支付相关代码必须都放到应用根目录下的“ceecloudpay”目录下。
-对于CEE其发货URL的IP只能填写为10.142.11.27或者10.142.52.17(详见:CEE_V2访问云支付)。
non-hosting应用(即应用部署在开发者自己的服务器上):
-发货URL必须使用HTTPS协议。
-必须使用443端口(外网端口)。
-必须填写发货服务器所在运营商(电信/联通)。
这是腾讯官方文档对于这个的解释,总之很麻烦的一个东西,中间遇到什么问题,建议找他们的企业支持。
5、证书的安装。
证书安装很坑爹的一个没有官方文档,官方有一个window浏览器的导入文档,没有linux的。这太无语了。
证书的安装可以安装在apache 或者 nginx 下面,我没有直接安装在tomcat下面,应该也是可以的吧,用apache或者nginx 可以做转发,转发到本地debug什么的。所以,我们用的是nginx做转发。首先腾讯后台下载一个这样的证书包。
这个里面带钥匙的那个需要密码,密码在readme里面,但是其实linux下面并没有用到,这个我估计是原始的密钥文件,可以和那个key生成 crt 文件,但是这里已经是生成好了的 crt 文件所以还是直接用比较好,先给第一个最长的那个起个别的名字。然后上传到 nginx 服务器的 conf 目录下面 ,nginx 在安装服务的时候应该是默认为支持https的 ssl 的,所以一般是不需要重新编译的,如果需要重新编译,可以去网上找找相关资料。如果你的 nginx 支持,那么就剩下一步,修改配置文件。 同样是conf目录下面的 nginx.conf
- server {
- listen 443;
- server_name xxxxxxx;
- ssl on;
- ssl_certificate oem.crt;
- ssl_certificate_key oem.key;
- ssl_verify_client off;
- ssl_session_timeout 5m;
- ssl_protocols SSLv2 SSLv3 TLSv1;
- ssl_ciphers ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP;
- ssl_prefer_server_ciphers on;
- ssl_client_certificate ca.crt;
- ssl_verify_depth 1;
- location ~ ^/xxxxxr/* {
- proxy_pass http://xxxxxx3;
- index index.jsp index.html index.htm;
- proxy_set_header Host $host;
- proxy_set_header X-Real-IP $remote_addr;
- proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
- }
- }
里面的
- ssl_client_certificate
- ssl_certificate
对应证书里面的名字,修改完成后记得reload ./nginx -s reload 一下应该就生效了,我是做了转发本地处理的,当然也可以转发到任意服务器或者本机。如果下订单成功但是收不到回调,多半是这个证书的问题,可以看 nginx的log日志看看有没有访问到。如果没有80%都是证书的问题,询问下腾讯的支持让他们帮你查下日志吧,不过等他们反馈,估计你已经找到原因了。
6、支付回调的验证,当你终于能收到回调了,恭喜你你就要成功了。
对于支付回调的处理,其实很简单,但是腾讯的就很蛋疼。这就是上面说的蛋疼的问题,没有文档。sdk里面的文档说去看 wiki ,wiki里面的文档貌似不是这一版的,而且sdk文档里面的连接还是去 wiki 的主页,哎。 这里忍不住吐槽太多太乱,大家看上去都差不多,我哪知道是我需要的接口。最终我看到这个貌似像 :
http://wiki.open.qq.com/wiki/%E5%9B%9E%E8%B0%83%E5%8F%91%E8%B4%A7URL%E7%9A%84%E5%8D%8F%E8%AE%AE%E8%AF%B4%E6%98%8E_V3
这个文档上面的参数回调,大部分都是正确的。注意是大部分,因为收到的所有参数都要参与 HmacSHA1 签名,所以一个参数错误就悲剧了,你都不知道去哪里找,贴一下我最终的回调处理。
- //qq支付回调接口,根据http://wiki.open.qq.com/wiki/%E5%9B%9E%E8%B0%83%E5%8F%91%E8%B4%A7URL%E7%9A%84%E5%8D%8F%E8%AE%AE%E8%AF%B4%E6%98%8E_V3 编写
- protected void processRequest(HttpServletRequest request, HttpServletResponse response)
- throws ServletException, IOException {
- response.setContentType("text/html;charset=UTF-8");
- PrintWriter out = response.getWriter();
- Map<String, Object> obj = new HashMap<String, Object>();
- try {
- String openid = request.getParameter("openid"); //根据APPID以及QQ号码生成,即不同的appid下,同一个QQ号生成的OpenID是不一样的。
- String appid = request.getParameter("appid"); //应用的唯一ID。可以通过appid查找APP基本信息。
- String ts = request.getParameter("ts"); //linux时间戳。 注意开发者的机器时间与腾讯计费开放平台的时间相差不能超过15分钟。
- String payitem = request.getParameter("payitem"); //接收标准格式为ID*price*num G001*10*1
- String token = request.getParameter("token"); //应用调用v3/pay/buy_goods接口成功返回的交易token
- String billno = request.getParameter("billno"); //支付流水号(64个字符长度。该字段和openid合起来是唯一的)。
- String version = request.getParameter("version"); //协议版本 号,由于基于V3版OpenAPI,这里一定返回“v3”。
- String zoneid = request.getParameter("zoneid"); //在支付营销分区配置说明页面,配置的分区ID即为这里的“zoneid”。 如果应用不分区,则为0。
- String providetype = request.getParameter("providetype");//发货类型 0表示道具购买,1表示营销活动中的道具赠送,2表示交叉营销任务集市中的奖励发放。
- //Q点/Q币消耗金额或财付通游戏子账户的扣款金额。可以为空 若传递空值或不传本参数则表示未使用Q点/Q币/财付通游戏子账户。注意,这里以0.1Q点为单位。即如果总金额为18Q点,则这里显示的数字是180。
- String amt = request.getParameter("amt");
- String payamt_coins = request.getParameter("payamt_coins");//扣取的游戏币总数,单位为Q点。
- String pubacct_payamt_coins = request.getParameter("pubacct_payamt_coins");//扣取的抵用券总金额,单位为Q点。
- String appmeta = request.getParameter("appmeta");
- String clientver = request.getParameter("clientver");
- String sig = request.getParameter("sig");
- String url = "/xxx/xxxx";
- Map<String, String> params = createCallbackParamsMap(openid, appid, ts, payitem, token, billno, version, zoneid,
- providetype, amt, payamt_coins, pubacct_payamt_coins, appmeta,clientver);
- if(SnsSigCheck.verifySig(request.getMethod(), url,params, PlatformUtil.QQ_APPKEY+"&", sig)){
- if(ok){
- }else{
- obj.put("ret", 0);
- obj.put("msg", "ok");
- }
- }else{
- log.info("qqPayCallback SnsSigCheck fail.");
- obj.put("ret", -5);
- obj.put("msg", "签名错误");
- }
- String resp = JSONObject.toJSONString(obj);
- out.println(resp);
- } catch (SQLException | DbException | ProtocolException | NumberFormatException | OpensnsException e) {
- e.printStackTrace();
- } finally {
- out.close();
- }
中间标红的地方都是有问题的地方,都是坑。首先
- pubacct_payamt_coins
是有可能传空的,因为你没有用抵用券对吧,但是记住这个也需要加入签名。 clientver 神坑。我最终也没再文档或者哪里找到这个参数为什么给我传过来,但是你就是传过来了,而且你还必须接收,必须加入签名中去,也许我水平太菜,反正我是没找到这个参数在那个文档上面写了。
createCallbackParamsMap 字面意思就是把参数弄到 map里面
SnsSigCheck.verifySig 这也是上面下载的那个工具项目中自带的功能,其实就是一个 HmacSHA1 的 utf 格式的签名。可以下载,有兴趣的也可以自己写写。
(三)总结
腾讯的支付接口应该做的不难,困难在于没有一个明确的文档。
参考链接:
http://blog.csdn.net/fanyun7654/article/details/24010489?reload
https://github.com/liujiuwu/OpenApi/blob/master/src/main/java/TestOpenApiV3.java
相关推荐
本"腾讯信鸽接入demo"是一个实例教程,旨在帮助开发者快速理解并实现腾讯信鸽推送服务的接入。 一、信鸽推送服务介绍 腾讯信鸽提供了iOS和Android平台的SDK,支持多种消息类型,包括通知消息和自定义消息。通知消息...
在Android应用开发中,接入腾讯广告的广点通SDK是一个常见的需求,这有助于开发者通过广告获得收益或提高用户参与度。本DEMO是针对Android平台的初级教程,它提供了全面的指南来集成开屏广告、插屏广告、Banner广告...
接下来,我们将讨论如何在PHP中集成腾讯云短信接口。首先,需要在腾讯云官网注册账号并创建短信应用,获取API密钥(AppID和AppKey)。然后,可以使用PHP的cURL库或者file_get_contents函数发起HTTP请求,向腾讯云的...
腾讯云直播SDK是一款由腾讯云提供的专业视频直播开发工具,旨在帮助开发者快速构建高质量、低延迟的直播应用。SDK包含了丰富的功能和优化的性能,适用于各种直播场景,如在线教育、游戏直播、企业会议等。在提供的...
在这款“基于腾讯云实时推送的demo”中,我们将探讨如何利用该服务实现Android端的实时消息推送功能。 1. **信鸽云推送服务详解** 信鸽云推送服务主要由以下几个核心组件构成: - **服务器端API**:开发者可以...
接下来,我们将编写代码来发送短信。首先,导入SDK并实例化SDK类: ```php require_once __DIR__ . '/vendor/autoload.php'; use Timetong\QCloudSms\Sms; $sms = new Sms(include 'config.php'); ``` 现在,...
uniapp接入腾讯滑动行为验证码(App、小程序、H5)
总的来说,“腾讯X5内核离线使用Demo”是一个宝贵的教育资源,可以帮助开发者深入了解离线Web应用的开发,以及腾讯X5内核的高效利用,尤其对于需要在各种网络环境下提供稳定服务的项目具有重要意义。通过深入研究和...
腾讯云 直播 模块 demo 博客介绍:https://blog.csdn.net/weixin_42749765/article/details/88074995
【腾讯COS云存储案例Demo】是一个以腾讯云对象存储服务(Cloud Object Storage,简称COS)为基础的应用示例,旨在帮助开发者更好地理解和使用腾讯云的COS服务。该Demo可能包括了上传、下载、管理对象(文件)等功能...
C#腾讯AI 接口签名工具 语音合成demo 在工具类中有个完整的语音合成的Demo 继之前的demo 做了一下修改,更加适合初学者使用。 具体接口文档地址参照https://ai.qq.com/doc/aaitts.shtml 在demo中将标注的字段改...
腾讯地图坐标拾取器demo腾讯地图坐标拾取器demo腾讯地图坐标拾取器demo腾讯地图坐标拾取器demo
5. **多终端支持**:TICKSDK不仅适用于Android平台,还支持iOS和其他平台,确保不同设备的学生都能接入课堂,实现跨平台的无缝学习。 6. **API接口与集成**:为了方便开发者集成到自己的教育应用中,TICKSDK提供了...
【标题】"用php写的一个简单的腾讯开放平台应用demo"主要展示了如何利用PHP语言与腾讯开放平台进行交互,实现一个基础的应用程序。这个Demo可能是为了帮助开发者快速理解腾讯开放平台API的使用方法,以及如何在PHP...
C#腾讯AI 接口签名工具 在工具类中有个完整的语音合成的Demo 具体接口文档地址参照https://ai.qq.com/doc/aaitts.shtml 在demo中将标注的字段改为你自己注册的相应字段即可,语音合成的demo就能跑起来,工具类和...
的 main() 方法,填入上述申请到的 **APPID**、**SecretId**、**SecretKey**、**BucketName** 2. 导入到 IDE:工程用 Maven 构建,以 Intellij IDEA 为例,导入方式为:Import Project -> 选择工程目录 -> Import...
在本"腾讯X5浏览器内核静态集成demo"中,我们将探讨两种集成方式,即动态集成和静态集成,以及它们的应用场景。 首先,我们来看**动态集成**。动态集成通常指的是在运行时通过下载和安装插件或组件来实现功能。在这...
【Android腾讯X5内核Demo】是一个用于展示和学习如何在Android应用中集成和使用腾讯X5内核的示例项目。X5内核是腾讯为优化移动浏览器和Webview性能而开发的一款高性能、轻量级的浏览核心,它基于开源的WebKit并进行...
【腾讯X5内核官方DEMO适配AS3.2】是针对Android开发中的一个关键环节,涉及到腾讯的X5浏览内核与Android Studio 3.2的集成问题。X5内核是腾讯公司推出的一款高性能、高稳定性的手机浏览器内核,广泛应用于微信、QQ等...
本Demo是针对Android开发者设计的,帮助他们快速集成并实现腾讯的"人脸核身·云智慧眼"功能。 首先,我们要了解这个SDK的核心功能。"云智慧眼"主要包含了以下几个关键部分: 1. **人脸检测**:通过摄像头捕获用户...