示例:www.zouke1220.xyz
本文档是参考网上的然后根据公司需要对代码进行了抽取和优化(主要是加了标题栏和对输出进行了格式化输出,更换了页面渲染方式(改为直接使用php进行渲染,原来的是使用了模板引擎),可读性较好),配置简单,读取方便,和项目耦合性较小,只需要将api_view这个文件夹放到和项目同级就可以使用,接口文档只有100多k大小
一.apiview目录结构说明
二.读取注释自动生成api接口文档和api接口调试
1.控制器上的注释写法
按照下图格式写接口方法注释(主是在控制器上面和方法上)
2.写读控制器方法注释的方法
common.php
<?php //@class 得到类标题 function get_class_title($str){ $target = '/@classs(.*)s/'; $res = preg_match($target,$str,$result); if($res == 1){ return $result[1]; } } //@title 得到方法标题 function get_title($str){ $target = '/@titles(.*)s/'; $res = preg_match($target,$str,$result); if($res == 1){ return $result[1]; } } //@param age 否 int 年龄参数的说明 function get_param($str){ $target = '/@params(.*)s/'; $res = preg_match_all($target,$str,$result); if($res){ $new_result = array(); foreach($result[1] as $k=>$v){ $new_array = explode(' ',$v);//print_r($new_array); if(is_array($new_array) && !empty($new_array)){ $new_result[] = $new_array; } } return $new_result; } } //@return 返回数据实例 function get_return($str){ $target = '/@returns(.*)s/'; $res = preg_match($target,$str,$result); if($res == 1){ return $result[1]; } } //@return_param_explain 返回数据说明 function get_return_param_explain($str){ $target = '/@return_param_explains(.*)s/'; $res = preg_match($target,$str,$result); if($res){ $new_result = array(); $new_array = explode(' ',trim($result[1])); foreach($new_array as $k=>$v){ if($v==null){ unset($new_array[$k]); } } if(is_array($new_array) && !empty($new_array)){ $new_result[] = $new_array; } return $new_result; } } //@example 调用示例 function get_example($str){ $target = '/@examples(.*)s/'; $res = preg_match($target,$str,$result); if($res == 1){ return $result[1]; } } //@method POST function get_method($str){ $target = '/@methods(.*)s/'; $res = preg_match($target,$str,$result); if($res == 1){ return $result[1]; } } //@author 开发者 function get_author($str){ $target = '/@authors(.*)s/'; $res = preg_match($target,$str,$result); if($res == 1){ return $result[1]; } } //组装数据 function parsing($str){ $target = '//*[sS]*?*//'; $res = preg_match_all($target,$str,$result); if($res){ $new_result = array(); foreach($result[0] as $k=>$v){ if($k == 0){ $new_result['title'] = get_class_title($v); }else{ $example=get_example($v); $new_result['api'][$k]['title'] = get_title($v); $new_result['api'][$k]['param'] = get_param($v); $new_result['api'][$k]['return']= get_return($v); $new_result['api'][$k]['return_param_explain']=get_return_param_explain($v); $new_result['api'][$k]['example']= $example; $new_result['api'][$k]['method'] = get_method($v); $new_result['api'][$k]['author'] = get_author($v); $in=stripos($example,"/"); $in2=stripos($example,"?"); $controller=substr($example,0,$in); $action=substr($example,$in+1,$in2-$in-1); $new_result['api'][$k]['controller']=strtolower($controller); $new_result['api'][$k]['action']=$action; } } return $new_result; } }
3.将接口文档放置在和项目同级(当然了也可以不同级)
三.配置文件修改
config.php
<?php $conf=array( 'app'=>array('url'=>'/webApp/Application/Webapp/Controller/*.php','title'=>'APP','domain'=>'app.zouke.com'), 'h5'=>array('url'=>'/wg/Application/Apph5/Controller/*.php','title'=>'H5','domain'=>'h5.zouke.com'), 'manage'=>array('url'=>'/manage/Application/Fmall_cloud/Controller/*.php','title'=>'管理后台','domain'=>'fenglei_manage.com'), 'inner_open'=>array('url'=>'/inner_open/Application/Inner/Model/*.php','title'=>'java调php接口','domain'=>'inner.test.feelee.cc'), );
上述配置文件的配置应该配置自己本地真实的配置,url为项目控制器所在的文件,这里有4个项目
注:domain域名前不要加http://
四.api接口文档效果图-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
上面的返回结果实例要格式化输出,在index.php里引入格式化文件jsonFormat.php,在index.html调用格式化函数
jsonFormat.php
<?php /** Json数据格式化 * @param Mixed $json 数据 * @return JSON */ function format_json($json, $html = false) { $tabcount = 0; $result = ''; $inquote = false; $ignorenext = false; if ($html) { $tab = " "; $newline = "<br/>"; } else { $tab = " "; $newline = " "; } for($i = 0; $i < strlen($json); $i++) { $char = $json[$i]; if ($ignorenext) { $result .= $char; $ignorenext = false; } else { switch($char) { case '{': $tabcount++; $result .= $char . $newline . str_repeat($tab, $tabcount); break; case '}': $tabcount--; $result = trim($result) . $newline . str_repeat($tab, $tabcount) . $char; break; case ',': $result .= $char . $newline . str_repeat($tab, $tabcount); break; case '"': $inquote = !$inquote; $result .= $char; break; case '\': if ($inquote) $ignorenext = true; $result .= $char; break; default: $result .= $char; } } } return $result; }
index.html
<!DOCTYPE html> <html lang="zh-CN" dir="ltr" class="client-nojs"> <head> <meta charset="UTF-8" /> <title>开发者接口文档</title> <meta http-equiv="X-UA-Compatible" content="IE=EDGE" /> <link rel="stylesheet" href="./view/front/css/load.css" /> <style> a:lang(ar),a:lang(kk-arab),a:lang(mzn),a:lang(ps),a:lang(ur){text-decoration:none} table { border-collapse: collapse; border-spacing: 0; 99%; border: 1px solid #b5c5da; border-top: 3px solid #b5c5da; margin: 10px 10px; } tbody { display: table-row-group; vertical-align: middle; border-color: inherit; } .grayBlueBg { background: #f4f4f5; } tr { display: table-row; vertical-align: inherit; border-color: inherit; } td { height: 30px; line-height: 30px; border: 1px solid #b5c5da; text-align: center; } th { border: none; border-right: 1px solid #b5c5da; } </style> </head> <body class="mediawiki ltr sitedir-ltr ns-0 ns-subject skin-vector action-view vector-animateLayout"> <!-- header --> <div class="headWrap"> <div class="header" id="header"> <div class="inner" style=" 1270px;"> <a class="logo" href="javascript:;" style="font-size: 26px;margin-right:200px;">API接口文档</a> <?php $i=0; $cn=count($conf); foreach($conf as $k=>$v){ $i++; ?> <a class="<?php echo $k?>" href="?par=<?php echo $k?>" style="font-size: 20px;"><?php echo $v['title']?></a> <?php if($i != $cn) echo " | ";?> <?php } ?> <a class="" href="index.php?par=<?php echo $params?>" style="font-size: 20px;;margin-left:100px;">API接口调试</a> <a class="" href="log.php?par=<?php echo $params?>" style="font-size: 20px;;margin-left:20px;">log记录</a> </div> </div> </div> <!-- main content container --> <div class="mainwrapper" style=" 1270px;"> <div class="inner"> <div id="content" class="mw-body scroll-bar-wrap" role="main"> <?php foreach($data as $k=>$v){ if(!empty($v['api'])){ foreach($v['api'] as $k2=>$v2){ if($k == 1 || $k2 == 1){ ?> <div class="scroll-box content_data" id="content_<?php echo $k?>_<?php echo $k2?>" style="display: none"> <?php }else{ ?> <div class="scroll-box content_data" id="content_<?php echo $k?>_<?php echo $k2?>"> <?php }?> <a id="top"></a> <div id="mw-js-message" style="display:none;"></div> <div class="content_hd"> <h2 id="firstHeading" class="firstHeading" style="100%;"><?php echo $v2['title']." 开发者:".$v2['author'];?></h2> </div> <div id="bodyContent" class="bodyContent"> <div id="mw-content-text" lang="zh-CN" dir="ltr" class="mw-content-ltr"> <ul><li>请求方式</li></ul> <pre><?php echo $v2['method']?></pre> <ul><li>请求示例 <a href="index.php?par=<?php echo $params?>&controller=<?php echo $v2['controller']?>&action=<?php echo $v2['action']?>">去调试</a></li></ul> <pre><?php echo $conf[$params]['domain']."/".$v2['example']?></pre> <ul><li>接收参数说明</li></ul> <table border="1" cellspacing="0" cellpadding="3" align="center" width="640px"> <tr class="grayBlueBg"> <th>参数</th> <th>是否必须</th> <th>类型</th> <th>说明</th> </tr> <?php if(!empty($v2['param'])){ foreach($v2['param'] as $k3=>$v3){ if($k3 % 2 == 0){ ?> <tr class="grayBlueBg"> <?php }else{?> <tr> <?php }?> <td align="center"><?php echo $v3[0]?></td> <td align="center"><?php echo $v3[1]?></td> <td align="center"><?php echo $v3[2]?></td> <td align="center"><?php echo $v3[3]?></td> </tr> <?php } } ?> </table> <ul> <li>返回结果实例</li> </ul> <pre id="return" readonly="readonly"> <?php echo "<br>"; if(empty($v2['return'])){ if(!empty($res_info)){ echo format_json($res_info[$v2['controller'].'/'.$v2['action']]); } } else { echo format_json($v2['return']); } echo "<br>"; ?> </pre> <ul> <li>返回参数说明</li> </ul> <pre> <?php if(!empty($v2['return_param_explain'][0])){ foreach($v2['return_param_explain'][0] as $k3=>$v3){ echo "<br>".$v3."<br>"; } }else{ echo "<br>无<br>"; } ?> </pre> </div> <div id='catlinks' class='catlinks catlinks-allhidden'></div> <div class="visualClear"></div> </div> </div> <?php } } } ?> </div> <!-- nav --> <div id="mw-panel" class="collapsible-nav scroll-bar-wrap"> <div class="scroll-box"> <div class="portal" > <h5 class="category separator">API_<?php echo $title;?></h5> </div> <?php foreach($data as $k=>$v){?> <div class="portal" role="navigation" > <h5><span class="portal_arrow"></span><?php echo $v['title']?></h5> <div class="body" > <ul> <?php if(!empty($v['api'])){ foreach($v['api'] as $k2=>$v2){ ?> <li ><a data-id="<?php echo $k?>_<?php echo $k2?>" title="<?php echo $v2['title']?>" class="item" href="JavaScript:;"><?php echo $v2['title']?></a></li> <?php } }else{ ?> <li><a data-id="0_0" class="item" href="JavaScript:;"></a></li> <?php } ?> </ul> </div> </div> <?php }?> </div> <div class="cover-bar"></div> </div> </div> </div> <!-- footer --> <div id="footer" role="contentinfo" class="footer"> <p class="copyright">Copyright @ 2017 邹柯. All Rights Reserved.</p> </div> <script type="text/javascript" src='./view/front/js/jquery-min.js'></script> <script type="text/javascript" src='./view/front/js/wiki.js'></script> <script> var type = GetQueryString('par'); $(function(){ $('.'+type).css('color','black'); $('.'+type).css('background-color','#EAEAEA'); }); $('.item').click(function(){ var id = $(this).data('id'); $('.content_data').hide(); $('#content_'+id).show(); }); function GetQueryString(name){ var reg = new RegExp("(^|&)"+ name +"=([^&]*)(&|$)"); var r = window.location.search.substr(1).match(reg); if(r!=null)return unescape(r[2]); return null; } </script> </body> </html>
apiview.php
<?php define('ACC',true); header('content-type:text/html;charset=utf-8'); require("./tool/jsonFormat.php"); require('./include/init.php'); require("./tool/common.php"); require("./tool/config.php"); $params = $_GET['par']; if(empty($params)){ //变动项 Header("Location: ?par=app"); } include('./data/return_json_'.$params.'.php'); $base_url= substr(dirname(__FILE__),0,-9); $title=$conf[$params]['title']; $file_url=$conf[$params]['url']; $path =$base_url.$file_url; $res = glob($path); $result = array(); if($res){ foreach($res as $k=>$v){ $str = file_get_contents($v); $result[] = parsing($str); } } //去除类注释标题为空的项 foreach($result as $k=>$v){ if(empty($v['title'])){ unset($result[$k]); } if(!empty($v['api'])){ foreach($v['api'] as $k2=>$v2){ //去除方法注释标题为空的项 if(empty($v2['title'])){ unset($result[$k]['api'][$k2]); } } }else{ //去除api为空的项 unset($result[$k]['api']); } } $result=array_values($result); $data=$result; include(ROOT . 'view/front/index.html'); ?>
注:这个变动项,需要根据项目实际情况进行配置修改,其他文件区域不用修改
五.接口调试文档效果图-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
下面是开发的接口调试文档,方便易用,都是读取的接口方法上的注释自动生成
点击POST或GET或JSON-POST生成的结果会出现在右侧,格式化json输出
index.html
<!doctype html> <head data-live-domain="jquery.com" > <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <meta charset="utf-8" /> <title>API接口测试文档</title> <script src="./view/front/js/jquery-min.js"></script> <script src="./view/front/js/init.js"></script> <script src="./view/front/js/md5.js"></script> <link rel="stylesheet" href="./view/front/css/load.css" /> <style> .content-box { font-size:0; } #out-put-view { 45%; font-size:14px; text-align: center; display:inline-block; margin-left:30px; margin-top:80px; } #out-put-view #api_iframe { 100%; min-height: 710px; background-color: #FFFFFE; border-radius: 5px; overflow:scroll; } #form-box { 45%; font-size:14px; border-radius: 5px; background-color: #FFFFFE; display:inline-block; vertical-align: top; margin-left:80px; margin-top:80px; } #form-box form { 95%; min-height: 600px; padding: 10px; height: 350px; overflow: auto; } #p-box { height: 340px; } #btn-box { height:30px; padding-left:10px; } #btn-box input { margin: 0; } #explan { margin: 10px; border: 1px #333 dotted; padding: 5px; font-size: 20px; } #footer{ position:fixed; bottom:0; } .bs-example bs-example-standalone { word-wrap: break-word; } .clear{ clear:both; } .headWrap{ position:fixed; top:0; } </style> </head> <body> <!-- header --> <div class="headWrap" style="margin-bottom:40px;"> <div class="header" id="header"> <div class="inner" style=" 1270px;"> <a class="logo" href="javascript:;" style="font-size: 26px;margin-right:200px;">API接口调试</a> <?php $i=0; $cn=count($conf); foreach($conf as $k=>$v){ $i++; ?> <a class="<?php echo $k?>" href="?par=<?php echo $k?>" style="font-size: 20px;"><?php echo $v['title']?></a> <?php if($i != $cn) echo " | ";?> <?php } ?> <a class="" href="apiview.php?par=<?php echo $params?>" style="font-size: 20px;;margin-left:100px;">API接口文档</a> <a class="" href="log.php?par=<?php echo $params?>" style="font-size: 20px;;margin-left:20px;">log记录</a> </div> </div> </div> <div class="clear"></div> <div class="content-box2" style="min-1500px;"> <div id="form-box" style="float:left"> <div style="padding: 10px 0 0 10px;"> <div> <label>控制器: </label><select id="c"></select> <label>方法: </label><select id="a"></select> <select id="loadAPI-Base-URL" hidden></select> <input id="POST-BTN" type="button" value="POST" /> <input id="GET-BTN" type="button" value="GET" /> <input id="JSON-BTN" type="button" value="JSON-POST" /> </div> <div id="explan"><?php echo $conf[$params]['title'];?>接口</div> </div> <form target="api_iframe"><table id="p-box"></table></form> </div> <div id="out-put-view" style="float:left;"> <div name="api_iframe" id="api_iframe"> </div> </div> </div> <div class="clear"></div> <!-- footer --> <div id="footer" role="contentinfo" class="footer" style="100%"> <p class="copyright">Copyright @ 2017 邹柯. All Rights Reserved.</p> </div> </body> <script type="text/javascript"> var API_Base_URLS = <?php echo $url_res;?>; var API_Doc=<?php echo $res;?>; var type = GetQueryString('par'); $(function(){ $('.'+type).css('color','black'); $('.'+type).css('background-color','#EAEAEA'); }); $('.item').click(function(){ var id = $(this).data('id'); $('.content_data').hide(); $('#content_'+id).show(); }); function GetQueryString(name){ var reg = new RegExp("(^|&)"+ name +"=([^&]*)(&|$)"); var r = window.location.search.substr(1).match(reg); if(r!=null)return unescape(r[2]); return null; } </script> </html>
init.js
$(document).ready(function(){ setC(); setUrl(); function setUrl(){ $u = $("#loadAPI-Base-URL"); for(var i=0;i<API_Base_URLS.length;i++) { $u.append('<option value ="'+ API_Base_URLS[i] +'">'+ API_Base_URLS[i] +'</option>'); } } function setC(){ var $c = $("#c").html('<option id="C" value ="'+ null +'">请选择控制器</option>'); var $a = $("#a").html('<option id="A" value ="'+ null +'">请选择执行器</option>'); var cmap = {}; for(var i=0;i<API_Doc.length;i++){ cmap[API_Doc[i].parameter.c] = API_Doc[i].parameter.c; } var controller=GetQueryString('controller'); for(var k in cmap){ if(controller==k){ $c.append('<option id="C" value ="'+ k +'" selected="selected">'+ cmap[k] +'</option>'); }else{ $c.append('<option id="C" value ="'+ k +'">'+ cmap[k] +'</option>'); } } } function setA(c){ var $a = $("#a").html('<option id="A" value ="'+ null +'">请选择执行器</option>'); var amap = {}; for(var i=0;i<API_Doc.length;i++){ if(API_Doc[i].parameter.c == c){ amap[API_Doc[i].parameter.a] = API_Doc[i].parameter.a; } } var action=GetQueryString('action'); for(var k in amap){ if(action==k){ $a.append('<option id="A" value ="'+ k +'" selected="selected">'+ amap[k] +'</option>'); }else{ $a.append('<option id="A" value ="'+ k +'">'+ amap[k] +'</option>'); } } } function GetQueryString(name){ var reg = new RegExp("(^|&)"+ name +"=([^&]*)(&|$)"); var r = window.location.search.substr(1).match(reg); if(r!=null)return unescape(r[2]); return null; } function setP(c,a){ for(var i=0;i<API_Doc.length;i++){ if(API_Doc[i].parameter.c == c && API_Doc[i].parameter.a == a){ var $explan = $("#explan").html(API_Doc[i].explan); var api = API_Doc[i]; var $pbox = $("#p-box"); for(var k in API_Doc[i].parameter){ if(k=="d" || k=="c" || k=="a"){ continue; }else{ var $p = $("<input/>").attr("name",k).attr("value",null).attr("style","600px;").attr("placeholder",API_Doc[i].parameter[k]); var $tr = $("<tr></tr>"); var $m = $("<a class='pick' tar='p-" + k + "' data-t='d' >PICK</a>"); $("<td>"+ k +"</td>").appendTo($tr); $("<td></td>").append($p).appendTo($tr).attr("id","p-"+k); $("<td></td>").append($m).appendTo($tr); $pbox.append($tr); } } } } } $(document).on("click",".pick",function(){ if($(this).data("t")=="d"){ $(this).data("t","s"); $td = $("#"+$(this).attr("tar")); $td.data("input",$td.html()); $td.html("Be Del-ed!"); }else{ $(this).data("t","d"); $td = $("#"+$(this).attr("tar")); $td.html($td.data("input")); } }); if($("#c option:selected").val() !=null){ setA($("#c option:selected").val()); if($("#c option:selected").val() !=null){ setP($("#c option:selected").val(),$("#a option:selected").val()); } } $("#c").change(function(){ $("#explan").html(""); $("#p-box").html(""); setA($("#c option:selected").val()); }); $("#a").change(function(){ $("#explan").html(""); $("#p-box").html(""); setP($("#c option:selected").val(),$("#a option:selected").val()); }); $("#POST-BTN").click(function(){ $("#form-box form").attr("method","post"); $("#form-box form").attr("action","http://"+$("#loadAPI-Base-URL option:selected").val()+'/'+$("#c option:selected").val()+'/'+$("#a option:selected").val()); $("#form-box form").submit(); /* var url = "http://"+$("#loadAPI-Base-URL option:selected").val()+'/'+$("#c option:selected").val()+'/'+$("#a option:selected").val(); var params = get_all_parameter(); $.ajax({ type: "POST", url: url, data: params, success: function (data) { var mes=JSON.stringify(data, null, 2); $("#api_iframe").empty(); $("#api_iframe").append("<textarea style=' 100%;min-height: 710px;overflow: auto; border:solid 0px #000;'>" + mes + "</textarea>"); } }); */ }); $("#GET-BTN").click(function(){ //$("#form-box form").attr("method","get"); //$("#form-box form").attr("action","http://"+$("#loadAPI-Base-URL option:selected").val()+'/'+$("#c option:selected").val()+'/'+$("#a option:selected").val()); //$("#form-box form").submit(); var url = "http://"+$("#loadAPI-Base-URL option:selected").val()+'/'+$("#c option:selected").val()+'/'+$("#a option:selected").val(); var params = get_all_parameter(); $.ajax({ type: "GET", url: url, data: params, success: function (data) { var mes=JSON.stringify(data, null, 2); $("#api_iframe").empty(); $("#api_iframe").append("<textarea style=' 100%;min-height: 710px;overflow: auto; border:solid 0px #000;'>" + mes + "</textarea>"); } }); }); $("#JSON-BTN").click(function(){ var url = "http://"+$("#loadAPI-Base-URL option:selected").val()+'/'+$("#c option:selected").val()+'/'+$("#a option:selected").val(); var params = get_all_parameter(); var myJson = JSON.stringify(params); //var headers = get_all_header(); $.ajax({ type: "POST", url: url, data: myJson, dataType: "json", headers:{'username':'zouke','sign':'11111','Content-Type':'application/json; charset=utf-8'}, success: function (data) { var mes=JSON.stringify(data, null, 2); $("#api_iframe").empty(); $("#api_iframe").append("<textarea style=' 100%;min-height: 710px;overflow: auto; border:solid 0px #000;'>" + mes + "</textarea>"); } }); }); //获取所有POST-json提交的值 function get_all_parameter() { var params = {}; $("#p-box input").each(function(){ var name = $(this).attr("name"); var value = $(this).val(); params[name]=value; }); return params } //获取所有POST提交的头信息 function get_all_header() { var headers = new Array(); $("#p-header input").each(function() { var name = $(this).attr("name"); var value = $(this).val(); headers.push({name: name,value: value}); }); return headers } });
index.php
<?php define('ACC',true); header('content-type:text/html;charset=utf-8'); require("./tool/jsonFormat.php"); require('./include/init.php'); require("./tool/common.php"); require("./tool/config.php"); error_reporting(E_ALL^E_NOTICE^E_WARNING); $params = $_GET['par']; if(empty($params)){ //变动项 Header("Location: ?par=app"); } $base_url= substr(dirname(__FILE__),0,-9); $title=$conf[$params]['title']; $file_url=$conf[$params]['url']; $path =$base_url.$file_url; $res = glob($path); $result = array(); if($res){ foreach($res as $k=>$v){ $str = file_get_contents($v); $result[] = parsing($str); } } //去除类注释标题为空的项 foreach($result as $k=>$v){ if(empty($v['title'])){ unset($result[$k]); } if(!empty($v['api'])){ foreach($v['api'] as $k2=>$v2){ //去除方法注释标题为空的项 if(empty($v2['title'])){ unset($result[$k]['api'][$k2]); } } }else{ //去除api为空的项 unset($result[$k]['api']); } } $data=array_values($result); $data2=array(); foreach($data as $k=>$v){ $arr2=array(); foreach($v['api'] as $k2=>$v2){ $in=stripos($v2['example'],"/"); $in2=stripos($v2['example'],"?"); $controller=substr($v2['example'],0,$in); $action=substr($v2['example'],$in+1,$in2-$in-1); $arr2[$k2]=array( 'name'=>trim($v['title']), 'explan'=>trim($v2['title']), 'path'=>trim($v2['example']), 'method'=>trim($v2['method']), 'parameter'=>array( 'c'=>strtolower($controller), 'a'=>$action, ) ); if(!empty($v2['param'])){ foreach($v2['param'] as $k3=>$v3){ $sr=trim($v3[0]); $arr2[$k2]['parameter'][$sr]="(".trim($v3[1]).")".trim($v3[3]); } } } /* $arr['name']=trim($params); $arr['explan']=trim($v['title']); $arr['path']="--------------------"; $arr['method']="get/post"; $arr['parameter']['c']="---------".trim($v['title'])."----------"; $arr2=array_merge($arr2,array($arr)); $first=array_pop($arr2); $arr2=array_values(array_merge(array($first),$arr2)); */ $data2[$k]=$arr2; } static $res_info=array(); foreach($data2 as $k=>$v){ $res_info=array_merge($res_info,$v); } $res=json_encode($res_info,true); $url=array($conf[$params]['domain']); $url_res=json_encode($url,true); include(ROOT . 'view/front/debug.html'); ?>
六.log记录效果图------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
log.html
<!DOCTYPE html> <html lang="zh-CN" dir="ltr" class="client-nojs"> <head> <meta charset="UTF-8" /> <title>开发者接口文档</title> <meta http-equiv="X-UA-Compatible" content="IE=EDGE" /> <link rel="stylesheet" href="./view/front/css/apilog/semantic.min.css"> <link rel="stylesheet" href="./view/front/css/apilog/table.min.css"> <link rel="stylesheet" href="./view/front/css/apilog/container.min.css"> <link rel="stylesheet" href="./view/front/css/apilog/message.min.css"> <style type="text/css"> a{ color:#c9c9c9; } #header{ position:fixed; top:0; left:0; z-index:99; min- auto; 100%; background: #FFF; text-align:center; height:60px; line-height:60px; border-bottom: 1px solid #c3c3c3; box-shadow: 0 1px 1px rgba(0,0,0,0.15),inset 0 -1px 0 0 #fcfcfc; -moz-box-shadow: 0 1px 1px rgba(0,0,0,0.15),inset 0 -1px 0 0 #fcfcfc; -webkit-box-shadow: 0 1px 1px rgba(0,0,0,0.15),inset 0 -1px 0 0 #fcfcfc; } #header .line{ color:#c9c9c9; } .btn{ position:fixed; top:15px; right:300px; border-radius:4px; height:40px; 60px; line-height:40px; border:1px solid #c9c9c9; } footer{ padding: 24px 0; color: #dadada; font-size: 14px; text-align: center; background-color: #727171; margin-top:200px; position: fixed; bottom: 0; 100%; } </style> </head> <body class="mediawiki ltr sitedir-ltr ns-0 ns-subject skin-vector action-view vector-animateLayout"> <header class="header" id="header"> <div class="inner" style=" 1570px;"> <a class="logo" href="javascript:;" style="font-size: 26px;margin-right:200px;">log记录</a> <?php $i=0; $cn=count($conf); foreach($conf as $k=>$v){ $i++; ?> <a class="<?php echo $k?>" href="?par=<?php echo $k?>" style="font-size: 20px;"><?php echo $v['title']?></a> <span class="line"><?php if($i != $cn) echo " | ";?></span> <?php } ?> <a class="" href="index.php?par=<?php echo $params?>" style="font-size: 20px;;margin-left:100px;">API接口调试</a> <a class="" href="apiview.php?par=<?php echo $params?>" style="font-size: 20px;;margin-left:20px;">API接口文档</a> <!--<a class="btn"href="file_open.php" style="font-size: 20px;;margin-left:20px;">添加</a>--> </div> </header> <?php foreach($data as $k=>$v){?> <div class="ui text container" style="max- none !important;margin-top:100px;1770px;" id=<?php echo $v['version']?>> <div class="ui floating message"> <h2 class="ui header"><?php echo $v['version']?></h2><br> <span class="ui teal tag label"><?php echo $v['date']?></span> <div class="ui raised segment"> <span class="ui red ribbon label">更新说明</span> <div class="ui message"> <h3>备注</h3> <pre> <?php foreach($v['area'] as $k4=>$v4){?> <h4><i style="color: red">(<?php echo $k4+1;?>) </i><?php echo $v4['desc_pos']?></h4><?php echo $v4['title']?> <?php }?> </pre> </div> </div> <h3>更新内容:</h3> <table class="ui green celled striped table"> <thead> <tr> <th>序号</th> <th>接口名称</th> <th>文档位置</th> <th>更新类型</th> <th>备注</th> </tr> </thead> <tbody> <?php foreach($v['param'] as $k3=>$v3){?> <tr> <td><?php echo $k3+1;?></td> <td><?php echo $v3['interface_name']?></td> <td><?php echo $v3['doc_posion']?></td> <td><?php echo $v3['type']?></td> <td><?php echo $v3['desc']?></td> </tr> <?php }?> </tbody> </table> </div> </div> <?php }?> </div> <script type="text/javascript" src='./view/front/js/jquery-min.js'></script> <script> var type = GetQueryString('par'); $(function(){ $('.'+type).css('color','black'); $('.'+type).css('background-color','#EAEAEA'); }); $('.item').click(function(){ var id = $(this).data('id'); $('.content_data').hide(); $('#content_'+id).show(); }); function GetQueryString(name){ var reg = new RegExp("(^|&)"+ name +"=([^&]*)(&|$)"); var r = window.location.search.substr(1).match(reg); if(r!=null)return unescape(r[2]); return null; } </script> </body> </html>
log.php
<?php define('ACC',true); header('content-type:text/html;charset=utf-8'); require('./include/init.php'); require("./tool/config.php"); $params = $_GET['par']; if(empty($params)){ //变动项 Header("Location: ?par=app"); } include('./data/log_info_'.$params.'.php'); include(ROOT . 'view/front/log.html'); ?>
七.优化
由于整个接口文档和log记录没有做管理后台的操作,所以log记录里的数据都是直接写在文件里读取的,还有上面提到的api接口文档里的返回结果实例注释写到控制器里会造成代码比较多比较乱,所以这块的返回的数据也直接读文件里的数据。
1.log记录里的数据存储在文件内
log_info_h5.php
由于没有做管理后台,也没有存储在数据库中,所以直接写在文件中读取,如果有多个版本,数组后面按照下面的格式直接加就可以咯,格式如下:
<?php $data=array( array( 'version'=>'V3.7.0', //版本号 'date'=>'2017-12-25', //日期 'param'=>array( array( 'interface_name'=>'Cloud/storeHomeList', //接口名称 'doc_posion'=>'云店/店铺首页', //文档位置 'type'=>'修改', //更新类型 'desc'=>'新增接收参数:version、keywords,当version=3.7.0时,返回的数据结构新增cate_info_search' //备注(备注少时写到这个地方) ), array( 'interface_name'=>'Cloud/storeGoodsManage', 'doc_posion'=>'云店/店铺商品管理 ', 'type'=>'修改', 'desc'=>'新增接收参数:version、keywords,当version=3.7.0时,返回的数据结构新增cate_info_search' ), array( 'interface_name'=>'Cloud/goods', 'doc_posion'=>'云店/店铺商品管理--渲染 ', 'type'=>'修改', 'desc'=>'新增接收参数:version、keywords,当version=3.7.0时,返回的数据结构新增cate_info_search' ), ), 'area'=>array( //备注多时写到这个地方 array( 'title'=> '商品分类接口--广告跳转返回字段redirect_url的具体字段内容: ad_link_type为1--商品详情页--redirect_url={"itemid":"商品sku_id","sno":"商品sku编号","store_id":"店铺id"} ad_link_type为2--关联模块--redirect_url={"plate_type":"关联模块类型--001限时蜂抢、002新品、003蜂神榜、004蜂觅、005首页"} ad_link_type为3--商品列表--redirect_url={"type":"2(固定2)","brand_id":"品牌id--格式:3,4,5","cate_type":"分类id--格式:44,45,46"} ad_link_type为4--H5页面--redirect_url={"url":"h5页面url地址"} ad_link_type为5--蜂雷头条详情页--redirect_url={"id":"67","title":"蜂雷头条标题"}', 'desc_pos'=>'店铺首页', ), ), ),
2.api接口文档里的数据存储在文件内
return_json_app.php
由于返回的json串可能有时比较多,类似上面的一大坨,所以以后返回结果实例就不写在方法注释里读取里,直接写在文件里读取,格式如下:
<?php $res_info=array( //控制器/方法 'app/kai_pin_ad'=>'{"msg":"加载成功!","status":"0","result":[{"id":"7","ad_effective_start":"2017-12-15 13:33:37","ad_effective_end":"2017-12-15 21:22:37","ad_link_type":"3","second":"4","ad_url":"http://img.test.feelee.cc/Public/Uploads/ad/thumb/640_960_1002883101.jpg","redirect_url":{"id":106,"title":"广告详情","content":"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF","url":"common/rich_text?id=106&type=2"},"is_deleted":"1"},{"id":"14","ad_effective_start":"2017-12-10 00:00:00","ad_effective_end":"2017-12-10 19:00:00","ad_link_type":"4","second":"10","ad_url":"http://img.test.feelee.cc/Public/Uploads/ad/thumb/640_960_1002883101.jpg","redirect_url":{"url":"www.baidu.com"},"is_deleted":"1"},{"id":"15","ad_effective_start":"2016-12-09 00:00:00","ad_effective_end":"2017-12-09 19:00:00","ad_link_type":"5","second":"10","ad_url":"http://img.test.feelee.cc/Public/Uploads/ad/thumb/640_960_1002883101.jpg","redirect_url":{"id":"63","title":"诗圣杜甫"},"is_deleted":"0"},{"id":"99","ad_effective_start":"2018-01-04 09:09:17","ad_effective_end":"2018-01-06 07:07:17","ad_link_type":"2","second":"8","ad_url":"http://img.test.feelee.cc/Public/Uploads/ad/thumb/640_960_5a227452bde39.png","redirect_url":{"plate_type":"003"},"is_deleted":"1"},{"id":"100","ad_effective_start":"2018-01-11 06:06:34","ad_effective_end":"2018-01-13 10:10:34","ad_link_type":"1","second":"8","ad_url":"http://img.test.feelee.cc/Public/Uploads/ad/thumb/640_960_5a229c940ca46.png","redirect_url":{"itemid":1000000008,"sno":"P001219-10","store_id":"117080350981001"},"is_deleted":"1"},{"id":"108","ad_effective_start":"2021-03-02 00:00:46","ad_effective_end":"2021-03-05 23:59:46","ad_link_type":"4","second":"1","ad_url":"http://img.test.feelee.cc/Public/Uploads/ad/thumb/640_960_5a24b794701b5.png","redirect_url":{"url":"http://fenglei_manage.com"},"is_deleted":"1"},{"id":"109","ad_effective_start":"2021-01-01 00:00:53","ad_effective_end":"2021-01-02 23:59:53","ad_link_type":"4","second":"5","ad_url":"http://img.test.feelee.cc/Public/Uploads/ad/thumb/640_960_5a24b97b0e289.png","redirect_url":{"url":"http://fenglei_manage.com/"},"is_deleted":"1"},{"id":"110","ad_effective_start":"2018-01-01 00:00:00","ad_effective_end":"2018-01-03 23:59:00","ad_link_type":"1","second":"5","ad_url":"http://img.test.feelee.cc/Public/Uploads/ad/thumb/640_960_5a2536a29fa2e.png","redirect_url":{"itemid":1000000013,"sno":"P001219-15","store_id":"117080350981001"},"is_deleted":"1"},{"id":"111","ad_effective_start":"2018-01-10 00:00:00","ad_effective_end":"2018-01-12 23:59:00","ad_link_type":"5","second":"6","ad_url":"http://img.test.feelee.cc/Public/Uploads/ad/thumb/640_960_5a2536cc11c0f.png","redirect_url":{"id":67,"title":null},"is_deleted":"1"},{"id":"112","ad_effective_start":"2018-01-15 00:00:00","ad_effective_end":"2018-01-17 23:59:00","ad_link_type":"4","second":"8","ad_url":"http://img.test.feelee.cc/Public/Uploads/ad/thumb/640_960_5a2536f978fc3.png","redirect_url":{"url":"http://fenglei_manage.com/"},"is_deleted":"1"},{"id":"115","ad_effective_start":"2017-12-21 00:00:00","ad_effective_end":"2017-12-30 23:59:00","ad_link_type":"5","second":"8","ad_url":"http://img.test.feelee.cc/Public/Uploads/ad/thumb/640_960_5a268632c171c.png","redirect_url":{"id":66,"title":null},"is_deleted":"1"}]}', 'app/rich_text'=>'{"msg":"加载成功!","status":"0","result":{"id":"27","title":"广告详情","content":null,"url":"http://api.test.feelee.cc/app/rich_text?id=27&type=2"}}',)
八.进一步优化
上面数据读取总感觉有些low(这里的low还是主要指读取data里的文件),后面有时间做个管理后台,将数据存储在数据库表中,通过页面添加log记录和api接口文档中的结果返回实例的数据。
后面还会进一步优化api接口调试文档中的数据请求方式这块(POST、GET、JSON-POST),目前JSON-POST是数据按照json格式传输,POST/GET都是按照表单提交或ajax直接调接口的方式去,后面会针对JSON-POST这种方式进一步优化,header传系统参数(验签参数:username、checkcode、timestramp、sign)
init.js
$("#POST-BTN").click(function(){ $("#form-box form").attr("method","post"); $("#form-box form").attr("action","http://"+$("#loadAPI-Base-URL option:selected").val()+'/'+$("#c option:selected").val()+'/'+$("#a option:selected").val()); $("#form-box form").submit(); /* var url = "http://"+$("#loadAPI-Base-URL option:selected").val()+'/'+$("#c option:selected").val()+'/'+$("#a option:selected").val(); var params = get_all_parameter(); $.ajax({ type: "POST", url: url, data: params, success: function (data) { var mes=JSON.stringify(data, null, 2); $("#api_iframe").empty(); $("#api_iframe").append("<textarea style=' 100%;min-height: 710px;overflow: auto; border:solid 0px #000;'>" + mes + "</textarea>"); } }); */ }); $("#GET-BTN").click(function(){ //$("#form-box form").attr("method","get"); //$("#form-box form").attr("action","http://"+$("#loadAPI-Base-URL option:selected").val()+'/'+$("#c option:selected").val()+'/'+$("#a option:selected").val()); //$("#form-box form").submit(); var url = "http://"+$("#loadAPI-Base-URL option:selected").val()+'/'+$("#c option:selected").val()+'/'+$("#a option:selected").val(); var params = get_all_parameter(); $.ajax({ type: "GET", url: url, data: params, success: function (data) { var mes=JSON.stringify(data, null, 2); $("#api_iframe").empty(); $("#api_iframe").append("<textarea style=' 100%;min-height: 710px;overflow: auto; border:solid 0px #000;'>" + mes + "</textarea>"); } }); }); $("#JSON-BTN").click(function(){ var url = "http://"+$("#loadAPI-Base-URL option:selected").val()+'/'+$("#c option:selected").val()+'/'+$("#a option:selected").val(); var params = get_all_parameter(); var myJson = JSON.stringify(params); //var headers = get_all_header(); $.ajax({ type: "POST", url: url, data: myJson, dataType: "json", headers:{'username':'zouke','sign':'11111','Content-Type':'application/json; charset=utf-8'}, success: function (data) { var mes=JSON.stringify(data, null, 2); $("#api_iframe").empty(); $("#api_iframe").append("<textarea style=' 100%;min-height: 710px;overflow: auto; border:solid 0px #000;'>" + mes + "</textarea>"); } }); }); //获取所有POST-json提交的值 function get_all_parameter() { var params = {}; $("#p-box input").each(function(){ var name = $(this).attr("name"); var value = $(this).val(); params[name]=value; }); return params } //获取所有POST提交的头信息 function get_all_header() { var headers = new Array(); $("#p-header input").each(function() { var name = $(this).attr("name"); var value = $(this).val(); headers.push({name: name,value: value}); }); return headers }
ajax接口跨域问题的解决方法
在php文件内增加这几项,标蓝色的几项是header中传参数允许的系统参数
header('Access-Control-Allow-Origin: *');
header("Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept,username,sign,checkcode,timestamp");
header('Access-Control-Allow-Methods: GET, POST, PUT,OPTION');
未完待续........