TSS API

编码及通讯协议

文档中所有的数据交互涉及编码统一使用 UTF-8,url 里的所有参数值请做 urlencode 编码, 响应类型为 application/json;charset=UTF-8。接口通讯协议支持 HTTP 和 HTTPS,请求方式支持 POST/GET,建议用 HTTPS 协议和 POST 方式发 送请求。

令牌及签名

根据不同的安全等级采用不同的接口访问权限校验机制:

  • TSS内,按登录用户的权限进行校验,借助cookie,无需传递其它参数
  • 安全等级 <= 6 (内部系统间调用), 采用uName + uToken 的方式进行校验;
  • 安全等级 = 7 (外部系统调用),采用uName + uSign + 时间戳 的方式进行校验,其中uSign = MD5(uToken + params + 时间戳);

签名示例

uToken: E5E0A2593A3AE4C038081D5F113CEC78
timestamp: 2019-03-31 21:39:34
Request Body: {"wh":"仓库1","aaa":"bbb","skuname":"货品X"}

字符串(uToken + body(以字段名按asc码表的顺序进行排序生成的字符串)+ timestamp)
排序后的body字符串:aaabbbskuname货品Xwh仓库1
签名前的字符串:E5E0A2593A3AE4C038081D5F113CEC78aaabbbskuname货品Xwh仓库12019-03-31 21:39:34
签名:MD5(E5E0A2593A3AE4C038081D5F113CEC78aaabbbskuname货品Xwh仓库12019-03-31 21:39:34) = A0653C36C426143156462D0B6FCAFD76

JS调用接口(系统内)

基于jQuery发起AJAX请求

jQuery.getJSON(url, params, function(data) {  });  //  GET请求
jQuery.post(url, params, function(result) {  });   //  POST请求 
jQuery.ajax({
        url : url,
        type : "GET|POST|DELETE",
        data : {}, 
        success: function(result) { }
});

基于tssJS发起AJAX请求

tssJS.ajax({
    url : url,
    method : "GET|POST|DELETE",
    params : { }, 
    ondata : function() {  }
});
tssJS.get(url, params, function(data) {  });
tssJS.post(url, params, function(result) {  });
tssJS.JSONP.getJSON(url, params, function(data) {  });

远程调用接口(JAVA、JSONP、微信小程序)

JAVA 远程调用,借助httpClient包

String url = "http://www.boubei.com/tss/data/json/5";
PostMethod postMethod = new PostMethod(url);
postMethod.setParameter("uName", "XXX");
postMethod.setParameter("timestamp ", "2018-12-22 09:18:11");          // 时间戳timestamp格式:yyyy-MM-dd hh:mi:ss
postMethod.setParameter("uSign ", "7fa59411844a5db3970b8ae81b3532cc"); // uSign 参考上面签名方式, 
postMethod.setParameter("paramX ", "...");

HttpClient httpClient = new HttpClient();
int statusCode = httpClient.executeMethod(postMethod);
if(statusCode == 200) {
    String result = postMethod.getResponseBodyAsString(); 
    ...... // 返回结果    
}

微信小程序访问TSS 接口(TSS可轻松为小程序提供后台服务)

  wx.request({
    url: "https://www.boubei.com/tss/data/json/5",
    method: "POST",
    header: { Cookie: wx.getStorageSync('cookie') },
    data: {"uName": "13588888888", "uToken": "XXXXXXXXXXXX", "param1": "2018-09-26"},
    success: res => { },
    fail: res => { },
    complete: res => { }
  })

JSONP远程调用报表数据服务接口,跨域调用 (只有数据服务支持,数据表接口等不支持JSONP调用)

tssJS.JSONP.getJSON(
    "http://www.boubei.com/tss/data/jsonp/5", 
    {'param1': 'hello jsonp!', "uName": "13588888888", "uSign": "7fa59411844a5db3970b8ae81b3532cc"}, 
    function(result) { console.log(result.length); }
);

取号器接口

