易接SDK接入:Android手游支付功能接口实现,完整代码奉上

来源:互联网 发布:国内实时数据库 编辑:程序博客网 时间:2024/05/29 12:20

  之前在一家游戏公司写过游戏服务端,游戏支付功能,这个是接入“易接”平台的SDK实现的,

由于涉及的坑比较多,所以总结一下经验,以及奉上完整代码。


首先我们的项目是以Cocos2dx引擎的手游,这个用visual Studio编写代码,
这个项目是LUA工程,但是里面有多个平台的代码,但是我们现在只写Android这一块
它可以实现跨平台:Android,IOS,blackberry,Linux,marmalade,window平台上跑,


Lua工程代码可以像swift 的编译器那样,写完即刻运行,更新的时候,不需要重新下载一个包,
打补丁更新!维护起来很方便


由于我是写服务端,这一块,所以我简单陈述这个实现的过程,
首先网游肯定有充值的功能,我现在通过接入第三方的SDK 接口,实现这个支付的功能

易接SDK 帮助文档


https://www.1sdk.cn/helpcenter.html


一、首先我们需要精确的定位!


此操作编译软件:Eclipse_SDK
我们是一个网游,我们的项目是Android最终的目的是完成一个支付的功能
先选择客户端,只有客户端的接口完善了才会发送请求到服务端验证,才会同步信息!



既然选择了Android,我的代码无疑是JAVA 
为什么不选择C++呢?cocos2dx 不是C++吗?已经说了,这里是一个Android的项目



二、下载官方的参考文档 demo 和 sdk包


  http://www.1sdk.cn/download





这个是生成渠道包的软件,就是写好接口后,在通过其他平台接入扩展功能
游戏客户端 → 游戏服务端 → 易接服务端 → 其他渠道服务端


写好接口代码,找一个渠道服务端注册申请开发者,

用 易接的PC端打包的APK,key在渠道服务端  这个获取,比如我注册“乐视/联想”的平台,然后上传app,可以获取key,打包后的apk,运行可以接入接口。 


三、我们打开下载的SDK包,
里面有很详细的内容,包括PDF文档,跟网页端的一样,只是稍微代码规范一点



资源包自己根据文档进行整理,该打上那些已经说的很详细了




demo有个易接的apk参考,文件夹里面是代码,
可以用ec导入,仔细查看


四、步骤流程:


