TXWeb--ROC RPC 调用协议说明
一.ROC协议说明
- 协议主要参照JSON-RPC 2.0,兼容resetFull API 方式,默认为传统页面开发模式。
- 通过协议头部信息确定返回数据和格式支持类型,同时本地还可以使用传统方式搭建页面。
- 传输主要是json格式,可以传输xml。
- 为了区分其他协议,这里就叫ROC协议,远程对象调用协议。
- 传输协议支持标准roc协议也可以是简化传输,简化同spring一样。
二.协议头
非加密方式:
headers: {'X-Requested-With': 'jspx.net-roc'}
加密方式, 存在密码这些才用:
headers: {'X-Requested-With': 'jspx.net-secret-roc'}
配置文件 apiSuffix=jwc
如果是用jwc请求,不需要写头协议,默认为roc非加密方式
三.URL地址说明
因为地址可以使用正规表达式,所以会出现如下的格式,表示可以多个地址都调用这个方法
例1: /jcms/aematter|aelink|aevote
表示如下地址都可以调用,效果一样
/jcms/aematter
/jcms/aelink
/jcms/aevote
例2 :/jcms/verify\w+
正规表达式verify\w+ 表示后边匹配字符串
/jcms/verify\w+
/jcms/(verify+字符串) 都能访问到
四.参数请求格式说明
注意:"protocol": "jspx.net-roc", 协议说明 有这个标识是用完整格式传输,没有标识简化传输
推荐使用:参数也可以使用对象传输,
{
"version": "3.0", //版本,不是必须
"protocol": "jspx.net-roc", //协议说明
"format": "json", //返回的格式要求,可以是xml,默认位json
"method": {
"name": "调用的方法", //调用的方法名称
"params": {'参数名称1':'参数值1','参数名称2':'参数值2',...} //方法参数
}
},
"params": { //类对象参数就是类的set方法,文档中叫全局参数
"参数1": 1,
"参数2": 2
}
}
- 注意:参数params在method叫内部参数,在外部叫全局参数, 全局参数只是为了兼容传统接口,推荐API接口,都使用内部参数方式.
简化调用说明,protocol为空的时候标识使用简化调用,可以不写method,不写params,直接传递参数,和spring方式一样,
场景说明,简化方式适用新接口,url和调用方法有唯一映射关系,系统自动填充全局或内部变量,内部变量优先
{'参数名称1':'参数值1','参数名称2':'参数值2',...}
五.返回参数说明
httpStatus头信息说明:
头信息 |
描述 |
200 | 正常执行 |
401 | token失效,需要登录 |
403 | 没有权限操作 |
403 | 服务器拒绝请求 |
404 | 无文件,无页面,无接口 |
405 | 不允许,特权资源 |
500 | 服务器异常 |
401 重新登录
{
"code": -32602,
"success": 0,
"message": "需要登录"
}
六.常用参数说明
- sort :参数用法 field:A 表示field字段正序 field:D 倒序
- count :行数,翻页使用
- currentPage :页数,翻页使用
- term :ssql查询条件
例1: field1:like['abc%'];field2:eq['abc'] ,相当于SQL的, field1 like 'abc%' AND field2='abc'
例2: images:is[H] 表示images字段必须有数据
ssql |
SQL |
bt | between |
eq | = |
le | < |
gt | > |
ne | <> |
in | in |
like | like |
N | Null |
H | NotNull |
七.返回字段显示控制
请求中加入dataField,下边例子标识两成对象显示 data为第一层,后边为user为第二层
{
"dataField" {
"data":["company","name","addresss","user"],
"user":["name","sex"]
}
}
八.注意事项
调用方法名和url文件名相同时,不用参数,url直接ROC调用,必须有协议头,
无协议头的调用方式,将被认为是传统的页面调用方式,会提示找不到文件。
否则是用api调用后缀,默认jwc,可以在配置文件中自己配置后缀,推荐方式
九.特别说明
文档是自动生成,属于jspx.net架构的功能一部分
写代码就是写文档,代码完成文档也就完成。
如果你不想暴露文档,可以屏蔽TXWeb里边的文档入口配置,或者设置权限拦截后,可以配置指定的角色访问。
返回错误信息,同jspn-rpc 2.0 一样。
{"jspx.net-roc": "2.0", "error": {"code": -32601, "message": "Method not found."}, id: "5"}
ode代码 |
message消息 |
Meaning意义 |
-32700 -32700 | Parse error.解析错误。 | Invalid JSON.无效的JSON。错误发生在服务器在解析JSON文本。 |
-32600 -32600 | Invalid Request.无效的请求。 | 接收的JSON是不是有效的JSON-RPC请求。 |
-32601 -32601 | Method not found.找不到方法。 | 所要求的远程过程不存在/不可用。 |
-32602 -32602 | Invalid params.参数无效。 | 无效的方法参数。 |
-32603 -32603 | Internal error.内部错误。 | 内部的JSON-RPC错误。 |
-32099..-32000 | Server error.服务器错误。 | 实施保留定义的服务器错误。 |
批量请求:不支持
前端模板例子
一边用Handlebars做个例子, 当然vue也一样只是说明流程
如果你还没用过Handlebars,不妨先去学习一下。
官方网站
http://handlebarsjs.com/。
这位老兄的blog上有中文,可以看看
http://www.cnblogs.com/iyangyuan/p/3471300.html。
下边看看如何解决函数调用的弱智问题呢?给大家两个函数注册进去就能够解决了。
在这里想抱怨一下,不明白作者是怎么想的,作为一个模板,就真的就只是一个模板,语言都完全被屏蔽了。
为什么不原生提供的函数挂接呢?registerHelper方式注册函数真是很丑,如果使用的函数太多,要注册很多的函数不是要当场晕死。
如果能提供javascript语言的挂接支持多好!模板部分都实现了在多提供一点也不难吧。好了不啰嗦了,希望作者以后改进。
加载后在你们模板上注册以下两个。
if (typeof(Handlebars)!='undefined'&&Handlebars!=undefined)
{
//Handlebars 模板扩展支持 jspx.net
Handlebars.registerHelper("eval",function(/* ... */){
var options = arguments[arguments.length-1];
var code = arguments[0];
eval("var result=" + code);
return result;
});
Handlebars.registerHelper("if",function(/*...*/){
var options = arguments[arguments.length-1];
var condit = arguments[0];
var result = false;
var exChars = ['.','<','>', '=','+','-','*','/','('];
if (condit==undefined || typeof(condit)!='string'&&!condit&& condit<=0 ) condit = false;
if (condit&&exChars.some(function(item, index){ return condit.indexOf(item)!=-1;}))
eval("result=" + condit);
else result = condit;
if(result){
return options.fn(this);
}else{
return options.inverse(this);
}
});
}
注册后if 会替换Handlebars默认原生的if,因为原生的if 太无聊了,除了会判断是否存在变量,其它的什么都不会判断。
替换后你就可以执行各种动态判断了,并且兼容原生if。eval 会提供你执行javascript调用的功能。
下边我们来演示一下如何使用:
例如有如下数据
var data = {
"title":'标题输出测试',
"student": [
{
"name": "张三4352345",
"sex": "0",
"age": 17
},
{
"name": "李四",
"sex": "0",
"age": 22
},
{
"name": "妞妞",
"sex": "1",
"age": 18
},
{
"sex": "1",
"age": 10
}
]
};
模板结构写法如下
<script id="table-template" type="text/x-handlebars-template">
{{title}}
{{#each student}}
{{#if "this.age>20"}}
<tr>
<td>{{eval @index "+1"}}.{{eval "this.name.substring(1,4)"}}</td>
<td>{{sex}}</td>
<td>{{age}}</td>
</tr>
{{else}}
<tr>
<td>?</td>
<td>{{sex}}</td>
<td>{{age}}</td>
</tr>
{{/if}}
{{/each}}
</script>
{{eval "this.name.substring(1,4)"}} substring(1,4) 是javascrpt的原生函数,这样你就可以任意执行javascript函数了。
each嵌套
var data = [{
"name":"张三",
"info":[
"眼睛",
"耳朵",
"鼻子"
]
},{
"name":"李四",
"info":[
"爸爸",
"妈妈",
"妻子"
]
}];
<!--id可以用来唯一确定一个模版,type是模版固定的写法-->
<script id="table-template" type="text/x-handlebars-template">
{{#each this}}
{{#each info}}
{{../name}}的{{this}}<br>
{{/each}}
{{/each}}
</script>
注意,上边的 if 和 eval 中变量必须加 this. 写法上目前只能如此了,也算看得过去。
如能够实现达到 {{#if age>20}} {{name.substring(1,4)}} 这样的效果就完美了。希望那位高人能够在写出更加优美的写法。
本人默认使用mootools 库:
中文文档
页面推荐引入
<script language="javascript" src="mootools.js"></script>
<script language="javascript" src="mootools-more.js"></script>
<script language="javascript" src="jspxnet.js"></script>
<script language="javascript" src="jspxnet-ui.js"></script>
<script language="javascript" src="handlebars.js"></script>
渲染模板
window.addEvent('domready', function() {
var myTemplate = Handlebars.compile($("table-template").get('html'));
$('tableList').set('html',myTemplate(data));
}
如何载从文件载入模板呢?我通过mootools 功能扩展了载入方法,载入jspxnet-ui.js 后会自动加载本功能。
template-file 为扩展方法 属性里边放文件url路径就可以了。
<script id="table-template" type="text/x-handlebars-template" template-file="/jcms/htdoc/test.hba" >
</script>
说明:jspxnet-ui.js 会自动载入以上两个定义的方法,所以如果你载入了jspxnet-ui.js 就不用再注册以上函数了,并且能够使用template-file属性。
以下是一个调用例子, posts 是一个简化的协议格式,字符串格式,协议头 X-Requested-With 为 jspx.net-roc,
TXWeb 才会调用执行你的调用。
var posts = JSON.encode({
"version": "3.0",
"params": {
"count": 5,
"currentPage": 1
},
"result": ["list","currentPage","auditingType"]
});
new Request.JSON({url: '/jcms/json/matterlist.jhtml',
headers:{'X-Requested-With':'jspx.net-roc'},
method: 'post',
onSuccess: function(data)
{
//data为json数据,在这里填充渲染页面
}}
).send(posts);
以上只是为了说明原理,实际使用中本构架提供了更简洁的方式
采用外部文件UI模板
var posts = {};
posts.params = {};
posts.params.count = 5;
posts.params.currentPage = 1;
posts.result = ["list","currentPage","auditingType"];
posts.version = 3;
new Request.Template('tableList',{'url':'/jcms/json/matterlist.jhtml',
'templateUrl':'/jcms/htdoc/test.dwt','progress':true}).render(posts);
ROC 协议Request,得到返回请求数据
var posts = {};
posts.params = {};
posts.method={'name':'list'};
posts.result = ["list"];
new Request.ROC({'url':'/xxx.json','data':posts,
onSuccess:function(obj)
{
//obj 返回结果
}
}).send();
提示:
tableList 表示需要填充的元素,可以是元素数组,填充相同的数据
也可以在onComplete 事件中完成渲染后的动作。
test.dwt 表示模板文件
/jcms/json/matterlist.jhtml 表示roc请求数据 URL
还有动画效果哦! 如果不喜欢可以设置 progress 为 false
加密传输
5.7版本后对加密做了 做了ROC加密传输支持。能够实现RSA,SM2的非对称加密密钥,配AES,DES,3DES数据包到加密传输。推荐使用
使用步骤:
- 创建 RSA配对到密匙对,RSA MD5WithRSA, AES/CBC/PKCS7Padding.将密匙配置放到jspx.properties(16进制),和jsencrypt.js.ftl 放公钥(base64)。
- TXWeb中配置Action事件为保密事件,设置secret="true"后必须加密方法提交才会接收。
- 页面需要引入js文件,jsencrypt.js.ftl,里边包含了js加密算法。
<action name="name" caption="加密传输" class="xxxAction" secret="true" >
</action>
请求头信息
headers: {'X-Requested-With': 'jspx.net-secret-roc'}
调用方式为和Request.JSON一样,区别就是将改用 Request.SECRET
传输到json数据有:
data:"97A5A9DA47D434FF91CBC0C2...C8196BDBBEB9E6ECB92D773"
dataType:"aes"
key:"AsKU2G3Zge6YHa2E3QgWxmw7...5F5Y4qg+X60cCLqgJSygvQ="
keyType:"rsa"
目前默认是rsa加密配合aes加密算法。
实际使用例子,感觉和普通提交并没多少不同,但传输的是加密数据
var posts = {
"version": "3.0",
"method":{"name": "votePost"},
"params": {"sign":sign,"data":"提交的数据"}
};
new Request.SECRET({'url':'xxxxx/url','data':posts,
onSuccess:function(msg)
{
if (msg.success)
{
alert(msg.message);
} else alert(msg.error.message);
}
}).send();
以下为测试用例的代码,接口key为sioc中配置
//Hessian 的原生调用方式
@Test
public static void testDaoCall() throws Exception {
String url = "http://127.0.0.1/user/service/memberDAO.jhtml?namespace=user&key=接口key";
HessianProxyFactory factory = new HessianProxyFactory();
JUserMemberDAO memberDAO =(JUserMemberDAO)factory.create(url);
List<Member> members = memberDAO.getList(null,null,null,null,null,1,10,false);
for (Member member:members)
{
System.out.println("---------------out=" + member.toString());
}
}
/*
Hessian 建议替代方式,因为提供了app登陆方式,能给得到更多权限,调用非DAO的逻辑服务接口,
逻辑服务接口,是自己些的,不是构架的哦
*/
@Test
public static void testJspxDaoCall() throws Exception {
String url = "http://127.0.0.1/user/service/memberDAO.jhtml?namespace=user&key=接口key";
ClientHessianProxyFactory factory = new ClientHessianProxyFactory();
//factory.login()
JUserMemberDAO memberDAO =(JUserMemberDAO)factory.create(url);
List<Member> members = memberDAO.getList(null,null,null,null,null,1,10,false);
for (Member member:members)
{
System.out.println("---------------out=" + member.toString());
}
}
//未加密方式
@Test
public static void testCall() throws Exception {
String url = "http://127.0.0.1/jcms/userlist.jhtml";
HttpClient httpClient = HttpClientFactory.createRocHttpClient(url);
JSONObject json = new JSONObject();
json.put("version","3.0");
JSONObject param = new JSONObject();
param.put("id",10001);
json.put("params",param);
JSONArray result = new JSONArray();
result.add("member");
json.put("result",result);
String out = httpClient.post(json);
System.out.println("----------out=" + out);
}
//ROC 加密方式调用,传输加密RSA
@Test
public static void testSecretCall() throws Exception {
String url = "http://127.0.0.1/jcms/userlist.jhtml";
HttpClient httpClient = HttpClientFactory.createRocSecretHttpClient(url);
JSONObject json = new JSONObject();
json.put("version","3.0");
json.put(Environment.rocProtocol,Environment.rocSecret);
JSONObject param = new JSONObject();
param.put("id",10001);
json.put("params",param);
JSONArray result = new JSONArray();
result.add("member");
json.put("result",result);
String out = httpClient.post(json);
System.out.println("----------out=" + out);
}