服务层
概述
服务层(Service Layer)是 XinAdmin 后端架构中重要的业务逻辑处理层,位于控制器(Controller)和数据仓库(Repository)之间。服务层的主要职责包括:
- 业务逻辑处理:封装复杂的业务规则和逻辑流程
- 事务管理:协调多个数据操作确保数据一致性
- 数据转换:处理控制器和仓库之间的数据转换
- 服务编排:协调多个仓库或其他服务的调用
XinAdmin 的服务层遵循单一职责原则,每个服务类专注于特定领域的业务逻辑。服务层继承自 BaseService,该基类提供了通用的响应处理和工具方法。
服务层与控制器的交互通过依赖注入实现,使得代码更加松耦合和易于测试。
BaseService
BaseService 是所有服务类的基类,提供了一系列通用方法来简化开发过程。
通用方法
BaseService 提供了以下通用方法:
-
树形数据构建
- 方法:
getTreeData(array &$list, int $parentId = 0)
- 功能:将平面结构的数据转换为树形结构,常用于菜单、分类等层级关系数据的处理
- 示例:
$treeData = $this->getTreeData($list, 0);
-
响应处理方法
通过引入 RequestJson trait,BaseService 提供了多种响应处理方法:
success($data, $message):返回成功的JSON响应
error($data, $message):返回失败的JSON响应
warn($data, $message):返回警告的JSON响应
throwSuccess($data, $message):抛出成功响应并中断程序运行
throwError($data, $message):抛出错误响应并中断程序运行
notification($msg, $description, $type, $placement):返回通知类型响应
事务处理
虽然 BaseService 本身不直接提供事务管理功能,但服务层可以使用 Laravel 的 DB 门面或模型的事务方法来处理复杂的数据操作:
use Illuminate\Support\Facades\DB;
public function complexOperation() {
DB::beginTransaction();
try {
// 执行多个数据库操作
$result1 = $this->repository->create($data1);
$result2 = $this->anotherRepository->update($data2);
DB::commit();
return $this->success(["result1" => $result1, "result2" => $result2]);
} catch (\Exception $e) {
DB::rollback();
return $this->error($e->getMessage());
}
}
Laravel 还提供了便捷的 DB::transaction() 方法,自动处理提交和回滚:
use Illuminate\Support\Facades\DB;
public function complexOperation() {
try {
$results = DB::transaction(function () use ($data1, $data2) {
$result1 = $this->repository->create($data1);
$result2 = $this->anotherRepository->update($data2);
return ["result1" => $result1, "result2" => $result2];
});
return $this->success($results);
} catch (\Exception $e) {
return $this->error($e->getMessage());
}
}
缓存处理
服务层可以通过 Laravel 的 Cache 门面或缓存服务来实现数据缓存,提升应用性能。常见的缓存模式包括:
-
读取缓存优先
use Illuminate\Support\Facades\Cache;
public function getData($id) {
$cacheKey = "data_{$id}";
return Cache::remember($cacheKey, 3600, function () use ($id) {
return $this->repository->find($id);
});
}
-
更新时清除缓存
public function updateData($id, $data) {
$result = $this->repository->update($id, $data);
if ($result) {
Cache::forget("data_{$id}"); // 清除对应缓存
Cache::forget('data_list'); // 清除可能相关的列表缓存
}
return $result;
}
创建服务
创建新的服务类需要遵循以下步骤:
-
确定服务名称:根据业务领域命名,如用户相关服务命名为 UserService
-
创建服务文件:服务文件应放置在 app/Services/ 目录下,对于系统相关服务则放在 app/Services/Sys/ 目录
-
继承 BaseService:新服务类必须继承 BaseService
<?php
namespace App\Services\Sys;
use App\Services\BaseService;
use Illuminate\Http\JsonResponse;
class CustomService extends BaseService
{
// 服务实现
}
-
实现业务逻辑:在服务类中实现具体的业务方法
<?php
namespace App\Services\Sys;
use App\Services\BaseService;
use App\Repositories\Sys\CustomRepository;
use Illuminate\Http\JsonResponse;
class CustomService extends BaseService
{
protected CustomRepository $repository;
public function __construct()
{
$this->repository = new CustomRepository();
}
public function getList(): JsonResponse
{
try {
$data = $this->repository->getList();
return $this->success($data);
} catch (\Exception $e) {
return $this->error($e->getMessage());
}
}
}
业务逻辑处理
服务层是处理业务逻辑的核心,应该包含:
- 数据验证:在处理业务前对输入数据进行验证
- 业务规则实现:实现具体的业务规则和逻辑判断
- 异常处理:妥善处理可能出现的异常情况
- 事务控制:对于涉及多个数据操作的业务,使用事务保证数据一致性
例如,用户注册服务的业务逻辑:
public function registerUser($userData) {
// 1. 数据验证
if ($this->userRepository->exists(['email' => $userData['email']])) {
return $this->error('该邮箱已被注册');
}
// 2. 业务规则:检查用户数量限制
if ($this->userRepository->count() > 10000) {
return $this->error('用户数量已达上限');
}
// 3. 事务处理:确保用户和相关数据的一致性
try {
$result = \DB::transaction(function () use ($userData) {
// 创建用户
$user = $this->userRepository->create($userData);
// 创建用户初始配置
$this->userConfigRepository->create([
'user_id' => $user['id'],
'theme' => 'light'
]);
return $user;
});
return $this->success($result, '注册成功');
} catch (\Exception $e) {
return $this->error('注册失败:' . $e->getMessage());
}
}
服务注入
服务类可以通过 Laravel 的依赖注入容器自动注入到控制器中。控制器方法可以直接声明服务作为参数,框架会自动解析并注入相应的服务实例:
<?php
namespace App\Http\Controllers\Sys;
use App\Http\Controllers\Controller;
use App\Services\Sys\CustomService;
use Illuminate\Http\Request;
use Illuminate\Http\JsonResponse;
class CustomController extends Controller
{
public function index(CustomService $customService): JsonResponse
{
return $customService->getList();
}
public function store(Request $request, CustomService $customService): JsonResponse
{
return $customService->create($request->all());
}
}
最佳实践
-
单一职责:每个服务类应专注于特定业务领域,避免功能过于复杂
-
保持简洁:服务方法应保持简短和专注,复杂逻辑可以拆分为多个私有方法
-
合理使用事务:仅在必要时使用事务,避免长时间锁定数据库资源
-
错误处理:提供有意义的错误信息,便于调试和问题排查
-
缓存策略:合理使用缓存,注意缓存失效策略
-
日志记录:对关键业务操作进行日志记录
-
参数验证:在服务层进行必要的业务参数验证
-
测试友好:编写易于单元测试的服务代码,避免过多硬编码依赖
遵循这些最佳实践可以确保服务层代码的可维护性、可扩展性和健壮性。