ContiNew Admin组件开发:可复用业务组件的设计与实现
引言:为什么需要可复用业务组件?
在企业级应用开发中,你是否经常遇到这样的场景:每个业务模块都需要实现相似的CRUD(Create, Read, Update, Delete)操作,重复编写相似的控制器、服务层代码,不仅效率低下,还容易产生代码冗余和不一致的问题?
ContiNew Admin通过精心设计的可复用业务组件架构,将通用业务逻辑抽象为可复用的基础组件,让开发者能够专注于业务核心逻辑,大幅提升开发效率和代码质量。本文将深入解析ContiNew Admin的可复用业务组件设计理念和实现细节。
组件架构设计概览
ContiNew Admin采用分层架构设计,通过基础组件、业务组件和扩展组件的组合,构建了一套完整的可复用组件体系。
核心组件层次结构
| 组件层级 | 核心类 | 主要职责 | 复用程度 |
|---|---|---|---|
| 基础层 | BaseController | 提供通用CRUD接口和权限校验 | 高 |
| 基础层 | BaseService | 定义通用业务接口契约 | 高 |
| 基础层 | BaseServiceImpl | 实现通用业务逻辑和数据填充 | 高 |
| 业务层 | 具体Controller | 处理特定业务逻辑和自定义接口 | 中 |
| 业务层 | 具体Service | 实现特定业务规则 | 中 |
基础控制器组件详解
BaseController:统一的请求处理入口
BaseController 是所有业务控制器的基类,它封装了通用的CRUD操作和权限校验逻辑:
public class BaseController<S extends BaseService<L, D, Q, C>, L, D, Q, C>
extends AbstractCrudController<S, L, D, Q, C> {
@Override
public void preHandle(CrudApi crudApi, Object[] args, Method targetMethod,
Class<?> targetClass) throws Exception {
// 忽略带签名的请求权限校验
SaRequest saRequest = SaHolder.getRequest();
Collection<String> paramNames = saRequest.getParamNames();
if (paramNames.stream().anyMatch(SaSignTemplate.sign::equals)) {
return;
}
// 忽略带有@SaIgnore注解的接口
if (AnnotationUtil.hasAnnotation(targetMethod, SaIgnore.class) ||
AnnotationUtil.hasAnnotation(targetClass, SaIgnore.class)) {
return;
}
// 权限校验逻辑
String permissionPrefix = CrudApiPermissionPrefixCache.get(targetClass);
String apiName = getApiName(crudApi.value());
StpUtil.checkPermission("%s:%s".formatted(permissionPrefix, apiName.toLowerCase()));
}
}
权限校验机制
ContiNew Admin采用基于Sa-Token的细粒度权限控制,通过统一的权限前缀缓存机制实现动态权限校验:
基础服务组件设计
BaseService:统一的业务接口契约
BaseService 接口定义了通用的业务操作方法,采用泛型设计支持不同类型的实体和DTO:
public interface BaseService<L, D, Q, C> extends CrudService<L, D, Q, C> {
// 根据实际项目需要,自行重写CRUD接口或增加自定义通用业务方法
}
BaseServiceImpl:通用的业务实现
BaseServiceImpl 提供了CRUD操作的默认实现,并集成了Crane4j数据自动填充功能:
public class BaseServiceImpl<M extends BaseMapper<T>, T extends BaseIdDO, L, D, Q, C>
extends CrudServiceImpl<M, T, L, D, Q, C> implements BaseService<L, D, Q, C> {
@Override
protected void fill(Object obj) {
if (obj == null) {
return;
}
OperateTemplate operateTemplate = SpringUtil.getBean(OperateTemplate.class);
operateTemplate.execute(obj);
}
}
实战:用户管理组件的实现
用户控制器组件
用户控制器继承自BaseController,在通用CRUD功能基础上增加了用户特有的业务方法:
@Tag(name = "用户管理 API")
@Validated
@RestController
@RequiredArgsConstructor
@CrudRequestMapping(value = "/system/user", api = {Api.PAGE, Api.LIST, Api.GET,
Api.CREATE, Api.UPDATE, Api.BATCH_DELETE, Api.EXPORT, Api.DICT})
public class UserController extends BaseController<UserService, UserResp, UserDetailResp, UserQuery, UserReq> {
// 下载导入模板
@SaCheckPermission("system:user:import")
@GetMapping(value = "/import/template", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
public void downloadImportTemplate(HttpServletResponse response) throws IOException {
baseService.downloadImportTemplate(response);
}
// 解析导入数据
@SaCheckPermission("system:user:import")
@PostMapping("/import/parse")
public UserImportParseResp parseImport(@RequestPart @NotNull(message = "文件不能为空") MultipartFile file) {
ValidationUtils.throwIf(file::isEmpty, "文件不能为空");
return baseService.parseImport(file);
}
// 重置密码
@SaCheckPermission("system:user:resetPwd")
@PatchMapping("/{id}/password")
public void resetPassword(@RequestBody @Valid UserPasswordResetReq req, @PathVariable Long id) {
String newPassword = SecureUtils.decryptByRsa(req.getNewPassword(), "新密码解密失败", true);
req.setNewPassword(newPassword);
baseService.resetPassword(req, id);
}
}
用户服务组件
用户服务接口继承自BaseService,定义了用户管理特有的业务方法:
public interface UserService extends BaseService<UserResp, UserDetailResp, UserQuery, UserReq>,
IService<UserDO> {
void downloadImportTemplate(HttpServletResponse response) throws IOException;
UserImportParseResp parseImport(MultipartFile file);
UserImportResp importUser(UserImportReq req);
void resetPassword(UserPasswordResetReq req, Long id);
void updateRole(UserRoleUpdateReq updateReq, Long id);
}
组件复用模式分析
1. 继承复用模式
通过继承基础组件,快速获得通用功能:
// 部门控制器 - 只需简单配置即可获得完整CRUD功能
@CrudRequestMapping(value = "/system/dept", api = {Api.TREE, Api.GET, Api.CREATE,
Api.UPDATE, Api.DELETE, Api.EXPORT, Api.DICT_TREE})
public class DeptController extends BaseController<DeptService, DeptResp, DeptDetailResp, DeptQuery, DeptReq> {
// 无需额外代码即可获得完整的部门管理功能
}
2. 组合复用模式
通过服务组合实现复杂业务逻辑:
3. 配置驱动模式
通过注解配置实现功能定制:
@CrudRequestMapping(value = "/system/user",
api = {Api.PAGE, Api.LIST, Api.GET, Api.CREATE,
Api.UPDATE, Api.BATCH_DELETE, Api.EXPORT, Api.DICT})
支持的功能配置选项:
| 配置选项 | 说明 | 示例值 |
|---|---|---|
| value | 接口路径前缀 | "/system/user" |
| api | 开放的API类型 | {Api.PAGE, Api.LIST, Api.GET} |
| permission | 权限前缀 | "system:user" |
高级特性:数据自动填充
ContiNew Admin集成Crane4j框架,实现了数据自动填充功能,显著减少联表查询:
public class BaseServiceImpl<M extends BaseMapper<T>, T extends BaseIdDO, L, D, Q, C>
extends CrudServiceImpl<M, T, L, D, Q, C> {
@Override
protected void fill(Object obj) {
if (obj == null) {
return;
}
OperateTemplate operateTemplate = SpringUtil.getBean(OperateTemplate.class);
operateTemplate.execute(obj);
}
}
数据填充流程:
最佳实践:组件开发指南
1. 控制器开发规范
// ✅ 正确示例:遵循统一的控制器结构
@Tag(name = "部门管理 API")
@RestController
@CrudRequestMapping(value = "/system/dept", api = {Api.TREE, Api.GET, Api.CREATE,
Api.UPDATE, Api.DELETE, Api.EXPORT, Api.DICT_TREE})
public class DeptController extends BaseController<DeptService, DeptResp, DeptDetailResp, DeptQuery, DeptReq> {
// 自定义接口需要明确权限注解
@SaCheckPermission("system:dept:customOperation")
@PostMapping("/custom-operation")
public void customOperation() {
// 业务逻辑
}
}
2. 服务层开发规范
// ✅ 正确示例:服务接口继承BaseService
public interface DeptService extends BaseService<DeptResp, DeptDetailResp, DeptQuery, DeptReq>,
IService<DeptDO> {
// 自定义业务方法
void customBusinessMethod(CustomReq req);
}
// ✅ 正确示例:服务实现继承BaseServiceImpl
public class DeptServiceImpl extends BaseServiceImpl<DeptMapper, DeptDO, DeptResp, DeptDetailResp, DeptQuery, DeptReq>
implements DeptService {
@Override
public void customBusinessMethod(CustomReq req) {
// 业务实现
}
}
3. 异常处理规范
ContiNew Admin提供了统一的异常处理机制,组件开发时应遵循:
- 业务异常使用
ServiceException抛出 - 参数校验异常使用Jakarta Validation注解
- 权限异常由Sa-Token统一处理
性能优化策略
1. 缓存策略优化
// 使用JetCache注解实现方法级缓存
@Cached(name = "user:", key = "#id", expire = 300)
@Override
public UserDetailResp get(Long id) {
return super.get(id);
}
2. 批量操作优化
// 批量操作减少数据库交互
@Transactional(rollbackFor = Exception.class)
@Override
public void delete(List<Long> ids) {
// 先执行业务逻辑校验
validateBeforeDelete(ids);
// 调用父类批量删除方法
super.delete(ids);
}
3. 数据查询优化
// 使用MyBatis Plus的Lambda查询优化
@Override
protected Wrapper<T> buildQueryWrapper(Q query) {
return Wrappers.<T>lambdaQuery()
.eq(ObjectUtils.isNotEmpty(query.getStatus()), T::getStatus, query.getStatus())
.like(ObjectUtils.isNotEmpty(query.getKeyword()), T::getKeyword, query.getKeyword())
.orderByDesc(T::getCreateTime);
}
组件测试策略
1. 单元测试覆盖
@ExtendWith(MockitoExtension.class)
class UserControllerTest {
@Mock
private UserService userService;
@InjectMocks
private UserController userController;
@Test
void shouldResetPasswordSuccessfully() {
// 测试数据准备
UserPasswordResetReq req = new UserPasswordResetReq();
Long userId = 1L;
// 执行测试
userController.resetPassword(req, userId);
// 验证结果
verify(userService).resetPassword(any(), eq(userId));
}
}
2. 集成测试方案
@SpringBootTest
@AutoConfigureMockMvc
class UserControllerIntegrationTest {
@Autowired
private MockMvc mockMvc;
@Test
void shouldReturnUserList() throws Exception {
mockMvc.perform(get("/system/user/list")
.header("Authorization", "Bearer token"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.data").isArray());
}
}
总结与展望
ContiNew Admin的可复用业务组件架构通过以下设计实现了高效的组件复用:
- 统一的基类设计:
BaseController和BaseService提供了通用的CRUD功能和权限校验 - 灵活的配置机制:通过注解配置实现功能定制,满足不同业务场景需求
- 数据自动填充:集成Crane4j框架,减少联表查询,提升性能
- 完善的异常处理:统一的异常处理机制,保证系统稳定性
未来,ContiNew Admin将继续优化组件架构,计划在以下方面进行改进:
- 支持更灵活的插件化组件机制
- 增强组件的可观测性,提供更详细的运行指标
- 优化组件间的通信机制,提升系统性能
- 提供更多的预制业务组件,进一步降低开发成本
通过可复用业务组件的设计和实现,ContiNew Admin为开发者提供了一套高效、稳定、易扩展的开发框架,让企业级应用开发变得更加简单和高效。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



