96SEO 2026-08-14 07:46 4
CRMEB Pro 二开新增后台功能时很多人第一反应是“加一个 Controller 方法”。但后台接口不是只要能访问就算完成,它还牵扯路由、权限名称、菜单权限、Controller、参数校验、Services、Dao、Model、缓存清理还有统一返回格式。
漏掉任何一环,都会出现一些很烦的问题:

接口能访问,但后台按钮没权限菜单里看不到
新增接口参数没校验。脏数据进库
列表能查,但弹窗选择器查不到
新增成功,却缓存不更新
返回格式不一致,前端不好处理
今天底层专题第三篇,就用 CRMEB Pro 真实模块把新增后台接口的完整链路讲清楚。不过,示例主要参考商品热词、商品单位和权限菜单。因为这些模块代码短、链路完整,适合二开照着落地。
这篇文章基于项目真实代码:
crmeb_pro/route/admin.php
crmeb_pro/app/controller/admin/AuthController.php
crmeb_pro/app/controller/admin/v1/product/StoreProductWords.php
crmeb_pro/app/controller/admin/v1/product/StoreProductUnit.php
crmeb_pro/app/controller/admin/v1/system/SystemMenus.php
crmeb_pro/app/services/product/product/StoreProductWordsServices.php
crmeb_pro/app/services/product/product/StoreProductUnitServices.php
crmeb_pro/app/dao/product/product/StoreProductWordsDao.php
crmeb_pro/app/model/product/product/StoreProductWords.php
crmeb_pro/app/validate/admin/product/StoreProductWordsValidate.php
crmeb_pro/app/validate/admin/product/StoreProductUnitValidate.php
一个完整后台接口至少要经过这几层:
route/admin.php → Controller → Validate → Services → Dao → Model →
权限菜单 → 前端 API 页面
后端最小闭环是:
• 路由能找到接口
• 权限程序能识别接口
• Controller 能接收参数
• Validate 能拦住非法输入
• Services 能处理业务规则
• Dao 能封装查询或写入
• Model 能映射表和搜索器
• 返回格式符合 success/fail
不要只盯 Controller。
商品热词路由在:
// crmeb_pro/route/admin.php
至于Route:。group {
// 热词列表 Route::get
// ->option;// 所有热词 Route::get
// ->option;// 热词详情 Route::get
// ->option;不过,// 热词添加、编辑 Route::post
// ->option;// 删除商品热词 Route::delete
// ->option;// 商品热词修改状态 Route::put('words/set_show/:id/:is_show',// 'v1.product.StoreProductWords/set_show')
// ->option;}),
这段代码里有几个关键信息:
痛点提醒:如果忘记写 real_name 或者写错了后台菜单会找不到对应权限;前端页面会报错 “按钮无权查看”。怎么说呢,
商品单位用的是资源路由:
从Route:来看。get('get_all_unit','v1.product.StoreProductUnit/getAllUnit')
->option;Route::resource('unit','v1.product.StoreProductUnit')
->option();
权限菜单模块在:
public function ruleList {
$this->app = app;$rule = $type == ''?说起来,'adminapi/' : 'storeapi/';$this->app->route->setTestMode;$this->app->route->clear;老实说,$path = $this->app->getRootPath . ‘route’ . DIRECTORY_SEPARATOR;不过,$files = is_dir?scandir :,foreach {
if ) {
include $path . $file;}
}
$ruleList = $this->app->route->getRuleList;$ruleNewList =;foreach {
if ) {
$ruleNewList = $item;}
}
...
}
以 商品热词 为例子:
class StoreProductWords extends AuthController{
# protected StoreProductWordsServices $services;}
...
public function index{
$where = $request->postMore;不过,return $this->success(
$this->services->getWordList
);}
...
public function save{
if){
return $this->fail;}
...
validate(\app\validate\admin\product\StoreProductWordValidate::
::class)->scene->check;,}
-
`checkSupplierPlatformResourceManageAuth` - 权限入口;
-
`postMore` - 参数读取;
-
`Validate` - 后端校验;
-
`Services` - 调业务逻辑;老实说,
-
`success/fail` - 统一返回格式。
按理说,
Validate:不要只靠前端校验
* 商品热词验证器示例:
// crmeb_pro/app/validate/admin/product/storeproductwordvalidate.php
class StoreProductsWordValidate extends Validate{
protected $rule=,];protected $message=;protected $scene=
];}
-
再看常见规则。require,length,number,in,mobile 等。
-
再看**痛点**。若仅前端做校验,一旦恶意请求绕过检查,数据库将被污染。
html
Services:业务规则与缓存都在这里
// crmeb_pro/...Service....
public function saveData{
/* 新增时不能重名 */
/* 编辑时不能和其他记录重名 /
/* 新增补 add_time /
/* 保存后更新缓存 */
}
- 用 AdminException 抛异常,让后台统一处理。>- 不要把 SQL 拼在此处,要通过 Dao 完成。>- 缓存逻辑也放在 Service 层。
说到Dao,封装列表分页排序与模型绑定
class StoreProductsWordDao extends BaseDao{
protected function setModel:string{return StoreProductsWord::class;}
public function getList(array$where。string$field='*',int$page=0,int$limit=15){
return…,}
}
- 对于基础 CRUD,只需 `setModel` 和 `getList` 即可。说起来,‑ 若有复杂查询。可再实现 `searchXXXAttr` 搜索器。**痛点** :若 Dao 未封装好。则每个 Service 都要自己写 SQL,易产生冗余且难以维护。
Model的观点是,表名与搜索器别忘了
class StoreProductsWord extends BaseModel{
use ModelTrait;protected $pk='id';protected $name='store_product_words';不过,}
再看搜索器示例。public function searchNameAttr{…}
**痛点** :缺少搜索器会导致分页等功能失效。
新增接口后一定要清理相关缓存
if ){
CacheService::redisHandler->clear;}
新建一个后台小功能,从这个文件清单走起
文件方法 | 功能描述 | 必须填写 | 可选填充 |
route/admin.php | 增加 product/recommend_words 路由 | option |
controller/Admin/V1/Product/
StoreRecommendWordController | AuthController + Service 注入 | 所有 CRUD + 状态切换 |
validate/.../
StoreRecommendWordValidate | name/sort/is_show 等规则 | scene |
service/.../
StoreRecommendWordService | 列表+保存+重名校验+状态切换+缓存更新 | throws AdminException |
dao/.../
StoreRecommendWordDao | setModel + getList | …|
model/.../
StoreRecommendWord | 表名主键 searcher| …|
SQL 文件| 安装升级脚本| COMMENT|
程序菜单| 自动扫描或手动添加至 system_menus| clear 缓存 |
前端 API 页面| 按现有风格编写,不重复造轮子| …|
控制器模板
class XxxController extends AuthController{
# protected XxxService $services;public function index{
$where=$request→getMore;$where=0,return $this→success(
$this→services→listData
);}
public function save{
$data=$request→postMore;validate::scene→check;$this→services→saveData$id,$data);return $this→success;}
public function delete{
ifreturn this→fail;$this→services→deleteData$id);return this→success;}
}
注意事项:
* 不直接使用 Db 或 Redis 实现业务逻辑;按理说,* 不直接拼 SQL 或改订单库存字段;* 避免出现 `new Redis` 或 `return json` 的混乱代码。
发布前自检流程 :
-
#rg 路由地址 – 确认无重复且已包含 real_name。
-
#rg Controller 方法 – 与路由匹配,并继承 AuthController。
-
#rg Validate 场景 – scene 名称书写无误且已调用。
-
#rg Services 方法 – 所有业务判断均放此层,而非 Controller。
-
#rg Dao 查询 – search 已封装完成,可复用 BaseDao 的通用方法。
-
#rg Model 搜索器 – filter 条件生效且无遗漏。
-
#打开后台管理页面 – 新增/编辑/删除/状态切换全部正常工作。
-
#检查返回值是否始终为 success/fail 格式,并包含 msg/data 字段。
-
#SQL 安装及升级文件是否同步维护完备。
作为专业的SEO优化服务提供商,我们致力于通过科学、系统的搜索引擎优化策略,帮助企业在百度、Google等搜索引擎中获得更高的排名和流量。我们的服务涵盖网站结构优化、内容优化、技术SEO和链接建设等多个维度。
| 服务项目 | 基础套餐 | 标准套餐 | 高级定制 |
|---|---|---|---|
| 关键词优化数量 | 10-20个核心词 | 30-50个核心词+长尾词 | 80-150个全方位覆盖 |
| 内容优化 | 基础页面优化 | 全站内容优化+每月5篇原创 | 个性化内容策略+每月15篇原创 |
| 技术SEO | 基本技术检查 | 全面技术优化+移动适配 | 深度技术重构+性能优化 |
| 外链建设 | 每月5-10条 | 每月20-30条高质量外链 | 每月50+条多渠道外链 |
| 数据报告 | 月度基础报告 | 双周详细报告+分析 | 每周深度报告+策略调整 |
| 效果保障 | 3-6个月见效 | 2-4个月见效 | 1-3个月快速见效 |
我们的SEO优化服务遵循科学严谨的流程,确保每一步都基于数据分析和行业最佳实践:
全面检测网站技术问题、内容质量、竞争对手情况,制定个性化优化方案。
基于用户搜索意图和商业目标,制定全面的关键词矩阵和布局策略。
解决网站技术问题,优化网站结构,提升页面速度和移动端体验。
创作高质量原创内容,优化现有页面,建立内容更新机制。
获取高质量外部链接,建立品牌在线影响力,提升网站权威度。
持续监控排名、流量和转化数据,根据效果调整优化策略。
基于我们服务的客户数据统计,平均优化效果如下:
我们坚信,真正的SEO优化不仅仅是追求排名,而是通过提供优质内容、优化用户体验、建立网站权威,最终实现可持续的业务增长。我们的目标是与客户建立长期合作关系,共同成长。
Demand feedback