1、请求地址:/tss/sn/{precode}/{count}
2、请求类型:POST | GET
3、请求参数:
参数名类型必填描述
{precode} String 取号器前缀,如:SO、XXyyMMddxxxx | XX-xxxx
{count} int 取号个数,一次可取1到100000个不等的号
4、返回结果: JSON of List< String >
5、示例
    jQuery.post('/tss/tss/SO-xxxx/1', function( sns ) { callback( sns ); } ); // 返回结果sns为数组

图形码生成接口

一、图形验证码生成接口

1、请求地址:/tss/img/api/ck/{code}
2、请求类型:GET
3、示例
    <img src="http://ebi.boubei.com/tss/img/api/ck/1234">

二、条形码生成接口

1、请求地址:/tss/img/api/bar/{code}?size=1.2
2、请求类型:GET
3、示例
    <img src="http://ebi.boubei.com/tss/img/api/bar/10249025592?size=1.2">

三、二维码生成接口

1、请求地址:/tss/img/api/qrbar/1?msg=xxxxxxxxx
2、请求类型:GET
3、示例
    <img src="http://ebi.boubei.com/tss/img/api/qrbar/1?msg=http://wx.boubei.com?id=2">

四、小程序码生成接口

1、请求地址:/tss/wx/api/acode2?appId=xxxxxxxxx
2、请求类型:GET | POST
3、示例
    <img src="https://ebi.boubei.com/tss/wx/api/acode2?appId=wx5255074da90a4dca&page=pages/homepage/index">

报表数据服务接口

1、请求地址:/tss/data/json/{report}
2、请求类型:POST | GET
3、请求参数:
参数名类型必填描述
{report} String 可以是 : reportId | reportCode | reportName
分页参数 数字 示例: {page:1, pagesize|rows:100}
查询条件参数 自定义 自定义 param1, param2, ..... paramN | paramCode
缓存策略参数 String noCache='true'(不缓存) | uCache='true'(按【用户 + 参数】缓存) | 默认按【参数 + 用户所在域】缓存
引用session值 String 自定义 用户登录后,用户相关的账号、组织、角色、域等信息存放在session中,如需引用,可以通过${key}方式去引用,比如:param2 = ${userGroup},更多可以引用的session值参考: Freemarker中可以使用的全局变量
4、返回结果: JSON of List< Map< String, Object > >
    如果请求里携带了分页参数rows或页码page,则返回分页查询结果 { "total": 1322, "rows": List< Map< String, Object > > }
5、示例
    var params = {"param1": "2017-06-01", "param2": "2017-06-30"};
    jQuery.getJSON('/tss/data/json/769', params, function(data) { console.log(data); } );
    
    注0:769为报表服务的ID,data 为报表的查询结果,数组格式
    注1:当请求参数里带有页码page参数时(即分页查询),返回结果为一个对象,格式如:{"total": 3242,  "rows": List< Map< String, Object > >}
    注2:要求用户先登录系统且用户对报表有浏览权限才能调用
6、调试SQL解析结果:http://localhost:9000/tss/data/json/xxx?debugSQL=true

报表导出Excel接口

1、请求地址:/tss/data/export/{reportId}/{page}/{pagesize}?param1=xxx& param2=xxx
2、请求类型:GET
3、请求参数:
参数名类型必填描述
自定义 自定义 自定义 各个报表服务自行定义参数
email String 导出数据后直接以电子邮件发送
4、返回结果: JSON of List< String >
5、示例: 具体实现参考 tools/tssJS/tssJS.data.js 里的 data2CSV、exportCSV
http://www.boudata.com/tss/data/export/42/1/10000?paramX=XXX&email=boubei@163.com

将前台Grid数据导出成Excel格式

1、请求地址:/tss/data/export/data2csv

数据表定义

1、请求地址:/tss/xdata/define/{record}
2、请求类型:GET

数据表查询接口

