/master/zh-CN/http-server/controller.html

TOC

控制器 Controller

控制器作为HTTP服务的核心组件,串接起一次请求的整个生命周期. 通过 注解 的方式,相较于传统的 Controller,代码更简洁,用户可以更关注业务逻辑。

路由 Route

主要通过 @Controller + @RequestMapping 注解实现,通常前者定义 前缀,后者定义 后缀

  • 如下, 访问 index() 的路由是 /users/list (/users + list)
/**
 * @Controller(prefix="/users")
 */
class RouteController
{
    /**
     * @RequestMapping("list")
     */
    public function index(): string
    {
    }
 }

@Controller

类注解,设置在 Controller 类上,标记当前类是一个http控制器类

  • 显式指定路由前缀: @Controller(prefix="/route")@Controller("/route")
  • 隐式指定路由前缀: @Controller() 默认自动解析 controller class 的名称,并且使用驼峰格式。

比如:

// file: app/Admin/HttpClientController.php

/**
 * @Controller()
 */
class HttpClientController
{}

上面的controller解析时,将会设置路由 prefixhttpClient,注意此操作不会解析文件夹,例如该 Controller 位于 app/Admin/HttpClientController.php,最终设置的路由 prefix 仍然为 httpClient

@RequestMapping

方法注解,用于控制类的Action方法上。

/**
 * @RequestMapping(route, method)
 */
 public function some() {}

注解参数:

  • route 设置路由path,也是默认参数。
  • method 设置允许的请求方法,可以多个。 e.g. GET POST

示例:

/**
 * @RequestMapping()
 * @RequestMapping(route="index")
 * @RequestMapping(route="index", method=RequestMethod::GET)
 * @RequestMapping(route="index", method={RequestMethod::POST,RequestMethod::PUT})
 */
 public function some()
 {}
  • 显式指定路由后缀: @RequestMapping(route="index")@RequestMapping("index")
  • 隐式指定路由后缀: 不使用 @RequestMapping 或者使用 @RequestMapping(), 默认解析方法名为后缀
  • 限定HTTP方法: @RequestMapping(route="index", method=RequestMethod::GET) 指定路由支持的HTTP方法,默认是支持GETPOST
    • 比如 method={RequestMethod::POST,RequestMethod::PUT} 设置路由支持 POSTPUT
  • 指定路由参数: @RequestMapping(route="anyName/{name}"),Action 方法中可以直接使用 $name 作为方法参数

使用说明

  • 通常一个完整的路由path等于 Controller的prefix + Action的route
  • 当你的action上的路由以 / 开头时,那完整的路由就是它,即不会再将 prefix 添加到它的前面。
  • 请切记要引入相关的注解类
use Swoft\Http\Server\Bean\Annotation\Controller;
use Swoft\Http\Server\Bean\Annotation\RequestMapping;
use Swoft\Http\Server\Bean\Annotation\RequestMethod;

快速创建控制器

可以通过命令行命令快速创建控制器类,以方便快速开发使用。

// Gen DemoController class to `@app/Controllers`
php bin/swoft gen:controller demo --prefix /demo -y

// Gen UserController class to `@app/Controllers`(RESTFul 风格,会默认创建一些action)
php bin/swoft gen:controller user --prefix /users --rest

示例

常用方法可以参考 Swoft项目app/Controllers/RouteController.php:

/**
 * @Controller(prefix="/route")
 */
class RouteController
{
    /**
     * @RequestMapping()
     */
    public function index(): string
    {
        return 'index';
    }

    /**
     * @RequestMapping(route="user/{uid}/book/{bid}/{bool}/{name}")
     */
    public function funcArgs(bool $bool, Request $request, int $bid, string $name, int $uid, Response $response): array
    {
        return [$bid, $uid, $bool, $name, \get_class($request), \get_class($response)];
    }
    ...
}

请求 Request

Swoft HTTP服务中的 Request,是对 \Swoole\Http\Request 基于 PSR-7 标准的封装,常用方法可以参考 app/Controllers/DemoController.php:

 public function index(Request $request)
{
    // 获取所有GET参数
    $get = $request->query();
    // 获取name参数默认值defaultName
    $getName = $request->query('name', 'defaultName');
    // 获取所有POST参数
    $post = $request->post();
    // 获取name参数默认值defaultName
    $postName = $request->post('name', 'defaultName');
    // 获取所有参,包括GET或POST
    $inputs = $request->input();
    // 获取name参数默认值defaultName
    $inputName = $request->input('name', 'defaultName');

    return compact('get', 'getName', 'post', 'postName', 'inputs', 'inputName');
}

注意: \Swoole\Http\Request 对 HTTP Request 进行了封装,不能像以往一样使用 $_POST / $_GET 等全局变量,也不推荐这样的使用方式,框架层通常都做了更好的封装和兼容,比如 $_POST 无法取到 application/json 格式的数据

响应 Response

Swoft 对HTTP服务的 Response 做了很好的封装,其中一个设计哲学:

返回的格式类型,不应该由服务端指定,而是根据客户端请求时的 Header 里面的 Accept 决定

当 Action 返回一个 array 或 Arrayable 对象,Response 将根据 Request Header 的 Accept 来返回数据,目前支持 View / Json / Raw

可以参考 app/Controllers/IndexController.php:

/**
 * @RequestMapping("/")
 * @View(template="index/index")
 * @return array
 */
public function index(): array
{
    $name = 'Swoft';
    $notes = [
        'New Generation of PHP Framework',
        'High Performance, Coroutine and Full Stack'
    ];
    $links = [
        [
            'name' => 'Home',
            'link' => 'http://www.swoft.org',
        ],
        [
            'name' => 'Documentation',
            'link' => 'http://doc.swoft.org',
        ],
        [
            'name' => 'Issue',
            'link' => 'https://github.com/swoft-cloud/swoft/issues',
        ],
        [
            'name' => 'GitHub',
            'link' => 'https://github.com/swoft-cloud/swoft',
        ],
    ];
    // 返回一个 array 或 Arrayable 对象,Response 将根据 Request Header 的 Accept 来返回数据,目前支持 View, Json, Raw
    return compact('name', 'notes', 'links');
}

支持返回的数据类型

  • 基本数据类型: bool int float(double) string
  • array
  • \Swoft\Contract\Arrayable 对象
  • XxxException: 在 Controller 内抛出异常将由 ExceptionHandler 捕获并进行处理, 4xx/5xx 的状态码也是通过抛异常, 然后由 ExceptionHandler 捕获并统一进行处理

使用视图

可以通过 @View 注解 或 view() 帮助函数来使用视图, 可以参考 app/Controllers/IndexController.php

最佳实践

  • 使用 PSR-7 标准来封装 HTTP服务的 Request 和 Response
  • 约定大于配置, 路由应该在用户看到 URI 的时候, 就能找到相应的 Controller/Action

其他

Controller 中也可以使用 Bean 相关的方法

注意: @Controller 注解已经实现了 @Bean 的功能, 不能和 @Bean 注解同时使用

其他注解方法, 比如 @Inject,参考 Bean容器

progress-bar