Java Web后台登录页面
·

下面我将为你提供一个完整的Java Web后台登录系统实现,包含安全认证、会话管理和权限控制。
📋 技术架构
| 组件 | 技术选择 | 说明 |
|---|---|---|
| 前端 | JSP + Bootstrap + jQuery | 响应式登录页面 |
| 控制层 | Servlet + Filter | 请求处理和安全过滤 |
| 安全框架 | 自定义认证 + Session管理 | 用户认证和权限控制 |
| 数据层 | DAO模式 + JDBC | 用户数据持久化 |
| 密码加密 | BCrypt | 安全密码哈希 |
🗂️ 项目结构
WebContent/
├── login.jsp # 登录页面
├── dashboard.jsp # 后台主页
├── WEB-INF/
│ ├── web.xml # 配置文件
│ └── classes/
│ ├── com/
│ │ └── admin/
│ │ ├── controller/ # Servlet控制器
│ │ ├── service/ # 业务逻辑
│ │ ├── dao/ # 数据访问
│ │ ├── model/ # 实体类
│ │ ├── filter/ # 过滤器
│ │ └── util/ # 工具类
├── css/
│ └── login.css # 登录页面样式
├── js/
│ └── login.js # 登录页面脚本
└── assets/
├── images/
└── fonts/
👤 用户数据模型
User.java
package com.admin.model;
import java.util.Date;
public class User {
private Integer id;
private String username;
private String password;
private String email;
private String realName;
private Integer roleId; // 角色ID
private Integer status; // 状态:1-启用,0-禁用
private Date lastLoginTime;
private Date createTime;
private Date updateTime;
// 构造方法
public User() {}
public User(String username, String password, String email, String realName) {
this.username = username;
this.password = password;
this.email = email;
this.realName = realName;
}
// Getter和Setter
public Integer getId() { return id; }
public void setId(Integer id) { this.id = id; }
public String getUsername() { return username; }
public void setUsername(String username) { this.username = username; }
public String getPassword() { return password; }
public void setPassword(String password) { this.password = password; }
public String getEmail() { return email; }
public void setEmail(String email) { this.email = email; }
public String getRealName() { return realName; }
public void setRealName(String realName) { this.realName = realName; }
public Integer getRoleId() { return roleId; }
public void setRoleId(Integer roleId) { this.roleId = roleId; }
public Integer getStatus() { return status; }
public void setStatus(Integer status) { this.status = status; }
public Date getLastLoginTime() { return lastLoginTime; }
public void setLastLoginTime(Date lastLoginTime) { this.lastLoginTime = lastLoginTime; }
public Date getCreateTime() { return createTime; }
public void setCreateTime(Date createTime) { this.createTime = createTime; }
public Date getUpdateTime() { return updateTime; }
public void setUpdateTime(Date updateTime) { this.updateTime = updateTime; }
}
Role.java (角色实体)
package com.admin.model;
public class Role {
private Integer id;
private String roleName;
private String description;
private String permissions; // 权限列表,JSON格式或逗号分隔
public Role() {}
public Role(Integer id, String roleName, String description) {
this.id = id;
this.roleName = roleName;
this.description = description;
}
// Getter和Setter
public Integer getId() { return id; }
public void setId(Integer id) { this.id = id; }
public String getRoleName() { return roleName; }
public void setRoleName(String roleName) { this.roleName = roleName; }
public String getDescription() { return description; }
public void setDescription(String description) { this.description = description; }
public String getPermissions() { return permissions; }
public void setPermissions(String permissions) { this.permissions = permissions; }
}
🗄️ 数据库设计
用户表 (users)
CREATE TABLE users (
id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(50) UNIQUE NOT NULL,
password VARCHAR(255) NOT NULL,
email VARCHAR(100),
real_name VARCHAR(50),
role_id INT DEFAULT 1,
status TINYINT DEFAULT 1 COMMENT '1-启用, 0-禁用',
last_login_time DATETIME,
create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
update_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX idx_username (username),
INDEX idx_status (status)
);
角色表 (roles)
CREATE TABLE roles (
id INT PRIMARY KEY AUTO_INCREMENT,
role_name VARCHAR(50) NOT NULL,
description VARCHAR(200),
permissions TEXT,
create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
初始化管理员数据
INSERT INTO users (username, password, email, real_name, role_id)
VALUES ('admin', '$2a$10$N.zmdr9k7uOCQb376NoUnuTJ8iAt6Z5EHsM8lE9lBOsl7iKTV5UiC', 'admin@example.com', '系统管理员', 1);
INSERT INTO roles (role_name, description, permissions) VALUES
('超级管理员', '系统最高权限管理员', 'user:view,user:edit,user:delete,content:view,content:edit,content:delete,system:config'),
('普通管理员', '普通内容管理员', 'content:view,content:edit');
🔐 数据访问层
UserDAO.java
package com.admin.dao;
import com.admin.model.User;
import com.admin.util.DBUtil;
import java.sql.*;
import java.util.Date;
public class UserDAO {
// 根据用户名查找用户
public User findByUsername(String username) {
User user = null;
String sql = "SELECT * FROM users WHERE username = ? AND status = 1";
try (Connection conn = DBUtil.getConnection();
PreparedStatement stmt = conn.prepareStatement(sql)) {
stmt.setString(1, username);
ResultSet rs = stmt.executeQuery();
if (rs.next()) {
user = extractUserFromResultSet(rs);
}
} catch (SQLException e) {
e.printStackTrace();
}
return user;
}
// 更新最后登录时间
public void updateLastLoginTime(Integer userId) {
String sql = "UPDATE users SET last_login_time = ? WHERE id = ?";
try (Connection conn = DBUtil.getConnection();
PreparedStatement stmt = conn.prepareStatement(sql)) {
stmt.setTimestamp(1, new Timestamp(new Date().getTime()));
stmt.setInt(2, userId);
stmt.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
}
}
// 从ResultSet提取User对象
private User extractUserFromResultSet(ResultSet rs) throws SQLException {
User user = new User();
user.setId(rs.getInt("id"));
user.setUsername(rs.getString("username"));
user.setPassword(rs.getString("password"));
user.setEmail(rs.getString("email"));
user.setRealName(rs.getString("real_name"));
user.setRoleId(rs.getInt("role_id"));
user.setStatus(rs.getInt("status"));
user.setLastLoginTime(rs.getTimestamp("last_login_time"));
user.setCreateTime(rs.getTimestamp("create_time"));
user.setUpdateTime(rs.getTimestamp("update_time"));
return user;
}
}
🔧 密码加密工具
PasswordUtil.java
package com.admin.util;
import org.mindrot.jbcrypt.BCrypt;
public class PasswordUtil {
// 加密密码
public static String hashPassword(String plainPassword) {
return BCrypt.hashpw(plainPassword, BCrypt.gensalt());
}
// 验证密码
public static boolean checkPassword(String plainPassword, String hashedPassword) {
try {
return BCrypt.checkpw(plainPassword, hashedPassword);
} catch (Exception e) {
return false;
}
}
// 生成随机密码
public static String generateRandomPassword(int length) {
String chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
StringBuilder sb = new StringBuilder();
for (int i = 0; i < length; i++) {
int index = (int) (Math.random() * chars.length());
sb.append(chars.charAt(index));
}
return sb.toString();
}
}
⚙️ 认证服务
AuthService.java
package com.admin.service;
import com.admin.dao.UserDAO;
import com.admin.model.User;
import com.admin.util.PasswordUtil;
public class AuthService {
private UserDAO userDAO = new UserDAO();
// 用户登录认证
public User authenticate(String username, String password) {
User user = userDAO.findByUsername(username);
if (user != null && PasswordUtil.checkPassword(password, user.getPassword())) {
// 更新最后登录时间
userDAO.updateLastLoginTime(user.getId());
return user;
}
return null;
}
// 检查用户是否存在
public boolean userExists(String username) {
return userDAO.findByUsername(username) != null;
}
// 验证密码强度
public boolean isPasswordStrong(String password) {
if (password == null || password.length() < 6) {
return false;
}
// 检查是否包含数字和字母
boolean hasLetter = false;
boolean hasDigit = false;
for (char c : password.toCharArray()) {
if (Character.isLetter(c)) hasLetter = true;
if (Character.isDigit(c)) hasDigit = true;
}
return hasLetter && hasDigit;
}
}
🎮 登录控制器
LoginServlet.java
package com.admin.controller;
import com.admin.model.User;
import com.admin.service.AuthService;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
@WebServlet("/login")
public class LoginServlet extends HttpServlet {
private AuthService authService = new AuthService();
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 如果已登录,直接跳转到后台首页
HttpSession session = request.getSession(false);
if (session != null && session.getAttribute("user") != null) {
response.sendRedirect("dashboard");
return;
}
// 否则显示登录页面
request.getRequestDispatcher("/login.jsp").forward(request, response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String username = request.getParameter("username");
String password = request.getParameter("password");
String captcha = request.getParameter("captcha");
String rememberMe = request.getParameter("rememberMe");
// 验证码验证
HttpSession session = request.getSession();
String sessionCaptcha = (String) session.getAttribute("captcha");
if (sessionCaptcha == null || !sessionCaptcha.equalsIgnoreCase(captcha)) {
sendErrorResponse(request, response, "验证码错误");
return;
}
// 输入验证
if (username == null || username.trim().isEmpty()) {
sendErrorResponse(request, response, "用户名不能为空");
return;
}
if (password == null || password.isEmpty()) {
sendErrorResponse(request, response, "密码不能为空");
return;
}
try {
// 用户认证
User user = authService.authenticate(username, password);
if (user != null) {
// 登录成功
session.setAttribute("user", user);
session.setAttribute("loginTime", new java.util.Date());
// 记住我功能
if ("on".equals(rememberMe)) {
session.setMaxInactiveInterval(7 * 24 * 60 * 60); // 7天
} else {
session.setMaxInactiveInterval(2 * 60 * 60); // 2小时
}
// 清除验证码
session.removeAttribute("captcha");
// 记录登录日志
logLoginSuccess(username, request.getRemoteAddr());
// 返回成功响应
response.sendRedirect("dashboard");
} else {
// 登录失败
sendErrorResponse(request, response, "用户名或密码错误");
}
} catch (Exception e) {
e.printStackTrace();
sendErrorResponse(request, response, "系统错误,请稍后重试");
}
}
private void sendErrorResponse(HttpServletRequest request, HttpServletResponse response, String message)
throws ServletException, IOException {
request.setAttribute("error", message);
request.setAttribute("username", request.getParameter("username"));
request.getRequestDispatcher("/login.jsp").forward(request, response);
}
private void logLoginSuccess(String username, String ip) {
System.out.println("用户 " + username + " 在 " + new java.util.Date() + " 从 IP " + ip + " 登录成功");
}
}
LogoutServlet.java
package com.admin.controller;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
@WebServlet("/logout")
public class LogoutServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
HttpSession session = request.getSession(false);
if (session != null) {
// 记录登出日志
Object user = session.getAttribute("user");
if (user instanceof com.admin.model.User) {
String username = ((com.admin.model.User) user).getUsername();
System.out.println("用户 " + username + " 在 " + new java.util.Date() + " 登出");
}
// 使session失效
session.invalidate();
}
// 重定向到登录页面
response.sendRedirect("login");
}
}
🔒 安全过滤器
AuthFilter.java
package com.admin.filter;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
@WebFilter("/*")
public class AuthFilter implements Filter {
// 不需要登录就可以访问的路径
private static final String[] PUBLIC_PATHS = {
"/login",
"/logout",
"/captcha",
"/css/",
"/js/",
"/assets/",
"/error/"
};
@Override
public void init(FilterConfig filterConfig) throws ServletException {
// 初始化
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
HttpSession session = httpRequest.getSession(false);
String path = httpRequest.getRequestURI().substring(httpRequest.getContextPath().length());
// 检查是否为公开路径
if (isPublicPath(path)) {
chain.doFilter(request, response);
return;
}
// 检查用户是否已登录
boolean loggedIn = (session != null && session.getAttribute("user") != null);
if (!loggedIn) {
// 未登录,重定向到登录页面
httpResponse.sendRedirect(httpRequest.getContextPath() + "/login");
return;
}
// 已登录,继续请求处理
chain.doFilter(request, response);
}
private boolean isPublicPath(String path) {
if (path == null || path.equals("/")) {
return true;
}
for (String publicPath : PUBLIC_PATHS) {
if (path.startsWith(publicPath)) {
return true;
}
}
return false;
}
@Override
public void destroy() {
// 清理资源
}
}
🖼️ 验证码生成
CaptchaServlet.java
package com.admin.controller;
import javax.imageio.ImageIO;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Random;
@WebServlet("/captcha")
public class CaptchaServlet extends HttpServlet {
// 验证码字符集
private static final String CHARTS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
private static final int WIDTH = 120;
private static final int HEIGHT = 40;
private static final int CODE_LENGTH = 4;
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 设置响应类型
response.setContentType("image/jpeg");
response.setHeader("Pragma", "no-cache");
response.setHeader("Cache-Control", "no-cache");
response.setDateHeader("Expires", 0);
// 创建图像
BufferedImage image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
Graphics2D g = image.createGraphics();
// 设置背景
g.setColor(Color.WHITE);
g.fillRect(0, 0, WIDTH, HEIGHT);
// 绘制干扰线
drawInterferenceLines(g);
// 生成验证码
String captchaCode = generateCaptchaCode(g);
// 保存到session
HttpSession session = request.getSession();
session.setAttribute("captcha", captchaCode);
// 输出图像
g.dispose();
ImageIO.write(image, "JPEG", response.getOutputStream());
}
private String generateCaptchaCode(Graphics2D g) {
Random random = new Random();
StringBuilder code = new StringBuilder();
for (int i = 0; i < CODE_LENGTH; i++) {
// 随机字符
String ch = String.valueOf(CHARTS.charAt(random.nextInt(CHARTS.length())));
code.append(ch);
// 设置字体和颜色
g.setFont(new Font("Arial", Font.BOLD, 24 + random.nextInt(6)));
g.setColor(getRandomColor(100, 150));
// 绘制字符(添加随机旋转)
double radian = Math.toRadians(random.nextInt(45) - 22);
g.rotate(radian, 20 + i * 25, 25);
g.drawString(ch, 20 + i * 25, 25 + random.nextInt(8) - 4);
g.rotate(-radian, 20 + i * 25, 25);
}
return code.toString();
}
private void drawInterferenceLines(Graphics2D g) {
Random random = new Random();
// 绘制干扰线
for (int i = 0; i < 6; i++) {
g.setColor(getRandomColor(160, 200));
int x1 = random.nextInt(WIDTH);
int y1 = random.nextInt(HEIGHT);
int x2 = random.nextInt(WIDTH);
int y2 = random.nextInt(HEIGHT);
g.drawLine(x1, y1, x2, y2);
}
// 绘制噪点
for (int i = 0; i < 50; i++) {
int x = random.nextInt(WIDTH);
int y = random.nextInt(HEIGHT);
g.setColor(getRandomColor(150, 250));
g.drawLine(x, y, x, y);
}
}
private Color getRandomColor(int fc, int bc) {
Random random = new Random();
if (fc > 255) fc = 255;
if (bc > 255) bc = 255;
int r = fc + random.nextInt(bc - fc);
int g = fc + random.nextInt(bc - fc);
int b = fc + random.nextInt(bc - fc);
return new Color(r, g, b);
}
}
🎨 登录页面
login.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>后台管理系统 - 登录</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.7.2/font/bootstrap-icons.css">
<style>
body {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
height: 100vh;
display: flex;
align-items: center;
}
.login-container {
max-width: 400px;
width: 100%;
margin: 0 auto;
}
.login-card {
background: white;
border-radius: 15px;
box-shadow: 0 15px 35px rgba(0,0,0,0.1);
overflow: hidden;
}
.login-header {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
padding: 30px 20px;
text-align: center;
}
.login-body {
padding: 30px;
}
.form-control {
border-radius: 8px;
padding: 12px 15px;
}
.btn-login {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border: none;
border-radius: 8px;
padding: 12px;
color: white;
font-weight: 600;
}
.btn-login:hover {
opacity: 0.9;
color: white;
}
.captcha-img {
cursor: pointer;
border-radius: 6px;
}
.input-group-text {
background: #f8f9fa;
border-radius: 8px;
}
</style>
</head>
<body>
<div class="container">
<div class="login-container">
<div class="login-card">
<div class="login-header">
<h3><i class="bi bi-shield-lock"></i> 后台管理系统</h3>
<p class="mb-0">请登录您的账户</p>
</div>
<div class="login-body">
<form id="loginForm" action="login" method="post">
<!-- 错误消息显示 -->
<c:if test="${not empty error}">
<div class="alert alert-danger alert-dismissible fade show" role="alert">
<i class="bi bi-exclamation-triangle"></i> ${error}
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
</div>
</c:if>
<!-- 用户名输入 -->
<div class="mb-3">
<label for="username" class="form-label">用户名</label>
<div class="input-group">
<span class="input-group-text"><i class="bi bi-person"></i></span>
<input type="text" class="form-control" id="username" name="username"
value="${username}" placeholder="请输入用户名" required>
</div>
</div>
<!-- 密码输入 -->
<div class="mb-3">
<label for="password" class="form-label">密码</label>
<div class="input-group">
<span class="input-group-text"><i class="bi bi-lock"></i></span>
<input type="password" class="form-control" id="password" name="password"
placeholder="请输入密码" required>
<button class="btn btn-outline-secondary" type="button" id="togglePassword">
<i class="bi bi-eye"></i>
</button>
</div>
</div>
<!-- 验证码 -->
<div class="mb-3">
<label for="captcha" class="form-label">验证码</label>
<div class="row g-2">
<div class="col-7">
<input type="text" class="form-control" id="captcha" name="captcha"
placeholder="请输入验证码" required maxlength="4">
</div>
<div class="col-5">
<img id="captchaImage" src="captcha" alt="验证码"
class="captcha-img w-100 h-100" title="点击刷新验证码">
</div>
</div>
</div>
<!-- 记住我和忘记密码 -->
<div class="mb-3 d-flex justify-content-between align-items-center">
<div class="form-check">
<input class="form-check-input" type="checkbox" id="rememberMe" name="rememberMe">
<label class="form-check-label" for="rememberMe">记住我</label>
</div>
<a href="#" class="text-decoration-none">忘记密码?</a>
</div>
<!-- 登录按钮 -->
<button type="submit" class="btn btn-login w-100 mb-3">
<i class="bi bi-box-arrow-in-right"></i> 登录
</button>
<!-- 版权信息 -->
<div class="text-center">
<small class="text-muted">© 2024 后台管理系统</small>
</div>
</form>
</div>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script>
$(document).ready(function() {
// 切换密码显示
$('#togglePassword').click(function() {
const passwordInput = $('#password');
const type = passwordInput.attr('type') === 'password' ? 'text' : 'password';
passwordInput.attr('type', type);
$(this).find('i').toggleClass('bi-eye bi-eye-slash');
});
// 刷新验证码
$('#captchaImage').click(function() {
$(this).attr('src', 'captcha?t=' + new Date().getTime());
});
// 表单提交验证
$('#loginForm').submit(function() {
const username = $('#username').val().trim();
const password = $('#password').val();
const captcha = $('#captcha').val().trim();
if (!username) {
showError('请输入用户名');
return false;
}
if (!password) {
showError('请输入密码');
return false;
}
if (!captcha) {
showError('请输入验证码');
return false;
}
// 显示加载状态
$('button[type="submit"]').prop('disabled', true)
.html('<span class="spinner-border spinner-border-sm" role="status"></span> 登录中...');
return true;
});
function showError(message) {
// 移除现有的错误提示
$('.alert').remove();
// 添加新的错误提示
const alertHtml = `
<div class="alert alert-danger alert-dismissible fade show" role="alert">
<i class="bi bi-exclamation-triangle"></i> ${message}
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
</div>
`;
$('#loginForm').prepend(alertHtml);
}
// 自动聚焦到用户名输入框
$('#username').focus();
});
</script>
</body>
</html>
🏠 后台主页示例
dashboard.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>后台管理系统 - 主页</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.7.2/font/bootstrap-icons.css">
</head>
<body>
<!-- 导航栏 -->
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
<div class="container-fluid">
<a class="navbar-brand" href="dashboard">
<i class="bi bi-shield-lock"></i> 后台管理系统
</a>
<div class="navbar-nav ms-auto">
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button"
data-bs-toggle="dropdown" aria-expanded="false">
<i class="bi bi-person-circle"></i> ${user.realName}
</a>
<ul class="dropdown-menu" aria-labelledby="navbarDropdown">
<li><a class="dropdown-item" href="#"><i class="bi bi-person"></i> 个人资料</a></li>
<li><a class="dropdown-item" href="#"><i class="bi bi-gear"></i> 系统设置</a></li>
<li><hr class="dropdown-divider"></li>
<li><a class="dropdown-item" href="logout"><i class="bi bi-box-arrow-right"></i> 退出登录</a></li>
</ul>
</li>
</div>
</div>
</nav>
<div class="container-fluid">
<div class="row">
<!-- 侧边栏 -->
<nav id="sidebar" class="col-md-3 col-lg-2 d-md-block bg-light sidebar collapse">
<div class="position-sticky pt-3">
<ul class="nav flex-column">
<li class="nav-item">
<a class="nav-link active" href="dashboard">
<i class="bi bi-speedometer2"></i> 控制台
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">
<i class="bi bi-people"></i> 用户管理
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">
<i class="bi bi-box-seam"></i> 商品管理
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">
<i class="bi bi-file-text"></i> 内容管理
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">
<i class="bi bi-gear"></i> 系统设置
</a>
</li>
</ul>
</div>
</nav>
<!-- 主内容区域 -->
<main class="col-md-9 ms-sm-auto col-lg-10 px-md-4">
<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
<h1 class="h2">控制台</h1>
<div class="btn-toolbar mb-2 mb-md-0">
<div class="btn-group me-2">
<button type="button" class="btn btn-sm btn-outline-secondary">分享</button>
<button type="button" class="btn btn-sm btn-outline-secondary">导出</button>
</div>
</div>
</div>
<!-- 欢迎信息 -->
<div class="alert alert-info">
<h4><i class="bi bi-info-circle"></i> 欢迎回来,${user.realName}!</h4>
<p class="mb-0">上次登录时间:${user.lastLoginTime}</p>
</div>
<!-- 统计卡片 -->
<div class="row">
<div class="col-md-3 mb-4">
<div class="card text-white bg-primary">
<div class="card-body">
<div class="d-flex justify-content-between">
<div>
<h4>1,234</h4>
<p class="mb-0">总用户数</p>
</div>
<div class="align-self-center">
<i class="bi bi-people fs-1"></i>
</div>
</div>
</div>
</div>
</div>
<div class="col-md-3 mb-4">
<div class="card text-white bg-success">
<div class="card-body">
<div class="d-flex justify-content-between">
<div>
<h4>567</h4>
<p class="mb-0">今日订单</p>
</div>
<div class="align-self-center">
<i class="bi bi-cart-check fs-1"></i>
</div>
</div>
</div>
</div>
</div>
<div class="col-md-3 mb-4">
<div class="card text-white bg-warning">
<div class="card-body">
<div class="d-flex justify-content-between">
<div>
<h4>¥12,345</h4>
<p class="mb-0">今日收入</p>
</div>
<div class="align-self-center">
<i class="bi bi-currency-yuan fs-1"></i>
</div>
</div>
</div>
</div>
</div>
<div class="col-md-3 mb-4">
<div class="card text-white bg-danger">
<div class="card-body">
<div class="d-flex justify-content-between">
<div>
<h4>23</h4>
<p class="mb-0">待处理</p>
</div>
<div class="align-self-center">
<i class="bi bi-bell fs-1"></i>
</div>
</div>
</div>
</div>
</div>
</div>
</main>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>
⚙️ Web配置
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<display-name>后台管理系统</display-name>
<!-- 首页设置 -->
<welcome-file-list>
<welcome-file>login.jsp</welcome-file>
</welcome-file-list>
<!-- 字符编码过滤器 -->
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>com.admin.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- 错误页面配置 -->
<error-page>
<error-code>404</error-code>
<location>/error/404.jsp</location>
</error-page>
<error-page>
<error-code>500</error-code>
<location>/error/500.jsp</location>
</error-page>
<!-- Session超时配置 -->
<session-config>
<session-timeout>30</session-timeout>
</session-config>
</web-app>
📦 依赖配置
Maven pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.admin</groupId>
<artifactId>admin-system</artifactId>
<version>1.0.0</version>
<packaging>war</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<!-- Servlet API -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
<!-- JSP API -->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
<version>2.3.3</version>
<scope>provided</scope>
</dependency>
<!-- JSTL -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<!-- MySQL驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.28</version>
</dependency>
<!-- BCrypt密码加密 -->
<dependency>
<groupId>org.mindrot</groupId>
<artifactId>jbcrypt</artifactId>
<version>0.4</version>
</dependency>
<!-- JSON处理 -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.13.3</version>
</dependency>
</dependencies>
<build>
<finalName>admin</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
🚀 部署和运行
-
环境要求
-
JDK 1.8+
-
Tomcat 9+
-
MySQL 5.7+CREATE DATABASE admin_system CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-
-
USE admin_system; -- 执行前面提供的建表语句
-
部署步骤
-
将项目打包为WAR文件
-
部署到Tomcat的webapps目录
-
启动Tomcat服务器
-
🔐 安全增强建议
-
登录限制 - 添加登录失败次数限制,防止暴力破解
-
IP白名单 - 限制后台管理系统的访问IP
-
操作日志 - 记录所有重要操作
-
双因素认证 - 增加短信或邮箱验证
-
Session安全 - 定期更换Session ID
这个完整的Java Web后台登录系统提供了现代化的UI设计、安全的认证机制和完善的会话管理,可以作为企业级后台管理系统的基础进行进一步开发。
更多推荐


所有评论(0)