要求

  • MySQL 5.7
  • JDK8

界面展示

登录界面

  1. 利用主管理员 admin 登录可以对学生和管理员都进行操作
  2. 其余管理员登录只能对学生进行操作

在这里插入图片描述

主管理员功能选择界面

在这里插入图片描述

操作管理员界面

操作学生界面

在这里插入图片描述

部分代码展示

生成大量学生表

InsertStudentData类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
package insertStudentData;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;

// 此类用来随机生成2000条学生数据并插入MySQL数据库,利用批处理
public class InsertStudentData {
public static void main(String[] args) {
RandInfo rand = new RandInfo();
try {
Class.forName("com.mysql.jdbc.Driver");
Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/"
+ "studentmanager?useSSL=false&characterEncoding=utf8", "root", "123456");
connection.setAutoCommit(false);//设置手动提交事务
long start = System.currentTimeMillis();
String sql = "insert into students(id,name,sex,age,class,address) "
+ "values(null,?,?,?,?,?)";
PreparedStatement prepareStatement = connection.prepareStatement(sql);
for (int i = 0; i < 2000; i++) {
String[] nameAndSex = rand.getNameAndSex(rand.getSex()); //得到名字和性别的数组
String familyName = rand.getFamilyName(); //得到姓氏
String name = nameAndSex[0]; //根据数组得到名字和性别
String sex = nameAndSex[1];
String classes = rand.getClasses(); //得到班级
String address = rand.getAddress(); //得到住址
int age = rand.getAge(); //得到年龄
prepareStatement.setObject(1, (familyName + name));
prepareStatement.setObject(2, sex);
prepareStatement.setObject(3, age);
prepareStatement.setObject(4, classes);
prepareStatement.setObject(5, address);
prepareStatement.addBatch();//依次将2000个SQL语句提交到命令列表
}
prepareStatement.executeBatch();//一次性执行命令列表中的所有SQL语句
connection.commit();//提交事务,使之前所有的sql命令都生效
long end = System.currentTimeMillis();
System.out.println("插入了2000条学生数据,共执行了" + (end - start) + "ms");
prepareStatement.close();
connection.close();
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
}
}
}

RandInfo类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
package insertStudentData;

import java.util.Random;

// 随机产生学生信息:name,age,sex,classes,address
// 参考https://blog.csdn.net/yeyu_xing/article/details/108844330

