API设计和代码结构组织心得

最近的一个项目尝试使用了laravel框架,在项目完成后,有关代码组织结构方面做一些总结,写一些心得体会。

一. api的设计

当你的项目需要后台同时对PC Web端,手机 Web端和app端做接口支持的时候,个人认为首先应该将返回json数据的接口和返回html页面的接口分开,比如:

  • api接口:/api/users/{id}
  • web页面url:/users/{id}

当你同时有pc web端(web)的网页和手机web端(wap)的网页,两者的数据还页面有区别,而且你的网页没有做响应式的时候,你就需要将url再细分,比如:

  • web页面:/users/{id}
  • wap页面:/mobile/users/{id}

当你的web页面有时也需要api接口的时候,你可以像这样继续划分api接口:

  • app api接口:/api/users/{id}
  • web端:/api/web/users/{id}

当然如果其请求和返回数据一致,便可以直接使用/api/users/{id}接口。
以上总结出来可以用下面的图来表示:
api设计

二. Controllers的组织结构

根据上面的api设计,Controller的目录结构也应该按照上面的层级来组织,个人认为可以用类似下面的结构:
Controllers的目录结构
当然这种目录会显得比较繁杂,把web端和api端分2个项目去做应该会更好,当然我在实验室这种小作坊里面就只能用一个项目去承载所有的后台接口=。=

php5.3之后引入了命名空间,所以同名的UsersController也不会造成冲突。在Controllers文件夹下的BaseUsersController.php文件是其他UsersController的父类,其中可以去实现一些获取基本数据(如用户的基本信息)或者获取业务块信息(如用户的评论数据)等公共方法,以供其他UsersController可以继承使用。

其他的UsersController主要负责接收、过滤请求参数以及返回格式化数据。然后一些与业务无关或耦合不紧的逻辑可以抽离出来写在相应的帮助类中,如UsersHelper.php中。

三. Model层的BaseModel

在laravel框架中,Model它提供了类似builder模式的查询构造器,在开发具体的业务model时,我们可以先建立一个BaseModel的父类,这样可以使重复的代码得到充分的复用。
以下是示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?php
namespace App\Models;
class BaseModel extends Models
{
//获取多行数据时
public function getManyByPage($page, $pageNum) {
$result = DB::table($this->table)
->orderBy('create_time', 'desc')
->skip(($page - 1)*$pageNum)
->take($pageNum);
return $result;
}
//获取单行数据时
public function getOneById($id) {
$result = DB::table($this->table)
->where('id', $id);
return $result;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<?php
namespace App\Models;
class UsersModel extends BaseModel
{
protected $table = 'users';
public function getUsers($page, $pageNum) {
$result = $this->getManyByPage($page, $pageNum)
->get();
return $result;
}
public function getVipUsers($page, $pageNum) {
$result = $this->getManyByPage($page, $pageNum)
->where('is_vip', 1)
->get();
return $result;
}
public function getOneUserById($id) {
$result = $this->getOneById($id)
->first();
return $result;
}
}

以上代码只是一个示例,创建BaseModel的宗旨就是尽量将可复用的代码抽到父类里面来,但是不要在父类里面做取数据操作,即调用get()first()方法,将这些方法放到子类里面去做,因为这样就可以在子类里面去加一些业务逻辑的SQL条件语句,最后调用get()first()输出数据。

当然你也可以为某些业务操作比较多的Model再建一个父类,如BaseUsersModel继承于BaseModel,在BaseUsersModel里面去抽象一个和业务结合更加紧密的方法。最后,创建UsersModel,在里面去最终取出数据。

当前网速较慢或者你使用的浏览器不支持博客特定功能,请尝试刷新或换用Chrome、Firefox等现代浏览器