下面我将为你提供一个完整的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">&copy; 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>

🚀 部署和运行

  1. 环境要求

    • JDK 1.8+

    • Tomcat 9+

    • MySQL 5.7+CREATE DATABASE admin_system CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

  2. USE admin_system;
    -- 执行前面提供的建表语句
  3. 部署步骤

🔐 安全增强建议

  1. 登录限制 - 添加登录失败次数限制,防止暴力破解

  2. IP白名单 - 限制后台管理系统的访问IP

  3. 操作日志 - 记录所有重要操作

  4. 双因素认证 - 增加短信或邮箱验证

  5. Session安全 - 定期更换Session ID

这个完整的Java Web后台登录系统提供了现代化的UI设计、安全的认证机制和完善的会话管理,可以作为企业级后台管理系统的基础进行进一步开发。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