前言

所有微服务的模型文件都必须继承于 MicroService 类,该类定义了一些常用的公共方法,便于在管理服务、调用服务时达到统一规范的目的。
在管理和使用服务时,会大量调用以下的方法,如果您需要更灵活的提供服务,可以在服务的模型文件重定义如下方法。

公共方法

getApis

该方法用于列出该服务支持的接口列表和外部说明文档,默认从描述文件获取数据,并按格式自动生成接口文档。当接口过多时,可以在服务端模型文件声明该方法,将完整的接口数据提供给继承的方法。
建议暂时使用外部接口文档。

源码详解

  1. /**
  2. * 获取该服务的API接口
  3. * @param array|null $data 附加接口数据
  4. * @return array API接口
  5. */
  6. public function getApis($data=array()){
  7. $apis = $this->service['apis'];
  8. $apis['schemas'] = array_merge($apis['schemas'], $data);
  9. return $apis;
  10. }
  11. //调用示例:其中identity为服务标识
  12. $apis = serv("identity")->getApis();

参数说明

  • $data :附加接口数据,默认会从描述文件内读取,可以在模型文件内定义同名方法补充该变量。(注意:该参数的格式必须统一并严格安装说明文档的结构)

    返回数据

    array(
      "wiki"=>"",            //接口外部说明文档,http或https开头
      "schemas"=>[]        //接口列表,其数组元素为接口的实例,具体结构请参考相关文档
    );
    

getMethods

该方法用于列出该服务支持的内置方法,默认从描述文件读取,并按格式自动生成服务的方法调用详解。当内置方法过多时,可以在服务端模型文件声明该方法,将完整的内置方法数据提供给继承的方法。

源码详解

/**
 * 获取该服务的内置方法
 * @param array|null $data 附加内置方法
 * @return array 内置方法数据
*/
public function getMethods($data=array()){
    $methods = $this->service['methods'];
    return array_merge($methods, $data);
}


//调用示例:其中identity为服务标识
$methods = serv("identity")->getMethods();

参数说明

  • $data :附加内置方法数据,默认会从描述文件内读取,可以在模型文件内定义同名方法补充该变量。(注意:该参数的格式必须统一并严格安装说明文档的结构)

    返回数据

    array(
      "wiki"=>"",            //内置方法的外部说明文档,http或https开头
      "method1"=>[],        //内置方法,结构请参考下方方法
      "UpdateInfo"=>[
          "name"=>"更新资料",
          "summary"=>"更新用户资料",
          "params"=>array(
              "uid"=>["UID","int"],
              "profile"=>["用户资料数组,字段一一对应","array"]
          ),
          "requires"=>["uid","profile"],
          "return"=>["更新结果","bool"]
      ]
    );
    

getEntry

该方法用于获取服务的后台管理入口,默认读取描述文件的entrance字段的值。当需要更灵活的方式访问入口时,可以在服务的模型文件重新定义方法。
当描述文件的entrance字段值为空,且不存在默认控制器 web/IndexController 时,表示该服务不需要后台管理,只需要通过接口和内置方法提供来服务。

源码详解

/**
 * 获取该服务的后台入口
 * @param string|null $entrance;
 * @return string 后台入口URL
*/
public function getEntry($entrance=""){
    if(empty($entrance)){
        $entrance = $this->service['entrance'];
    }
    if (strpos($entrance,'http')===0) return $entrance;
    if ($this->service['drive']=='php'){
        if ($entrance=='' && file_exists($this->serverpath.$this->identity."/web/IndexController.php")){
            $entrance = 'index';
        }
        if (!empty($entrance)){
            return $this->url($entrance);
        }
        return $entrance;
    }else{
        return $entrance;
    }
}


//调用示例:其中identity为服务标识
$weburl = serv("identity")->getEntry();

参数说明

  • $entrance :入口路由名称,默认会从描述文件内读取。当需要更灵活的生成入口时,可以在模型文件内定义同名方法提供变量。

    返回数据

    $weburl = serv("ucenter")->getEntry("member");
    //返回 "/serv/ucenter/member"
    

error

该方法返回统一的错误信息格式