1、请求地址:/tss/xdata/json/{record}
2、请求类型:POST | GET
3、请求参数:
参数名类型必填描述
{record} String record可以是:数据表的ID | Name | Table
查询参数 自定义 自定义 数据表定义的所有字段,以及创建人、创建时间、修改人、修改时间,支持按区间查询(适合日期时间、数字类字段,格式:[fromVal, toVal])和 in查询(多个条件有英文逗号分隔)
非空查询 null 支持查询null或not null的记录,参数示例 'f1': 'is null', 'f2': 'is not null'
精确查询
strictQuery
布尔 查询参数及匹配方式:strictQuery="true" 精确查询,否则为模糊查询;系统默认 strictQuery="false"
如需某个字段始终要精确查询(比如一些状态类字段:正常、不正常),可以在字段定义里加属性,'strictQuery': 'true'
分页参数 数字 示例: {page:1, pagesize|rows:100}, 默认pagesize = 1000
fields String 指定字段,查询结果只返回指定的字段,格式如:f1 as code, f2 as name 。导出数据表时也可以通过fields来完成数据表头自定义。
注:系统会对fields进行防SQL注入检查,如果fields比较复杂,比如带子查询等,可以把fields定义在自定义SQL里(避开SQL注入检查),自定义SQL编码命名为"macro_"打头,使用时传递 fields = macro_xxx
groupby String 汇总维度字段
sortField String 对结果集按此字段进行排序,多个字段排序用逗号, 例如:money desc, day asc
sortType String desc | asc| onlynull | notnull,分别对应降序、升序、只取空值、只取非空
引用session值 String 自定义 用户登录后,用户相关的账号、组织、角色、域等信息存放在session中,如需引用,可以通过${key}方式去引用,比如:org = ${userGroup},更多可以引用的session值参考: Freemarker中可以使用的全局变量
4、返回结果: JSON of List< Map< String, Object > >, 如fields参数为空,返回所有字段值,包括创建人/时间等信息
    如果请求里携带了分页参数rows,则返回分页查询结果 { "total": 1322, "rows": List< Map< String, Object > > }
5、示例:
var params = {"code": "XX", "createtime": "[2017-06-01, 2017-06-30]"};
jQuery.getJSON('/tss/xdata/json/769',  params,  function(data) {  console.log(data); } );  // 769为数据表的ID

注1:查询数据按用户所拥有的权限进行过滤,如只有录入权限的用户,只能查询自己录入的数据;拥有浏览权限的用户可以查询所有数据。  
    所有参数值不得含有SQL关键字,后台会进行防SQL注入检查。 fields可以是个子查询,通过 macro_xxx 调用SQLDef里的定义脚本。
6、权限控制:此接口按调用者被授予的角色、所属的组织结构等严格过滤数据.
  • 拥有"录入数据"权限的,只能查询自己录入的数据
  • 拥有"浏览数据"和"维护数据"权限的,可以查询其它人的录入数据
  • 审批表提交模式下,只能查询本人提交的流程记录; 如果其指定了其它"创建人"作为查询条件,将什么都查不到
  • 审批表审批模式下,只能查询本人审批或待审批的流程记录;
7、调试数据表查询SQL解析结果:http://localhost:9000/tss/xdata/json/xxx?debugSQL=true

数据表按ID读取单行数据

1、请求地址:/tss/xdata/{record}/{id}
2、请求类型:GET
3、请求参数:
参数名类型必填描述
{record} String record可以是:数据表的ID | Name | Table
id int 记录ID值
4、返回结果: JSON of Map< String, Object >
5、示例:
jQuery.getJSON('/tss/xdata/769/12', {}, function(data) {  console.log(data); } );  // 12为数据行的ID
6、权限控制:查询用户需要对此记录有编辑或浏览权限,否则看不到该记录,系统将报"权限不足"的异常。

数据表新增一行数据

1、请求地址:/tss/xdata/{record}
2、请求类型:POST
3、请求参数:
参数名类型必填描述
{record} String record可以是:数据表的ID | Name | Table
字段 数据表定义 数据表里定义的字段,key:value
_after_ String 可定义新增后续操作, eg: _after_ = '[{ \"sqlCode\": \"s24\", \"data\": {} }]', 其中s24在数据表【SQL自定义表】里定义,更多参考MultiSQLExcutor
4、返回结果: {"result": newID}
5、示例:
var params = {‘code’: ‘A1’, ‘name’: ‘Jack’, ……}; 
jQuery.post('/tss/xdata/769',  params,  function(info) {  callback(info.result); } ); 
6、权限控制:用户需要对当前录入表有录入权限,否则系统将报"权限不足"的异常。

数据表修改一行数据

