记录一下开发过程遇到的坑。因为金蝶云在webapi开发能查阅到的资料少之又少,java有些SDK包用不了,或者版本不兼容等各种问题。故再此记录一下用okhttp的方法来调用api接口。
目录
一、事前准备
二、打开金蝶云,找到web api开发查看参数
三、上代码
登录接口:
构造的JSON:
返回的JSON:
message:
myHandler :
准备好postman工具(对api做提交测试用的)。
抓包工具 httpdebug pro (用于抓到请求接口,不过我这里抓到现成的的,直接复制过去就好了)
Android studio 2022
只要看参数,因为我们没调用SDK包,下面看了也是白看。。。而且下面的实例代码是c#的。。和安卓不能说长得一模一样吧,简直毫无相干。。。
但是可以借鉴代码里面的账套id,这个是必须的。
http://+你自己公司的域名+/Kingdee.BOS.WebApi.ServicesStub.AuthService.ValidateUser.common.kdsvc
构造请求头文件:
UUID uuid = UUID.randomUUID();
Log.d("qy1314", "" + uuid);
JSONArray jparas = new JSONArray();
jparas.put("638232c2dab4fd6"); // 638232c2dab4fd6 测试
jparas.put(zhanghao.getText().toString());
jparas.put(mima.getText().toString());
jparas.put(2052); //语言
jparas.toString();
Log.d("qy1314", "" + jparas);
//金蝶API要求参数
JSONObject jsonObject = new JSONObject();
try {
jsonObject.put("format", 1);
jsonObject.put("useragent", "apiClient"); //HTTP HEADER
jsonObject.put("rid", uuid.toString());
jsonObject.put("parameters", jparas); //登录验证信息,就是上面
jsonObject.put("timestamp", new Date().toString());设置好的Json
数组
jsonObject.put("v", "1.0");
} catch (JSONException e) {
e.printStackTrace();
}
RequestBody myrequsetbody = RequestBody.create(MediaType.parse("application/json;charset=utf-8"), jsonObject.toString());
OkHttpClient okHttpClient = new OkHttpClient();
Request request = new Request.Builder()
.post(myrequsetbody)
.url(url)
.addHeader("Content-Type", "application/json")
.addHeader("User-Agent", "PostmanRuntime/7.29.2")
.addHeader("Accept-Encoding", "gzip, deflate, br")
.addHeader("Connection", "keep-alive")
.addHeader("Accept", "*/*")
.addHeader("Cookie", "ASP.NET_SessionId=lk3qjqdeoddchtf5lv20r4la; kdservice-sessionid=50396dcc-7504-4c2a-9365-118513d2bb65")
.build();
这样一个请求的就构造好了。
{
"format":1,
"useragent":"apiClient",
"rid":"5f753e1d-ed4c-42dc-a644-fc2f0cb37eda",
"parameters":[
"63242c2dab4fd6",
"user",
"password",
2052
],
"timestamp":"Mon Nov 21 02:26:25 GMT 2022",
"v":"1.0"
}
接下来就是对返回结果进行操作了。要记住一点:
云星空对数据操作都是要cookie的,这个cookie就是从登录的返回结果里取出。
{
"Message":null,
"MessageCode":"CheckPasswordPolicy",
"LoginResultType":1,
"Context":{
"UserLocale":"zh-CN",
"LogLocale":"zh-CN",
"DBid":"63842c2dab4fd6",
"DatabaseType":3,
"SessionId":"cmofveb1mkbyxadag2rytqt4",
"UseLanguages":[
{
"LocaleId":2052,
"LocaleName":"中文(简体)",
"Alias":"CN",
"LicenseType":0
}
],
"UserId":792671,
"UserName":"杨**",
"CustomName":"江苏*****限公司",
"DisplayVersion":"8.1.410.13",
"DataCenterName":"测试专用",
"UserToken":"6d5950ca-91bd-4bdc-b571-be026057420b",
"CurrentOrganizationInfo":{
"ID":100377,
"AcctOrgType":"1",
"Name":"江苏*****限公司",
"FunctionIds":[
101,
102,
103,
104,
108,
107,
109,
110,
111,
112,
113,
114
]
},
"IsCH_ZH_AutoTrans":false,
"ClientType":32,
"WeiboAuthInfo":{
"WeiboUrl":null,
"NetWorkID":null,
"CompanyNetworkID":null,
"Account":" @",
"AppKey":"FkdTqJiNeCQC0ugp",
"AppSecret":"yCP3ucK2IQUm2D3heHxiarq1RJZwfcnKullRSMOIEM",
"TokenKey":" ",
"TokenSecret":" ",
"Verify":null,
"CallbackUrl":null,
"UserId":" ",
"Charset":{
"BodyName":"utf-8",
"EncodingName":"Unicode (UTF-8)",
"HeaderName":"utf-8",
"WebName":"utf-8",
"WindowsCodePage":1200,
"IsBrowserDisplay":true,
"IsBrowserSave":true,
"IsMailNewsDisplay":true,
"IsMailNewsSave":true,
"IsSingleByte":false,
"EncoderFallback":{
"DefaultString":"�",
"MaxCharCount":1
},
"DecoderFallback":{
"DefaultString":"�",
"MaxCharCount":1
},
"IsReadOnly":true,
"CodePage":65001
}
},
"UTimeZone":{
"OffsetTicks":288000000000,
"StandardName":"(UTC+08:00)北京,重庆,香港特别行政区,乌鲁木齐",
"Id":230,
"Number":"1078_SYS",
"CanBeUsed":true
},
"STimeZone":{
"OffsetTicks":288000000000,
"StandardName":"(UTC+08:00)北京,重庆,香港特别行政区,乌鲁木齐",
"Id":230,
"Number":"1078_SYS",
"CanBeUsed":true
},
"GDCID":"",
"Gsid":null,
"TRLevel":0,
"ProductEdition":0,
"DataCenterNumber":"999",
"ContextResultType":0,
"TenantId":"",
"IsDeployAsPublicCloud":false
},
"KDSVCSessionId":"4914d4b5-36f8-4dfe-8ae6-da11cc672fab",
"FormId":null,
"RedirectFormParam":null,
"FormInputObject":null,
"ErrorStackTrace":null,
"Lcid":0,
"AccessToken":null,
"CustomParam":{
"GlobalWatermarkConfigStr":"eyJ3aWR0aCI6MzAwLCJoZWlnaHQiOjE2MCwiYW5nbGUiOi0xNSwid2F0ZXJtYXJrdGV4dCI6IiAiLCJsaWN0ZXh0IjoiIiwib3BhY2l0eSI6MC4xLCJmb250ZmFtaWx5IjoiTWljcm9zb2Z0IFlhSGVpIiwiZm9udHNpemUiOjE0LCJiaWdfZm9udHNpemUiOjE2LCJzaG93dHlwZSI6MH0="
},
"KdAccessResult":null,
"IsSuccessByAPI":true
}
看见这个就是登录成功啦!可是有没有发现,在返回的JSON数据里没有看见cookies,其实是放在请求头里面,我们看一下返回结果的头部
然后定义一个Helder 存放返回的数据,同for循环将cookie解析出来。
Response response = okHttpClient.newCall(request).execute();
String cookie = "";
if (response.isSuccessful()) {
//Handlers handler = response.headers();
Headers headers = response.headers();
Listcookies =headers.values("Set-Cookie");
for(int a=0;a<2;a++) {
if (cookies.size() > 0) {
String session = cookies.get(a);
int size = session.length();
int i = session.indexOf(";");
if (i <= size && i >= 0) {
cookie += session.substring(0, i)+";";
Log.d("qy1314", "session" + cookie);
}
}
}
至此,登录就完成80%了。登录完成后需要进行跳转页面进入数据管理页(自定义的界面),这边通过bundle 存放数据,通过message +handler处理线程产生的数据从而更新页面
Bundle bundle = new Bundle();
bundle.putString("username", username);
bundle.putString("token", cookie);
bundle.putString("userid",userid);
Message msg = Message.obtain();
msg.what = 1;
msg.obj = bundle;
Log.d("qy1314", "res_msg" + msg.what);
myHandler.handleMessage(msg);
MyHandler myHandler = new MyHandler(){
@SuppressLint("HandlerLeak")
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
if(msg.what==1){
Bundle bundle =(Bundle)msg.obj;
String name =bundle.getString("username");
String tk =bundle.getString("token");
String uid =bundle.getString("userid");
Intent a = new Intent(MainActivity.this,MainActivity_saoma.class);
a.putExtra("name",name);
a.putExtra("token",tk);
Log.e("qy1314","puttoken"+tk);
a.putExtra("user",zhanghao.getText().toString());
a.putExtra("psd",mima.getText().toString());
a.putExtra("userid",uid);
startActivity(a);
Looper.prepare();
Toast.makeText(MainActivity.this,"SESSUSS",Toast.LENGTH_LONG).show();
Looper.loop();
}
网络配置和安全证书的配置百度都有,就不细讲了。