第一步:安装swagger-ui前端
用cd命令进入到存放静态文件的目录,例如public目录。执行下面命令:
git clone https://github.com/swagger-api/swagger-ui.git
注意:上面的命令,下载的是当前最新版本3.0,但是3.0有个已知的问题,不支持中文。如果想支持中文,需要指定版本。
git clone --branch v2.2.10 https://github.com/swagger-api/swagger-ui.git
第二步:安装swagger-php后端
进入tp框架找到根目录下,打开composer.json找到require项,添加一行,然后使用更新命令。
"zircote/swagger-php": "*"
注意,每行用逗号分隔,不要忘了。
或者执行命令:
composer require "zircote/swagger-php"
注意:这个命令默认下载的是当前最新的版本,也就是3.x。我到git上查了一下,想要跟swagger-ui的2.x版本配合使用,需要使用swagger-php 2.x版本。指定版本:
composer require "zircote/swagger-php:2.0.13"
第三步:生成swagger.json文件
1、教程上,让执行下面命令(实际执行的命令,要根据你那边的目录来确定)
php E:/WampServer/WWW/tpSwagger/tp5/vendor/zircote/swagger-php/bin/swagger E:/WampServer/WWW/tpSwagger/tp5/vendor/zircote/swagger-php/Examples -o E:/WampServer/WWW/tpSwagger/tp5/swaggerApi/swagger.json
第1个路径是你安装成功后组件的路径;
第2个路径是你想要生成这个目录下所有用swagger方式注释的php文件,把所有注释生成api文档;
第3个路径是你存放生成swagger.json的路径。
可能是我这边默认安装的是新版的swagger(查看版本是3.0),提示找不到swagger
我到bin这个目录,发现没有swagger文件,但是有一个openapi文件。
于是就把bin/swagger改为bin/openapi,再次执行。
结果虽然报了很多警告,但是确实生成了json文件。
2、swagger-ui加载生成的json文件
进入到swagger-ui的下载目录,找到dist目录,打开里面的index.html文件,修改文件引用的.json文件的路径为你的json文件的路径(就是上面生成的那个swagger.json)
如果json文件的目录设置不对,则会提示Failed to load API definition.
3、编写控制器方法生成swagger.json:
如果我们每次修改了api,还要手动执行第三步的代码,有些繁琐,那我们就在控制器中写一个方法,每次访问swagger-ui的时候自动执行,然后跳转到前台swagger界面中。
快速更新文档
<?php
namespace app\index\controller;
use think\Controller;
class Index extends Controller
{ public function index(){
$path = 'D:/WampServer/WWW/tpSwagger/tp5/application'; //你想要哪个文件夹下面的注释生成对应的API文档
$swagger = \OpenApi\scan($path);
// header('Content-Type: application/json');
// echo $swagger;
$swagger_json_path = 'D:/WampServer/WWW/tpSwagger/tp5/swaggerApi/swagger.json';
$res = file_put_contents($swagger_json_path, $swagger);
if ($res == true) {
$this->redirect('http://localhost/tpSwagger/swagger-ui/dist/index.html');
}
}
}我这边在使用Swagger方法的时候,不能用这个\OpenApi\scan($path);提示找不到方法,需要用\Swagger\scan($path);
扫描的结果是对象,如果要写入文件,需要转换为字符串。另外在写入文件的时候,遇到权限问题。我最后没有使用file_put_contents函数
$path = APP_PATH.'portal/test'; //你想要哪个文件夹下面的注释生成对应的API文档
$swagger = \Swagger\scan($path);
// header('Content-Type: application/json');
// echo $swagger;
$swagger_json_path = ROOT_PATH.'public/swaggerApi/swagger.json'; // 检测模板目录
$dir = dirname($swagger_json_path);
if (!is_dir($dir)) {
mkdir($dir, 0755, true);
}
$myfile = fopen($swagger_json_path, "w") or die("Unable to open file!");
$swagger=json_encode($swagger, true);
fwrite($myfile, $swagger);
fclose($myfile);
第四步:编写swagger注释
控制器的注释写法
/**
* @SWG\Resource(
* basePath="http://skyapi.dev",
* resourcePath="/vps",
* @SWG\Api(
* path="/vps",
* @SWG\Operation(
* method="GET",
* type="array",
* summary="Fetch vps lists",
* nickname="vps/index",
* @SWG\Parameter(
* name="expand",
* description="Models to expand",
* paramType="query",
* type="string",
* defaultValue="vps,os_template"
* )
* )
* )
* )
*/
class VpsController extends Controller
{
// ...
}这只是个简单的实例具体的注释写法请自己百度
2、swagger注释使用
参考这个(写的比较全面):https://learnku.com/laravel/t/7430/how-to-write-api-documents-based-on-swagger-php#747b67
还有这个:https://blog.csdn。net/dyt19941205/article/details/79025266(链接中‘。’换成‘.’访问哈,不然发表不了)
这个:https://www.jianshu.com/p/554cd3762ab1
结合上面这几篇文章学习写了一个借口文档,也就四个方法,基本需要的东西都有了,以后再写文档可以照搬了
写接口文档真的很费时间,尤其写在php注释里,比较简单的文档可以使用swagger提供的编辑工具,直接在上面修改json文件后导出使用就可以了:http://editor.swagger.io/
下面给一个完整的接口注释:
<?php
namespace app\app\controller;use think\Controller;use think\Request;use think\Db;/**
* @SWG\Swagger(
* schemes={"http"},
* host="127.0.0.1",
* basePath="/restudy/public/index.php/app/",
* consumes={"multipart/form-data","X-Requested-With/XMLHttpRequest"},
* produces={"application/json"},
* @SWG\Info(
* version="1.0",
* title="我的测试学习api项目",
* description="接口学习,目前只写了一个Api类,把顶级栏目接口、二级栏目接口、文章列表接口、文章内容接口写到了一起"
* ),
*
* @SWG\Tag(
* name="Api",
* description="新闻webapp四大接口",
* ),
* ) */class Api extends Controller
{ /**
*@SWG\Get(path="/api/gettopnav", tags={"Api"},
* summary="获取顶级栏目列表",
* description="获取顶级栏目列表,返回栏目id,名称,和是否启用栏目",
@SWG\Parameter(
* description="ajax请求要加上X-Requested-With:XMLHttpRequest头字段",
* format="string",
* in="header",
* name="X-Requested-With",
* required=true,
* type="string",
default="XMLHttpRequest",
*
* ),
@SWG\Response(response="200", description="操作成功", @SWG\Schema(
* required={""},
* @SWG\Property(
* property="code",
* type="integer",
example=200,
* ),
* @SWG\Property(
* property="msg",
* type="string",
example="顶级栏目返回成功",
* ),
@SWG\Property(
* property="data",
* type="object",
example="[{cate_id:5,cate_name:'栏目1',cate_ison:1},{cate_id:6,cate_name:'栏目2',cate_ison:0}]",
* ),
*
* )),
@SWG\Response(response="201", description="数据为空", @SWG\Schema(
* required={""},
* @SWG\Property(
* property="code",
* type="integer",
example=201,
* ),
* @SWG\Property(
* property="msg",
* type="string",
example="数据为空!",
* ),
*
* )),
@SWG\Response(response="400", description="非法请求,不是ajax请求", @SWG\Schema(
* required={""},
* @SWG\Property(
* property="code",
* type="integer",
example=400,
* ),
* @SWG\Property(
* property="msg",
* type="string",
example="非法请求",
* ),
*
* )),
* ) */
//顶级栏目接口
public function getTopnav(){ if(request()->isAjax()){ $data=Db::table('re_cate')->where('cate_pid',0)->field('cate_id,cate_name,cate_ison')->select(); if(!empty($data)){ return json(['code'=>200,'msg'=>'顶级栏目返回成功','data'=>$data]);
}else{ return json(['code'=>201,'msg'=>'数据为空!']);
}
}else{ return json(['code'=>400,'msg'=>'非法请求']);
}
} /**
*@SWG\Post(path="/api/getsonnav", tags={"Api"},
* summary="获取二级栏目列表",
* description="根据栏目id获取二级栏目列表,返回栏目id,名称,和是否启用栏目",
@SWG\Parameter(
* description="ajax请求要加上X-Requested-With:XMLHttpRequest头字段",
* format="string",
* in="header",
* name="X-Requested-With",
* required=true,
* type="string",
default="XMLHttpRequest",
*
* ),
* @SWG\Parameter(name="id",type="integer", required=true, in="formData",
* description="顶级栏目id"
* ),
@SWG\Response(response="200", description="操作成功", @SWG\Schema(
* required={""},
* @SWG\Property(
* property="code",
* type="integer",
example=200,
* ),
* @SWG\Property(
* property="msg",
* type="string",
example="二级栏目返回成功",
* ),
@SWG\Property(
* property="data",
* type="object",
example="[{cate_id:5,cate_name:'栏目1',cate_ison:1},{cate_id:6,cate_name:'栏目2',cate_ison:0}]",
* ),
*
* )),
@SWG\Response(response="201", description="数据为空", @SWG\Schema(
* required={""},
* @SWG\Property(
* property="code",
* type="integer",
example=201,
* ),
* @SWG\Property(
* property="msg",
* type="string",
example="数据为空!",
* ),
*
* )),
@SWG\Response(response="400", description="非法请求,不是ajax请求", @SWG\Schema(
* required={""},
* @SWG\Property(
* property="code",
* type="integer",
example=400,
* ),
* @SWG\Property(
* property="msg",
* type="string",
example="非法请求",
* ),
*
* )),
* ) */
//二级栏目接口
public function getSonnav(){ if(request()->isAjax()){ $cate_id=input('id'); $data=Db::table('re_cate')->where('cate_pid',$cate_id)->field('cate_id,cate_name,cate_ison')->select(); if(!empty($data)){ return json(['code'=>200,'msg'=>'二级栏目返回成功','data'=>$data]);
}else{ return json(['code'=>201,'msg'=>'无二级栏目']);
}
}else{ return json(['code'=>400,'msg'=>'非法请求']);
}
} /**
*@SWG\Post(path="/api/getarticlelist", tags={"Api"},
* summary="获取文章列表",
* description="根据栏目id获取文章列表(需要参数:栏目id,页码,一页显示文章数量)",
@SWG\Parameter(
* description="ajax请求要加上X-Requested-With:XMLHttpRequest头字段",
* format="string",
* in="header",
* name="X-Requested-With",
* required=true,
* type="string",
default="XMLHttpRequest",
*
* ),
* @SWG\Parameter(name="id",type="integer", required=true, in="formData",
* description="栏目id"
* ),
@SWG\Parameter(name="p",type="integer", required=true, in="formData",
* description="页码"
* ),
@SWG\Parameter(name="num",type="integer", required=true, in="formData",
* description="每页文章数量"
* ),
@SWG\Response(response="200", description="操作成功", @SWG\Schema(
* required={""},
* @SWG\Property(
* property="code",
* type="integer",
example=200,
* ),
* @SWG\Property(
* property="msg",
* type="string",
example="文章列表返回成功",
* ),
@SWG\Property(
* property="data",
* type="object",
example="{total:null,per_page:5,current_page:1,last_page:null,data:[{ar_id:1,cate_id:10,ar_title:'文章标题一',ar_keywords:'文章关键字',ar_pic:'url',ar_content:'文章内容',ar_ison:1}]}",
* ),
*
* )),
@SWG\Response(response="201", description="数据为空", @SWG\Schema(
* required={""},
* @SWG\Property(
* property="code",
* type="integer",
example=201,
* ),
* @SWG\Property(
* property="msg",
* type="string",
example="数据为空!",
* ),
*
* )),
@SWG\Response(response="400", description="非法请求,不是ajax请求", @SWG\Schema(
* required={""},
* @SWG\Property(
* property="code",
* type="integer",
example=400,
* ),
* @SWG\Property(
* property="msg",
* type="string",
example="非法请求",
* ),
*
* )),
* ) */
//指定栏目文章列表(需要参数:栏目id,页码,一页显示文章数量)
/*
返回json格式
{
"code": 200,
"msg": "文章返回成功",
"data": {
"total": null,
"per_page": "1",
"current_page": 1,
"last_page": null,
"data": [
{
"ar_id": 1,
"cate_id": 10,
"ar_title": "title",
"ar_keywords": "k,e,y",
"ar_pic": "public/static/uploads/20190902\\98edeb3d27fe4342da8b07d5ae3e98de.jpg",
"ar_content": "<p>内容<br/></p>",
"ar_ison": 1
}
]
}
} */
public function getArticlelist(){ if(request()->isAjax()){ $cate_id=input('id'); $page=input('p'); $number=input('num'); $data=Db::table('re_article')->where('cate_id',$cate_id)->paginate($number,true,['page'=>$page]); if(!empty($data)){
return json(['code'=>200,'msg'=>'文章返回成功','data'=>$data]);
}else{ return json(['code'=>201,'msg'=>'没有数据了']);
}
}else{ return json(['code'=>400,'msg'=>'非法请求']);
}
} /**
*@SWG\Post(path="/api/getarticlecontent", tags={"Api"},
* summary="获取文章内容",
* description="根据文章id获取文章信息",
@SWG\Parameter(
* description="ajax请求要加上X-Requested-With:XMLHttpRequest头字段",
* format="string",
* in="header",
* name="X-Requested-With",
* required=true,
* type="string",
default="XMLHttpRequest",
*
* ),
* @SWG\Parameter(name="id",type="integer", required=true, in="formData",
* description="文章id"
* ),
@SWG\Response(response="200", description="操作成功", @SWG\Schema(
* required={""},
* @SWG\Property(
* property="code",
* type="integer",
example=200,
* ),
* @SWG\Property(
* property="msg",
* type="string",
example="文章返回成功",
* ),
@SWG\Property(
* property="data",
* type="object",
example="{ar_id:1,ar_title:'文章1',ar_pic:'url',ar_keywords:'文章关键字',ar_content:'文章内容',ar_ison:1}",
* ),
*
* )),
@SWG\Response(response="201", description="数据为空", @SWG\Schema(
* required={""},
* @SWG\Property(
* property="code",
* type="integer",
example=201,
* ),
* @SWG\Property(
* property="msg",
* type="string",
example="数据为空!",
* ),
*
* )),
@SWG\Response(response="400", description="非法请求,不是ajax请求", @SWG\Schema(
* required={""},
* @SWG\Property(
* property="code",
* type="integer",
example=400,
* ),
* @SWG\Property(
* property="msg",
* type="string",
example="非法请求",
* ),
*
* )),
* ) */
//获取指定文章内容
public function getArticlecontent(){ if(request()->isAjax()){ $ar_id=input('id'); $data=Db::table('re_article')->where('ar_id',$ar_id)->find(); if(!empty($data)){ return json(['code'=>200,'msg'=>'文章返回成功','data'=>$data]);
}else{ return json(['code'=>201,'msg'=>'无此文章']);
}
}else{ return json(['code'=>400,'msg'=>'非法请求']);
}
}
}