public class RandInfo {
String familyName1 = "赵钱孙李周吴郑王冯陈褚卫蒋沈韩杨朱秦尤许何吕施张孔曹严华金魏陶姜戚谢邹喻水云苏潘葛奚范彭郎鲁韦昌马苗凤花方俞任袁柳鲍史唐费岑薛雷贺倪汤滕殷罗毕郝邬安常乐于时傅卞齐康伍余元卜顾孟平"
+ "黄和穆萧尹姚邵湛汪祁毛禹狄米贝明臧计成戴宋茅庞熊纪舒屈项祝董粱杜阮席季麻强贾路娄危江童颜郭梅盛林刁钟徐邱骆高夏蔡田胡凌霍万柯卢莫房缪干解应宗丁宣邓郁单杭洪包诸左石崔吉"
+ "龚程邢滑裴陆荣翁荀羊甄家封芮储靳邴松井富乌焦巴弓牧隗山谷车侯伊宁仇祖武符刘景詹束龙叶幸司韶黎乔苍双闻莘劳逄姬冉宰桂牛寿通边燕冀尚农温庄晏瞿茹习鱼容向古戈终居衡步都耿满弘国文东殴沃曾关红游盖益桓公晋楚闫";
String familyName2 = "欧阳太史端木上官司马东方独孤南宫万俟闻人夏侯诸葛尉迟公羊赫连澹台皇甫宗政濮阳公冶太叔申屠公孙慕容仲孙钟离长孙宇文司徒鲜于司空闾丘子车亓官司寇巫马公西颛孙壤驷公良漆雕乐正宰父谷梁拓跋夹谷轩辕令狐段干百里呼延东郭南门羊舌微生公户公玉公仪梁丘公仲公上公门公山公坚左丘公伯西门公祖第五公乘贯丘公皙南荣东里东宫仲长子书子桑即墨达奚褚师吴铭";
String girlName = "秀娟英华慧巧美娜静淑惠珠翠雅芝玉萍红娥玲芬芳燕彩春菊兰凤洁梅琳素云莲真环雪荣爱妹霞香月莺媛艳瑞凡佳嘉琼勤珍贞莉桂娣叶璧璐娅琦晶妍茜秋珊莎锦黛青倩婷姣婉娴瑾颖露瑶怡婵雁蓓纨仪荷丹蓉眉君琴蕊薇菁梦岚苑婕馨瑗琰韵融园艺咏卿聪澜纯毓悦昭冰爽琬茗羽希宁欣飘育滢馥筠柔竹霭凝晓欢霄枫芸菲寒伊亚宜可姬舒影荔枝思丽";
String boyName = "伟刚勇毅俊峰强军平保东文辉力明永健世广志义兴良海山仁波宁贵福生龙元全国胜学祥才发武新利清飞彬富顺信子杰涛昌成康星光天达安岩中茂进林有坚和彪博诚先敬震振壮会思群豪心邦承乐绍功松善厚庆磊民友裕河哲江超浩亮政谦亨奇固之轮翰朗伯宏言若鸣朋斌梁栋维启克伦翔旭鹏泽晨辰士以建家致树炎德行时泰盛雄琛钧冠策腾楠榕风航弘";

/**
* 功能:随机产生姓氏
*
* @return 姓氏
*/
public String getFamilyName() {
String str;
int randNum = new Random().nextInt(2) + 1;
int strLen = randNum == 1 ? familyName1.length() : familyName2.length();
int index = new Random().nextInt(strLen);
if (randNum == 1) {
str = String.valueOf(familyName1.charAt(index));
} else {
str = (index & 1) == 0 ? familyName2.substring(index, index + 2) :
familyName2.substring(index - 1, index + 1);
}
return str;
}

/**
* 功能:随机产生性别
*
* @return 性别
*/
public String getSex() {
int randNum = new Random().nextInt(2) + 1;
return randNum == 1 ? "男" : "女";
}

/**
* 功能:传入性别参数,依据性别产生名字
* 返回的数组 ,索引0是名字;索引1是性别
*
* @param sex:性别
* @return 返回[名字,性别]
*/
public String[] getNameAndSex(String sex) {
String[] nameSex = new String[2];
int randNum = new Random().nextInt(2) + 1;
int strLen = sex.equals("男") ? boyName.length() : girlName.length();
int index = (randNum & 1) == 0 ? new Random().nextInt(strLen - 1) :
new Random().nextInt(strLen);
nameSex[0] = sex.equals("男") ? boyName.substring(index, index + randNum) :
girlName.substring(index, index + randNum);
nameSex[1] = sex.equals("男") ? "男" : "女";
return nameSex;
}

/**
* 功能:随机产生18-24的整数作为年龄
*
* @return 18-24的整数
*/
public int getAge() {
return (int) (Math.random() * 7 + 18);
}

/**
* 功能:随机产生班级(1、2、3、4班)
*
* @return (1 、 2 、 3 、 4班)
*/
public String getClasses() {
int classId = (int) (Math.random() * 4 + 1);

return classId + "班";

}

/**
* 功能:随机产生住址 3-8号楼 1-4层
* 例:401-409 411 - 419 421 - 429 431-439
* 一房4人,一层30房,4层 则 一栋楼住480人
* 一共6栋楼,共可以住2880人
* 格式:8#401
*
* @return x#xxx
*/
public String getAddress() {
String address;
int buildingId = (int) (Math.random() * 6 + 3);//3-8
int floorId = (int) (Math.random() * 4 + 1);//1-4
int roomId = (int) (Math.random() * 39 + 1);//1-39

if (roomId < 10) {
address = buildingId + "#" + floorId + "0" + roomId;
} else if (roomId >= 11 && roomId <= 19 || roomId >= 21 && roomId <= 29 || roomId >= 31 && roomId <= 39) {
address = buildingId + "#" + floorId + (roomId + "");
} else {
//当roomId为10、20、30时,重新赋予一个不为10、20、30随机数
address = getAddress();
}
return address;
}

}

管理员信息和JDBC配置文件

管理员信息

在管理管理员界面可以对该XML文件进行更改

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?xml version="1.0" encoding="utf-8"?>

<Admins>
<Admin>
<userName>admin</userName>
<userPassword>admin</userPassword>
</Admin>
<Admin>
<userName>zhangsan</userName>
<userPassword>zhangsan123</userPassword>
</Admin>
<Admin>
<userName>nihao</userName>
<userPassword>nihao123</userPassword>
</Admin>
</Admins>

JDBC配置文件

用properties文件储存JDBC信息,便于修改

1
2
3
4
mysqlDriver=com.mysql.jdbc.Driver
mysqlUrl=jdbc:mysql://localhost:3306/studentmanager?useSSL=false&characterEncoding=utf8
mysqlUser=root
mysqlPwd=123456

基本结构

  • dao包:主要实现增删查改的接口
  • entity包:学生信息和管理员信息类
  • main包:执行类
  • ui包:各界面Swing构造类
  • utils包:各个辅助类

由于代码复用性低,且量比较多,我就不往上贴了
只贴一下复用性较高的辅助类代码

DBUtils类

