学习成绩管理系统
前言:本次课设我们小组倾尽所有心血而成,制作不易,还需鼓励。界面是由GUI制成,内含数据库,正则分布式等方法技能。
功能介绍
学生登录
添加学生个人成绩信息
修改学生个人成绩信息
查询成绩
删除成绩
登录界面
登录界面相对是比较好写的,因为其内容和按钮相对较少。我们先新增用户名及密码的标签Label、用户名及密码的文本框TextFiled、登录及注册的按钮Button。
JLabel userNameLabel = new JLabel("用户名:");
JTextField userTxt = new JTextField();
JLabel pwdLabel = new JLabel("密码:");
JPasswordField pwdField = new JPasswordField();
JButton loginBtn = new JButton("登录");
JButton zhuceBtn = new JButton("注册");
然后再添加组件
centerPanel.add(userNameLabel);
centerPanel.add(userTxt);
centerPanel.add(pwdLabel);
centerPanel.add(pwdField);
centerPanel.add(loginBtn);
centerPanel.add(zhuceBtn);
下图为演示的登录界面
为了界面的美观性,我们采用了弹簧布局
SpringLayout springLayout = new SpringLayout();
JPanel centerPanel = new JPanel(springLayout);
layoutCenter();
但仅仅这样是不够的,为了是组件在窗口中间位置,我们通过繁杂但又易懂的方式,计算了各个组件的面积,使其在窗口的中间位置。
Spring childWidth = Spring.sum(Spring.sum(Spring.width(userNameLabel), Spring.width(userTxt)),
Spring.constant(20));
int offsetX = childWidth.getValue() / 2;
springLayout.putConstraint(SpringLayout.WEST,userNameLabel,-offsetX,
SpringLayout.HORIZONTAL_CENTER,centerPanel);
springLayout.putConstraint(SpringLayout.NORTH,userNameLabel,20,SpringLayout.NORTH,centerPanel);
// userTxt
springLayout.putConstraint(SpringLayout.WEST,userTxt,20,SpringLayout.EAST,userNameLabel);
springLayout.putConstraint(SpringLayout.NORTH,userTxt,0,SpringLayout.NORTH,userNameLabel);
// pwdLabel
springLayout.putConstraint(SpringLayout.EAST,pwdLabel,0,SpringLayout.EAST,userNameLabel);
springLayout.putConstraint(SpringLayout.NORTH,pwdLabel,20,SpringLayout.SOUTH,userNameLabel);
// pwdField
springLayout.putConstraint(SpringLayout.WEST,pwdField,20,SpringLayout.EAST,pwdLabel);
springLayout.putConstraint(SpringLayout.NORTH,pwdField,0,SpringLayout.NORTH,pwdLabel);
// loginBtn
springLayout.putConstraint(SpringLayout.WEST,loginBtn,50,SpringLayout.WEST,pwdLabel);
springLayout.putConstraint(SpringLayout.NORTH,loginBtn,20,SpringLayout.SOUTH,pwdLabel);
// resetBtn
springLayout.putConstraint(SpringLayout.WEST,zhuceBtn,50,SpringLayout.EAST,loginBtn);
springLayout.putConstraint(SpringLayout.NORTH,zhuceBtn,0,SpringLayout.NORTH,loginBtn);
然后就是我们的事件监听了,这里我们不仅仅是运用了鼠标事件监听
loginBtn.addKeyListener(loginHandler);
centerPanel.add(loginBtn);
zhuceBtn.addActionListener(loginHandler);
centerPanel.add(zhuceBtn);
也运用了键盘监听
@Override
public void keyPressed(KeyEvent e) {
if (KeyEvent.VK_ENTER == e.getKeyCode()) {
login();
}
}
这样就可以用ENTER键登录系统啦。
当然不要忘记最重要的设置窗口
setSize(600,400);
setLocationRelativeTo(null);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setResizable(false);
setVisible(true);
如何判断用户名与密码格式是否正确呢?
首先我们获取用户名与密码的文本框内容
String user = loginView.getUserTxt().getText();
char[] chars = loginView.getPwdField().getPassword();
若获取内容为null或“ ”
if (user == null || "".equals(user.trim()) ||
chars == null) {
JOptionPane.showMessageDialog(loginView, "用户名密码必填");
return;
}
则输出
若获取内容与数据库内容相符,则可以进入系统。
若获取内容与数据库不相符,则输出
主界面
主界面我们上半部分采用的是靠左的流式布局
JPanel northPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
然后是跟登录界面一样,新增增加,修改,删除,查询,等组件
JButton addBtn = new JButton("增加");
JButton updateBtn = new JButton("修改");
JButton delBtn = new JButton("删除");
JTextField searchTxt = new JTextField(15);
JButton searchBtn = new JButton("查询");
之后添加组件
northPanel.add(addBtn);
northPanel.add(updateBtn);
northPanel.add(delBtn);
northPanel.add(searchTxt);
northPanel.add(searchBtn);
还是不要忘记设置窗口
setExtendedState(JFrame.MAXIMIZED_BOTH);
setLocationRelativeTo(null);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setResizable(true);
setVisible(true);
我们也考虑到如果数据太多导致一页装不下,所以在主界面上添加了“上一页”和“下一页”的按键,但还是为了美观性,当当前页数为1时,我们默认隐藏按键。
private void showPreNext(int totalCount) {
if (pageNow == 1) {
preBtn.setVisible(false);
} else {
preBtn.setVisible(true);
}
int pageCount = 0;//总共有多少页
if (totalCount % pageSize == 0) {
pageCount = totalCount / pageSize;
} else {
pageCount = totalCount / pageSize + 1;
}
if (pageNow == pageCount||pageNow==0) {
nextBtn.setVisible(false);
} else {
nextBtn.setVisible(true);
}
}
上一页与下一页的事件监听
else if ("上一页".equals(text)) {
mainView.setPageNow(mainView.getPageNow() - 1);
mainView.reloadTable();
}else if ("下一页".equals(text)) {
mainView.setPageNow(mainView.getPageNow() + 1);
mainView.reloadTable();
增加事件监听
addBtn.addActionListener(mainViewHandler);
updateBtn.addActionListener(mainViewHandler);
delBtn.addActionListener(mainViewHandler);
searchBtn.addActionListener(mainViewHandler);
exportBtn.addActionListener(mainViewHandler);
添加界面
毫无疑问当我们点击主界面的增加按钮时,会弹出一个新的窗口用来输入信息。因此我们需要新建一个窗口。
if ("增加".equals(text)) {
new AddStudentView(mainView);
在添加页面中,还是老样子,新建一些组件,且依然是流式布局
JPanel jPanel = new JPanel(new FlowLayout(FlowLayout.CENTER,10,20));
JLabel nameLabel = new JLabel("姓名:",JLabel.RIGHT);
JTextField nameTxt = new JTextField();
JLabel genderLabel = new JLabel("性别:",JLabel.RIGHT);
JTextField genderTxt = new JTextField();
JLabel birthLabel = new JLabel("生日:",JLabel.RIGHT);
JTextField birthTxt1 = new JTextField();
JTextField birthTxt2 = new JTextField();
JTextField birthTxt3 = new JTextField();
JLabel javaLabel = new JLabel("JAVA成绩:",JLabel.RIGHT);
JTextField javaTxt = new JTextField();
JLabel peLabel = new JLabel("体育成绩:",JLabel.RIGHT);
JTextField peTxt = new JTextField();
JLabel mathLabel = new JLabel("数学成绩:",JLabel.RIGHT);
JTextField mathTxt = new JTextField();
之后在界面内添加这些组件。这边注意,因为我们数据库的生日格式是年月日,所以这边添加了三个文本框,下图所示
值得注意的是,为了准确录入学生成绩,我们对各个项目的文本格式运用正则表达式进行了筛查。
判定姓名必须为汉字
public boolean regStr(){
String str = nameTxt.getText();
return !Pattern.matches("[\u4e00-\u9fa5]*",str);
}
否则会输出"姓名必须是汉字"
if(addStudentView.regStr()) {
JOptionPane.showMessageDialog(addStudentView, "姓名必须是汉字");
return;
}
}
判定性别只能为“男 女”
public boolean regstrgender(){
String str = genderTxt.getText();
return !Pattern.matches("[男]|[女]",str);
}
否则会输出“性别只能是男女!”
if(addStudentView.regstrgender()){
JOptionPane.showMessageDialog(addStudentView, "性别只能为男女!");
return;
}
判断生日格式是否正确,这里比较复杂,我们区分了30天跟31天,还有闰年跟平年2月的天数
public boolean regstrbirth(){
String str1 =birthTxt1.getText();
String str2=birthTxt2.getText();
String str3=birthTxt3.getText();
if(!Pattern.matches("[0-9][0-9]*", str1))return false;
if(!Pattern.matches("[1-9]|[1][0-2]", str2))return false;
if(!Pattern.matches("[1-9]|[1-2][0-9]|[3][0-1]", str3))return false;
if(Pattern.matches("(1|3|5|7|8||10|12)",str3))return false;
if(str2.equals("2")){
Integer day=Integer.parseInt(str3);
if(day%4==0&&day%100!=0){
if(!Pattern.matches("[1-9]|[1-2][0-9]",str3))return false;
}else if(!Pattern.matches("[1-9]|[1][0-9]|[2][0-8]",str3))return false;
}
return true;
}
若格式错误,则会输出
判断成绩格式就比较简单了,只需要判定成绩在0-100以内即可
public boolean regstrscore(){
String str1 = javaTxt.getText();
String str2 = peTxt.getText();
String str3 = mathTxt.getText();
if(!Pattern.matches("[1][0][0]|[1-9]?[0-9]?",str1))return false;
if(!Pattern.matches("[1][0][0]|[1-9]?[0-9]?",str2))return false;
if(!Pattern.matches("[1][0][0]|[1-9]?[0-9]?",str3))return false;
return true;
}
若成绩格式错误,则会输出"成绩范围为0-100!"
成功演示
if(addStudentView.regstrscore()==false){
JOptionPane.showMessageDialog(addStudentView,"成绩范围为0-100!");
return;
}
修改界面
修改界面跟增加界面其实是类似的,不同的地方就是要将原表格覆盖
修改时,需要选定一行进行修改,不然会提示“请选择一行进行修改”
else if(selectedStudentIds.length==0){
JOptionPane.showMessageDialog(mainView,"请选择一行进行修改!");
return;
而且我们设置了一次只能修改一行
if (selectedStudentIds.length > 1) {
JOptionPane.showMessageDialog(mainView,"一次只能修改一行!");
return;
若要修改信息,只需要选取一个学生的表格框,然后单击修改则会弹出修改界面
输入完信息后便会将原数据覆盖掉。
当然我们的修改界面也是需要限定格式的,这边我们设置的跟增加界面一样。
查询
查询按钮我们放置在主界面上
当我们点击“查询”时,会先进行数据库搜索同时生成一个tabledto
public void reloadTable() {
TableDTO dto = getTableDTO();
MainViewTableModel.updateModel(dto.getData());
mainViewTable.renderRule();
showPreNext(dto.getTotalCount());
}
private TableDTO getTableDTO() {
StudentService studentService = new StudentServiceImpl();
StudentRequest request = new StudentRequest();
request.setPageNow(pageNow);
request.setPageSize(pageSize);
request.setSearchKey(searchTxt.getText().trim());
TableDTO tableDTO = studentService.retrieveStudents(request);
return tableDTO;
}
然后讲搜索到内容更新到主界面同时再次渲染最后判断上下页
这个搜索是支持姓名的模糊匹配和学号双条件查询同时满足了两个功能
StringBuilder sql = new StringBuilder();
sql.append("select * from student ");
if (request.getSearchKey() != null && !"".equals(request.getSearchKey().trim())) {
sql.append(" where name like '%"+request.getSearchKey().trim()+"%'");
sql.append("|| id = '"+request.getSearchKey()+"'");
}
sql.append(" order by id asc limit ").append(request.getStart()).append(",").append(request.getPageSize());
最后展示搜索到的内容
数据库算法
自动生成学号是通过搜索最大值实现的,再每次加1
String sql = "select max(id) from student";
添加就是用通配符填充
StringBuilder sql = new StringBuilder();
sql.append(" insert into student(id,name,gender,birth,java_score,pe_score,math_score) ");
sql.append(" values(?,?,?,?,?,?,?) ");
Connection conn = null;
PreparedStatement ps = null;
try {
conn = DBUtil.getConn();
ps = conn.prepareStatement(sql.toString());
ps.setInt(1,studentDO.getId());
ps.setString(2,studentDO.getName());
ps.setString(3,studentDO.getGender());
ps.setString(4,studentDO.getBirth());
ps.setDouble(5,studentDO.getJavaScore());
ps.setDouble(6,studentDO.getPeScore());
ps.setDouble(7,studentDO.getMathScore());
return ps.executeUpdate() == 1;
}catch (Exception e) {
e.printStackTrace();
}finally {
DBUtil.closePs(ps);
DBUtil.closeConn(conn);
}
配合table实现了多天删除
public boolean delete(int[] selectedStudentIds) {
StringBuilder sql = new StringBuilder();
sql.append(" delete from student where id in ( ");
int length = selectedStudentIds.length;
for (int i = 0; i < length; i++) {
if (i == (length - 1)) {
sql.append(" ? ");
}else {
sql.append(" ?, ");
}
}
sql.append(" ) ");
Connection conn = null;
PreparedStatement ps = null;
try {
conn = DBUtil.getConn();
ps = conn.prepareStatement(sql.toString());
for (int i = 0; i < length; i++) {
// 设置参数,从1开始
ps.setInt(i + 1, selectedStudentIds[i]);
}
return ps.executeUpdate() == length;
}catch (Exception e) {
e.printStackTrace();
}finally {
DBUtil.closePs(ps);
DBUtil.closeConn(conn);
}
return false;
}
对结果的包装
private Vector<Vector<Object>> fillData(ResultSet rs) throws SQLException {
Vector<Vector<Object>> data = new Vector<>();
while (rs.next()) {
// 处理查出的每一条记录
Vector<Object> oneRecord = new Vector<>();
int id = rs.getInt("id");
String name = rs.getString("name");
String gender = rs.getString("gender");
String birth = rs.getString("birth");
Double javaScore = rs.getDouble("java_score");
Double peScore = rs.getDouble("pe_score");
Double mathScore = rs.getDouble("math_score");
Double totalScore = javaScore + peScore + mathScore;
oneRecord.addElement(id);
oneRecord.addElement(name);
oneRecord.addElement(gender);
oneRecord.addElement(birth);
oneRecord.addElement(javaScore);
oneRecord.addElement(peScore);
oneRecord.addElement(mathScore);
oneRecord.addElement(totalScore);
data.addElement(oneRecord);
}
return data;
}
对于用户表的处理就比较简单只写了三个功能添加一个用户,查询用户是否存在,以及查询用户名是否与密码匹配。