1、请求地址:/tss/xdata/{record}/{id}
2、请求类型:POST
3、请求参数:
参数名类型必填描述
{record} String record可以是:数据表的ID | Name | Table
id int 记录ID值
字段 数据表定义 数据表定义的字段(一个以上,creator、updator、version等除外),参数里包含的字段将被修改,没有包含的不做修改。
_after_ String 可定义修改后续操作, eg: _after_ = '[{ \"sqlCode\": \"s24\", \"data\": {} }]', 其中s24在数据表【SQL自定义表】里定义,更多参考MultiSQLExcutor
4、返回结果: {"result": "修改成功"},失败时返回{"errorMSg": 失败原因}
5、示例:
jQuery.post('/tss/xdata/769/12',  params,  function(info) {  console.log(info.result) } ); 
6、权限控制:用户需要对当前录入表有维护权限或当前记录的创建人,否则系统将报"权限不足"的异常。

数据表删除一行数据

1、请求地址:/tss/xdata/{record}/{id}
2、请求类型:DELETE
3、请求参数:
参数名类型必填描述
{record} String record可以是:数据表的ID | Name | Table
id int 记录ID值
4、返回结果: {"result": "删除成功"},失败时返回{"errorMSg": 失败原因}
5、示例:
jQuery.ajax({
        url : '/tss/xdata/769/12',
        type : "DELETE",
        success: function(result) { }
});

支持逻辑删除,可以在以下两个地方配置:
    1、系统参数 LOGIC_DEL=true   则对本站所有录入表都生效,全部执行逻辑删除;
    2、录入表备注 LOGIC_DEL:=true 此录入表只执行逻辑删除;

另外还提供了数据表批量删除接口:
DELETE  /tss/xdata/batch/{record}  参数 {"ids": "1,2,3,4,5"}, 根据参数ids(逗号分隔)批量删除数据
6、权限控制:用户需要对被删除记录有删除权限(通常能编辑即能删除),否则系统将报"权限不足"的异常。

数据表查询结果导出Excel

1、请求地址:/tss/xdata/export/{record}
2、请求类型:POST | GET
3、请求参数:同数据表查询接口的参数,参考数据表查询接口;可以通过 fields 参数来定制导出格式。
4、返回结果: {"result": "删除成功"},失败时返回{"errorMSg": 失败原因}
5、示例:
var url = encodeURI("/tss/xdata/export/769?" + queryString);
tssJS("#downloadFrame").attr( "src", url);  // 通过设置导出地址到一个隐藏的iframe,来执行导出

数据表批量增删改

POST  /tss/xdata/batch/{record}   批量更新选中记录行的某个字段值(一次只能更新一个字段),用在批量审批等场景 
示例: $.post("/tss/xdata/batch/13", {'ids':'1,2,3,4', 'field': 'brand', 'value': '农夫'} , function(data) {});

POST /tss/xdata/cud/json/{record}  JSON批量保存数据表的记录集,新增、修改、删除All in one (注:此方法没有强事务一致性,值支持换行)
示例: tssJS.post("/tss/xdata/cud/json/{recordId}", {"json": "[{...}, {...}, ...]"},  function(result) { } );

POST /tss/xdata/cud/{record}        CSV批量保存数据表的记录集,新增、修改、删除All in one (注:此方法没有强事务一致性,值不支持换行)
示例: tssJS.post("/tss/xdata/cud/{recordId}", {"csv": "......"},  function(result) { } );   
参数: csv(逗号分隔,每一行的逗号个数应严格一致),如下:
    id,f1,f2,f3
    ,30.1,test3,2017-05-03     // 无ID,新增
    1,11.1,test-u,2016-05-01   // 有ID,修改
    2,,,                       // 只有ID,删除
权限控制:需要操作者有相应的权限,每一行都会严格进行权限检测。

数据表定义读取

1、请求地址:/tss/xdata/define/{record}
2、请求类型:GET
3、返回结果: 数据表的详细定义

数据表自定义接口

除了针对数据表单行操作以外,如果希望一次操作多张表的多条数据记录,可以用自定义接口来实现。

