写一个部门管理,按controller,service,mapper三层架构写
首先,我需要确认用户的技术栈,可能使用的是Spring Boot,结合MyBatis或者JPA。根据用户之前的提问历史,他曾询问过微信支付的实现,可能对Java和Spring生态比较熟悉。所以我会默认使用Spring Boot和MyBatis-Plus,因为MyBatis-Plus在国内比较流行,能简化CRUD操作。
接下来,我需要分解三层架构的职责。Controller负责处理HTTP请求,Service处理业务逻辑,Mapper(或DAO)负责数据库交互。需要确保每层之间的调用关系正确,比如Controller调用Service,Service调用Mapper。
然后,考虑部门管理的核心功能。通常包括添加部门、删除部门、修改部门信息、查询部门列表、获取部门详情等。所以需要设计对应的RESTful API,比如POST /depts,DELETE /depts/{id},PUT /depts/{id},GET /depts等。
在实体类设计方面,部门通常有ID、名称、父部门ID、排序号、状态等字段。需要创建对应的Department实体类,并使用MyBatis-Plus的注解来映射数据库表。
对于Mapper层,使用MyBatis-Plus的BaseMapper可以快速实现基本的CRUD方法,无需手动编写XML文件,提高效率。Service层需要实现具体的业务逻辑,比如添加部门前检查名称是否重复,删除部门时检查是否存在子部门等。这些业务规则需要明确,并在代码中处理。
Controller层需要处理参数校验,比如使用@Valid注解验证传入的DTO是否符合要求。同时,统一返回格式,比如使用Result类包装响应数据,便于前端处理。
异常处理也是一个重点。在Service层抛出业务异常,比如部门名称重复时抛出异常,然后通过全局异常处理器捕获,返回统一的错误信息。这能提高代码的可维护性。
另外,用户可能需要分页查询部门列表,所以示例中使用了MyBatis-Plus的Page类来实现分页,方便用户扩展。
最后,考虑代码的规范性和最佳实践,比如使用lombok简化代码,合理使用事务注解,以及遵循RESTful设计原则。同时,给出一些扩展建议,比如添加部门负责人、树形结构展示,帮助用户根据实际需求进行后续开发。
总结来说,我需要提供一个结构清晰、符合三层架构的示例代码,并解释各层的职责和关键点,确保用户能够理解并应用到实际项目中。同时,提醒用户注意事务管理、日志记录等细节,确保代码的健壮性和可维护性。以下是基于Spring Boot + MyBatis-Plus实现的部门管理模块完整示例,采用标准的三层架构:
一、项目结构
src/main/java
├── com.example.department
│ ├── controller
│ │ └── DeptController.java # 控制层
│ ├── service
│ │ ├── DeptService.java # 服务接口
│ │ └── impl
│ │ └── DeptServiceImpl.java # 服务实现
│ ├── mapper
│ │ └── DeptMapper.java # 数据访问层
│ ├── entity
│ │ └── Department.java # 实体类
│ └── dto
│ └── DeptDTO.java # 数据传输对象
二、具体实现代码
1. 实体类 (entity/Department.java)
@Data
@TableName("sys_dept")
@AllArgsConstructor
@NoArgsConstructor
public class Department {
@TableId(type = IdType.AUTO)
private Long id;
private String deptName;
private Long parentId;
private Integer orderNum;
private Integer status; // 0-正常 1-停用
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateTime;
}
2. Mapper层 (mapper/DeptMapper.java)
@Mapper
public interface DeptMapper extends BaseMapper<Department> {
// 自定义查询示例
@Select("SELECT * FROM sys_dept WHERE parent_id = #{parentId}")
List<Department> selectByParentId(Long parentId);
}
3. Service层 (service/DeptService.java)
public interface DeptService extends IService<Department> {
List<Department> getDeptTree();
boolean addDept(DeptDTO deptDTO);
boolean updateDeptStatus(Long id, Integer status);
}
4. Service实现 (service/impl/DeptServiceImpl.java)
@Service
@Slf4j
public class DeptServiceImpl extends ServiceImpl<DeptMapper, Department> implements DeptService {
@Override
public List<Department> getDeptTree() {
List<Department> allDepts = baseMapper.selectList(null);
return buildDeptTree(0L, allDepts); // 从根节点(0)开始构建
}
private List<Department> buildDeptTree(Long parentId, List<Department> allDepts) {
return allDepts.stream()
.filter(dept -> dept.getParentId().equals(parentId))
.peek(dept -> dept.setChildren(buildDeptTree(dept.getId(), allDepts)))
.collect(Collectors.toList());
}
@Override
@Transactional
public boolean addDept(DeptDTO deptDTO) {
// 检查部门名称是否重复
Long count = lambdaQuery()
.eq(Department::getDeptName, deptDTO.getDeptName())
.count();
if (count > 0) {
throw new BusinessException("部门名称已存在");
}
Department dept = new Department();
BeanUtils.copyProperties(deptDTO, dept);
return save(dept);
}
@Override
public boolean updateDeptStatus(Long id, Integer status) {
return lambdaUpdate()
.eq(Department::getId, id)
.set(Department::getStatus, status)
.update();
}
}
5. Controller层 (controller/DeptController.java)
@RestController
@RequestMapping("/dept")
@RequiredArgsConstructor
public class DeptController {
private final DeptService deptService;
@GetMapping("/tree")
public Result<List<Department>> getDeptTree() {
return Result.success(deptService.getDeptTree());
}
@PostMapping
public Result<Boolean> addDept(@Valid @RequestBody DeptDTO deptDTO) {
return Result.success(deptService.addDept(deptDTO));
}
@PutMapping("/{id}/status")
public Result<Boolean> updateStatus(@PathVariable Long id,
@RequestParam Integer status) {
return Result.success(deptService.updateDeptStatus(id, status));
}
@DeleteMapping("/{id}")
public Result<Boolean> deleteDept(@PathVariable Long id) {
// 删除前校验是否存在子部门
Long count = deptService.lambdaQuery()
.eq(Department::getParentId, id)
.count();
if (count > 0) {
throw new BusinessException("存在子部门,无法删除");
}
return Result.success(deptService.removeById(id));
}
}
三、辅助类说明
1. 统一返回格式 (Result.java)
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Result<T> {
private Integer code;
private String msg;
private T data;
public static <T> Result<T> success(T data) {
return new Result<>(200, "成功", data);
}
}
2. DTO对象 (dto/DeptDTO.java)
@Data
public class DeptDTO {
@NotBlank(message = "部门名称不能为空")
private String deptName;
@NotNull
private Long parentId;
@Min(0)
private Integer orderNum;
}
四、关键实现细节
树形结构构建:
- 使用递归算法实现部门树
- 前端可通过
children
属性渲染树形组件
事务控制:
@Transactional
注解保证数据库操作的原子性- 在删除部门时进行存在性校验
参数校验:
- 使用
@Valid
进行DTO参数校验 - 自定义业务异常
BusinessException
- 使用
MyBatis-Plus特性:
- 自动填充时间字段(需配置
MetaObjectHandler
) - 使用LambdaQueryWrapper进行类型安全查询
- 自动填充时间字段(需配置
五、扩展建议
权限控制:
@PreAuthorize("hasRole('ADMIN')") // 在Controller方法上添加权限控制
日志记录:
@Slf4j public class DeptServiceImpl { public boolean addDept(...) { log.info("新增部门:{}", deptDTO); } }
分页查询:
@GetMapping("/page") public Result<Page<Department>> getDeptPage( @RequestParam(defaultValue = "1") Integer pageNum, @RequestParam(defaultValue = "10") Integer pageSize) { Page<Department> page = new Page<>(pageNum, pageSize); return Result.success(deptService.page(page)); }
完整实现需要配合数据库表创建(示例SQL):
CREATE TABLE sys_dept (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
dept_name VARCHAR(50) NOT NULL,
parent_id BIGINT DEFAULT 0,
order_num INT DEFAULT 0,
status TINYINT DEFAULT 0,
create_time DATETIME,
update_time DATETIME
);
建议根据实际需求扩展以下功能:
- 部门负责人关联
- 部门层级路径存储(如1.2.3)
- 部门人数统计
- 部门转移合并功能
相关推荐


