JDBC辅助类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
package com.ding.utils;

import java.io.FileReader;
import java.io.IOException;
import java.sql.*;
import java.util.*;

public class DBUtils {
private Connection connection = null;
private PreparedStatement preparedStatement = null;
private ResultSet resultSet = null;

static Properties properties = null;//存放mysql连接信息的配置文件

//加载驱动
static {
try {
//实例化配置文件信息
properties = new Properties();
properties.load(new FileReader("entity/JDBC.properties"));
//利用配置文件加载数据库
Class.forName(properties.getProperty("mysqlDriver"));
} catch (ClassNotFoundException | IOException e) {
e.printStackTrace();
}
}

/**
* 获取连接
*/
public void getConnection() {
try {
String url = properties.getProperty("mysqlUrl");
String userName = properties.getProperty("mysqlUser");
String userPassword = properties.getProperty("mysqlPwd");
connection = DriverManager.getConnection(url, userName, userPassword);
} catch (SQLException e) {
e.printStackTrace();
}
}

/**
* 关闭各连接
*/
public void close() {
try {
if (resultSet != null) {
resultSet.close();
}
if (resultSet != null) {
preparedStatement.close();
}
if (resultSet != null) {
connection.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}

/**
* 更新操作
*
* @param sql 查询sql语句
* @param obj sql语句中各占位符对应的值
* @return 更新的行数(若为DDL语句 , 因没有操作行 , 则默认返回0)
*/
public int update(String sql, Object[] obj) {
int row = -1;
getConnection();
try {
preparedStatement = connection.prepareStatement(sql);
for (int i = 0; i < obj.length; i++) {
preparedStatement.setObject(i + 1, obj[i]);
}
row = preparedStatement.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
} finally {
close();
}
return row;
}

/**
* 查询操作
*
* @param sql 查询sql语句
* @param obj sql语句中各占位符对应的值
* @return List<Map < String, String>>(储存查询到的学生信息)
*/
public List<Map<String, String>> query(String sql, Object[] obj) {
List<Map<String, String>> list = new ArrayList<>();
getConnection();
try {
preparedStatement = connection.prepareStatement(sql);
for (int i = 0; i < obj.length; i++) {
preparedStatement.setObject(i + 1, obj[i]);
}
resultSet = preparedStatement.executeQuery();
while (resultSet.next()) {
Map<String, String> map = new HashMap<>();
ResultSetMetaData resultSetMetaData = resultSet.getMetaData();
for (int i = 1; i <= resultSetMetaData.getColumnCount(); i++) {
String columnName = resultSetMetaData.getColumnName(i);//按顺序获取表的列名
map.put(columnName, resultSet.getString(columnName));
}
list.add(map);
}

} catch (SQLException e) {
e.printStackTrace();
} finally {
close();
}
return list;
}
}

RegExpHelp

正则表达式辅助类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
package com.ding.utils;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class RegExpHelp {

/**
* 判断 待检测的字符串s 是否满足 正则表达式regEx
*/
public boolean checkRegexp(String regEx, String s) {
Pattern pattern = Pattern.compile(regEx);
Matcher matcher = pattern.matcher(s);
return matcher.matches();
}

/**
* 正则表达式检验:输入的是否是 m-n 位的非0正整数
*/
public boolean notZeroAndPositiveAndLimitDigit(String s, int m, int n) {
String regEx1 = "^\\+?[1-9][0-9]*$";//字符串只能为非0的正整数
String regEx2 = "^\\d{" + m + "," + n + "}$";//字符串只能为m-n位数字
boolean judge1 = checkRegexp(regEx1, s);//判断是否满足 非0的正整数
boolean judge2 = checkRegexp(regEx2, s);//判断是否满足 m-n位的数字
return (judge1 && judge2); //判断是否满足 m-n位的非0正整数;
}

/**
* 正则表达式检验:第一位 1-4 ;第二位 0-3;第三位1-9;格式的3位数房间号
*/
public boolean formatRoomNum(String s) {
String regEx = "^[1-4][0-3][1-9]$";//房间号格式
return checkRegexp(regEx, s);
}

/**
* 正则表达式检验:输入的是否是 2-4位汉字
*/
public boolean formatChinese(String s) {
String regEx = "^[\\u4e00-\\u9fa5]{2,4}$";
return checkRegexp(regEx, s);
}

/**
* 正则表达式检验:字母开头,5-16字节,允许字母数字下划线
* 用来检验管理员账号和密码
*/
public boolean checkUserNameAndUserPassword(String s) {
String regEx = "^[a-zA-Z][a-zA-Z0-9_]{4,15}$";
return checkRegexp(regEx, s);
}


}

XMLUtils

XML辅助类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
package com.ding.utils;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;

import java.io.FileWriter;
import java.io.IOException;
import java.util.*;

/**
* 方法1,2是对xml的解析辅助,适用于任何情况
* xml读取操作一般分为:
* 解析 -> 操作
* xml更新操作一般分为:
* 解析 -> 操作 ->写入
* 其中 解析 和 写入 可以通过其帮你完成,操作 可以自己撰写
* 用方法1,2和自己撰写的中间操作就可以完成对xml的所有操作
* <p>
* 方法3,4,5,6是对xml的读取、新增、修改、删除操作。
* 根据不同的xml文件和项目要求,需要对 方法进行一定的修改。
* 仅供参考,必要时自己撰写中间操作
*/
public class XMLUtils {

private String pathName; //xml文件所在路径

public XMLUtils() {
}

//在构造XMLUtils对象时,传入xml文件所在路径pathName
public XMLUtils(String pathName) {
this.pathName = pathName;
}

/**
* 1
* 解析XML文件,得到document对象
*/
public Document xmlParse() {
// 创建DOM4J解析器
SAXReader saxReader = new SAXReader();
Document document = null;

// 通过解析器去解读XML文件
try {
document = saxReader.read(pathName);
} catch (DocumentException e) {
e.printStackTrace();
}
return document;
}


/**
* 2
* 把对document的操作写入xml文档
* document:通过解析XML文件,获得的document对象
*/
public void xmlWrite(Document document) {
// 格式化输出
OutputFormat of = OutputFormat.createPrettyPrint();
of.setEncoding("utf-8");

// 写入的操作
XMLWriter xmlWriter = null;
try {
xmlWriter = new XMLWriter(new FileWriter(pathName), of);
xmlWriter.write(document);//将document的操作写入pathName路径下的xml文档
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (xmlWriter != null) {
xmlWriter.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}

/**
* 3
* 读取xml数据
* 返回List<Element>集合
* 需要根据xml文档更改,并不是写死的
*/
public List<Map<String, String>> xmlRead(Document document) {
List<Element> nodes = document.selectNodes("/Admins/Admin");//需要看情况修改
List<Map<String, String>> list = new ArrayList<>();
for (Element node : nodes) {
Map<String, String> map = new HashMap<>();
map.put("userName", node.elementText("userName"));//需要看情况修改
map.put("userPassword", node.elementText("userPassword"));//需要看情况修改
list.add(map);
}
return list;
}

/**
* 4
* 添加xml数据
* values:给xml中key对应的value添加的值
* 需要根据xml文档更改,并不是写死的
*/
public boolean xmlAdd(Document document, String[] values) {
Element rootNode = document.getRootElement();
Element childNode = rootNode.addElement("Admin");//需要看情况修改
String[] keys = {"userName", "userPassword"};//需要看情况修改
for (int i = 0; i < keys.length; i++) {
childNode.addElement(keys[i]).addText(values[i]);
}
xmlWrite(document);//执行写入操作
return true;
}

/**
* 5
* 修改xml数据
* 返回是否修改成功(xml中是否有满足修改条件的数据)
* values:给xml中key对应的value修改的值
* userName:需要修改的管理员 的用户名
* 需要根据xml文档更改,并不是写死的
*/
public boolean xmlUpdate(Document document, String[] values, String userName) {
List<Element> nodes = document.selectNodes("/Admins/Admin");//需要看情况修改
boolean judge = false;
for (Element node : nodes) {
if (node.elementText("userName").equals(userName)) {//需要看情况修改
judge = true;
node.element("userName").setText(values[0]);//需要看情况修改
node.element("userPassword").setText(values[1]);//需要看情况修改
xmlWrite(document);//执行写入操作
break;
}
}
return judge;
}

/**
* 6
* 删除xml数据
* 返回是否删除成功(xml中是否有满足删除条件的数据)
* userName:需要修改的管理员 的用户名
* 需要根据xml文档更改,并不是写死的
*/
public boolean xmlDelete(Document document, String userName) {
List<Element> nodes = document.selectNodes("/Admins/Admin");//需要看情况修改
boolean judge = false;
for (Element node : nodes) {
if (node.elementText("userName").equals(userName)) {//需要看情况修改
judge = true;
node.getParent().remove(node);//删除该节点
xmlWrite(document);//执行写入操作
break;
}
}
return judge;
}
}

生成.exe可执行文件

IntelliJ的方法:看到生成jar包那一步就可以了,exe4j的操作有错

Eclipse的方法:生成jar包和exe4j的操作看这个就行了

可能遇到的问题

  1. .exe文件的图标.ico文件不能由.jpg.png文件改后缀名得到。
    可以利用.ico文件转换网址来得到.ico文件
  2. 若有项目中有图片、配置文件等需要从本地读取的信息,应该把这些文件放到与.exe文件同一目录下。

在这里插入图片描述