TXWeb--ROC RPC 调用协议说明

一.ROC协议说明

  1. 协议主要参照JSON-RPC 2.0,兼容resetFull API 方式,默认为传统页面开发模式。
  2. 通过协议头部信息确定返回数据和格式支持类型,同时本地还可以使用传统方式搭建页面。
  3. 传输主要是json格式,可以传输xml。
  4. 为了区分其他协议,这里就叫ROC协议,远程对象调用协议。
  5. 传输协议支持标准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
    }
}
简化调用说明,protocol为空的时候标识使用简化调用,可以不写method,不写params,直接传递参数,和spring方式一样, 场景说明,简化方式适用新接口,url和调用方法有唯一映射关系,系统自动填充全局或内部变量,内部变量优先
 {'参数名称1':'参数值1','参数名称2':'参数值2',...} 

五.返回参数说明

httpStatus头信息说明:
头信息 描述
200 正常执行
401 token失效,需要登录
403 没有权限操作
403 服务器拒绝请求
404 无文件,无页面,无接口
405 不允许,特权资源
500 服务器异常
401 重新登录
{
    "code": -32602,
    "success": 0,
    "message": "需要登录"
}

六.常用参数说明

例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数据包到加密传输。推荐使用 使用步骤:
  1. 创建 RSA配对到密匙对,RSA MD5WithRSA, AES/CBC/PKCS7Padding.将密匙配置放到jspx.properties(16进制),和jsencrypt.js.ftl 放公钥(base64)。
  2. TXWeb中配置Action事件为保密事件,设置secret="true"后必须加密方法提交才会接收。
  3. 页面需要引入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);
    }