/**
 * 返回错误信息
 * @param string $msg 说明
 * @param int|null $code 状态码
 * @param array 统一错误格式
*/
public function error($msg, $code=-1){
    return error($code, $msg);
}

success

该方法返回统一的接口数据格式(一般是交互成功时)

/**
 * 返回成功信息
 * @param string|array|object $msg 说明或者数据内容
 * @param string|null $redirect 成功后跳转地址
 * @return array 返回成功输出
*/
public function success($msg, $redirect=""){
    return array(
        'message'=>$msg,
        'redirect'=>trim($redirect),
        'type'=>'success'
    );
}

api

该方法用于生成服务的接口URL

源码详解

/**
 * 生成API URL
 * @param string $route 路由名称
 * @param array|null $query URL参数
 * @param string|null $platform 接口通道
 * @return string API接口
*/
public function api($route, $query=array(), $platform=""){
    global $_W;
    $query['i'] = $_W['uniacid'];
    return "{$_W['siteroot']}/api/serv/". $this->identity . "/{$route}?" . http_build_query($query, '', '&');;
}


//调用示例:其中identity为服务标识
$api = serv("identity")->api("member", array("groupid"=>1));

参数说明

  • $route:路由名称,默认情况下,访问该方法生成的URL,最终会运行下方的HttpRequest()方法,并将此参数传递给对应的 $route 参数,对应的 $platform 参数值为”api
  • $query:数组格式的URL参数,在系统内可以通过全局变量$_GPC获得
  • $platform:接口通道,默认是API,可以自定义(例如app、web、wxapp等),不同管道对应不同的控制器文件夹。

    返回数据

    $api = serv("ucenter")->api("connect/register", array("from"=>'discuzx'));
    //返回:"https://yourdomain.com/api/serv/ucenter/connect/register?i=1&from=discuzx"
    

url

该方法用于根据路由和参数生成服务的后台页面的URL

源码详解

/**
 * 生成后台URL
 * @param string|null $do 路由名称
 * @param array|null $query URL参数
 * @param bool|null $full 是否完整拼接
 * @return string 后台URL
 */
public function url($route='', $query=array(), $full=false){
    if(empty($query['do'])){
        $query['do'] = 'server';
    }
    $query['server'] = $this->identity;
    $ctrl = str_replace("/", ".", $route);
    if (!empty($ctrl)) {
        $query['ctrl'] = $ctrl;
    }
    $query['m'] = MODULE_IDENTIFIE;
    $url = wurl('site/entry', $query);
    if (!$full) return $url;
    global $_W;
    return $_W['siteroot'] . "web/" . substr($url, 2);
}


//调用示例:其中identity为服务标识
$weburl = serv("identity")->url("member", array("groupid"=>1));

参数说明

  • $route :路由名称,默认情况下,访问该方法生成的URL,最终会运行下方的HttpRequest()方法,并将此参数传递给对应的 $route 参数,对应的 $platform 参数值为”web
  • $query:数组格式的URL参数,在系统内可以通过全局变量$_GPC获得
  • $full:是否返回完整的网址(带http和域名),否则返回相对路径的URL

    返回数据

    $weburl = serv("ucenter")->url("member", array("groupid"=>1), true);
    //返回 "https://yourdomain.com/serv/ucenter/member?groupid=1"
    

HttpRequest

当通过HTTP方式访问的服务时,最终运行的是服务的该方法。
微服务提供者可以在该方法内定义自己的路由规则,来实现任何功能。

源码详解

/**
 * 接管路由
 * @param string|null $platform 路由通道,可选web、app、api及自定义通道
 * @param string|null $route 路由名称
 * @return array|error 返回接口数据或报错信息
 */
public function HttpRequest($platform="web", $route=""){
    global $_GPC;

    ...

    $route = str_replace(".","/",$route);
    list($controller, $method) = explode("/", $route);


    ...

    //定义运行目录
    $basepath = $this->serverpath . $this->identity;
    //定义控制器
    $ctrl = "$basepath/$platform/".ucfirst($controller)."Controller.php";

    ...

    //引用控制器
    include_once $ctrl;
    $class = ucfirst($controller)."Controller";
    $instance = new $class();
    return $instance->$method();
}

