【JavaWeb学习 | 第23篇】监听器(Listener)与 RBAC 权限模型
恭喜你坚持学到第23篇!前面我们已经掌握了 Filter过滤器、AJAX+JSON、文件上传下载 等实用技术。今天这篇将介绍两个重要内容:
- Listener(监听器):基于事件驱动的组件,能监听应用、会话、请求的生命周期。
- RBAC 权限模型:企业级系统中最常用的权限控制思想,常与 Filter 结合实现细粒度权限管理。
两者结合后,你就能搭建一个相对完整的“用户-角色-权限”后台管理系统框架。
一、什么是 Listener(监听器)?
Listener 是 Servlet 规范提供的事件监听机制,基于观察者模式。它可以在特定事件发生时(比如 Session 创建、应用启动等)自动执行代码,而无需手动调用。
Listener 不需要在请求中显式调用,容器会自动触发。
1. JavaWeb 中主要的 Listener 接口
| Listener 接口 | 监听对象 | 主要方法 | 常见应用场景 |
|---|---|---|---|
| ServletContextListener | application | contextInitialized / contextDestroyed | 应用启动时加载全局数据、初始化连接池 |
| HttpSessionListener | session | sessionCreated / sessionDestroyed | 在线人数统计、Session 超时处理 |
| ServletRequestListener | request | requestInitialized / requestDestroyed | 请求日志记录、统一处理 |
| HttpSessionAttributeListener | session 属性 | attributeAdded / attributeRemoved / attributeReplaced | Session 属性变化监控 |
| ServletContextAttributeListener | application 属性 | attributeAdded / … | 全局属性变化监控 |
| ServletRequestAttributeListener | request 属性 | attributeAdded / … | 请求属性变化监控 |
其中最常用的是前三个。
2. Listener 的开发步骤
步骤1:编写监听器类,实现对应接口。
步骤2:使用注解或 web.xml 配置(推荐注解)。
示例1:应用启动/销毁监听(ServletContextListener)
// com.example.listener.AppListener.java
@WebListener
public class AppListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
// 应用启动时执行(服务器启动或项目部署)
ServletContext context = sce.getServletContext();
System.out.println("【应用启动】" + context.getContextPath() + " 已启动");
// 初始化全局数据,例如加载字典、连接池等
context.setAttribute("appName", "我的JavaWeb系统");
context.setAttribute("onlineCount", 0); // 在线人数初始值
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
// 应用销毁时执行(服务器关闭或项目卸载)
System.out.println("【应用销毁】系统正在关闭...");
}
}
示例2:在线人数统计(HttpSessionListener) —— 经典案例
@WebListener
public class OnlineListener implements HttpSessionListener {
@Override
public void sessionCreated(HttpSessionEvent se) {
// 新用户打开浏览器,Session 创建时
ServletContext context = se.getSession().getServletContext();
Integer count = (Integer) context.getAttribute("onlineCount");
if (count == null) count = 0;
count++;
context.setAttribute("onlineCount", count);
System.out.println("【在线人数 +1】 当前在线:" + count);
}
@Override
public void sessionDestroyed(HttpSessionEvent se) {
// Session 超时或 invalidate() 时
ServletContext context = se.getSession().getServletContext();
Integer count = (Integer) context.getAttribute("onlineCount");
if (count != null && count > 0) {
count--;
context.setAttribute("onlineCount", count);
}
System.out.println("【在线人数 -1】 当前在线:" + count);
}
}
前端显示在线人数(任意 JSP 页面):
当前在线人数:${applicationScope.onlineCount}
注意:同一个用户在多个标签页仍算1人(因为共享同一个 Session)。若要统计“并发 Session 数”,可进一步记录用户 IP + SessionId。
二、RBAC 权限模型(Role-Based Access Control)
RBAC 是目前企业系统中最主流的权限控制模型,核心思想是:
权限不直接给用户,而是给角色;用户再关联角色。
这样极大简化了权限管理(用户数量多时特别明显)。
1. RBAC 核心概念(RBAC0 基础模型)
- 用户(User):系统登录者
- 角色(Role):权限的集合(如 “管理员”、“普通用户”、“财务专员”)
- 权限(Permission):具体操作(如 “用户列表查看”、“订单删除”)
- 关系:
- 用户 ↔ 多对多 ↔ 角色
- 角色 ↔ 多对多 ↔ 权限
经典数据库表结构(5张表):
sys_user(用户表)sys_role(角色表)sys_permission(权限/菜单/URL 表)sys_user_role(用户-角色中间表)sys_role_permission(角色-权限中间表)
扩展模型:
- RBAC1:角色继承(管理员继承普通用户权限)
- RBAC2:角色约束(互斥角色、基数约束等)
- RBAC3:RBAC1 + RBAC2
2. JavaWeb 中 RBAC 的经典实现方式
核心思路:
- 用户登录成功后,在 LoginServlet 中查询该用户拥有的所有权限(或 URL 列表),存入 Session。
- 使用 Filter(权限过滤器)拦截请求,检查当前请求的 URL 是否在用户 Session 的权限列表中。
- 如果没有权限 → 跳转到“无权限提示页”或返回 JSON 错误。
示例:权限过滤器(结合之前学习的 Filter)
@WebFilter("/*")
public class PermissionFilter implements Filter {
@Override
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) resp;
String uri = request.getRequestURI();
// 1. 放行静态资源和登录相关
if (uri.contains("/login") || uri.contains("/static/")
|| uri.endsWith(".css") || uri.endsWith(".js") || uri.endsWith(".png")) {
chain.doFilter(request, response);
return;
}
// 2. 检查是否登录(结合之前的 LoginFilter)
HttpSession session = request.getSession(false);
if (session == null || session.getAttribute("user") == null) {
request.setAttribute("errorMsg", "请先登录!");
request.getRequestDispatcher("/login.jsp").forward(request, response);
return;
}
// 3. RBAC 权限校验
@SuppressWarnings("unchecked")
List<String> userPermissions = (List<String>) session.getAttribute("userPermissions");
// 假设权限存储为 URL 列表,如 ["/user/list", "/order/add"]
boolean hasPermission = false;
if (userPermissions != null) {
for (String perm : userPermissions) {
if (uri.contains(perm)) {
hasPermission = true;
break;
}
}
}
if (hasPermission || isAdmin(session)) { // 管理员特殊放行
chain.doFilter(request, response);
} else {
// 无权限
if (request.getHeader("X-Requested-With") != null) {
// AJAX 请求返回 JSON
response.setContentType("application/json");
response.getWriter().write("{\"code\":403,\"msg\":\"无权限访问!\"}");
} else {
request.setAttribute("errorMsg", "抱歉,您没有权限访问该页面!");
request.getRequestDispatcher("/error/noPermission.jsp").forward(request, response);
}
}
}
private boolean isAdmin(HttpSession session) {
// 简单判断是否为管理员角色
return "admin".equals(session.getAttribute("userRole"));
}
}
登录时加载权限(LoginServlet 片段):
// 登录成功后
User user = ...;
List<String> perms = permissionService.getUserPermissions(user.getId()); // 查询数据库
session.setAttribute("user", user);
session.setAttribute("userPermissions", perms);
session.setAttribute("userRole", user.getRoleCode());
三、实际开发建议
- Listener 适合做全局初始化和被动事件响应,不要放复杂业务逻辑。
- 在线人数统计建议结合
HttpSessionBindingListener(让 User 对象实现该接口,销毁时自动减数)更精确。 - RBAC 在中小项目中常用 URL 权限 + Filter 实现;大型项目推荐引入 Spring Security 或 Shiro。
- 菜单权限:登录后把用户有权限的菜单也存入 Session,前端用 JSTL/c:if 动态显示菜单。
- 权限颗粒度:可以细化到按钮级别(用自定义标签或 JS 控制按钮显示)。
四、练习建议(强烈推荐完成)
- 实现在线人数统计(Listener + application 作用域),并在首页实时显示。
- 实现Session 监听,当用户注销(session.invalidate())时自动减在线人数。
- 搭建简易 RBAC:
- 创建用户、角色、权限表(可用 MySQL)
- 登录时加载权限到 Session
- 编写 PermissionFilter 实现 URL 权限控制
- 结合之前 Filter 系列,做一个登录过滤器 + 权限过滤器链。
- 进阶:实现角色继承(管理员自动拥有普通用户所有权限)。
完成这些,你的 JavaWeb 项目已经具备了“用户管理 + 权限控制 + 在线监控”的基础骨架,非常接近真实后台管理系统!
系列文章导航(持续更新中):
- 第21篇:AJAX与JSON详解
- 第22篇:文件上传下载与 Excel 导入导出
- 第23篇:监听器与 RBAC 权限模型(本文)
- 第24篇:综合案例 —— 基于 Servlet + JSP + MVC + Filter + Listener + RBAC 的简易后台管理系统(推荐)
有任何疑问(比如想看更完整的在线用户列表代码、RBAC 数据库表设计、或如何把权限细化到按钮级别),欢迎在评论区留言,我会尽快补充详细示例!
掌握了 Listener 和 RBAC,你已经具备了独立开发中小型 JavaWeb 管理系统的能力。继续加油,下一篇文章我们将把前面所有知识点整合起来,做一个完整的小项目!💪
下一篇文章见~ 🚀