1、请求地址:/tss/api/dml/multi
2、请求类型:POST
3、请求参数:数据源,自定义SQL集
4、返回结果: {"result": "Success", 每一条SQL的执行结果}
5、示例(一次性完成insert、select、update、delete四个SQL,满足事务一致性):
1、在SQL自定义表(SQLDef,dm_sql_def)里定义以下四个SQL语句:
  s1: insert into tbl_jx(name,score,day,createtime,creator,version) values ('${name}', ${score}, '${day}', '${day}', 'Admin', 0)
  s2: select IFNULL(max(id), 1) as maxid from tbl_jx
  s3: update tbl_jx t set t.score = ${score} where t.id = ${maxid}
  s4: delete from tbl_jx  where id = ${maxid} - 1
  
2、在页面通过AJAX发起以下请求:
  var json = [];
  json.push({ "sqlCode": "s1", data: {"name": "JK", "score": 59, "day": "2017-01-01"} });
  json.push({ "sqlCode": "s1", data: {"name": "Jon", "score": 58, "day": "2017-01-02"} });
  json.push({ "sqlCode": "s2", data: {} });
  json.push({ "sqlCode": "s3", data: {"score": 100} });
  json.push({ "sqlCode": "s4", data: {} });
  
  var params = {};
  params.ds = "connectionpool";
  params.json = JSON.stringify(json);
  tssJS.post("/tss/api/dml/multi", params, function(result) { console.log(result); } );
  
  返回结果: {result: "Success", maxid: 2, step1: 1, step2: 1, step4: 1, step5: 0}

数据表附件列表获取、附件下载、附件删除接口

POST    /tss/auth/file/upload?afterUploadClass=com.boubei.tss.dm.record.file.CreateAttach&recordId={record}&itemId=xxx  上传附件
POST    /tss/remote/upload?afterUploadClass=com.boubei.tss.dm.record.file.CreateAttach&recordId={record}&itemId=xxx  小程序等上传
GET     /tss/xdata/attach/json/{record}/{itemId}  数据表某行数据附件清单
GET     /tss/xdata/attach/download/{id}           下载指定附件
DELETE  /tss/xdata/attach/{id}                    删除指定附件的记录
注1:操作附件前提是操作人对附件所属的数据表数据记录有相应的浏览或编辑权限。

更详细的附件操作参考:modules/dm/recorder_upload.html,任何数据表自定义页面都可以集成附件上传功能。需要引入下面资源文件,及一段脚本
< link rel="stylesheet" href="../tools/tssJS/css/reset.css">
< link rel="stylesheet" href="../tools/tssJS/css/tool.css">
< link rel="stylesheet" href="../tools/tssJS/css/message.css">
< script src="../tools/tssJS/tssJS.all.js">

var tableId = -101;
var globalValiable = {"tableId": tableId}
function uploadX(itemId) {
    globalValiable.itemId = itemId;
    var title = "上传员工的证件照";
    tssJS.openIframePanel("if1", title, 710, 255, "../modules/dm/recorder_upload.html", true);
}
权限控制:读取或删除附件记录需要操作者对附件所属的数据记录有查询或维护权限。

参数配置(Param)接口

GET  /tss/param/json/simple/{code}         [parma.value]
GET  /tss/param/json/combo/{code}          List<[param.id, param.text, param.value]>
GET  /tss/param/json/combo/{code}?KV=true  List<{"text": param.text, "value": param.value}>
GET  /tss/param/json/tree/{code}           List<[param.id, param.parentId, param.text, param.value]>

function getParam(key, callback) {
  tssJS.getJSON("/tss/param/json/simple/" + key, 
    function(val) {
        callback && val && callback(val);
    },  'GET');
}

用户信息接口

GET /tss/auth/service/roles  --> List< [role.id, role.name] > 获取当前用户有查看权限的角色,用于前台生成角色下拉列表
GET /tss/auth/service/rusers/{roleId}  --> List< User > 获取拥有指定角色的用户列表
GET /tss/auth/service/gusers/{groupId} --> List< User > 获取指定用户组下的用户列表

