Alpaca-Laravel 框架(三) --- 编写代码生成工具,自动生成代码

目的

代码自动生成工具(Alpaca-Builder)目的用来快速的编写代码,减少一些重复的工作。使用Alpaca-Laravel框架开发项目时,可以利用代码生成工具,快速的生成代码,减少工作时间,提高工作效率。

Alpaca-Spa-Laravel 是 前后端分离 开发的一个后台管理系统的DEMO。Laravel用来实现后端功能,Alpaca-Spa用来实现前端功能,前后端之间通过Json交换数据。

详情请阅读《Alpaca-Laravel 框架(一) — 概述,前后分离的后台管理系统》。

Alpaca-Builder使用灵活的模版格式来配置代码生成文件,如果现有的代码模版不能满足需求,只需要修改代码模版,或者新增代码模版即可。

主要内容

主要功能是根据输入的数据库表名声生成一下内容:

1 生成后端实体类 2 生成后端控制器 3 生成后端路由 4 生成前端JS控制器 5 生成前端编辑页面 6 生成前端列表页面 7 生成配置接口url 8 选择是否复制到对应页面

访问方式,浏览器中输入地址:你的域名builder

(注意: 只有当配置文件中APP_ENV=local时,才容许访问)

实现原理 根据输入的数据库表名称,查询数据库,获取表结构,字段、字段类型、字段注释等。 格式化字段内容 读取相应的代码模版,将字段内容填充到代码模版中,输出文件,生成完毕 一个简单的视图模版引擎

你当然直接使用Laravel的视图模板, 在这里,我们编写一个简单的视图模版引擎,

主要的功能能,读取指定模版文件,将数据渲染到模版指定位置。

代码如下:

<?php namespace BuilderView; /** * View – 视图模板 * @author Chengcheng * @date 2017-2-27 15:50:00 */ class View { //单例 private static $instance = null; //数据 private $data; //模板 private $template; //布局模板 public $layout = null; /** * 创建视图 * @author Chengcheng * @param string $template 视图模板名字 * @param array $data 视图数据 * @date 2016年11月5日 14:47:40 * @return static */ public static function tbl($template, $data = null) { //实例化新的对象 $newTpl = new static; //设置视图 $newTpl->template = __DIR__ . \\\’/Template/\\\’ . $template . ".php"; //数据 $newTpl->data = $data; //layout $newTpl->layout = static::layoutTpl(); //返回 return $newTpl; } /** * 创建layout视图 * @author Chengcheng * @param string $template 视图模板名字 * @param array $data 视图数据 * @date 2016年11月5日 14:47:40 * @return static */ public static function layoutTpl($template = \\\’layout\\\’, $data = null) { //实例化新的对象 $newTpl = new static; //设置视图 $newTpl->template = __DIR__ . \\\’/Template/\\\’ . $template . ".php"; //数据 $newTpl->data = $data; //返回 return $newTpl; } /** * 创建视图 * @author Chengcheng * @param null $data * @return null|string * @throws Exception */ public function html($data = null) { //加载自己的模板 if (!empty($this->data)) { foreach ($this->data as $key => $value) { $this->$key = $value; } } //参数中的数据 if (!empty($data)) { foreach ($data as $key => $value) { $this->$key = $value; } } //读取模板中的信息 $html = null; try { ob_start(); require $this->template; $html = ob_get_clean(); } catch (Exception $ex) { ob_end_clean(); throw $ex; } //加载layout的模板 if ($this->layout) { $html = $this->layout->html([\\\’content\\\’ => $html]); } //返回信息 return $html; } } 交互页面

编写一个交互页面,用来接受用户输入的数据库表名,生成的内容等。

<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width,initial-scale=1,user-scalable=0"> <title>Alpaca – Builder</title> <link rel="stylesheet" href="//g.alicdn.com/msui/sm/0.6.2/css/sm.min.css"> <link rel="stylesheet" href="//g.alicdn.com/msui/sm/0.6.2/css/sm.min.css,sm-extend.min.css"> <script type=\\\’text/javascript\\\’ src=\\\’//g.alicdn.com/sj/lib/zepto/zepto.min.js\\\’ charset=\\\’utf-8\\\’></script> <script type=\\\’text/javascript\\\’ src=\\\’//g.alicdn.com/msui/sm/0.6.2/js/sm.min.js\\\’ charset=\\\’utf-8\\\’></script> <script type=\\\’text/javascript\\\’ src=\\\’//g.alicdn.com/msui/sm/0.6.2/js/sm.min.js,sm-extend.min.js\\\’ charset=\\\’utf-8\\\’></script> <style> .line-right { text-align: right; } </style> </head> <body ontouchstart> <div class="page-group"> <div class="page page-current"> <!– 你的html代码 –> <header class="bar bar-nav"> <a class="button button-link button-nav pull-left" href="" data-transition=\\\’slide-out\\\’> <span class="icon icon-left"></span> 返回 </a> <h1 class="title">Alpaca-Builder</h1> </header> <nav class="bar bar-tab"> <a class="tab-item active" href="#"> <span class="icon icon-home"></span> <span class="tab-label">首页</span> </a> <a class="tab-item" href="#"> <span class="icon icon-me"></span> <span class="tab-label">我</span> </a> <a class="tab-item" href="#"> <span class="icon icon-settings"></span> <span class="tab-label">设置</span> </a> </nav> <div class="content"> <form action="/builder/create/builder" id="sub-form"> <div class="content-block-title">配置</div> <div class="list-block"> <ul> <!– Text inputs –> <li> <div class="item-content"> <div class="item-media"><i class="icon icon-form-name"></i></div> <div class="item-inner"> <div class="item-title label">数据表名称</div> <div class="item-input"> <input type="text" placeholder="请输入数据表名称" name="table_name"> </div> </div> </div> </li> <li> <div class="item-content"> <div class="item-media"><i class="icon icon-form-email"></i></div> <div class="item-inner"> <div class="item-title label">表名前缀</div> <div class="item-input"> <input type="text" placeholder="E-mail" value="tb_" name="table_prefix"> </div> </div> </div> </li> <li> <div class="item-content"> <div class="item-media"><i class="icon icon-form-email"></i></div> <div class="item-inner"> <div class="item-title label">中文名称</div> <div class="item-input"> <input type="text" placeholder="中文名称" value="" name="table_name_cn"> </div> </div> </div> </li> <li> <div class="item-content"> <div class="item-media"><i class="icon icon-form-email"></i></div> <div class="item-inner"> <div class="item-title label">二级模块</div> <div class="item-input"> <input type="text" placeholder="二级模块" value="" name="sub_module_name"> </div> </div> </div> </li> <li> <div class="item-content"> <div class="item-media"><i class="icon icon-form-email"></i></div> <div class="item-inner"> <div class="item-title label">后端模块</div> <div class="item-input"> <input type="text" placeholder="后端模块" value="manage" name="b_module_name"> </div> </div> </div> </li> <li> <div class="item-content"> <div class="item-media"><i class="icon icon-form-email"></i></div> <div class="item-inner"> <div class="item-title label">前端模块</div> <div class="item-input"> <input type="text" placeholder="前端模块" value="admin" name="f_module_name"> </div> </div> </div> </li> </ul> </div> <div class="content-block-title">后端</div> <div class="list-block"> <ul> <!– Switch (Checkbox) –> <li> <div class="item-content"> <div class="item-media"><i class="icon icon-form-toggle"></i></div> <div class="item-inner"> <div class="item-title label">生成Model</div> <div class="item-input line-right"> <label class="label-switch"> <input type="checkbox" checked name="is_init_model"> <div class="checkbox"></div> </label> </div> </div> </div> </li> <li> <div class="item-content"> <div class="item-media"><i class="icon icon-form-toggle"></i></div> <div class="item-inner"> <div class="item-title label">生成Controller</div> <div class="item-input line-right"> <label class="label-switch"> <input type="checkbox" checked name="is_init_b_controller"> <div class="checkbox"></div> </label> </div> </div> </div> </li> <li> <div class="item-content"> <div class="item-media"><i class="icon icon-form-toggle"></i></div> <div class="item-inner"> <div class="item-title label">配置Router</div> <div class="item-input line-right"> <label class="label-switch"> <input type="checkbox" checked name="is_init_b_router"> <div class="checkbox"></div> </label> </div> </div> </div> </li> </ul> </div> <div class="content-block-title">前端</div> <div class="list-block"> <ul> <li> <div class="item-content"> <div class="item-media"><i class="icon icon-form-toggle"></i></div> <div class="item-inner"> <div class="item-title label">List页面</div> <div class="item-input line-right"> <label class="label-switch"> <input type="checkbox" checked name="is_init_list"> <div class="checkbox"></div> </label> </div> </div> </div> </li> <li> <div class="item-content"> <div class="item-media"><i class="icon icon-form-toggle"></i></div> <div class="item-inner"> <div class="item-title label">Edit页面</div> <div class="item-input line-right"> <label class="label-switch"> <input type="checkbox" checked name="is_init_edit"> <div class="checkbox"></div> </label> </div> </div> </div> </li> <li> <div class="item-content"> <div class="item-media"><i class="icon icon-form-toggle"></i></div> <div class="item-inner"> <div class="item-title label">前端Controller</div> <div class="item-input line-right"> <label class="label-switch"> <input type="checkbox" checked name="is_init_f_controller"> <div class="checkbox"></div> </label> </div> </div> </div> </li> <li> <div class="item-content"> <div class="item-media"><i class="icon icon-form-toggle"></i></div> <div class="item-inner"> <div class="item-title label">配置接口url</div> <div class="item-input line-right"> <label class="label-switch"> <input type="checkbox" checked name="is_init_inter"> <div class="checkbox"></div> </label> </div> </div> </div> </li> </ul> </div> <div class="content-block-title">自动复制到对应目录</div> <div class="list-block"> <ul> <li> <div class="item-content"> <div class="item-media"><i class="icon icon-form-toggle"></i></div> <div class="item-inner"> <div class="item-title label">复制到对应目录</div> <div class="item-input line-right"> <label class="label-switch"> <input type="checkbox" checked name="is_auto_copy"> <div class="checkbox"></div> </label> </div> </div> </div> </li> </ul> </div> <div class="content-block"> <div class="row"> <div class="col-50"><a href="#" class="button button-big button-fill button-danger">取消</a></div> <div class="col-50"><a href="#" class="button button-big button-fill button-success" onclick="submit()">提交</a></div> </div> </div> </form> </div> </div> </div> <script> var submit = function () { $(\\\’#sub-form\\\’).submit(); } </script> </body> </html> 解析表结构

根据输入的表名称,查询数据库,获取表结构,解析字段内容,然后格式化字段内容。

public function builder() { $table_name = request()->input(\\\’table_name\\\’); $table_prefix = request()->input(\\\’table_prefix\\\’, \\\’\\\’); $table_name_cn = request()->input(\\\’table_name_cn\\\’); $sub_module_name = request()->input(\\\’sub_module_name\\\’); $b_module_name = request()->input(\\\’b_module_name\\\’, \\\’manage\\\’); $f_module_name = request()->input(\\\’f_module_name\\\’, \\\’admin\\\’); $is_init_model = request()->input(\\\’is_init_model\\\’); $is_init_b_controller = request()->input(\\\’is_init_b_controller\\\’); $is_init_b_router = request()->input(\\\’is_init_b_router\\\’); $is_init_list = request()->input(\\\’is_init_list\\\’); $is_init_edit = request()->input(\\\’is_init_edit\\\’); $is_init_f_controller = request()->input(\\\’is_init_f_controller\\\’); $is_init_inter = request()->input(\\\’is_init_inter\\\’); $is_auto_copy = request()->input(\\\’is_auto_copy\\\’, false); if (empty($table_name)) { die(\\\’Table Name Is Null!\\\’); } if (empty($table_name_cn)) { $table_name_cn = $table_name; } $orgName = $table_name; $table = str_replace(\\\’ \\\’, \\\’\\\’, $orgName); $className = ucwords(str_replace(array(\\\’.\\\’, \\\’-\\\’, \\\’_\\\’), \\\’ \\\’, $table)); $moduleName = explode(\\\’,\\\’, $className)[0]; if (!empty($sub_module_name)) { $moduleName = $sub_module_name; } $b_module_name = ucwords($b_module_name); $f_module_name = ucwords($f_module_name); $b_module_name_lc = lcfirst($b_module_name); $f_module_name_lc = lcfirst($f_module_name); $className = str_replace(\\\’ \\\’, \\\’\\\’, $className); $classNameLc = lcfirst($className); $moduleNameLc = lcfirst($moduleName); $result = DB::select("SHOW FULL COLUMNS FROM " . $table_prefix . $table); $fields = []; foreach ($result as $r) { if (in_array($r->Field, $this->ignoreField)) { continue; } $field = []; $field[\\\’db_type\\\’] = $r->Type; $field[\\\’field\\\’] = $r->Field; $field[\\\’comment\\\’] = $r->Comment; $field[\\\’in_type\\\’] = \\\’string\\\’; $field[\\\’in_name\\\’] = $r->Comment; $comment = str_replace(\\\’,\\\’, \\\’,\\\’, $r->Comment); $comment = preg_replace("# #", \\\’\\\’, $comment); $array = explode(\\\’,\\\’, $comment); $field[\\\’in_common\\\’] = $array[0]; if (!empty($array[1])) { $typeContent = explode(\\\’|\\\’, $array[1]); switch ($typeContent[0]) { case \\\’枚举\\\’: $field[\\\’in_type\\\’] = \\\’enum\\\’; $in_value = []; foreach ($typeContent as $index => $typeContentValue) { if ($index == 0) { continue; } $key = explode(\\\’-\\\’, $typeContentValue); $value = []; $value[\\\’value\\\’] = $key[0]; $value[\\\’label\\\’] = (isset($key[1]) ? $key[1] : $key[0]); $value[\\\’key\\\’] = $field[\\\’field\\\’] . "_" . (isset($key[2]) ? $key[2] : (isset($key[1]) ? $key[1] : $key[0])); $value[\\\’common\\\’] = \\\’//\\\’ . $field[\\\’in_common\\\’] . ":" . (isset($key[1]) ? $key[1] : $key[0]); $value[\\\’const\\\’] = \\\’const \\\’ . strtoupper($value[\\\’key\\\’]) . \\\’ = \\\’ . $key[0] . \\\’; \\\’ . $value[\\\’common\\\’]; array_push($in_value, $value); } $field[\\\’in_value\\\’] = $in_value; break; case \\\’开关\\\’: $field[\\\’in_type\\\’] = \\\’switch\\\’; $in_value = []; foreach ($typeContent as $index => $typeContentValue) { if ($index == 0) { continue; } $key = explode(\\\’-\\\’, $typeContentValue); $value = []; $value[\\\’value\\\’] = $key[0]; $value[\\\’label\\\’] = (isset($key[1]) ? $key[1] : $key[0]); $value[\\\’key\\\’] = $field[\\\’field\\\’] . "_" . (isset($key[2]) ? $key[2] : (isset($key[1]) ? $key[1] : $key[0])); $value[\\\’common\\\’] = \\\’//\\\’ . $field[\\\’in_common\\\’] . ":" . (isset($key[1]) ? $key[1] : $key[0]); $value[\\\’const\\\’] = \\\’const \\\’ . strtoupper($value[\\\’key\\\’]) . \\\’ = \\\’ . $key[0] . \\\’; \\\’ . $value[\\\’common\\\’]; array_push($in_value, $value); } $field[\\\’in_value\\\’] = $in_value; break; case \\\’富文本\\\’: $field[\\\’in_type\\\’] = \\\’rtext\\\’; break; default: { $field[\\\’in_type\\\’] = \\\’string\\\’; break; } } } array_push($fields, $field); } } 生成代码

读取相应的代码模版,填充数据字段内容,生成代码文件

$viewResult = []; //创建目录 $filePath = base_path() . "\\\\bootstrap\\\\builder\\\\output\\\\{$table}\\\\"; if (!is_dir($filePath)) { mkdir($filePath, 0777, true); } $data = []; $data[\\\’tableName\\\’] = "tb_" . $table; $data[\\\’fields\\\’] = $fields; $data[\\\’className\\\’] = $className; $data[\\\’moduleName\\\’] = $moduleName; $data[\\\’classNameLc\\\’] = $classNameLc; $data[\\\’moduleNameLc\\\’] = $moduleNameLc; $data[\\\’b_module_name\\\’] = $b_module_name; $data[\\\’f_module_name\\\’] = $f_module_name; $data[\\\’b_module_name_lc\\\’] = $b_module_name_lc; $data[\\\’f_module_name_lc\\\’] = $f_module_name_lc; $data[\\\’orgName\\\’] = $orgName; //创建 – model if (!empty($is_init_model)) { $view = View::tbl(\\\’model\\\’, $data); $view->layout = false; $html = $view->html(); $fileName = $filePath . $className . \\\’_M\\\’; $resultItem = []; $resultItem[\\\’title\\\’] = \\\’model-后端\\\’; $resultItem[\\\’fileName\\\’] = $fileName; array_push($viewResult, $resultItem); file_put_contents($fileName, $html, LOCK_EX); /*拷贝到指定目录*/ /*后端模型,目录*/ if ($is_auto_copy) { $models_dir = base_path() . "\\\\app\\\\Models\\\\"; $models_file_name = $className; if (!file_exists($models_dir . $models_file_name . \\\’.php\\\’)) { copy($fileName, $models_dir . $models_file_name . \\\’.php\\\’); } else { copy($fileName, $models_dir . $models_file_name . \\\’\\\’); } } } //创建 – controller if (!empty($is_init_b_controller)) { $view = View::tbl(\\\’controller\\\’, $data); $view->layout = false; $html = $view->html(); $fileName = $filePath . $className . \\\’_Controller\\\’; $resultItem = []; $resultItem[\\\’title\\\’] = \\\’Controller-后端\\\’; $resultItem[\\\’fileName\\\’] = $fileName; array_push($viewResult, $resultItem); file_put_contents($fileName, $html, LOCK_EX); /*拷贝到指定目录*/ /*后端Controller,目录*/ if ($is_auto_copy) { $controller_dir = base_path() . "\\\\app\\\\Modules\\\\{$b_module_name}\\\\Controllers\\\\"; $controller_file_name = $className . \\\’Controller\\\’; if (!file_exists($controller_dir . $controller_file_name . \\\’.php\\\’)) { copy($fileName, $controller_dir . $controller_file_name . \\\’.php\\\’); } else { copy($fileName, $controller_dir . $controller_file_name . \\\’\\\’); } } } //创建 – list if (!empty($is_init_list)) { //创建 – list_view $view = View::tbl(\\\’list_view\\\’, $data); $view->layout = false; $html = $view->html(); $fileName = $filePath . $className . \\\’_ListView\\\’; $resultItem = []; $resultItem[\\\’title\\\’] = \\\’list页面-前端\\\’; $resultItem[\\\’fileName\\\’] = $fileName; array_push($viewResult, $resultItem); file_put_contents($fileName, $html, LOCK_EX); /*拷贝到指定目录*/ /*前端Controller,目录*/ if ($is_auto_copy) { $display_dir = base_path() . "\\\\public\\\\{$f_module_name_lc}\\\\main\\\\view\\\\" . $classNameLc . "\\\\"; if (!is_dir($display_dir)) { mkdir($display_dir, 0777, true); } $display_file_name = $classNameLc . \\\’ListView\\\’; if (!file_exists($display_dir . $display_file_name . \\\’.html\\\’)) { copy($fileName, $display_dir . $display_file_name . \\\’.html\\\’); } else { copy($fileName, $display_dir . $display_file_name . \\\’\\\’); } } //创建 – list_display $view = View::tbl(\\\’list_display\\\’, $data); $view->layout = false; $html = $view->html(); $fileName = $filePath . $className . \\\’_ListDisplay\\\’; $resultItem = []; $resultItem[\\\’title\\\’] = \\\’list-table页面-前端\\\’; $resultItem[\\\’fileName\\\’] = $fileName; array_push($viewResult, $resultItem); file_put_contents($fileName, $html, LOCK_EX); /*拷贝到指定目录*/ /*前端Controller,目录*/ if ($is_auto_copy) { $display_dir = base_path() . "\\\\public\\\\{$f_module_name_lc}\\\\main\\\\view\\\\" . $classNameLc . "\\\\"; if (!is_dir($display_dir)) { mkdir($display_dir, 0777, true); } $display_file_name = $classNameLc . \\\’ListDisplay\\\’; if (!file_exists($display_dir . $display_file_name . \\\’.html\\\’)) { copy($fileName, $display_dir . $display_file_name . \\\’.html\\\’); } else { copy($fileName, $display_dir . $display_file_name . \\\’\\\’); } } } //创建 – Edit-html if (!empty($is_init_edit)) { $view = View::tbl(\\\’edit_html\\\’, $data); $view->layout = false; $html = $view->html(); $fileName = $filePath . $className . \\\’_EditView\\\’; $resultItem = []; $resultItem[\\\’title\\\’] = \\\’edit-编辑页面-前端\\\’; $resultItem[\\\’fileName\\\’] = $fileName; array_push($viewResult, $resultItem); file_put_contents($fileName, $html, LOCK_EX); /*拷贝到指定目录*/ /*前端Controller,目录*/ if ($is_auto_copy) { $edit_dir = base_path() . "\\\\public\\\\{$f_module_name_lc}\\\\main\\\\view\\\\" . $classNameLc . "\\\\"; if (!is_dir($edit_dir)) { mkdir($edit_dir, 0777, true); } $edit_file_name = $classNameLc . \\\’EditView\\\’; if (!file_exists($edit_dir . $edit_file_name . \\\’.html\\\’)) { copy($fileName, $edit_dir . $edit_file_name . \\\’.html\\\’); } else { copy($fileName, $edit_dir . $edit_file_name . \\\’\\\’); } } } //创建 – Controller – JS if (!empty($is_init_f_controller)) { $view = View::tbl(\\\’controller_js\\\’, $data); $view->layout = false; $html = $view->html(); $fileName = $filePath . $className . \\\’_Controller_JS\\\’; $resultItem = []; $resultItem[\\\’title\\\’] = \\\’controller_js-前端\\\’; $resultItem[\\\’fileName\\\’] = $fileName; array_push($viewResult, $resultItem); file_put_contents($fileName, $html, LOCK_EX); /*拷贝到指定目录*/ /*前端Controller,目录*/ if ($is_auto_copy) { $controller_js_dir = base_path() . "\\\\public\\\\{$f_module_name_lc}\\\\main\\\\controller\\\\"; $controller_js_file_name = $classNameLc . \\\’\\\’; if (!file_exists($controller_js_dir . $controller_js_file_name . \\\’.js\\\’)) { copy($fileName, $controller_js_dir . $controller_js_file_name . \\\’.js\\\’); } else { copy($fileName, $controller_js_dir . $controller_js_file_name . \\\’\\\’); } } } //创建 – 后台路由 if (!empty($is_init_b_router)) { //创建 – Router $view = View::tbl(\\\’router\\\’, $data); $view->layout = false; $html = $view->html(); $fileName = $filePath . $className . \\\’_Router\\\’; $resultItem = []; $resultItem[\\\’title\\\’] = \\\’router_路由-后端\\\’; $resultItem[\\\’fileName\\\’] = $fileName; array_push($viewResult, $resultItem); file_put_contents($fileName, $html, LOCK_EX); /*拷贝到指定目录*/ /*前端Controller,目录*/ if ($is_auto_copy) { $router_name = base_path() . "\\\\app\\\\Modules\\\\{$b_module_name}\\\\router.php";; if (!file_exists($router_name)) { } else { file_put_contents($router_name, $html, FILE_APPEND | LOCK_EX); } } } //创建 – config_js if (!empty($is_init_inter)) { $view = View::tbl(\\\’config_js\\\’, $data); $view->layout = false; $html = $view->html(); $fileName = $filePath . $className . \\\’_Config_js\\\’; $resultItem = []; $resultItem[\\\’title\\\’] = \\\’config_接口配置文件-前端\\\’; $resultItem[\\\’fileName\\\’] = $fileName; array_push($viewResult, $resultItem); file_put_contents($fileName, $html, LOCK_EX); } //设置菜单 $result[\\\’result\\\’] = $viewResult; $view = View::tbl(\\\’result\\\’,$result); $view->layout = false; echo $view->html(); die(); 详细内容请参考源代码

主页 (Alpaca-Spa): http://www.tkc8.com

后台(Alpaca-Spa-Laravel) : http://full.tkc8.com

手机端sui(Alpaca-Spa-Sui) : http://full.tkc8.com/app

代码 (oschina ): http://git.oschina.net/cc-sponge/Alpaca-Spa-Laravel

代码 (github ): https://github.com/big-sponge/Alpaca-Spa-Laravel

 

更多关于云服务器域名注册虚拟主机的问题,请访问西部数码官网:www.west.cn

赞(0)
声明:本网站发布的内容(图片、视频和文字)以原创、转载和分享网络内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-62778877-8306;邮箱:fanjiao@west.cn。本站原创内容未经允许不得转载,或转载时需注明出处:西部数码知识库 » Alpaca-Laravel 框架(三) --- 编写代码生成工具,自动生成代码

登录

找回密码

注册