EH-ADMIN:一个springboot + vue 前后端分离的后台管理模板,一键生成CRUD操作,RBAC权限控制...
EH-ADMIN:一个springboot + vue 前后端分离的后台管理模板,一键生成CRUD操作,RBAC权限控制...
一、背景与问题
在企业级应用开发中,后台管理系统的开发往往面临以下挑战:
- 重复性开发:每个模块都需要编写CRUD接口、前端页面、权限控制逻辑
- 权限控制复杂:需要实现RBAC(基于角色的访问控制)模型,处理角色-权限-资源的多维关系
- 技术栈整合困难:前后端分离架构需要处理API接口设计、数据格式转换、跨域等问题
- 开发效率低下:需要大量手动编写代码,缺乏自动化工具支持
EH-ADMIN作为一款开源模板,通过以下创新点解决上述问题:
- 基于代码生成器的自动化开发
- 嵌入式RBAC权限控制体系
- 前后端分离的完整架构支持
- 丰富的可配置选项
二、基本原理
1. 技术架构设计
EH-ADMIN采用前后端分离架构,核心组件包括:
- 后端:Spring Boot + MyBatis Plus + Spring Security
- 前端:Vue 3 + Element Plus + Axios
- 数据库:MySQL + Redis(可选)
核心流程:
用户请求 -> 前端组件 -> Axios请求 -> 后端接口 -> 服务层处理 -> 数据库访问 -> 响应返回2. 代码生成原理
通过模板引擎(如Freemarker)实现代码生成,核心流程:
1. 定义实体类模板(Entity.java.ftl)
2. 生成Service/Controller层代码(基于注解)
3. 自动生成前端组件(基于Vue单文件组件模板)
4. 动态生成API文档(Swagger)3. RBAC权限控制原理
采用三元组模型(User-Role-Permission):
User → Role → Permission → Resource通过数据库表结构实现:
CREATE TABLE role (
id BIGINT PRIMARY KEY,
name VARCHAR(50) NOT NULL
);
CREATE TABLE permission (
id BIGINT PRIMARY KEY,
name VARCHAR(50) NOT NULL,
resource VARCHAR(255) NOT NULL
);
CREATE TABLE role_permission (
role_id BIGINT,
permission_id BIGINT
);三、环境准备
1. 后端环境配置
# 创建Spring Boot项目
spring init --build=maven --java=17 --build-gradle --no-interactive eh-admin
# 添加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>2. 前端环境配置
# 创建Vue3项目
npm create vue@latest eh-admin-vue
# 安装依赖
npm install element-plus axios四、核心实现
1. 实体类生成示例
创建实体类模板(Entity.java.ftl):
<#assign className = table.className>
<#assign classNameWithoutPackage = className?replace('.', '/')>
package ${table.namespace};
import com.baomidou.mybatisplus.annotation.*;
<#assign tableId = table.id>
<#assign tablePk = table.pk>
@TableName("${table.name}")
public class ${className} {
@TableId(value = "${tableId}", type = IdType.AUTO)
private Long id;
@TableField(value = "name")
private String name;
@TableField(value = "created_time")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date createdTime;
@TableField(value = "updated_time")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date updatedTime;
// Getters and Setters
}2. 权限控制配置
Spring Security配置类:
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsService userDetailsService;
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/api/**").authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.logout()
.logoutSuccessUrl("/login")
.permitAll()
.and()
.csrf().disable()
.sessionManagement()
.maximumSessions(1)
.expiredSessionStrategy(new CustomSessionExpiredStrategy());
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService);
}
}3. 前端组件示例
创建用户管理组件(UserList.vue):
<template>
<el-table :data="users" border style="width: 100%">
<el-table-column prop="id" label="ID" width="180"></el-table-column>
<el-table-column prop="name" label="名称"></el-table-column>
<el-table-column prop="createdTime" label="创建时间" width="180">
<template slot-scope="scope">
{{ formatDate(scope.row.createdTime) }}
</template>
</el-table-column>
<el-table-column label="操作">
<template slot-scope="scope">
<el-button @click="editUser(scope.row)">编辑</el-button>
<el-button @click="deleteUser(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
</template>
<script>
export default {
data() {
return {
users: []
};
},
mounted() {
this.fetchUsers();
},
methods: {
async fetchUsers() {
const res = await this.$axios.get('/api/users');
this.users = res.data;
},
formatDate(date) {
return dayjs(date).format('YYYY-MM-DD HH:mm:ss');
}
}
};
</script>五、完整案例
1. 用户管理模块开发
后端实现
创建实体类:
@TableName("user")
public class User {
@TableId(value = "id", type = IdType.AUTO)
private Long id;
private String name;
private Date createdTime;
private Date updatedTime;
// Getters and Setters
}创建Mapper接口:
public interface UserMapper extends BaseMapper<User> {
}创建Service层:
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
public List<User> getAllUsers() {
return userMapper.selectList(null);
}
public void saveUser(User user) {
user.setCreatedTime(new Date());
user.setUpdatedTime(new Date());
userMapper.insert(user);
}
public void deleteUser(Long id) {
userMapper.deleteById(id);
}
}创建Controller:
@RestController
@RequestMapping("/api/users")
public class UserController {
@Autowired
private UserService userService;
@GetMapping
public List<User> getAllUsers() {
return userService.getAllUsers();
}
@PostMapping
public void saveUser(@RequestBody User user) {
userService.saveUser(user);
}
@DeleteMapping("/{id}")
public void deleteUser(@PathVariable Long id) {
userService.deleteUser(id);
}
}前端实现
创建页面组件:
<template>
<div>
<el-button @click="addUser">新增</el-button>
<el-table :data="users" border style="width: 100%">
<el-table-column prop="id" label="ID" width="180"></el-table-column>
<el-table-column prop="name" label="名称"></el-table-column>
<el-table-column prop="createdTime" label="创建时间" width="180">
<template slot-scope="scope">
{{ formatDate(scope.row.createdTime) }}
</template>
</el-table-column>
<el-table-column label="操作">
<template slot-scope="scope">
<el-button @click="editUser(scope.row)">编辑</el-button>
<el-button @click="deleteUser(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
</div>
</template>
<script>
export default {
data() {
return {
users: []
};
},
mounted() {
this.fetchUsers();
},
methods: {
async fetchUsers() {
const res = await this.$axios.get('/api/users');
this.users = res.data;
},
formatDate(date) {
return dayjs(date).format('YYYY-MM-DD HH:mm:ss');
}
}
};
</script>六、源码解析
1. 代码生成器核心逻辑
public class CodeGenerator {
public static void main(String[] args) {
// 1. 读取配置文件
Properties props = new Properties();
try (InputStream is = new FileInputStream("generator.properties")) {
props.load(is);
} catch (IOException e) {
e.printStackTrace();
}
// 2. 创建模板引擎
Configuration configuration = Configuration.defaultConfiguration();
configuration.setClassForTemplateLoading("templates", "java");
configuration.setTemplateExceptionHandler(WrapperTemplateExceptionHandler.class);
// 3. 生成实体类
Template template = configuration.getTemplate("entity.ftl");
Map<String, Object> model = new HashMap<>();
model.put("entity", new Entity());
try (Writer writer = new FileWriter("src/main/java/com/example/demo/Entity.java")) {
template.process(model, writer);
} catch (Exception e) {
e.printStackTrace();
}
}
}2. 权限控制核心逻辑
public class PermissionService {
public boolean checkPermission(String username, String resource) {
// 1. 查询用户角色
List<Role> roles = roleRepository.findByUser(username);
// 2. 查询角色权限
Set<String> permissions = roles.stream()
.flatMap(role -> role.getPermissions().stream())
.map(Permission::getName)
.collect(Collectors.toSet());
// 3. 检查资源权限
return permissions.contains(resource);
}
}七、进阶使用
1. 多租户支持
通过在实体类中添加tenant字段:
@TableName("tenant")
public class Tenant {
@TableId(value = "id", type = IdType.AUTO)
private Long id;
private String name;
private String tenantId;
// Getters and Setters
}在SQL查询中添加租户过滤:
public List<User> getTenantUsers(String tenantId) {
return userMapper.selectList(new QueryWrapper<User>().eq("tenant_id", tenantId));
}2. 工作流集成
结合Flowable实现审批流程:
public void startProcess(String userId, String processDefinitionId) {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RuntimeService runtimeService = processEngine.getRuntimeService();
ProcessInstanceEntity processInstance = runtimeService.startProcessInstanceById(processDefinitionId,
Collections.singletonMap("userId", userId));
}3. 审计日志
通过AOP记录操作日志:
@Aspect
@Component
public class AuditAspect {
@Around("execution(* com.example.demo.controller.*.*(..))")
public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
long start = System.currentTimeMillis();
Object result = joinPoint.proceed();
long duration = System.currentTimeMillis() - start;
// 记录日志
return result;
}
}八、性能与工程实践
1. 性能优化策略
数据库优化:
- 为常用查询字段添加索引
- 使用分页查询(
limit offset) - 对大数据量使用分库分表
缓存策略:
- 对频繁访问的权限数据使用Redis缓存
- 对数据更新操作使用缓存失效策略
异步处理:
- 使用Spring Task处理定时任务
- 使用RabbitMQ处理耗时操作
2. 安全防护措施
防止SQL注入:
- 使用MyBatis Plus的
QueryWrapper构建查询 - 避免直接拼接SQL语句
- 使用MyBatis Plus的
防止XSS攻击:
- 使用Vue的
v-html时进行内容过滤 - 对用户输入进行HTML转义处理
- 使用Vue的
防止CSRF攻击:
- 使用Spring Security的
CsrfToken机制 - 对关键操作添加token验证
- 使用Spring Security的
九、常见问题与踩坑
1. 权限验证失败
问题表现:用户访问授权资源时提示403 Forbidden
原因分析:
- 权限配置错误
- 权限缓存未更新
- 未正确处理角色继承关系
解决办法:
// 确保权限缓存及时更新
@Cacheable(value = "permissions", key = "#username")
public Set<String> getPermissions(String username) {
// 查询逻辑
}2. 前端页面加载缓慢
问题表现:首次访问页面时出现明显延迟
优化方案:
- 使用Vue的懒加载组件(
lazy) - 对大数据量使用虚拟滚动(
vue-virtual-scroller) - 对接口进行分页处理
3. 权限配置错误
问题表现:新增权限后未生效
解决办法:
- 检查RBAC配置是否正确
- 检查权限分配是否完整
- 确认缓存是否已清除
十、最佳实践
1. 使用建议
适用场景:
- 快速开发标准CRUD功能
- 需要RBAC权限控制的管理系统
- 需要前后端分离的项目架构
开发规范:
- 保持代码结构清晰
- 使用统一的命名规范
- 对关键业务逻辑进行单元测试
2. 避免使用场景
不适合的场景:
- 需要高度定制化业务逻辑的项目
- 需要复杂工作流的系统
- 需要高性能实时处理的场景
十一、总结
EH-ADMIN作为一款Spring Boot + Vue的后台管理模板,通过代码生成器和RBAC权限控制模块,有效解决了传统开发中的重复性工作和权限管理难题。其核心价值体现在:
- 自动化代码生成提高开发效率
- 嵌入式权限控制体系确保安全
- 前后端分离架构适应现代开发需求
- 灵活的扩展能力适应不同业务场景
在实际应用中,开发者需要根据项目需求合理使用该模板,同时注意避免在需要高度定制化或复杂业务逻辑的场景中过度依赖。通过合理配置和优化,EH-ADMIN能够显著提升开发效率,降低维护成本,是企业级后台管理系统开发的理想选择。
评论已关闭