控制器 Controller

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

路由 Route

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

  • 如下, 访问 index() 的路由是 /users/list (/users + list)
  1. /**
  2. * @Controller(prefix="/users")
  3. */
  4. class RouteController
  5. {
  6. /**
  7. * @RequestMapping("list")
  8. */
  9. public function index(): string
  10. {
  11. }
  12. }

@Controller

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

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

比如:

  1. // file: app/Admin/HttpClientController.php
  2. /**
  3. * @Controller()
  4. */
  5. class HttpClientController
  6. {}

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

@RequestMapping

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

  1. /**
  2. * @RequestMapping(route, method)
  3. */
  4. public function some() {}

注解参数:

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

示例:

  1. /**
  2. * @RequestMapping()
  3. * @RequestMapping(route="index")
  4. * @RequestMapping(route="index", method=RequestMethod::GET)
  5. * @RequestMapping(route="index", method={RequestMethod::POST,RequestMethod::PUT})
  6. */
  7. public function some()
  8. {}
  • 显式指定路由后缀: @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 添加到它的前面。
  • 请切记要引入相关的注解类
  1. use Swoft\Http\Server\Bean\Annotation\Controller;
  2. use Swoft\Http\Server\Bean\Annotation\RequestMapping;
  3. use Swoft\Http\Server\Bean\Annotation\RequestMethod;

快速创建控制器

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

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

示例

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

  1. /**
  2. * @Controller(prefix="/route")
  3. */
  4. class RouteController
  5. {
  6. /**
  7. * @RequestMapping()
  8. */
  9. public function index(): string
  10. {
  11. return 'index';
  12. }
  13. /**
  14. * @RequestMapping(route="user/{uid}/book/{bid}/{bool}/{name}")
  15. */
  16. public function funcArgs(bool $bool, Request $request, int $bid, string $name, int $uid, Response $response): array
  17. {
  18. return [$bid, $uid, $bool, $name, \get_class($request), \get_class($response)];
  19. }
  20. ...
  21. }

请求 Request

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

  1. public function index(Request $request)
  2. {
  3. // 获取所有GET参数
  4. $get = $request->query();
  5. // 获取name参数默认值defaultName
  6. $getName = $request->query('name', 'defaultName');
  7. // 获取所有POST参数
  8. $post = $request->post();
  9. // 获取name参数默认值defaultName
  10. $postName = $request->post('name', 'defaultName');
  11. // 获取所有参,包括GET或POST
  12. $inputs = $request->input();
  13. // 获取name参数默认值defaultName
  14. $inputName = $request->input('name', 'defaultName');
  15. return compact('get', 'getName', 'post', 'postName', 'inputs', 'inputName');
  16. }

注意: \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:

  1. /**
  2. * @RequestMapping("/")
  3. * @View(template="index/index")
  4. * @return array
  5. */
  6. public function index(): array
  7. {
  8. $name = 'Swoft';
  9. $notes = [
  10. 'New Generation of PHP Framework',
  11. 'High Performance, Coroutine and Full Stack'
  12. ];
  13. $links = [
  14. [
  15. 'name' => 'Home',
  16. 'link' => 'http://www.swoft.org',
  17. ],
  18. [
  19. 'name' => 'Documentation',
  20. 'link' => 'http://doc.swoft.org',
  21. ],
  22. [
  23. 'name' => 'Issue',
  24. 'link' => 'https://github.com/swoft-cloud/swoft/issues',
  25. ],
  26. [
  27. 'name' => 'GitHub',
  28. 'link' => 'https://github.com/swoft-cloud/swoft',
  29. ],
  30. ];
  31. // 返回一个 array 或 Arrayable 对象,Response 将根据 Request Header 的 Accept 来返回数据,目前支持 View, Json, Raw
  32. return compact('name', 'notes', 'links');
  33. }

支持返回的数据类型

  • 基本数据类型: 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容器