我大体上的思路是:
1、在onCreate()创建窗口加载游戏的时候,初始化SDK ——initSDK();
并且写上登录监听
SFOnlineHelper.setLoginListener(activity, newSFOnlineLoginListener() {
@Override 
public void onLoginSuccess(SFOnlineUser user, Object customParams) { 
//登陆成功回调 

@Override 
public void onLoginFailed(String reason, Object customParams) { 
//登陆失败回调 

@Override 
public voidon Logout(Object customParams) { 
//登出回调 

});


2、在onStart()方法中,使用登录方法 SFOnlineHelper.login(activity, "Login");

监听到登录后,跳转登录验证
public void onLoginSuccess()


3、登录验证后,创建角色,验证角色
setRoleData(Context context, String roleId, String roleName, String roleLevel, String zoneId, String zoneName){
}


4、角色OK后,写支付的接口——定额计费,非定额计费
pay (Context context, intunitPrice, String unitName, int count, String callBackInfo, String callBackUrl,SFOnlinePayResultListenerpayResultListener){


}


5、扩展接口暂时不用写


注意:只有退出才清空内容 System.exit(0); ,


或许你打开原来的项目会说:
1.wtf,这不是继承Activity,不是FragmentActivity,而是
extends Cocos2dxActivity ?
2、wtf,这游戏项目没有xml页面?
3、退出按钮不听话了?游戏无法退出?无法监听按键?


这跟demo不一样啊!
该什么说呢?其实游戏页面只有一个activity,所有的页面都在这里显示


如果遇到闪退:1、登录验证失败,回退 2、代码报错 3、6.0的权限问题,降低为4.3 这样




五、完整代码公布:

1、LuaTest.java 主activity

(因为我只是一只菜鸟,所以狂打 log日志跟踪)

package com.android.zdhsoft;import java.io.UnsupportedEncodingException;import java.net.URLEncoder;import com.snowfish.cn.ganga.helper.SFOnlineExitListener;import com.snowfish.cn.ganga.helper.SFOnlineHelper;import com.snowfish.cn.ganga.helper.SFOnlineLoginListener;import com.snowfish.cn.ganga.helper.SFOnlinePayResultListener;import com.snowfish.cn.ganga.helper.SFOnlineUser;import android.app.Activity;import android.app.AlertDialog;import android.app.AlertDialog.Builder;import android.content.Context;import android.content.DialogInterface;import android.content.Intent;import android.net.Uri;import android.os.Bundle;import android.provider.Settings;import android.util.Log;import android.view.KeyEvent;import android.widget.FrameLayout;import android.widget.Toast;import org.cocos2dx.lib.Cocos2dxActivity;import org.cocos2dx.lib.Cocos2dxGLSurfaceView;import org.json.JSONException;import org.json.JSONObject;import utils.LoginHelper;public class luaTest extends Cocos2dxActivity {private static final String TAG = "--luaTest--";FrameLayout mViewContainer;String tag = null;static LoginHelper helper = null;protected void onCreate(Bundle savedInstanceState) {Log.d(TAG, "——————luaTest启动,onCreate——————");super.onCreate(savedInstanceState);//登录监听loginListener();Log.d(TAG, "——————启动登录监听,loginListener——————");// TODO 初始化易接sdk 不带初始化监听的接口SFOnlineHelper.onCreate(this);Log.d(TAG, "——————初始化SDK,onCreate——————");}public Cocos2dxGLSurfaceView onCreateGLSurfaceView() {return new Cocos2dxGLSurfaceView(this);}static {System.loadLibrary("cocos2dlua");}@Overridepublic void onStart() {super.onStart();Log.d(TAG, "——————开始启动游戏——————");//这里 模拟一下 调用登录SFOnlineHelper.login(this, "Login"); Log.d(TAG, "——————登录游戏,login——————");}@Overridepublic void onPause() {super.onPause();Log.d(TAG, "——————暂停游戏——————");SFOnlineHelper.onPause(this);//除非退出游戏否则绝对不能调用  !!!!//System.exit(0);}public void onStop() {super.onStop();Log.d(TAG, "——————停止游戏——————");SFOnlineHelper.onStop(this);}@Overridepublic void onResume() {super.onResume();Log.d(TAG, "——————重新开始游戏——————");SFOnlineHelper.onResume(this);}public void onDestroy() {super.onDestroy();Log.d(TAG, "——————销毁游戏——————");SFOnlineHelper.onDestroy(this);}/*protected void onRestart() {Log.d(TAG, "——————重新启动游戏——————");SFOnlineHelper.onRestart(this);}*///登录的监听方法public void loginListener(){SFOnlineHelper.setLoginListener(this, new SFOnlineLoginListener(){@Overridepublic void onLoginSuccess(SFOnlineUser user, Object customParams) {/** * 获取用户信息 传到你们的游戏内,绑定游戏玩家  用户的唯一标示是  channneluserid * 用户唯一标示  --- 该玩家在 该渠道 的唯一标示。若要实现全渠道 唯一 请自行处理映射关系 建议 使用 {sdk_userID}*/String userID = user.getChannelUserId();String app = user.getProductCode();String sdk = user.getChannelId();String token = user.getToken();String userName = user.getUserName(); // 这个参数是 可选的 不是用户唯一标示,通常建议不用。System.out.println("————"+"userID:"+userID+",app:"+app+",sdk:"+sdk +",token"+token+",userName:"+userName);// 用户信息获取结束//登录验证try {if(helper != null){helper.setOnlineUser(user);}LoginCheck(user);Toast.makeText(getContext(), "验证:账户登录成功", 3000).show();} catch (JSONException e) {e.printStackTrace();} catch (UnsupportedEncodingException e) {e.printStackTrace();}}@Overridepublic void onLoginFailed(String reason, Object customParams) {Log.d(TAG, "——————登录失败!——————");Toast.makeText(getContext(), "验证:账户登录失败", 3000).show();}@Overridepublic void onLogout(Object customParams) {Log.d(TAG, "——————登出成功!——————");Toast.makeText(getContext(), "验证:登出成功", 3000).show();}});}//登出public void onlogout(Object customParams){Log.d(TAG, "——————登出游戏——————"+ customParams);SFOnlineHelper.logout(this, "LoginOut");Toast.makeText(this, "账户登出", Toast.LENGTH_LONG).show();/*if(helper!=null){helper.setOnlineUser(null);helper.setLogin(false);helper.getHandler(this).postDelayed(new Runnable(){@Overridepublic void run() {SFOnlineHelper.login((Activity) getContext(), "Login"); Log.d(TAG, "——————登出游戏,切换账号——————");}}, 200);}*/}//登录验证public void LoginCheck(final SFOnlineUser user) throws JSONException, UnsupportedEncodingException{Log.d(TAG, "——————登录验证!——————");//此处进行的登录验证是 模拟验证 // 正确的验证流程是    游戏客户端 ----》游戏服务器----》易接服务器---》渠道服务器// 这里就不做了 留个 空//TODO  实现真实的验证 String url = "http://192.168.0.105:8000/run"+createLoginURL(user);if (url == null)return;System.out.println("url:"+url);new Thread(new Runnable(){@Overridepublic void run() {MainActivity.SendErrorToGMServer(user.getProductCode(), user.getChannelId(), user.getToken(), user.getChannelId());System.out.println("————1、发送登录验证到本地服务器————");}}).start();String result = LoginHelper.executeHttpGet(url);Log.e(TAG,"————发送信息成功————"+result);if(result==null ||!result.equals("SUCCESS")){if(helper != null){helper.setLogin(false);}LoginHelper.showMessage("未登录", this);}else{if(helper != null){helper.setLogin(true);}}// 通常在游戏内调用 上传角色信息的接口    这里模拟设置角色信息 setRole();// 这些做完就接好了 用户 系统  下面是支付  通常是用户触发pay();onBackPressed();/*Toast.makeText(getContext(), "退出!", 3000).show(); */}//模拟设置角色基本信息@SuppressWarnings("unused")private void setRole() throws JSONException{SFOnlineHelper.setRoleData(this, "1","骑士", "100", "1", "阿狸一区");Log.d(TAG, "——————角色初始化——————");// setData  key  --?  enterserver  levelup   createrole 最常见的三个场景。// info  用户信息  参考 demo的json  JSONObject  info = new JSONObject(); info.put("roleName", "saber");//当前登录的玩家角色ID,必须为数字 info.put("roleId", "775522233"); //当前登录的玩家角色名,不能为空,不能为null info.put("roleLevel", "100");//当前登录的玩家角色等级,必须为数字,且不能为0,若无,传入1 info.put("zoneId", "1");//当前登录的游戏区服ID,必须为数字,且不能为0,若无,传入1 info.put("zoneName", "阿狸一区");//当前登录的游戏区服名称,不能为空,不能为null info.put("balance", "0");//用户游戏币余额,必须为数字,若无,传入0 info.put("vip", "1");//当前用户VIP等级,必须为数字,若无,传入1 info.put("partyName", "无帮派");//当前角色所属帮派,不能为空,不能为null,若无,传入“无帮派” info.put("roleCTime", "234234");//单位为秒,创建角色的时间 info.put("roleLevelMTime", "54456556");//单位为秒,角色等级变化时间  //实现完整角色验证SFOnlineHelper.setData(this, "key", info.toString()); //一定要 toString  !LoginHelper.showMessage("角色saber,登录验证成功!", this);Log.d(TAG, "——————角色验证成功!——————");}//传递地址private String createLoginURL(SFOnlineUser user) throws UnsupportedEncodingException{StringBuilder builder = new StringBuilder();builder.append("?app=");builder.append(URLEncoder.encode(user.getProductCode(), "utf-8"));builder.append("&sdk=");builder.append(URLEncoder.encode(user.getChannelId(), "utf-8"));builder.append("&uin=");builder.append(URLEncoder.encode(user.getChannelUserId(), "utf-8"));builder.append("&sess=");builder.append(URLEncoder.encode(user.getToken(), "utf-8"));return builder.toString();}// 退出@Overridepublic void onBackPressed() {Log.d(tag, "————onBackPressed,退出游戏————");// exit方法用于系统全局退出SFOnlineHelper.exit(this, new SFOnlineExitListener() {@Overridepublic void onSDKExit(boolean bool) {if (bool) {// apk退出函数,demo中也有使用System.exit()方法;但请注意360SDK的退出使用exit()会导致游戏退出异常finish();}}/* * onNoExiterProvide *  * @description SDK没有退出方法及界面,回调该函数,可在此使用游戏退出界面 */@Overridepublic void onNoExiterProvide() {AlertDialog.Builder builder = new Builder(luaTest.this);builder.setTitle("是否要退出游戏界面");builder.setPositiveButton("退出",new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog,int which) {luaTest.this.finish();System.exit(0);}});builder.show();}});}//定额计费接口@SuppressWarnings("unused")private void pay(){int unitPrice = 10 ;  //游戏道具价格,单位为 分String itemName="钻石";  //虚拟货币名称int count= 1; //默认道具数量String callBackInfo="12345678910"; //自定义的说明,判断交易详细内容,不要用空格和特殊字符; 暂时设定为订单IDString callBackUrl = "http://123.57.12.130:8000/paycallback" ; // arg5 ,将交易结果传给服务器的通知url,可看到explain的信息// arg6透传参数 不要有汉字空格,可自定义try{SFOnlineHelper.pay(this, unitPrice, itemName, count, callBackInfo,callBackUrl, new SFOnlinePayResultListener() {@Overridepublic void onSuccess(String remain) {Toast.makeText(getContext(), "支付成功,获得1钻石", 2000).show();Log.d(TAG,"—————支付成功———————");}@Overridepublic void onFailed(String remain) {// 支付失败Log.d(TAG,"—————支付失败———————");Toast.makeText(getContext(), "错误信息,支付失败!", 2000).show();}@Overridepublic void onOderNo(String orderNo) {// 订单创建成就会回调通常记录到服务器 Log.e(TAG, "————订单创建,发生到服务器");LoginHelper.showMessage("购买钻石订单号:" + orderNo, getContext());}});}catch(Exception e){e.printStackTrace();Log.e(TAG, "————错误,没有进入支付!————");}}//非定额计费接口@SuppressWarnings("unused")private void charge(int price){if(!LoginHelper.instance().isLogin()){Toast.makeText(this,"用户未登陆",Toast.LENGTH_SHORT).show();return ;}Log.e(TAG, "—————非定额计费—————");String itemName="钻石";  //虚拟货币名称int unitPrice = 10 ;  //游戏道具价格,单位为 分 int count= 1; //默认道具数量String callBackInfo="123456"; //自定义的说明,判断交易详细内容,不要用空格和特殊字符,暂时设置为订单IDString callBackUrl = "http://123.57.12.130:8000/paycallback" ;  // arg5 ,将交易结果传给服务器的通知url,可看到explain的信息// arg6透传参数 不要有汉字空格,可自定义try{SFOnlineHelper.charge(this,itemName,unitPrice, count,callBackInfo, callBackUrl, new SFOnlinePayResultListener() {@Overridepublic void onSuccess(String remain) {Toast.makeText(getContext(), "支付成功,获得10钻石,5黄金,20积分", 2000).show();System.out.println("—————支付成功———————");}@Overridepublic void onFailed(String remain) {// 支付失败Toast.makeText(getContext(), "错误信息,支付失败!", 2000).show();}@Overridepublic void onOderNo(String orderNo) {LoginHelper.showMessage("订单号:" + orderNo, getContext());}});}catch(Exception e){e.printStackTrace();Log.e(TAG, "————错误,没有进入定额支付!————");}}}class LuaGLSurfaceView extends Cocos2dxGLSurfaceView {public LuaGLSurfaceView(Context context) {super(context);}public boolean onKeyDown(int keyCode, KeyEvent event) {if (keyCode == KeyEvent.KEYCODE_BACK) {android.os.Process.killProcess(android.os.Process.myPid());}return super.onKeyDown(keyCode, event);}}

2、客户端(当前ec—sdk项目)请求发送/接收 服务端消息 activity 

MainActivity :

package com.android.zdhsoft;import java.io.IOException;import java.io.UnsupportedEncodingException;import java.util.ArrayList;import java.util.List;import org.apache.http.NameValuePair;import org.apache.http.client.ClientProtocolException;import org.apache.http.client.entity.UrlEncodedFormEntity;import org.apache.http.client.methods.HttpPost;import org.apache.http.impl.client.DefaultHttpClient;import org.apache.http.message.BasicNameValuePair;import com.android.zdhsoft.R;import android.app.Activity;import android.content.ComponentName;import android.content.Context;import android.content.Intent;import android.content.ServiceConnection;import android.os.Bundle;import android.os.IBinder;import android.os.Message;import android.os.Messenger;import android.os.RemoteException;import android.util.Log;import android.view.View;public class MainActivity extends Activity {private static final String TAG ="--MainActivity--";private static  String GMSERVER_API = "http://192.168.0.105:8000/run";  //公司外网地址,这个请自己填写 Messenger mes; boolean isBound;    @Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);Log.d(TAG, "—————onCreate—————");}//登录发生请求      public void doLogin(View view) {          Intent intent = new Intent(MainActivity.this, luaTest.class);          startActivity(intent);  Log.d(TAG, "—————doLogin—————");    }      protected void onStart(){    super.onStart();     }    @Override    protected void onStop() {        super.onStop();        Log.d(TAG,"—————onStop—————");    }public static void setErrorCollectApi(String api){GMSERVER_API = api;}
//多抛出异常public static void SendErrorToGMServer(String app,String sdk,String token,String userName){Log.d(TAG, "—————SendErrorToGMServer—————");List<NameValuePair> params = new ArrayList<NameValuePair>();try {HttpPost post = new HttpPost(GMSERVER_API);params.add(new BasicNameValuePair("app",app));params.add(new BasicNameValuePair("sdk",sdk));params.add(new BasicNameValuePair("token",token));params.add(new BasicNameValuePair("userName",userName));/*params.add(new BasicNameValuePair("sys_version",android.os.Build.VERSION.RELEASE));*/params.add(new BasicNameValuePair("dev",android.os.Build.MODEL));post.setEntity(new UrlEncodedFormEntity(params));new DefaultHttpClient().execute(post);System.out.println("—————异常一—————");} catch (UnsupportedEncodingException e) {e.printStackTrace();Log.d(TAG, "—————异常一—————");} catch (ClientProtocolException e) {e.printStackTrace();Log.d(TAG, "—————异常二—————");} catch (IOException e) {e.printStackTrace();Log.d(TAG, "—————异常三—————");}Log.d(TAG, "—————SendErrorToGMServer完成—————");}}

3、AndroidManifest.xml 

(仅供参考)

<?xml version="1.0" encoding="UTF-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android"    package="com.android.zdhsoft"    android:versionCode="1"    android:versionName="1.0" >    <uses-sdk        android:minSdkVersion="19"        android:targetSdkVersion="20" />
//权限    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />    <uses-permission android:name="android.permission.ACCESS_MOCK_LOCATION" />    <uses-permission android:name="android.permission.INTERNET" />    <uses-permission android:name="android.permission.READ_PHONE_STATE" />    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />    <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />    <uses-permission android:name="android.permission.GET_TASKS" />    <uses-permission android:name="android.permission.WAKE_LOCK" />    <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />    <uses-permission android:name="android.permission.KILL_BACKGROUND_PROCESSES" />    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />    <uses-feature android:glEsVersion="0x00020000" />-    <application        android:name="com.snowfish.cn.ganga.helper.SFOnlineApplication"        android:allowBackup="true"        android:icon="@drawable/aa"        android:label="@string/app_name" >-//屏幕控制        <activity            android:name="activity.DemoMainActivity"            android:configChanges="orientation|keyboardHidden|navigation|screenSize"            android:label="@string/app_name"            android:launchMode="singleTop"            android:screenOrientation="sensor"            android:theme="@android:style/Theme.NoTitleBar.Fullscreen" >            <!-- <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> -->        </activity>-        <activity            android:name=".MainActivity"            android:label="@string/app_name"            android:theme="@android:style/Theme.NoTitleBar.Fullscreen" >            <!-- <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> -->        </activity>        <!-- android:screenOrientation="" landscape:横屏;portrait:竖屏;sensor:物理感应器 -->-        <activity            android:name=".luaTest"            android:configChanges="orientation|keyboardHidden|navigation|screenSize"            android:label="@string/title_activity_main"            android:screenOrientation="sensor"            android:theme="@android:style/Theme.NoTitleBar.Fullscreen" >-            <intent-filter>                <action android:name="android.intent.action.MAIN" />                <category android:name="android.intent.category.LAUNCHER" />            </intent-filter>        </activity>        <activity            android:name="view.PaymentView"            android:label="@string/title_activity_payment" >        </activity>-        <service            android:name="com.snowfish.a.a.s.ABGSvc"            android:enabled="true"            android:process="com.snowfish.a.a.bg" >-            <intent-filter>                <action android:name="com.snowfish.a.a.s.ABGSvc" />                <category android:name="android.intent.category.DEFAULT" />            </intent-filter>        </service>        <meta-data            android:name="com.snowfish.customer"            android:value="SNOWFISH" >        </meta-data>        <meta-data            android:name="com.snowfish.channel"            android:value="SNOWFISH" >        </meta-data>        <meta-data            android:name="com.snowfish.sdk.version"            android:value="2" >        </meta-data>        <!-- END SNOWFISH SDK -->        <!-- 此参数不做修改,保持默认就行,打包会自动替换 -->        <!-- com.snowfish.appid 游戏的唯一标识,用于区分不同游戏的唯一标准。在易接开发者中心游戏管理模块中创建新游戏获取 -->        <meta-data            android:name="com.snowfish.appid"            android:value="{4477D4AB-399F0338}" >        </meta-data>        <!-- com.snowfish.channelid 支付渠道标识,此id可区分渠道,在易接后台有相应的渠道对照表 -->        <meta-data            android:name="com.snowfish.channelid"            android:value="{4ff036a1-3254eafe}" >        </meta-data>    </application>    <supports-screens        android:anyDensity="true"        android:largeScreens="true"        android:normalScreens="true"        android:smallScreens="true" /></manifest>

其他修改请参考帮助文档!


六、服务端代码公布:

Eclipse,这个是另外一个ec,不是ec_sdk

1、BaseServlet.java

package com.test;import java.io.IOException;import java.io.PrintWriter;import java.net.URLEncoder;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;public  class BaseServlet extends HttpServlet{// 应用在易接服务获取的同步密钥private final String PRIVATE_KEY = "V2X0XE5DSZ4AGFXJCA5YZ5CDUQO4LPJY";  //自己在轨道SDK申请,我这个是乐视的private final int LOGIN_RESULT_SUCCESS = 0;private final String CHECK_LOGIN_URL = "http://sync.1sdk.cn/login/check.html";private static final long serialVersionUID = 1L;@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException {System.out.println("BaseServlet.doGet()"); doPost(req, resp);  }@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {System.out.println("BaseServlet.doPost()");PrintWriter w = resp.getWriter();String app = req.getParameter("app");String sdk = req.getParameter("sdk");String uin = req.getParameter("token");String sess = req.getParameter("userName");StringBuilder getUrl = new StringBuilder();getUrl.append(CHECK_LOGIN_URL);getUrl.append("?app=");getUrl.append(app);getUrl.append("&sdk=");getUrl.append(sdk);getUrl.append("&uin=");getUrl.append(URLEncoder.encode(uin, "UTF-8"));getUrl.append("&sess=");getUrl.append(URLEncoder.encode(sess, "UTF-8"));try {ServerLauncher.SimpleHTTPResult ret = ServerLauncher.simpleInvoke ("GET", getUrl.toString(), null, null);// 下面的返回值由CP服务器和客户端定义,这里的返回值只做参考用if (ret.code != 200) {w.write("ERROR");return;}if (ret.data == null || ret.data.length == 0) {w.write("ERROR");return;} else {String r = new String (ret.data);Integer i = new Integer(r);if (i == LOGIN_RESULT_SUCCESS) {w.write("SUCCESS");System.out.println("app:"+app);System.out.println("sdk:"+sdk);System.out.println("token:"+uin);System.out.println("userName:"+sess);System.out.println("————登录验证完成————");} else {w.write("ERROR");System.out.println("————登录验证失败!————");}return;}} catch (Exception e) {e.printStackTrace();}finally{w.flush();w.close();}/* * 以上登录验证流程完成! * 以下是订单支付的接收信息 */String app2 = req.getParameter("app2");String cbi = req.getParameter("cbi");String ct = req.getParameter("ct");String fee = req.getParameter("fee");String pt = req.getParameter("pt");String ssid = req.getParameter("ssid");String st = req.getParameter("st");String tcd = req.getParameter("tcd");String uid = req.getParameter("uid");String ver = req.getParameter("ver");StringBuffer sbEnc = new StringBuffer (); sbEnc.append ("app="); sbEnc.append (req.getParameter("app"));sbEnc.append ("&cbi="); sbEnc.append (req.getParameter("cbi")); sbEnc.append ("&ct="); sbEnc.append (req.getParameter("ct")); sbEnc.append ("&fee="); sbEnc.append (req.getParameter("fee"));  sbEnc.append ("&pt="); sbEnc.append (req.getParameter("pt"));sbEnc.append ("&sdk="); sbEnc.append (req.getParameter("sdk"));sbEnc.append ("&ssid="); sbEnc.append (req.getParameter("ssid")); sbEnc.append ("&st=");sbEnc.append (req.getParameter("st")); sbEnc.append ("&tcd="); sbEnc.append (req.getParameter("tcd"));sbEnc.append ("&uid="); sbEnc.append (req.getParameter("uid")); sbEnc.append ("&ver="); sbEnc.append (req.getParameter("ver")); String sign = req.getParameter("sign");boolean result = MD5.encode(sbEnc + PRIVATE_KEY).equalsIgnoreCase(sign);if(result){// 此处CP可以持久化消费记录//st==1是支付成功,才能给用户发道具// 操作成功后需要返回SUCCESS告诉易接服务器已经接收成功w.write("SUCCESS");System.out.println("开始验证订单!");System.out.println("生成的订单信息:"+cbi+ct+fee+pt+ssid+st+tcd+uid+ver);}else{// 返回ERROR易接服务器会根据一定的策略重新同步消费记录给CPw.write("ERROR");System.out.println("开始验证订单失败!");}w.flush();w.close();}}

2、ServerLauncher.java

package com.test;import java.io.ByteArrayOutputStream;import java.io.IOException;import java.io.InputStream;import java.io.OutputStream;import java.net.HttpURLConnection;import java.net.URL;import org.mortbay.jetty.Server;import org.mortbay.jetty.nio.SelectChannelConnector;import org.mortbay.jetty.servlet.Context;import org.mortbay.jetty.servlet.ServletHolder;import org.mortbay.thread.BoundedThreadPool;public class ServerLauncher {private void launch(int port) throws Exception {Server server = new Server();BoundedThreadPool threadPool = new BoundedThreadPool();threadPool.setMinThreads(50);threadPool.setMaxThreads(1000);server.setThreadPool(threadPool);SelectChannelConnector connector = new SelectChannelConnector();connector.setPort(port);//server.addHandler(webContext);server.addConnector(connector);Context root = new Context(server, "/", 1);root.addServlet(new ServletHolder(new BaseServlet()),"/run");server.start();}public static void main(String[] args) throws Exception {new ServerLauncher().launch(8000);System.out.println("Start ");}//易接例子public static class SimpleHTTPResult {public int code;public byte[] data;}public static SimpleHTTPResult simpleInvoke (String method, String url, String contentType, byte[] outdata) throws IOException {SimpleHTTPResult res = new SimpleHTTPResult ();HttpURLConnection http = (HttpURLConnection)(new URL (url)).openConnection ();http.setRequestMethod (method);if (contentType != null)http.setRequestProperty ("Content-Type", contentType);if (outdata != null) {http.setRequestProperty ("Content-Length", Integer.toString (outdata.length));}http.setDoOutput (outdata != null ? true : false);http.setDoInput (true);http.connect ();if (outdata != null) {OutputStream outs = http.getOutputStream ();outs.write (outdata);outs.close ();}res.code = http.getResponseCode ();if (res.code == 404) {return res;}InputStream stream = http.getInputStream ();try {int len = http.getContentLength ();byte[] data;if (len >= 0) {data = new byte[len];int off = 0;while (off < len) {int read = stream.read (data, off, len - off);if (read < 0)throw new IOException ();off += read;}} else {ByteArrayOutputStream baos = new ByteArrayOutputStream ();byte[] buffer = new byte[4096];for (;;) {int read = stream.read (buffer, 0, buffer.length);if (read < 0)break;baos.write (buffer, 0, read);}baos.close ();data = baos.toByteArray ();}res.data = data;} finally {stream.close ();}return res;}public static byte[] post (URL url, String contentType, byte[] outdata) throws IOException {HttpURLConnection http = (HttpURLConnection)url.openConnection ();http.setRequestProperty ("Content-Type", contentType);http.setDoOutput (true);http.setDoInput (true);http.connect ();OutputStream outs = http.getOutputStream ();outs.write (outdata);outs.close ();int code = http.getResponseCode ();if (code != 200) {throw new IOException ("Bad RPC '" + url.toString () + "': " + code);}InputStream stream = http.getInputStream ();try {int len = http.getContentLength ();byte[] data;if (len >= 0) {data = new byte[len];int off = 0;while (off < len) {int read = stream.read (data, off, len - off);if (read < 0)throw new IOException ();off += read;}} else {ByteArrayOutputStream baos = new ByteArrayOutputStream ();byte[] buffer = new byte[4096];for (;;) {int read = stream.read (buffer, 0, buffer.length);if (read < 0)break;baos.write (buffer, 0, read);}baos.close ();data = baos.toByteArray ();}return data;} finally {stream.close ();}}}

3、MD5.java 这个加密用的


package com.test;import java.security.MessageDigest;import java.security.NoSuchAlgorithmException;public class MD5 {        // 全局数组    private final static String[] strDigits = { "0", "1", "2", "3", "4", "5",            "6", "7", "8", "9", "a", "b", "c", "d", "e", "f" };    public MD5() {    }    // 返回形式为数字跟字符串    private static String byteToArrayString(byte bByte) {        int iRet = bByte;        // System.out.println("iRet="+iRet);        if (iRet < 0) {            iRet += 256;        }        int iD1 = iRet / 16;        int iD2 = iRet % 16;        return strDigits[iD1] + strDigits[iD2];    }    // 返回形式只为数字    private static String byteToNum(byte bByte) {        int iRet = bByte;        System.out.println("iRet1=" + iRet);        if (iRet < 0) {            iRet += 256;        }        return String.valueOf(iRet);    }    // 转换字节数组为16进制字串    private static String byteToString(byte[] bByte) {        StringBuffer sBuffer = new StringBuffer();        for (int i = 0; i < bByte.length; i++) {            sBuffer.append(byteToArrayString(bByte[i]));        }        return sBuffer.toString();    }    public static String encode(String strObj) {        String resultString = null;        try {            resultString = new String(strObj);            MessageDigest md = MessageDigest.getInstance("MD5");            // md.digest() 该函数返回值为存放哈希值结果的byte数组            resultString = byteToString(md.digest(strObj.getBytes()));        } catch (NoSuchAlgorithmException ex) {            ex.printStackTrace();        }        return resultString;    }    public static void main(String[] args) {        System.out.println(MD5.encode("000000"));    }}