GET /tss/auth/user/userHas  用户个人、组织、角色信息, 返回一个如下数组
    userHas[0] = List< [groupId, groupName] >  用户所处的组织信息,数组格式,从高到低
    userHas[1] = List< roleId >  用户拥有的角色ID列表,数组格式
    userHas[2] = userId;  用户ID
    userHas[3] = Environment.getUserCode();  -- 用户账号
    userHas[4] = Environment.getUserName();  -- 用户姓名
    userHas[5] = List< groupId >;   用户所属辅助组ID列表,数组格式
    userHas[6] = Environment.isFirstTimeLogon();
    userHas[11] = List< String>  用户拥有的角色名称列表,数组格式
    userHas[12] = Domain  用户所属域

POST /tss/auth/message         参数:title, content, receiverIds,发送站内消息
POST /tss/auth/message/email   参数:title, content, receivers,发送普通文本邮件
POST /tss/auth/message/email2  参数:title, content, receivers,发送HTML格式邮件
    其中参数receivers,支持 email/登陆账号/角色(可指定域xx@role@domain)/用户组/辅助组,如:lovejava@163.com,BD0001,12@tssRole@domain,2@tssGroup
    function email(receivers, title, content) {
      $.post("/tss/auth/message/email2",  {"receivers": receivers, "title": title, "content": content});
    }
    function sendMessage(receivers, title, content) {
      $. post ("/tss/auth/message",  {"receivers": receivers, "title": title, "content": content});
    }

栏目文章接口

供Ajax调用(来自ArticleAction):
GET   /tss/auth/article/list/xml/{channelId}/{page}/{pageSize}/{needPic}   获取文章(包含附件)列表
GET   /tss/auth/article/channels/{channelIds}/{page}/{pageSize}            根据栏目ids,获取这些栏目下的所有文章列表
GET   /tss/auth/article/channelDeeply/{channelId}/{page}/{pageSize}        取指定栏目以及其所有子栏目的所有文章列表
GET   /tss/auth/article/journal/{channelId}/{year}/{month}                 根据栏目和日期来获取文章列表,用于期刊类需求
GET   /tss/auth/article/channelTree/{channelId}                            获取栏目树,用以显示"当前位置"等地方
GET   /tss/auth/article/xml/{articleId}                                    获得已发布文章生成的xml信息 
POST  /tss/auth/article/import/{channelId}  参数:articleXml                第三方文章数据导入
POST  /tss/auth/article/search              参数:searchStr                 全文检索
POST  /tss/auth/article/{articleId}/comment  参数:comment  新增一条评论
GET   /tss/auth/article/{articleId}/comment             查看文章评论列表
DELETE  /tss/auth/article/{articleId}/comment/{index}  删除一条评论
GET   /tss/download?id=文章ID&seqNo=附件序号   文件附件查看下载

菜单(Menu)清单接口

GET /tss/auth/navigator/json/{id}   List< MenuDTO >
GET /tss/auth/navigator/xml/{id}

动态Portlet使用
Portal支持通过Freemarker模板引擎和AJAX两种形式访问栏目内容等接口服务。
一、  动态portlet和 ajax portlet 的区别
➢ Ajax portlet是生成网页发送到客户端后,再由客户端发送AJAX请求后台接口服务获具体数据,然后解析显示。不支持网页静态发布。
➢ 动态portlet是通过Freemarker引擎解析portlet中的宏代码,直接调用java方法获取相应数据,再生成网页。支持网页静态发布。

二、参考 classes/freemarker/common.ftl
< #macro showMenu menuId>
  < #assign data = menuService.getMenuXML(menuId) />
  < #assign doc  = manager.translateValue(data) />
  < #assign menu = doc.Menu />
  < TABLE height=33 width="90%" align=center>< TBODY>< TR> 
  < #list menu.MenuItem as item>
    < TD class=mainTd id=td_${item.@id}>
     < SPAN class=menuSpan id=manegeMenu_${item.@id}>
      < a href='${item.@url}'>${item.@name}< /a>
     < /SPAN>
    < /TD> 
  < /#list>
  < /TR>< /TBODY>< /TABLE>
< /#macro>
创建一个portlet:
< div id=${id} > < @common.showMenu menuId=26 < /div>

注:引用common.ftl中定义的任何变量或者方法都需要加上前缀common,如:common.showMenu。
Request Parameters取到的都是String型,所以自定义的 macro 方法参数最好都为String