TARS RestAPI应用
# Smart之TARS RestAPI应用
# 1. 说明
TARS中包含了RestAPI功能,可以通过HTTPURL的形式去访问来实现TARS的各个功能。在使用本范例前,需在TARS中的[参数设置]-[常规设置]
中勾选验证用户身份
,设定用户数据库为TARS
。

在[参数设置]-[REST/SSL]
中启用开启REST
,设置REST数据库的访问方式为通过SQL编号(安全性高)
。

在[用户管理]
中设置RestAPI的登录用户。

在[预设SQL管理]
中设置SQL编号的相关命令。

通过范例学习,可以掌握TARS中RestAPI的使用方法,并结合Smart实现访问的相关功能。
# 2. 设计明细
开启Smart智慧控制平台,分别加入下插图之控件。或者通过点击菜单栏[文件]
-[打开项目]
选择项目打开该范例。

①:TEdit组件,控件名称为edtHost
。
②:TEdit组件,控件名称为edtPort
。
③:TComboBox组件,控件名称为cbbCompressMode
。
④:TCheckBox组件,控件名称为chkNeedLogin
。
⑤:TCheckBox组件,控件名称为chkNeedSign
。
⑥:TPageControl组件,控件名称为PageControl1
。
⑦:TEdit组件,控件名称为edtConnectionDefName
。
⑧:TEdit组件,控件名称为edtUserName
。
⑨:TEdit组件,控件名称为edtPassword
。
⑩:TEdit组件,控件名称为edtVerifyCode
。
(11):TImage组件,控件名称为imgVerifyCode
(12):TEdit组件,控件名称为edtToken
。
(13):TDBGrid组件,控件名称为grd1
。
(14):TDataSource组件,控件名称为ds1
(15):TRFDataSet组件,控件名称为RFDataSet1
。
(16):TButton组件,控件名称为btnLogin
。
(17):TButton组件,控件名称为btnLogOut
。
Main窗体属性设置
BorderStyle
:设置窗体显示的边框样式=bsDialog
。ClientHeight
:窗体客户区高度=706
。ClientWidth
:窗体客户区宽度=901
。
①edtHost属性设置
Height
:设置控件高度=21
。Width
:设置控件宽度=145
。Name
:设置控件名称=edtHost
。Text
:设置显示的文本内容=127.0.0.1
。
②edtPort属性设置
Height
:设置控件高度=21
。Width
:设置控件宽度=146
。Name
:设置控件名称=edtPort
。Text
:设置显示的文本内容=8809
。
③cbbCompressMode属性设置
Height
:设置控件高度=21
。Width
:设置控件宽度=174
。Name
:设置控件名称=cbbCompressMode
。Item
:设置显示的选项,双击该属性或者点击右侧[...]
打开编辑界面。
ItemIndex
:设置默认选择的项的索引=0
。
④chkNeedLogin属性设置
Caption
:设置单选框的标签名称,设置为验证用户
。Checked
:设置是否处于勾选状态,设置为True
。
⑤chkNeedSign属性设置
Caption
:设置单选框的标签名称,设置为验证签名
。Checked
:设置是否处于勾选状态,设置为False
。
⑥PageControl1属性设置
- 通过在其界面上右键点击,选择
Next Page
以新增页面。 - 分别为几个页面标签取名为
登录
、查询数据
、更新数据
、存储过程
。
- 通过在其界面上右键点击,选择
⑦edtConnectionDefName属性设置
Height
:设置控件高度=21
。Width
:设置控件宽度=139
。Name
:设置控件名称=edtConnectionDefName
。Text
:设置显示的文本内容=TARS
。
⑧edtUserName属性设置
Height
:设置控件高度=21
。Width
:设置控件宽度=139
。Name
:设置控件名称=edtUserName
。Text
:设置显示的文本内容=admin
。
⑨edtPassword属性设置
Height
:设置控件高度=21
。Width
:设置控件宽度=139
。Name
:设置控件名称=edtPassword
。Text
:设置显示的文本内容=admin
。
⑩edtVerifyCode属性设置
Height
:设置控件高度=21
。Width
:设置控件宽度=139
。Name
:设置控件名称=edtVerifyCode
。TextHint
:设置显示的文本提示信息=六位数字
。Visible
:设置控件是否可见=False
。
(11)imgVerifyCode属性设置
Height
:设置控件高度=33
。Width
:设置控件宽度=121
。Name
:设置控件名称=imgVerifyCode
。
(12)edtToken属性设置
Height
:设置控件高度=21
。Width
:设置控件宽度=731
。
(13)grd1属性设置
Align
:该控件位于pgcDataSet
中,设置该属性为alClient
,即占满客户端区域。Name
:设置控件名称=grd1
。DataSource
:设置其数据源控件,设置为ds1
。
(14)ds1属性设置
DataSet
:设置其数据集控件,设置为RFDataSet1
。Name
:设置控件名称=ds1
。
(16)btnLogin属性设置
Caption
:设置控件字幕=登录
。Height
:设置控件高度=55
。Width
:设置控件宽度=75
。Name
:设置控件名称=btnLogin
。
(17)btnLogout属性设置
Caption
:设置控件字幕=注销
。Height
:设置控件高度=55
。Width
:设置控件宽度=75
。Name
:设置控件名称=btnLogout
。
# 3. 程序设计
# 3.1. 程序初始设置
设置初始变量与常量。
private
FAccessToken: string;
FImageBase64Data: string;
FAppSecret: string;
//FStopWatch: TStopwatch;
FHaveDataSet: Boolean;
2
3
4
5
6
const
// 用户名是 admin ,密码是123456的md5值 e10adc3949ba59abbe56e057f20f883e
STATUS_OK = 0; // ok
STATUS_PARAMETER_INVALID = 1; // 请求参数错误
STATUS_TOKEN_INVALID = 2; // 令牌错误
STATUS_VERIFY_FAILURE = 3; // 验证错误/用户名或密码错误
STATUS_DBMS_ERROR = 4; // 数据库系统错误
STATUS_NOT_LOGINED = 5; // 未登录
STATUS_VERIFYCODE_INVALID = 6; // 验证码错误
STATUS_TOKEN_EXPIRED = 7; // 授权已过期
STATUS_VERIFYCODE_REQUEST = 9; // 请输入验证码
2
3
4
5
6
7
8
9
10
11
12
TyrParse
解析JSON的函数。
function TyrParse(const AJSON: string; out Value: TRtcRecord): Boolean;
begin
Result := True;
try
Value := TRtcRecord.FromJSON(AJSON);
except
Result := False;
end;
end;
2
3
4
5
6
7
8
9
CheckJSON
检验JSON。
function TMyHandler.CheckJSON(var AJsonObject: TRtcRecord; AJSON: string): Boolean;
begin
Result := TyrParse(AJSON, AJsonObject);
if not Result then
FThis.pgcDataSet.ActivePageIndex := 1;
// AJsonObject.asDateTime['datetime']:=Now;
// InfoDlg(AJsonObject.toJSON);
end;
2
3
4
5
6
7
8
9
GetTimestamp
获取时间格式的函数。
function GetTimestamp: string;
begin
Result := FormatDateTime('yyyy-MM-dd HH:mm:ss', Now);
end;
2
3
4
Log
记录日志的过程。
procedure TMyHandler.Log(const S: string);
begin
FThis.mmoJSON.Lines.Add(DateTimeToStr(Now) + ':' + S);
end;
2
3
4
MakeSign
用于生成签名的函数。
function MakeSign(const AParams: TStringList; const AppSecret: string): string;
var
I: Integer;
Data, SignMethod: string;
begin
SignMethod := AParams.Values['sign_method'];
// 参数排序
AParams.Sort;
// 参数拼接
Data := '';
for I := 0 to AParams.Count - 1 do
Data := Data + AParams[I].Replace('=', '');
// MD5 算法
if SignMethod = 'md5' then
Result := paxfunc.GetStringMD5(AppSecret + Data + AppSecret).ToUpper
else
Result := paxfunc.GetHMAC(Data, AppSecret).ToUpper;
end;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Login
登录的过程。
procedure TMyHandler.Login(const ChangeVerifyCode: Boolean);
var
Response, URL: string;
Params: TStringList;
JsonObj: TRtcRecord;
begin
URL := Format('http://%s:%s/rest/user/login', [FThis.edtHost.Text, FThis.edtPort.Text]);
Params := TStringList.Create;
try
Params.Values['user_name'] := FThis.edtUserName.Text;
Params.Values['password'] := paxfunc.GetStringMD5(FThis.edtPassword.Text);
Params.Values['db_name'] := FThis.edtConnectionDefName.Text;
Params.Values['version'] := '2.0';
URL := URL + '?user_name=' + FThis.edtUserName.Text
+ #38 + 'password=' + paxfunc.GetStringMD5(FThis.edtPassword.Text)
+ #38 + 'db_name=' + FThis.edtConnectionDefName.Text
+ #38 + 'version=' + '2.0';
if not ChangeVerifyCode then
begin
if not (FImageBase64Data = '') then
begin
Params.Values['verify_code'] := FThis.edtVerifyCode.Text;
URL := URL + '=' + FThis.edtVerifyCode.Text;
end;
end;
Response := paxfunc.NetHttpGet(URL,'');
//Log(URL+ Params.Text);
finally
FreeAndNil(Params);
end;
if not CheckJSON(JsonObj, Response) then
Log('接收的数据有误,不是合法的 JSON')
else
begin
Log('用户登录回复:' + JsonObj.toJSON);
if JsonObj.asInteger['status'] = STATUS_OK then
begin
FAccessToken := JsonObj.asText['token'];
FAppSecret := JsonObj.asText['app_secret'];
FThis.edtVerifyCode.Hide;
FThis.imgVerifyCode.Hide;
FImageBase64Data := '';
FThis.edtToken.Text:= FAccessToken;
end
else if JsonObj.asInteger['status'] = STATUS_VERIFYCODE_REQUEST then
begin
FThis.edtVerifyCode.Show;
FThis.imgVerifyCode.Show;
FImageBase64Data := JsonObj.asText['verify_code'];
paxfunc.LoadVerifycode(FImageBase64Data,FThis.imgVerifyCode);
end
else
begin
Log(JsonObj.asText['message']);
FAccessToken := '';
end;
FreeAndNil(JsonObj);
end;
FThis.pgcDataSet.ActivePageIndex := 1;
end;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# 3.2. 事件设置
- ①btnLogin-OnClick事件
点击登录
标签页中的[登录]
按钮,执行登录操作。
procedure TMyHandler.btnLoginClick;
begin
Login(false);
end;
2
3
4
- btnQuery-OnClick事件
点击查询数据
标签页中的[查询]
按钮,执行查询操作。
procedure TMyHandler.btnQueryClick;
var
Response: string;
URL: string;
Params: TStringList;
JsonObj: TRtcRecord;
S: string;
begin
//if not CheckLogin then
// Exit;
//检查 JSON 语法是否正确。
if not CheckJSON(JsonObj, FThis.mmoOpenSQL.Lines.text) then
begin
Log('JSON 语法有误。');
Exit;
end;
FHaveDataSet := True;
//FStopWatch := TStopwatch.StartNew;
URL := Format('http://%s:%s/rest/db/opensql', [FThis.edtHost.Text, FThis.edtPort.Text]);
Params := TStringList.Create;
try
Params.Values['token'] := FThis.edtToken.Text;// FAccessToken;
Params.Values['data'] := JsonObj.toJSON;
URL := URL + '?token=' + FThis.edtToken.Text // FAccessToken;
+ #38+ 'data=' + JsonObj.toJSON;
if FThis.chkNeedSign.Checked then // 验证签名
begin
Params.Values['sign_method'] := 'md5'; // hmac,md5
Params.Values['timestamp'] := GetTimestamp;
Params.Values['version'] := '2.0';
URL := URL + #38 + 'sign_method=' + 'md5' // hmac,md5
+ #38 + 'timestamp=' + Params.Values['timestamp']
+ #38 + 'version=' + '2.0'
+ #38 + 'sign=' + MakeSign(Params, FAppSecret);
end;
// 异步模式提交参数
//AsyncHTTPClient.Post(URL, Params);
Response := paxfunc.NetHttpGet(URL,'');
if not CheckJSON(JsonObj, Response) then
begin
Log('接收的数据有误,不是合法的 JSON');
Exit;
end;
if JsonObj.asInteger['status'] = STATUS_OK then
begin
// 将 JSON 转为 DataSet
if FHaveDataSet then
begin
DM.JsonObjToDataSet(FThis.RFDataSet1,JsonObj);
Log('获取到:'+IntToStr(FThis.RFDataSet1.RecordCount)+'条记录.');
end
else
Log(JsonObj.toJSON);
end
else
Log('服务端回复:' + JsonObj.asText['message']);
finally
FreeAndNil(Params);
FreeAndNil(JsonObj);
end;
end;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
- btnExecSQL-OnClick事件
点击更新数据
标签页中的[执行]
按钮,执行SQL。
procedure TMyHandler.btnExecSQLClick;
var
URL, Response: string;
Params: TStringList;
JsonObj: TRtcRecord;
begin
//if not CheckLogin then
// Exit;
// 检查 JSON 语法是否正确。
if not CheckJSON(JsonObj, FThis.mmoExecSQL.Lines.Text) then
begin
Log('JSON 语法有误。');
Exit;
end;
FHaveDataSet := False;
URL := Format('http://%s:%s/rest/db/execsql', [FThis.edtHost.Text, FThis.edtPort.Text]);
Params := TStringList.Create;
try
Params.Values['token'] := FAccessToken;
Params.Values['data'] := JsonObj.toJSON;
URL := URL + '?token=' + FThis.edtToken.Text // FAccessToken;
+ #38 + 'data=' + JsonObj.toJSON;
if FThis.chkNeedSign.Checked then
begin
Params.Values['sign_method'] := 'md5'; // hmac,md5
Params.Values['timestamp'] := GetTimestamp;
Params.Values['version'] := '2.0';
URL := URL + #38 + 'sign_method=' + 'md5' // hmac,md5
+ #38 + 'timestamp=' + Params.Values['timestamp']
+ #38 + 'version=' + '2.0'
+ #38 + 'sign=' + MakeSign(Params, FAppSecret);
end;
//Response := HttpClient.Post(URL, Params).ContentAsString;
Response := paxfunc.NetHttpGet(URL,'');
finally
FreeAndNil(Params);
FreeAndNil(JsonObj);
end;
if not CheckJSON(JsonObj, Response) then
Log('接收的数据有误,不是合法的 JSON')
else
begin
try
Log(JsonObj.toJSON);
if JsonObj.asInteger['status'] <> STATUS_OK then
Log('服务端回复:' + JsonObj.asText['message']);
finally
FreeAndNil(JsonObj);
end;
end;
FThis.pgcDataSet.ActivePageIndex := 1;
end;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
- btnStoreProc-OnClick事件
点击存储过程
标签页中的[执行]
按钮,执行存储过程。
procedure TMyHandler.btnStoreProcClick;
var
URL,Response: string;
Params: TStringList;
JsonObj: TRtcRecord;
begin
//if not CheckLogin then
// Exit;
// 检查 JSON 语法是否正确。
if not CheckJSON(JsonObj, FThis.mmoStoredProc.Lines.Text) then
begin
Log('JSON 语法有误。');
Exit;
end;
FHaveDataSet := JsonObj.asText['method'] = 'open_proc';
URL := Format('http://%s:%s/rest/db/storedproc', [FThis.edtHost.Text, FThis.edtPort.Text]);
Params := TStringList.Create;
try
Params.Values['token'] := FAccessToken;
Params.Values['data'] := JsonObj.toJSON;
URL := URL + '?token=' + FThis.edtToken.Text // FAccessToken;
+ #38 + 'data=' + JsonObj.toJSON;
if FThis.chkNeedSign.Checked then
begin
Params.Values['sign_method'] := 'md5'; // hmac,md5
Params.Values['timestamp'] := GetTimestamp;
Params.Values['version'] := '2.0';
URL := URL + #38 + 'sign_method=' + 'md5' // hmac,md5
+ #38 + 'timestamp=' + Params.Values['timestamp']
+ #38 + 'version=' + '2.0'
+ #38 + 'sign=' + MakeSign(Params, FAppSecret);
end;
// 异步提交请求
//AsyncHTTPClient.Post(URL, Params);
Response := paxfunc.NetHttpGet(URL,'');
showmessage(Response);
finally
FreeAndNil(Params);
FreeAndNil(JsonObj);
end;
end;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
- Button1-OnClick事件
设置使用自定义参数执行SQL。点击更新数据
标签页中的[执行2]
按钮以执行操作。
procedure TMyHandler.Button1Click;
var
URL, Response: string;
Params: TStringList;
JsonObj: TRtcRecord;
jsonStr:String;
begin
//if not CheckLogin then
// Exit;
FHaveDataSet := False;
URL := Format('http://%s:%s/rest/db/execsql', [FThis.edtHost.Text, FThis.edtPort.Text]);
jsonStr := '{'+#13#10
+' "db_name": "FastERP",'+#13#10
+' "sql": "UPDATE Table_Test SET phone=:phone WHERE id=:id",'+#13#10
+' "params": ['+#13#10
+' {'+#13#10
+' "name": "phone",'+#13#10
+' "value": "1888888888" '+#13#10
+' },'+#13#10
+' {'+#13#10
+' "name": "id",'+#13#10
+' "value": "7FA504F4-F331-4200-9B37-00BA77F8CAB9" '+#13#10
+' }'+#13#10
+' ]'+#13#10
+'}';
FThis.mmoExecSQL.Lines.Text:= jsonStr;
Params := TStringList.Create;
try
Params.Values['token'] := FAccessToken;
Params.Values['data'] := jsonStr;
URL := URL + '?token=' + FThis.edtToken.Text // FAccessToken;
+ #38 + 'data=' + jsonStr;
if FThis.chkNeedSign.Checked then
begin
Params.Values['sign_method'] := 'md5'; // hmac,md5
Params.Values['timestamp'] := GetTimestamp;
Params.Values['version'] := '2.0';
URL := URL + #38 + 'sign_method=' + 'md5' // hmac,md5
+ #38 + 'timestamp=' + Params.Values['timestamp']
+ #38 + 'version=' + '2.0'
+ #38 + 'sign=' + MakeSign(Params, FAppSecret);
end;
//Response := HttpClient.Post(URL, Params).ContentAsString;
Response := paxfunc.NetHttpGet(URL,'');
finally
FreeAndNil(Params);
end;
if not CheckJSON(JsonObj, Response) then
Log('接收的数据有误,不是合法的 JSON')
else
begin
try
Log(JsonObj.toJSON);
if JsonObj.asInteger['status'] <> STATUS_OK then
Log('服务端回复:' + JsonObj.asText['message']);
finally
FreeAndNil(JsonObj);
end;
end;
FThis.pgcDataSet.ActivePageIndex := 1;
end;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
- Button2-OnClick事件
点击更新数据
标签页中的[批量插入]
按钮以执行操作。
procedure TMyHandler.Button2Click;
var
URL, Response: string;
Params: TStringList;
JsonObj: TRtcRecord;
begin
//if not CheckLogin then
// Exit;
// 检查 JSON 语法是否正确。
if not CheckJSON(JsonObj, FThis.mmoExecSQL.Lines.Text) then
begin
Log('JSON 语法有误。');
Exit;
end;
FHaveDataSet := False;
URL := Format('http://%s:%s/rest/db/batch_insert', [FThis.edtHost.Text, FThis.edtPort.Text]);
Params := TStringList.Create;
try
Params.Values['token'] := FAccessToken;
Params.Values['data'] := JsonObj.toJSON;
URL := URL + '?token=' + FThis.edtToken.Text // FAccessToken;
+ #38 + 'data=' + JsonObj.toJSON;
if FThis.chkNeedSign.Checked then
begin
Params.Values['sign_method'] := 'md5'; // hmac,md5
Params.Values['timestamp'] := GetTimestamp;
Params.Values['version'] := '2.0';
URL := URL + #38 + 'sign_method=' + 'md5' // hmac,md5
+ #38 + 'timestamp=' + Params.Values['timestamp']
+ #38 + 'version=' + '2.0'
+ #38 + 'sign=' + MakeSign(Params, FAppSecret);
end;
//Response := HttpClient.Post(URL, Params).ContentAsString;
Response := paxfunc.NetHttpGet(URL,'');
finally
FreeAndNil(Params);
FreeAndNil(JsonObj);
end;
if not CheckJSON(JsonObj, Response) then
Log('接收的数据有误,不是合法的 JSON')
else
begin
try
Log(JsonObj.toJSON);
if JsonObj.asInteger['status'] <> STATUS_OK then
Log('服务端回复:' + JsonObj.asText['message']);
finally
FreeAndNil(JsonObj);
end;
end;
FThis.pgcDataSet.ActivePageIndex := 1;
end;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
- (17)btnLogout-OnClick事件
点击登录
标签页中的[注销]
按钮,注销登录。
procedure TMyHandler.btnLogoutClick;
var
JsonObj: TRtcRecord;
URL, Response: string;
begin
//if not CheckLogin then
// Exit;
URL := Format('http://%s:%s/rest/user/logout?token=%s', [FThis.edtHost.Text, FThis.edtPort.Text, FAccessToken]);
Log(URL);
//Response := HttpClient.Get(URL).ContentAsString;
Response := paxfunc.NetHttpGet(URL,'');
if not CheckJSON(JsonObj, Response) then
Log('接收的数据有误,不是合法的 JSON')
else
Log('服务端回复:' + JsonObj.asText['message']);
end;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
- (11)imgVerifyCode-OnClick事件
点击验证码图片切换验证码。
procedure TMyHandler.imgVerifyCodeClick;
begin
Login(True);
end;
2
3
4
# 4. 运行结果
使用鼠标点击工具栏运行(Run),测试运行结果。
通过工具栏保存,将程序保存为 sdb 项目文件。
在登录框中输入TARS所在的服务器地址,确认用户名与密码,点击[登录]
按钮获取Token,可执行接下来的页面中显示的查询,插入以及执行存储过程等方法。