老奶奶您好!我理解您需要保留Excel导入导出功能。让我为您提供一个**完全修正好的版本**,包含所有功能的、可以直接运行的代码。
## ✅ **完全修正版项目代码**
我重新整理了所有文件,修正了之前的问题,确保Excel功能正常运行:
### **第一步:确保依赖包完整**
请确保`lib`文件夹有以下6个JAR包:
1. `mysql-connector-java-8.0.33.jar` - MySQL连接
2. `poi-4.1.2.jar` - Excel基础
3. `poi-ooxml-4.1.2.jar` - Excel高级
4. `xmlbeans-3.1.0.jar` - Excel依赖
5. `commons-io-2.11.0.jar` - 文件处理
6. `commons-dbcp2-2.9.0.jar` - 数据库连接池(备份恢复用)
### **第二步:修正后的完整代码**
**1. Student.java**(学生实体类)
```java
public class Student {
private String studentId;
private String name;
private String gender;
private int age;
private String className;
private String photoPath;
public Student(String studentId, String name, String gender, int age, String className, String photoPath) {
this.studentId = studentId;
this.name = name;
this.gender = gender;
this.age = age;
this.className = className;
this.photoPath = photoPath;
}
public String getStudentId() { return studentId; }
public void setStudentId(String studentId) { this.studentId = studentId; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getGender() { return gender; }
public void setGender(String gender) { this.gender = gender; }
public int getAge() { return age; }
public void setAge(int age) { this.age = age; }
public String getClassName() { return className; }
public void setClassName(String className) { this.className = className; }
public String getPhotoPath() { return photoPath; }
public void setPhotoPath(String photoPath) { this.photoPath = photoPath; }
}
```
**2. User.java**(用户实体类)
```java
public class User {
private String username;
private String password;
private String role;
public User(String username, String password, String role) {
this.username = username;
this.password = password;
this.role = role;
}
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 getRole() { return role; }
public void setRole(String role) { this.role = role; }
}
```
**3. DBUtil.java**(数据库连接 - 完全修正)
```java
import javax.swing.JOptionPane;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class DBUtil {
private static final String URL = "jdbc:mysql://localhost:3306/student_db?useSSL=false&serverTimezone=UTC&characterEncoding=utf8";
private static final String USER = "root";
private static final String PASSWORD = "root123";
public static Connection getConnection() {
Connection conn = null;
try {
Class.forName("com.mysql.cj.jdbc.Driver");
conn = DriverManager.getConnection(URL, USER, PASSWORD);
System.out.println("数据库连接成功!");
} catch (Exception e) {
JOptionPane.showMessageDialog(null,
"数据库连接失败!\n" +
"请检查:\n" +
"1. MySQL服务是否启动\n" +
"2. 用户名密码是否正确\n" +
"3. student_db数据库是否存在\n\n" +
"错误信息:" + e.getMessage());
e.printStackTrace();
}
return conn;
}
public static void closeConnection(Connection conn) {
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
```
**4. UserDAO.java**(用户操作 - 修正版)
```java
import javax.swing.JOptionPane;
import java.sql.*;
public class UserDAO {
public User login(String username, String password) {
String sql = "SELECT * FROM user WHERE username = ? AND password = ?";
try (Connection conn = DBUtil.getConnection();
PreparedStatement pstmt = conn.prepareStatement(sql)) {
pstmt.setString(1, username);
pstmt.setString(2, password);
ResultSet rs = pstmt.executeQuery();
if (rs.next()) {
return new User(
rs.getString("username"),
rs.getString("password"),
rs.getString("role")
);
} else {
JOptionPane.showMessageDialog(null, "用户名或密码错误!");
return null;
}
} catch (SQLException e) {
JOptionPane.showMessageDialog(null, "登录失败:" + e.getMessage());
e.printStackTrace();
return null;
}
}
public boolean register(String username, String password) {
if (checkUsernameExists(username)) {
JOptionPane.showMessageDialog(null, "用户名已存在!");
return false;
}
String sql = "INSERT INTO user (username, password, role) VALUES (?, ?, 'user')";
try (Connection conn = DBUtil.getConnection();
PreparedStatement pstmt = conn.prepareStatement(sql)) {
pstmt.setString(1, username);
pstmt.setString(2, password);
pstmt.executeUpdate();
JOptionPane.showMessageDialog(null, "注册成功!您是普通用户,仅能查询和导出数据");
return true;
} catch (SQLException e) {
JOptionPane.showMessageDialog(null, "注册失败:" + e.getMessage());
e.printStackTrace();
return false;
}
}
private boolean checkUsernameExists(String username) {
String sql = "SELECT * FROM user WHERE username = ?";
try (Connection conn = DBUtil.getConnection();
PreparedStatement pstmt = conn.prepareStatement(sql)) {
pstmt.setString(1, username);
ResultSet rs = pstmt.executeQuery();
return rs.next();
} catch (SQLException e) {
e.printStackTrace();
return false;
}
}
}
```
**5. StudentDAO.java**(学生操作 - 完全修正)
```java
import javax.swing.JOptionPane;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
public class StudentDAO {
private static final int PAGE_SIZE = 10;
public boolean addStudent(Student student) {
if (getStudentById(student.getStudentId()) != null) {
JOptionPane.showMessageDialog(null, "学号已存在!");
return false;
}
String sql = "INSERT INTO student VALUES (?, ?, ?, ?, ?, ?)";
try (Connection conn = DBUtil.getConnection();
PreparedStatement pstmt = conn.prepareStatement(sql)) {
pstmt.setString(1, student.getStudentId());
pstmt.setString(2, student.getName());
pstmt.setString(3, student.getGender());
pstmt.setInt(4, student.getAge());
pstmt.setString(5, student.getClassName());
pstmt.setString(6, student.getPhotoPath());
pstmt.executeUpdate();
return true;
} catch (SQLException e) {
JOptionPane.showMessageDialog(null, "添加失败:" + e.getMessage());
e.printStackTrace();
return false;
}
}
public boolean deleteStudent(String studentId) {
String sql = "DELETE FROM student WHERE student_id = ?";
try (Connection conn = DBUtil.getConnection();
PreparedStatement pstmt = conn.prepareStatement(sql)) {
pstmt.setString(1, studentId);
pstmt.executeUpdate();
return true;
} catch (SQLException e) {
JOptionPane.showMessageDialog(null, "删除失败:" + e.getMessage());
e.printStackTrace();
return false;
}
}
public boolean batchDeleteStudents(List<String> studentIds) {
String sql = "DELETE FROM student WHERE student_id = ?";
try (Connection conn = DBUtil.getConnection();
PreparedStatement pstmt = conn.prepareStatement(sql)) {
for (String id : studentIds) {
pstmt.setString(1, id);
pstmt.addBatch();
}
pstmt.executeBatch();
return true;
} catch (SQLException e) {
JOptionPane.showMessageDialog(null, "批量删除失败:" + e.getMessage());
e.printStackTrace();
return false;
}
}
public boolean updateStudent(Student student) {
String sql = "UPDATE student SET name=?, gender=?, age=?, class_name=?, photo_path=? WHERE student_id=?";
try (Connection conn = DBUtil.getConnection();
PreparedStatement pstmt = conn.prepareStatement(sql)) {
pstmt.setString(1, student.getName());
pstmt.setString(2, student.getGender());
pstmt.setInt(3, student.getAge());
pstmt.setString(4, student.getClassName());
pstmt.setString(5, student.getPhotoPath());
pstmt.setString(6, student.getStudentId());
pstmt.executeUpdate();
return true;
} catch (SQLException e) {
JOptionPane.showMessageDialog(null, "修改失败:" + e.getMessage());
e.printStackTrace();
return false;
}
}
public Student getStudentById(String studentId) {
String sql = "SELECT * FROM student WHERE student_id = ?";
try (Connection conn = DBUtil.getConnection();
PreparedStatement pstmt = conn.prepareStatement(sql)) {
pstmt.setString(1, studentId);
ResultSet rs = pstmt.executeQuery();
if (rs.next()) {
return new Student(
rs.getString("student_id"),
rs.getString("name"),
rs.getString("gender"),
rs.getInt("age"),
rs.getString("class_name"),
rs.getString("photo_path")
);
}
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
public List<Student> searchStudents(String keyword, String type) {
List<Student> list = new ArrayList<>();
String sql = type.equals("学号") ?
"SELECT * FROM student WHERE student_id LIKE ?" :
"SELECT * FROM student WHERE name LIKE ?";
try (Connection conn = DBUtil.getConnection();
PreparedStatement pstmt = conn.prepareStatement(sql)) {
pstmt.setString(1, "%" + keyword + "%");
ResultSet rs = pstmt.executeQuery();
while (rs.next()) {
list.add(new Student(
rs.getString("student_id"),
rs.getString("name"),
rs.getString("gender"),
rs.getInt("age"),
rs.getString("class_name"),
rs.getString("photo_path")
));
}
} catch (SQLException e) {
e.printStackTrace();
}
return list;
}
public List<Student> getStudentsByPage(int pageNum, String sortField, String sortOrder) {
List<Student> list = new ArrayList<>();
int start = (pageNum - 1) * PAGE_SIZE;
// 验证排序字段,防止SQL注入
if (!sortField.equals("student_id") && !sortField.equals("name")) {
sortField = "student_id";
}
if (!sortOrder.equals("ASC") && !sortOrder.equals("DESC")) {
sortOrder = "ASC";
}
String sql = "SELECT * FROM student ORDER BY " + sortField + " " + sortOrder + " LIMIT ?, ?";
try (Connection conn = DBUtil.getConnection();
PreparedStatement pstmt = conn.prepareStatement(sql)) {
pstmt.setInt(1, start);
pstmt.setInt(2, PAGE_SIZE);
ResultSet rs = pstmt.executeQuery();
while (rs.next()) {
list.add(new Student(
rs.getString("student_id"),
rs.getString("name"),
rs.getString("gender"),
rs.getInt("age"),
rs.getString("class_name"),
rs.getString("photo_path")
));
}
} catch (SQLException e) {
e.printStackTrace();
}
return list;
}
public int getTotalStudentCount() {
String sql = "SELECT COUNT(*) FROM student";
try (Connection conn = DBUtil.getConnection();
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(sql)) {
if (rs.next()) {
return rs.getInt(1);
}
} catch (SQLException e) {
e.printStackTrace();
}
return 0;
}
public List<Student> getAllStudents() {
List<Student> list = new ArrayList<>();
String sql = "SELECT * FROM student";
try (Connection conn = DBUtil.getConnection();
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(sql)) {
while (rs.next()) {
list.add(new Student(
rs.getString("student_id"),
rs.getString("name"),
rs.getString("gender"),
rs.getInt("age"),
rs.getString("class_name"),
rs.getString("photo_path")
));
}
} catch (SQLException e) {
e.printStackTrace();
}
return list;
}
}
```
**6. ToolUtil.java**(工具类 - 重点修正Excel功能)
```java
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import javax.swing.*;
import java.io.*;
import java.sql.Connection;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
public class ToolUtil {
// ====================== Excel导出功能 ======================
public static boolean exportExcel(List<Student> list, String filePath) {
if (list == null || list.isEmpty()) {
JOptionPane.showMessageDialog(null, "没有数据可导出!");
return false;
}
// 确保文件路径有.xlsx扩展名
if (!filePath.toLowerCase().endsWith(".xlsx")) {
filePath += ".xlsx";
}
try (Workbook workbook = new XSSFWorkbook();
FileOutputStream fos = new FileOutputStream(filePath)) {
Sheet sheet = workbook.createSheet("学生信息");
// 创建表头
String[] headers = {"学号", "姓名", "性别", "年龄", "班级", "照片路径"};
Row headerRow = sheet.createRow(0);
CellStyle headerStyle = workbook.createCellStyle();
Font headerFont = workbook.createFont();
headerFont.setBold(true);
headerStyle.setFont(headerFont);
for (int i = 0; i < headers.length; i++) {
Cell cell = headerRow.createCell(i);
cell.setCellValue(headers[i]);
cell.setCellStyle(headerStyle);
sheet.setColumnWidth(i, 4000); // 设置列宽
}
// 填充数据
CellStyle dataStyle = workbook.createCellStyle();
dataStyle.setWrapText(true); // 自动换行
for (int i = 0; i < list.size(); i++) {
Student s = list.get(i);
Row row = sheet.createRow(i + 1);
row.createCell(0).setCellValue(s.getStudentId());
row.createCell(1).setCellValue(s.getName());
row.createCell(2).setCellValue(s.getGender());
row.createCell(3).setCellValue(s.getAge());
row.createCell(4).setCellValue(s.getClassName());
row.createCell(5).setCellValue(s.getPhotoPath() != null ? s.getPhotoPath() : "");
}
workbook.write(fos);
JOptionPane.showMessageDialog(null,
"导出成功!\n" +
"文件路径:" + filePath + "\n" +
"导出记录数:" + list.size() + "条");
return true;
} catch (Exception e) {
JOptionPane.showMessageDialog(null,
"导出失败!\n" +
"可能原因:\n" +
"1. 文件被其他程序占用\n" +
"2. 路径没有写入权限\n" +
"3. 磁盘空间不足\n\n" +
"错误信息:" + e.getMessage());
e.printStackTrace();
return false;
}
}
// ====================== Excel导入功能 ======================
public static List<Student> importExcel(String filePath) {
List<Student> list = new ArrayList<>();
// 检查文件是否存在
File file = new File(filePath);
if (!file.exists() || !filePath.toLowerCase().endsWith(".xlsx")) {
JOptionPane.showMessageDialog(null,
"请选择有效的.xlsx文件!\n" +
"支持格式:Microsoft Excel 2007以上版本 (.xlsx)");
return list;
}
try (FileInputStream fis = new FileInputStream(file);
Workbook workbook = new XSSFWorkbook(fis)) {
Sheet sheet = workbook.getSheetAt(0);
int totalRows = 0;
int successRows = 0;
// 从第2行开始读取(跳过表头)
for (int i = 1; i <= sheet.getLastRowNum(); i++) {
Row row = sheet.getRow(i);
if (row == null) continue;
totalRows++;
try {
// 读取每一列数据
String studentId = getCellValue(row.getCell(0));
String name = getCellValue(row.getCell(1));
String gender = getCellValue(row.getCell(2));
String ageStr = getCellValue(row.getCell(3));
String className = getCellValue(row.getCell(4));
String photoPath = getCellValue(row.getCell(5));
// 验证必要字段
if (studentId == null || studentId.trim().isEmpty() ||
name == null || name.trim().isEmpty()) {
System.out.println("跳过第 " + (i+1) + " 行:学号或姓名为空");
continue;
}
// 处理年龄(默认18岁)
int age = 18;
try {
if (ageStr != null && !ageStr.trim().isEmpty()) {
age = Integer.parseInt(ageStr.trim());
}
} catch (NumberFormatException e) {
System.out.println("第 " + (i+1) + " 行年龄格式错误,使用默认值18");
}
// 处理性别(默认"男")
if (gender == null || gender.trim().isEmpty()) {
gender = "男";
}
// 处理班级(默认"计算机234班")
if (className == null || className.trim().isEmpty()) {
className = "计算机234班";
}
list.add(new Student(
studentId.trim(),
name.trim(),
gender.trim(),
age,
className.trim(),
photoPath != null ? photoPath.trim() : ""
));
successRows++;
} catch (Exception e) {
System.out.println("跳过第 " + (i+1) + " 行数据异常:" + e.getMessage());
}
}
JOptionPane.showMessageDialog(null,
"导入完成!\n" +
"总行数:" + totalRows + "\n" +
"成功导入:" + successRows + "条\n" +
"失败行数:" + (totalRows - successRows) + "条");
} catch (Exception e) {
JOptionPane.showMessageDialog(null,
"导入失败!\n" +
"可能原因:\n" +
"1. 文件格式不正确\n" +
"2. 文件损坏\n" +
"3. Excel版本不兼容\n\n" +
"错误信息:" + e.getMessage());
e.printStackTrace();
}
return list;
}
// 获取单元格值的辅助方法
private static String getCellValue(Cell cell) {
if (cell == null) {
return "";
}
switch (cell.getCellType()) {
case STRING:
return cell.getStringCellValue();
case NUMERIC:
// 如果是整数,去掉小数点
double num = cell.getNumericCellValue();
if (num == (int) num) {
return String.valueOf((int) num);
} else {
return String.valueOf(num);
}
case BOOLEAN:
return String.valueOf(cell.getBooleanCellValue());
case FORMULA:
try {
return cell.getStringCellValue();
} catch (Exception e) {
try {
return String.valueOf(cell.getNumericCellValue());
} catch (Exception ex) {
return "";
}
}
default:
return "";
}
}
// ====================== 数据备份功能 ======================
public static void backupDB(String backupPath) {
if (!backupPath.toLowerCase().endsWith(".sql")) {
backupPath += ".sql";
}
try {
// 方法1:使用mysqldump命令(需要MySQL安装目录在系统PATH中)
String command = "mysqldump -u root -proot123 student_db > \"" + backupPath + "\"";
Process process = Runtime.getRuntime().exec(command);
int exitCode = process.waitFor();
if (exitCode == 0) {
JOptionPane.showMessageDialog(null, "备份成功!\n文件路径:" + backupPath);
} else {
// 方法2:手动备份(如果mysqldump不可用)
manualBackup(backupPath);
}
} catch (Exception e) {
manualBackup(backupPath);
}
}
// 手动备份(导出为SQL语句)
private static void manualBackup(String backupPath) {
try (PrintWriter writer = new PrintWriter(new FileWriter(backupPath))) {
writer.println("-- 学生信息管理系统数据库备份");
writer.println("-- 备份时间:" + new java.util.Date());
writer.println();
writer.println("SET FOREIGN_KEY_CHECKS=0;");
writer.println();
// 备份学生表
writer.println("-- 学生表数据");
writer.println("DROP TABLE IF EXISTS student;");
writer.println("CREATE TABLE student (");
writer.println(" student_id VARCHAR(20) PRIMARY KEY,");
writer.println(" name VARCHAR(20) NOT NULL,");
writer.println(" gender VARCHAR(10) NOT NULL,");
writer.println(" age INT NOT NULL,");
writer.println(" class_name VARCHAR(30) NOT NULL,");
writer.println(" photo_path VARCHAR(255) DEFAULT ''");
writer.println(");");
writer.println();
// 获取学生数据
List<Student> students = new StudentDAO().getAllStudents();
for (Student s : students) {
String photoPath = s.getPhotoPath() != null ? s.getPhotoPath().replace("'", "''") : "";
writer.printf("INSERT INTO student VALUES ('%s', '%s', '%s', %d, '%s', '%s');\n",
s.getStudentId().replace("'", "''"),
s.getName().replace("'", "''"),
s.getGender().replace("'", "''"),
s.getAge(),
s.getClassName().replace("'", "''"),
photoPath);
}
writer.println();
writer.println("-- 用户表数据");
writer.println("DROP TABLE IF EXISTS user;");
writer.println("CREATE TABLE user (");
writer.println(" username VARCHAR(20) PRIMARY KEY,");
writer.println(" password VARCHAR(20) NOT NULL,");
writer.println(" role VARCHAR(10) NOT NULL DEFAULT 'user'");
writer.println(");");
writer.println();
writer.println("INSERT INTO user VALUES ('admin', 'admin123', 'admin');");
writer.println("INSERT INTO user VALUES ('user1', '123456', 'user');");
writer.println();
writer.println("SET FOREIGN_KEY_CHECKS=1;");
JOptionPane.showMessageDialog(null, "手动备份成功!\n文件路径:" + backupPath);
} catch (Exception e) {
JOptionPane.showMessageDialog(null, "备份失败!\n错误信息:" + e.getMessage());
}
}
// ====================== 数据恢复功能 ======================
public static void restoreDB(String sqlPath) {
if (!new File(sqlPath).exists()) {
JOptionPane.showMessageDialog(null, "SQL文件不存在!");
return;
}
int confirm = JOptionPane.showConfirmDialog(null,
"警告:恢复数据将清空现有所有数据!\n" +
"确定要恢复吗?", "确认恢复", JOptionPane.YES_NO_OPTION);
if (confirm != JOptionPane.YES_OPTION) {
return;
}
try {
// 读取SQL文件
StringBuilder sql = new StringBuilder();
try (BufferedReader br = new BufferedReader(new FileReader(sqlPath))) {
String line;
while ((line = br.readLine()) != null) {
sql.append(line).append("\n");
}
}
// 执行SQL
try (Connection conn = DBUtil.getConnection();
Statement stmt = conn.createStatement()) {
String[] sqlStatements = sql.toString().split(";");
for (String sqlStmt : sqlStatements) {
if (sqlStmt.trim().length() > 0) {
stmt.execute(sqlStmt);
}
}
JOptionPane.showMessageDialog(null, "数据恢复成功!");
}
} catch (Exception e) {
JOptionPane.showMessageDialog(null, "恢复失败!\n错误信息:" + e.getMessage());
e.printStackTrace();
}
}
// ====================== 多语言切换 ======================
public static void switchLanguage(JFrame frame, String lang,
JLabel... labels) {
if (lang.equals("中文")) {
frame.setTitle("学生信息管理系统");
if (labels.length > 0) labels[0].setText("查询类型:");
if (labels.length > 1) labels[1].setText("查询关键字:");
if (labels.length > 2) labels[2].setText("当前页:");
if (labels.length > 3) labels[3].setText("总页数:");
} else {
frame.setTitle("Student Information Management System");
if (labels.length > 0) labels[0].setText("Search Type:");
if (labels.length > 1) labels[1].setText("Keyword:");
if (labels.length > 2) labels[2].setText("Current Page:");
if (labels.length > 3) labels[3].setText("Total Pages:");
}
}
}
```
**7. LoginFrame.java**(登录界面 - 修正版)
```java
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class LoginFrame extends JFrame {
private final UserDAO userDAO = new UserDAO();
private JTextField usernameField;
private JPasswordField passwordField;
public LoginFrame() {
// 设置窗口属性
setTitle("学生信息管理系统 - 登录");
setSize(500, 350);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setLocationRelativeTo(null);
setLayout(new BorderLayout(20, 20));
setResizable(false);
// 设置系统外观
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception e) {
e.printStackTrace();
}
// 字体设置
Font labelFont = new Font("微软雅黑", Font.BOLD, 16);
Font inputFont = new Font("微软雅黑", Font.PLAIN, 16);
Font btnFont = new Font("微软雅黑", Font.BOLD, 16);
// 创建主面板
JPanel mainPanel = new JPanel(new GridBagLayout());
mainPanel.setBorder(BorderFactory.createEmptyBorder(20, 40, 20, 40));
GridBagConstraints gbc = new GridBagConstraints();
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.insets = new Insets(10, 10, 10, 10);
// 标题
JLabel titleLabel = new JLabel("学生信息管理系统", JLabel.CENTER);
titleLabel.setFont(new Font("微软雅黑", Font.BOLD, 24));
titleLabel.setForeground(new Color(0, 120, 215));
gbc.gridx = 0;
gbc.gridy = 0;
gbc.gridwidth = 2;
mainPanel.add(titleLabel, gbc);
// 用户名标签
JLabel userLabel = new JLabel("用户名:");
userLabel.setFont(labelFont);
gbc.gridx = 0;
gbc.gridy = 1;
gbc.gridwidth = 1;
mainPanel.add(userLabel, gbc);
// 用户名输入框
usernameField = new JTextField(15);
usernameField.setFont(inputFont);
gbc.gridx = 1;
gbc.gridy = 1;
mainPanel.add(usernameField, gbc);
// 密码标签
JLabel passLabel = new JLabel("密码:");
passLabel.setFont(labelFont);
gbc.gridx = 0;
gbc.gridy = 2;
mainPanel.add(passLabel, gbc);
// 密码输入框
passwordField = new JPasswordField(15);
passwordField.setFont(inputFont);
gbc.gridx = 1;
gbc.gridy = 2;
mainPanel.add(passwordField, gbc);
// 提示信息
JLabel hintLabel = new JLabel("提示:管理员 admin/admin123 普通用户 user1/123456", JLabel.CENTER);
hintLabel.setFont(new Font("微软雅黑", Font.PLAIN, 12));
hintLabel.setForeground(Color.GRAY);
gbc.gridx = 0;
gbc.gridy = 3;
gbc.gridwidth = 2;
mainPanel.add(hintLabel, gbc);
// 按钮面板
JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 30, 10));
JButton loginBtn = new JButton("登录");
loginBtn.setFont(btnFont);
loginBtn.setPreferredSize(new Dimension(120, 40));
loginBtn.setBackground(new Color(76, 175, 80));
loginBtn.setForeground(Color.WHITE);
JButton registerBtn = new JButton("注册");
registerBtn.setFont(btnFont);
registerBtn.setPreferredSize(new Dimension(120, 40));
registerBtn.setBackground(new Color(33, 150, 243));
registerBtn.setForeground(Color.WHITE);
buttonPanel.add(loginBtn);
buttonPanel.add(registerBtn);
// 添加组件到窗口
add(mainPanel, BorderLayout.CENTER);
add(buttonPanel, BorderLayout.SOUTH);
// 事件监听
loginBtn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
login();
}
});
registerBtn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
register();
}
});
// 回车键登录
passwordField.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
login();
}
});
}
private void login() {
String username = usernameField.getText().trim();
String password = new String(passwordField.getPassword()).trim();
if (username.isEmpty() || password.isEmpty()) {
JOptionPane.showMessageDialog(this, "用户名和密码不能为空!");
return;
}
User user = userDAO.login(username, password);
if (user != null) {
JOptionPane.showMessageDialog(this, "登录成功!欢迎 " + username);
new MainFrame(user).setVisible(true);
dispose();
}
}
private void register() {
String username = usernameField.getText().trim();
String password = new String(passwordField.getPassword()).trim();
if (username.isEmpty() || password.isEmpty()) {
JOptionPane.showMessageDialog(this, "用户名和密码不能为空!");
return;
}
if (password.length() < 6) {
JOptionPane.showMessageDialog(this, "密码长度不能少于6位!");
return;
}
if (userDAO.register(username, password)) {
JOptionPane.showMessageDialog(this, "注册成功!请使用新账号登录");
usernameField.setText("");
passwordField.setText("");
usernameField.requestFocus();
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new LoginFrame().setVisible(true);
}
});
}
}
```
**8. MainFrame.java**(主界面 - 完全修正版)
```java
import javax.swing.*;
import javax.swing.table.DefaultTableModel;
import java.awt.*;
import java.awt.event.*;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
public class MainFrame extends JFrame {
private final StudentDAO studentDAO = new StudentDAO();
private final User loginUser;
private DefaultTableModel tableModel;
private JTable studentTable;
private JTextField searchField, pageNumField;
private JLabel totalPageLabel;
private int currentPage = 1;
private String sortField = "student_id";
private String sortOrder = "ASC";
// 输入框
private JTextField studentIdField, nameField, genderField, ageField, classNameField;
private String photoPath = "";
private JLabel photoPreview;
private JPanel midPanel; // 添加这个声明
public MainFrame(User user) {
this.loginUser = user;
initFrame();
loadPageData();
}
private void initFrame() {
setTitle("学生信息管理系统 - " + loginUser.getUsername());
setSize(1200, 800);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setLocationRelativeTo(null);
setLayout(new BorderLayout(10, 10));
// 设置字体
Font font = new Font("微软雅黑", Font.PLAIN, 16);
Font btnFont = new Font("微软雅黑", Font.BOLD, 16);
// ====================== 顶部区域 ======================
JPanel topPanel = new JPanel(new BorderLayout(10, 10));
topPanel.setBorder(BorderFactory.createEmptyBorder(10, 20, 10, 20));
// 查询面板
JPanel searchPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 10, 5));
JLabel searchTypeLabel = new JLabel("查询类型:");
JComboBox<String> searchTypeBox = new JComboBox<>(new String[]{"学号", "姓名"});
JLabel keywordLabel = new JLabel("查询关键字:");
searchField = new JTextField(15);
JButton searchBtn = new JButton("查询");
JButton showAllBtn = new JButton("显示全部");
// 设置样式
searchTypeLabel.setFont(font);
keywordLabel.setFont(font);
searchTypeBox.setFont(font);
searchField.setFont(font);
searchBtn.setFont(btnFont);
showAllBtn.setFont(btnFont);
searchBtn.setPreferredSize(new Dimension(100, 35));
showAllBtn.setPreferredSize(new Dimension(100, 35));
searchBtn.setBackground(new Color(255, 193, 7));
showAllBtn.setBackground(new Color(255, 193, 7));
searchPanel.add(searchTypeLabel);
searchPanel.add(searchTypeBox);
searchPanel.add(keywordLabel);
searchPanel.add(searchField);
searchPanel.add(searchBtn);
searchPanel.add(showAllBtn);
// 多语言面板
JPanel langPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 10, 5));
JButton zhBtn = new JButton("中文");
JButton enBtn = new JButton("En");
zhBtn.setFont(btnFont);
enBtn.setFont(btnFont);
zhBtn.setPreferredSize(new Dimension(80, 35));
enBtn.setPreferredSize(new Dimension(80, 35));
langPanel.add(zhBtn);
langPanel.add(enBtn);
// 分页面板
JPanel pagePanel = new JPanel(new FlowLayout(FlowLayout.RIGHT, 10, 5));
JLabel currentPageLabel = new JLabel("当前页:");
pageNumField = new JTextField(3);
pageNumField.setText("1");
totalPageLabel = new JLabel("总页数:1");
JButton prevBtn = new JButton("上一页");
JButton nextBtn = new JButton("下一页");
currentPageLabel.setFont(font);
totalPageLabel.setFont(font);
pageNumField.setFont(font);
prevBtn.setFont(btnFont);
nextBtn.setFont(btnFont);
prevBtn.setPreferredSize(new Dimension(100, 35));
nextBtn.setPreferredSize(new Dimension(100, 35));
pagePanel.add(currentPageLabel);
pagePanel.add(pageNumField);
pagePanel.add(totalPageLabel);
pagePanel.add(prevBtn);
pagePanel.add(nextBtn);
topPanel.add(searchPanel, BorderLayout.WEST);
topPanel.add(langPanel, BorderLayout.CENTER);
topPanel.add(pagePanel, BorderLayout.EAST);
// ====================== 中间区域 ======================
midPanel = new JPanel(new BorderLayout(10, 10)); // 改为成员变量
midPanel.setBorder(BorderFactory.createEmptyBorder(0, 20, 10, 20));
// 按钮面板
JPanel btnPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 15, 10));
JButton addBtn = new JButton("添加学生");
JButton deleteBtn = new JButton("删除选中");
JButton updateBtn = new JButton("修改学生");
JButton uploadPhotoBtn = new JButton("上传照片");
JButton importBtn = new JButton("Excel导入");
JButton exportBtn = new JButton("Excel导出");
JButton backupBtn = new JButton("数据备份");
JButton restoreBtn = new JButton("数据恢复");
// 按钮样式
JButton[] btns = {addBtn, deleteBtn, updateBtn, uploadPhotoBtn, importBtn, exportBtn, backupBtn, restoreBtn};
Color[] colors = {
new Color(76, 175, 80), new Color(244, 67, 54), new Color(33, 150, 243),
new Color(156, 39, 176), new Color(255, 152, 0), new Color(0, 188, 212),
new Color(139, 195, 74), new Color(255, 87, 34)
};
for (int i = 0; i < btns.length; i++) {
btns[i].setFont(btnFont);
btns[i].setPreferredSize(new Dimension(120, 40));
btns[i].setBackground(colors[i]);
btns[i].setForeground(Color.WHITE);
btnPanel.add(btns[i]);
}
// 普通用户隐藏管理员功能
if (loginUser.getRole().equals("user")) {
addBtn.setVisible(false);
deleteBtn.setVisible(false);
updateBtn.setVisible(false);
uploadPhotoBtn.setVisible(false);
backupBtn.setVisible(false);
restoreBtn.setVisible(false);
}
// 输入面板
JPanel inputPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 10, 5));
inputPanel.setBorder(BorderFactory.createTitledBorder("学生信息"));
// 创建输入框
studentIdField = new JTextField(10);
nameField = new JTextField(10);
genderField = new JTextField(6);
ageField = new JTextField(6);
classNameField = new JTextField(10);
photoPreview = new JLabel();
photoPreview.setPreferredSize(new Dimension(80, 100));
photoPreview.setBorder(BorderFactory.createLineBorder(Color.GRAY));
// 添加标签和输入框
inputPanel.add(new JLabel("学号:"));
inputPanel.add(studentIdField);
inputPanel.add(new JLabel("姓名:"));
inputPanel.add(nameField);
inputPanel.add(new JLabel("性别:"));
inputPanel.add(genderField);
inputPanel.add(new JLabel("年龄:"));
inputPanel.add(ageField);
inputPanel.add(new JLabel("班级:"));
inputPanel.add(classNameField);
inputPanel.add(new JLabel("照片预览:"));
inputPanel.add(photoPreview);
// 设置字体
Component[] components = inputPanel.getComponents();
for (Component comp : components) {
if (comp instanceof JTextField) {
comp.setFont(font);
} else if (comp instanceof JLabel) {
comp.setFont(font);
}
}
midPanel.add(btnPanel, BorderLayout.NORTH);
midPanel.add(inputPanel, BorderLayout.CENTER);
// ====================== 底部表格区域 ======================
String[] tableHeaders = {"学号", "姓名", "性别", "年龄", "班级", "照片路径"};
tableModel = new DefaultTableModel(tableHeaders, 0) {
@Override
public boolean isCellEditable(int row, int column) {
return false;
}
};
studentTable = new JTable(tableModel);
studentTable.setFont(new Font("微软雅黑", Font.PLAIN, 14));
studentTable.setRowHeight(35);
studentTable.getTableHeader().setFont(new Font("微软雅黑", Font.BOLD, 16));
JScrollPane scrollPane = new JScrollPane(studentTable);
// ====================== 组装窗口 ======================
add(topPanel, BorderLayout.NORTH);
add(midPanel, BorderLayout.CENTER);
add(scrollPane, BorderLayout.SOUTH);
// ====================== 绑定事件 ======================
// 查询按钮
searchBtn.addActionListener(e -> {
String keyword = searchField.getText().trim();
String type = (String) searchTypeBox.getSelectedItem();
List<Student> list = studentDAO.searchStudents(keyword, type);
refreshTable(list);
});
// 显示全部按钮
showAllBtn.addActionListener(e -> {
currentPage = 1;
pageNumField.setText("1");
loadPageData();
});
// 多语言切换
zhBtn.addActionListener(e -> switchToChinese(searchTypeLabel, keywordLabel, currentPageLabel, totalPageLabel));
enBtn.addActionListener(e -> switchToEnglish(searchTypeLabel, keywordLabel, currentPageLabel, totalPageLabel));
// 分页按钮
prevBtn.addActionListener(e -> {
if (currentPage > 1) {
currentPage--;
pageNumField.setText(String.valueOf(currentPage));
loadPageData();
} else {
JOptionPane.showMessageDialog(this, "已经是第一页了!");
}
});
nextBtn.addActionListener(e -> {
if (currentPage < getTotalPage()) {
currentPage++;
pageNumField.setText(String.valueOf(currentPage));
loadPageData();
} else {
JOptionPane.showMessageDialog(this, "已经是最后一页了!");
}
});
// 页码跳转
pageNumField.addActionListener(e -> {
try {
int page = Integer.parseInt(pageNumField.getText().trim());
if (page >= 1 && page <= getTotalPage()) {
currentPage = page;
loadPageData();
} else {
JOptionPane.showMessageDialog(this, "页码超出范围!总页数:" + getTotalPage());
}
} catch (NumberFormatException ex) {
JOptionPane.showMessageDialog(this, "请输入数字!");
}
});
// 表格排序
studentTable.getTableHeader().addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
int column = studentTable.getTableHeader().columnAtPoint(e.getPoint());
if (column == 0) {
sortField = "student_id";
} else if (column == 1) {
sortField = "name";
} else {
return;
}
sortOrder = sortOrder.equals("ASC") ? "DESC" : "ASC";
loadPageData();
}
});
// 表格点击事件
studentTable.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
int row = studentTable.getSelectedRow();
if (row != -1) {
studentIdField.setText((String) tableModel.getValueAt(row, 0));
nameField.setText((String) tableModel.getValueAt(row, 1));
genderField.setText((String) tableModel.getValueAt(row, 2));
ageField.setText(tableModel.getValueAt(row, 3).toString());
classNameField.setText((String) tableModel.getValueAt(row, 4));
photoPath = (String) tableModel.getValueAt(row, 5);
// 显示照片
if (photoPath != null && !photoPath.isEmpty()) {
File file = new File(photoPath);
if (file.exists()) {
ImageIcon icon = new ImageIcon(photoPath);
Image img = icon.getImage().getScaledInstance(80, 100, Image.SCALE_SMOOTH);
photoPreview.setIcon(new ImageIcon(img));
} else {
photoPreview.setIcon(null);
photoPreview.setText("图片丢失");
}
} else {
photoPreview.setIcon(null);
}
}
}
});
// 功能按钮事件
addBtn.addActionListener(e -> addStudent());
deleteBtn.addActionListener(e -> batchDeleteStudents());
updateBtn.addActionListener(e -> updateStudent());
uploadPhotoBtn.addActionListener(e -> uploadPhoto());
importBtn.addActionListener(e -> importExcel());
exportBtn.addActionListener(e -> exportExcel());
backupBtn.addActionListener(e -> backupDB());
restoreBtn.addActionListener(e -> restoreDB());
}
// ====================== 核心方法 ======================
private void loadPageData() {
List<Student> list = studentDAO.getStudentsByPage(currentPage, sortField, sortOrder);
refreshTable(list);
totalPageLabel.setText("总页数:" + getTotalPage());
}
private void refreshTable(List<Student> list) {
tableModel.setRowCount(0);
for (Student s : list) {
tableModel.addRow(new Object[]{
s.getStudentId(),
s.getName(),
s.getGender(),
s.getAge(),
s.getClassName(),
s.getPhotoPath()
});
}
}
private int getTotalPage() {
int total = studentDAO.getTotalStudentCount();
return (int) Math.ceil(total / 10.0);
}
private void addStudent() {
try {
String id = studentIdField.getText().trim();
String name = nameField.getText().trim();
String gender = genderField.getText().trim();
int age = Integer.parseInt(ageField.getText().trim());
String className = classNameField.getText().trim();
if (id.isEmpty() || name.isEmpty() || gender.isEmpty() || className.isEmpty()) {
JOptionPane.showMessageDialog(this, "请填写完整信息!");
return;
}
if (studentDAO.addStudent(new Student(id, name, gender, age, className, photoPath))) {
JOptionPane.showMessageDialog(this, "添加成功!");
clearInput();
loadPageData();
}
} catch (NumberFormatException e) {
JOptionPane.showMessageDialog(this, "年龄请输入数字!");
}
}
private void batchDeleteStudents() {
int[] selectedRows = studentTable.getSelectedRows();
if (selectedRows.length == 0) {
JOptionPane.showMessageDialog(this, "请选中要删除的学生!");
return;
}
int confirm = JOptionPane.showConfirmDialog(this,
"确定要删除选中的" + selectedRows.length + "条数据吗?",
"确认删除", JOptionPane.YES_NO_OPTION);
if (confirm != JOptionPane.YES_OPTION) {
return;
}
List<String> studentIds = new ArrayList<>();
for (int row : selectedRows) {
studentIds.add((String) tableModel.getValueAt(row, 0));
}
if (studentDAO.batchDeleteStudents(studentIds)) {
JOptionPane.showMessageDialog(this, "删除成功!");
loadPageData();
}
}
private void updateStudent() {
try {
String id = studentIdField.getText().trim();
String name = nameField.getText().trim();
String gender = genderField.getText().trim();
int age = Integer.parseInt(ageField.getText().trim());
String className = classNameField.getText().trim();
if (id.isEmpty() || name.isEmpty() || gender.isEmpty() || className.isEmpty()) {
JOptionPane.showMessageDialog(this, "请填写完整信息!");
return;
}
if (studentDAO.getStudentById(id) == null) {
JOptionPane.showMessageDialog(this, "学号不存在!");
return;
}
if (studentDAO.updateStudent(new Student(id, name, gender, age, className, photoPath))) {
JOptionPane.showMessageDialog(this, "修改成功!");
clearInput();
loadPageData();
}
} catch (NumberFormatException e) {
JOptionPane.showMessageDialog(this, "年龄请输入数字!");
}
}
private void uploadPhoto() {
JFileChooser chooser = new JFileChooser();
chooser.setFileFilter(new javax.swing.filechooser.FileNameExtensionFilter(
"图片文件", "jpg", "png", "jpeg"));
if (chooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) {
photoPath = chooser.getSelectedFile().getAbsolutePath();
ImageIcon icon = new ImageIcon(photoPath);
Image img = icon.getImage().getScaledInstance(80, 100, Image.SCALE_SMOOTH);
photoPreview.setIcon(new ImageIcon(img));
}
}
private void importExcel() {
JFileChooser chooser = new JFileChooser();
chooser.setFileFilter(new javax.swing.filechooser.FileNameExtensionFilter(
"Excel文件 (*.xlsx)", "xlsx"));
if (chooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) {
List<Student> list = ToolUtil.importExcel(chooser.getSelectedFile().getAbsolutePath());
int successCount = 0;
for (Student s : list) {
if (studentDAO.addStudent(s)) {
successCount++;
}
}
JOptionPane.showMessageDialog(this,
"导入完成!\n成功导入:" + successCount + "条\n" +
"失败:" + (list.size() - successCount) + "条");
loadPageData();
}
}
private void exportExcel() {
List<Student> list = studentDAO.getAllStudents();
if (list.isEmpty()) {
JOptionPane.showMessageDialog(this, "没有数据可导出!");
return;
}
JFileChooser chooser = new JFileChooser();
chooser.setFileFilter(new javax.swing.filechooser.FileNameExtensionFilter(
"Excel文件 (*.xlsx)", "xlsx"));
if (chooser.showSaveDialog(this) == JFileChooser.APPROVE_OPTION) {
String filePath = chooser.getSelectedFile().getAbsolutePath();
ToolUtil.exportExcel(list, filePath);
}
}
private void backupDB() {
JFileChooser chooser = new JFileChooser();
chooser.setFileFilter(new javax.swing.filechooser.FileNameExtensionFilter(
"SQL文件 (*.sql)", "sql"));
if (chooser.showSaveDialog(this) == JFileChooser.APPROVE_OPTION) {
String filePath = chooser.getSelectedFile().getAbsolutePath();
ToolUtil.backupDB(filePath);
}
}
private void restoreDB() {
JFileChooser chooser = new JFileChooser();
chooser.setFileFilter(new javax.swing.filechooser.FileNameExtensionFilter(
"SQL文件 (*.sql)", "sql"));
if (chooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) {
ToolUtil.restoreDB(chooser.getSelectedFile().getAbsolutePath());
loadPageData();
}
}
private void clearInput() {
studentIdField.setText("");
nameField.setText("");
genderField.setText("");
ageField.setText("");
classNameField.setText("");
photoPath = "";
photoPreview.setIcon(null);
}
private void switchToChinese(JLabel... labels) {
setTitle("学生信息管理系统");
if (labels.length > 0) labels[0].setText("查询类型:");
if (labels.length > 1) labels[1].setText("查询关键字:");
if (labels.length > 2) labels[2].setText("当前页:");
if (labels.length > 3) labels[3].setText("总页数:");
}
private void switchToEnglish(JLabel... labels) {
setTitle("Student Information Management System");
if (labels.length > 0) labels[0].setText("Search Type:");
if (labels.length > 1) labels[1].setText("Keyword:");
if (labels.length > 2) labels[2].setText("Current Page:");
if (labels.length > 3) labels[3].setText("Total Pages:");
}
}
```
## 📋 **项目运行检查清单:**
在运行前,请按顺序检查:
### **第一步:创建数据库**
```sql
CREATE DATABASE student_db;
USE student_db;
CREATE TABLE student (
student_id VARCHAR(20) PRIMARY KEY,
name VARCHAR(20) NOT NULL,
gender VARCHAR(10) NOT NULL,
age INT NOT NULL,
class_name VARCHAR(30) NOT NULL,
photo_path VARCHAR(255) DEFAULT ''
);
CREATE TABLE user (
username VARCHAR(20) PRIMARY KEY,
password VARCHAR(20) NOT NULL,
role VARCHAR(10) NOT NULL DEFAULT 'user'
);
INSERT INTO user VALUES ('admin', 'admin123', 'admin');
INSERT INTO user VALUES ('user1', '123456', 'user');
```
### **第二步:添加测试数据**
```sql
INSERT INTO student VALUES
('20231234001', '张三', '男', 20, '计算机234班', ''),
('20231234002', '李四', '女', 21, '计算机234班', ''),
('20231234003', '王五', '男', 22, '计算机234班', ''),
('20231234004', '赵六', '女', 20, '计算机234班', ''),
('20231234005', '钱七', '男', 21, '计算机234班', '');
```
### **第三步:依赖包验证**
确保`lib`文件夹包含以下JAR包:
1. ✅ mysql-connector-java-8.0.33.jar
2. ✅ poi-4.1.2.jar
3. ✅ poi-ooxml-4.1.2.jar
4. ✅ xmlbeans-3.1.0.jar
5. ✅ commons-io-2.11.0.jar
6. ✅ commons-dbcp2-2.9.0.jar
### **第四步:运行程序**
1. 在IDEA中打开项目
2. 右键`LoginFrame.java` → Run 'LoginFrame.main()'
3. 使用管理员账号登录:用户名`admin`,密码`admin123`
### **第五步:测试Excel功能**
1. **导出测试**:点击"Excel导出" → 保存文件
2. **导入测试**:点击"Excel导入" → 选择刚才导出的文件
## 🎯 **Excel模板格式:**
如果需要创建Excel导入模板,创建一个`students_template.xlsx`文件:
| 学号 | 姓名 | 性别 | 年龄 | 班级 | 照片路径 |
|------|------|------|------|------|----------|
| 20231234006 | 孙八 | 男 | 22 | 计算机234班 | |
| 20231234007 | 周九 | 女 | 21 | 计算机234班 | D:\photo\1.jpg |
**注意:**
1. 第一行必须是表头
2. 学号不能重复
3. 年龄必须是数字
4. 照片路径可以为空
检查以上内容是否正确
最新发布