参数说明

  • $platform:路由通道,可选web、app、api及自定义通道。正常情况下,通过url()方法获取的链接,访问时该参数值为”web“,通过api()方法获取的链接,访问时该参数值为”api
  • $route:自定义路由名称。默认情况下,该参数与上方的api()方法和url()方法的$route参数对应。

Event

微服务的内置方法可以声明要广播的事件名,当调用该方法时,会将特定数据广播给系统。如果在开发应用或其它插件需要监听这个事件并处理对应数据时,只需要按对应规范指定监听器来监听对应事件即可。
事件广播的更多说明请参考:https://www.yuque.com/shenwa/qingru/hng28f#C6hH5

源码详解

/**
* 事件广播
* @param string $listener 广播事件名
* @param array|null $data 广播数据
* @param array|null|mixed 服务构造参数
* @return bool 广播结果
*/
public function Event($listener, $data=array(), $param=null){
    ......
    //发送事件广播,将会触发所有监听该事件的微服务
    return true;
}

参数说明

  • $listener:广播事件名
  • $data:要广播给监听器的数据
  • $param:微服务构造参数,部分微服务的实例化需要给定参数

Processor

当微服务需要监听其它微服务的事件时,需要在manifest.json文件指定需要监听的广播事件名。当该事件被触发时,会执行对应微服务的此方法,并传递事件名和对应参数。
注:

  1. 在处理器内请慎用exit()die()等强制结束语句;
  2. 请务必严谨处理器内的事件广播逻辑,避免反复嵌套执行事件死循环。
    {
    "application":{
      "name": "用户服务"
      ......
    }
    ......
    "events": ["storage.remove"],    #监听的事件列表
    ......
    }
    
    /**
    * 事件处理器
    * @param string $listener 事件名
    * @param array|null $data 广播数据
    * @return bool
    */
    public function Processor($listener, $data=array()){
    //Todo something
    return true;
    }
    

    参数说明

  • $listener:广播事件名
  • $data:传递的数据

View

微服务的视图编译方法,会自动将数据渲染到指定的HTML模板或Blade模板。
具体的使用方法与原理请参考视图View详解

源码详解

/**
* 视图编译
* @param array $data 模板数据
* @param string $template 模板名称
* @return bool
*/
public function View($data, $template=''){
    global $_W,$_GPC;
    ......
    //判断模板通道
    $platform = defined('IN_SYS') ? 'web' : 'app';
    if ($this->ComplieDrive=='smarty'){
        //默认HTML模板
        ......
        include $compile;
        exit();
    }else{
        //Laravel Blade 模板
    }
    return true;
}

参数说明

  • $data:需要动态渲染的数据
  • $template:模板名称。默认值是当前请求的路由名称,该名称与视图文件名一一对应。

    $weburl = serv("ucenter")->url("member/post");
    //该方法返回的URL是 "/serv/ucenter/member/post"
    //该URL路由名称为 "member/post"
    //该URL最终运行的是 web/MemberController 控制器的 post() 方法
    //在该控制器的post()方法调用时,编译的视图文件是 /template/web/member/post.html
    /**
    * 当编译引擎为Blade模板引擎时
    * 编译的视图文件是 /blade/web/member/post.blade.php
    */
    

    调用示例

    ```php class MemberController extends UcenterService {

    public function post(){

      $this->View(array(
          'title'=>"调用示例"
      ));
    

    }

}


<a name="lM9bd"></a>
### Composer
通过类名判断第三方依赖包是否已安装
<a name="CsRjo"></a>
#### 源码详解
```php
/**
* composer检测
* @param string $className 第三方类名
* @return bool|void
*/
public function Composer($className){
    if (!class_exists($className)){
        //自动加载或者进入composer require 引导
    }
    return true;
}

参数说明

  • $className:第三方类名,该类是否存在代表这composer是否已加载。(注:了使用命名空间的类必须要加上对应的命名空间)

    调用示例

    ```php class StorageService extends MicroService {

    public function remoteUpload($file){

      $this->Composer("JohnLui\AliyunOSS");
    

    }

} ```