一、实验目的及要求
(1)实验目的:掌握Java Swing窗口、常用组件和布局,熟悉MVC结构的概念和特点,掌握事件处理机制,通过事件处理程序将GUI与后台数据库连接,完成学生成绩的查询、修改、删除、退出功能。
(2)实验要求:管理系统采用MVC结构,实验前对可能出现的数据库连接、事件响应等问题预先分析,确定调试步骤和测试方法,编写源程序,实现可行的应用程序,尽可能考虑程序的健壮性,对实验中出现的问题进行分析、总结。
二、实验环境(工具、配置等)
1.硬件要求:计算机一台。
2.软件要求:Windows操作系统,使用Java语言,集成开发环境建议使用如Eclipse。
三、实验内容(实验方案、实验步骤、设计思路等)
1.实验方案:实验中,设计一个UI功能操作界面,通过界面输入功能输入n条学生的成绩,每条记录由学号、姓名和分数组成,然后编写事件处理程序完成下列操作:查询功能:实现学生成绩查询功能;修改功能:实现学生成绩修改功能;删除功能:实现学生成绩删除功能;退出功能等,完成实验报告。
2.实验步骤:根据教材和老师课堂的讲解。
1)设计两个类 Demo类和SqlConnect类
2)Demo类中进行窗口、按钮、文本框、标签的添加和组合,并且为五个按钮添加指定的动作侦听器,以接收发每个按钮的动作事件。
3)SqlConnect类中对数据库进行链接,创建了五个函数,用来插入学号,姓名,成绩、查询姓名,成绩、修改成绩、删除一条记录。
3.设计思路:
首先在SqlConnect类中加载驱动和数据库建立链接,然后创建五个函数,insert()函数中通过链接创建一个sql命令发送器PreparedStatement,设置参数,使用sql命令发送器向数据库发送sql命令,执行预处理插入语句,插入成功输出insert successfully!;findSname()函数中,通过链接创建一个sql命令发送器PreparedStatement,设置参数,使用sql命令发送器向数据库发送sql命令,执行预处理查询姓名语句,并将一开始初始值为” ”的name赋值为查询到的sno的值,返回name;findSgrade()函数中和findSname()函数不一样的是sql命令是查询成绩,将成绩grade赋值为查询到的sgrade的值,返回grade;changeSgrade()函数是发送的命令是update命令,对指定的sno更改sgrade;delete()函数就是发送的是delete语句,删除指定sno的那一行的记录,删除成功后输出delete succeessfully!。然后在Demo类中new一个SqlConnect类的对象sql,然后创建底层容器jf,接着创建了五个按钮、四个文本框、四个标签,并添加到了容器上,进行了一定的排列和设计,然后为插入按钮添加监视器,将前三个文本框的内容都传入insert()函数;为查询按钮添加监视器,将文本框1获得的学号信息传入findSname()和findSgrade()函数,将返回来的信息填入文本框2和3,如果findSname()函数的返回值仍是name初始值” ”,则意味着没有查询到,弹出提示框显示查不到;为修改按钮添加监视器,获取文本框1和4的学号和修改后的成绩的信息,传入changeSgrade()函数,然后清空文本框4的内容,此时重新点击查询就可以看见更改后的内容了;为删除按钮添加监视器,获取文本框1的学号信息,然后传入delete()函数,删除这一条记录;最后为退出按钮添加监视器,jf调用dispose()函数,关闭窗体,释放资源。
- 实验结果与分析
- 数据库原始表和初始运行界面如图4-1、图4-2所示:
图4-1 数据库原始表
图4-2 运行初始界面
- 运行结果如图4-3、图4-4、图4-5、图4-6、图4-7、图4-8、图4-9、图4-10:
图4-3 插入数据
图4-4 查询前
图4-5 查询后
图4-6 修改成绩前
图4-7修改成绩后查询
图4-8 删除数据
图4-9 删除后查询
图4-10 退出界面
实验分析:
1.实验遇到的问题:
1)jl4.setBounds(380,70,60,50)语句不起作用,在容器上的位置不按照设定的位置进行排列,花费大量时间进行排列仍不起效果。
2)报错:Statement.executeQuery() cannot issue statements that do not produce result sets.
2.问题解决的方法:
1)原因是忘记设置jf.setLayout(null),把容器的布局设置为null布局,然后组件调用setBounds(int a,int b,int width,int height)函数设置本身大小和在容器中的位置。
2)update语句对应于executeUpdate 方法,而我的代码里调用到了executeQuery方法。
修改调用的方法即可,并且返回int,所以新增int rs1。
- 附源程序
-
Demo类: package shiyanbaogao_qi; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.*; public class Demo { public static void main(String[] args) { // TODO Auto-generated method stub SqlConnect sql=new SqlConnect(); //创建的底层窗口 JFrame jf=new JFrame("学生成绩管理系统"); jf.setBounds(200,200,500,300); //创建按钮 //查询、修改、删除、退出 JButton jb1=new JButton("查询"); jb1.setBounds(20,10,100,50); JButton jb2=new JButton("修改"); jb2.setBounds(130,10,100,50); JButton jb3=new JButton("删除"); jb3.setBounds(240,10,100,50); JButton jb4=new JButton("退出"); jb4.setBounds(350,10,100,50); //插入 JButton jb=new JButton("插入"); jb.setBounds(190,190,100,50); //创建文本框 //查询、修改、删除、退出 JTextField jt1=new JTextField(); jt1.setBounds(20,130,100,50); JTextField jt2=new JTextField(); jt2.setBounds(130,130,100,50); JTextField jt3=new JTextField(); jt3.setBounds(240,130,100,50); JTextField jt4=new JTextField(); jt4.setBounds(350,130,100,50); //创建标签 //查询、修改、删除、退出 JLabel jl1=new JLabel("学号"); jl1.setBounds(50,70,60,50); JLabel jl2=new JLabel("姓名"); jl2.setBounds(160,70,60,50); JLabel jl3=new JLabel("成绩"); jl3.setBounds(270,70,60,50); JLabel jl4=new JLabel("成绩1"); jl4.setBounds(380,70,60,50); //将按钮 文本框 标签 添加到容器上 jf.add(jb1); jf.add(jb2); jf.add(jb3); jf.add(jb4); jf.add(jb); jf.add(jt1); jf.add(jt2); jf.add(jt3); jf.add(jt4); jf.add(jl1); jf.add(jl2); jf.add(jl3); jf.add(jl4); // 居中 jf.setLocationRelativeTo(null); //关闭退出程序 jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //设置用户界面上的屏幕组件的格式布局 jf.setLayout(null); //设置为 可见 jf.setVisible(true); //插入按钮 监视器 jb.addActionListener(new ActionListener() { //重写接口中的方法作为事件处理 @Override public void actionPerformed(ActionEvent e) { // TODO Auto-generated method stub //获取 学号 姓名 成绩 的信息 String s1=jt1.getText(); String s2=jt2.getText(); String s3=jt3.getText(); //调用insert()函数插入信息 sql.insert(s1, s2, s3); } }); //查询按钮 监视器 jb1.addActionListener(new ActionListener(){ //重写接口中的方法作为事件处理 public void actionPerformed(ActionEvent e) { //获取文本框1 学号的信息 String s1=jt1.getText(); //将 返回回来的name和grade打印到文本框2 和 文本框3 jt2.setText(sql.findSname(s1)); jt3.setText(sql.findSgrade(s1)); //如果findSname(s1)返回值是函数里的name的初始值" ",则说明没有查询到name //弹出提示框 显示 数据查不到 if(sql.findSname(s1)==" ") { JOptionPane.showMessageDialog(null, "查询不到此数据,请重新输入"); } } }); //修改按钮 监视器 jb2.addActionListener(new ActionListener() { //重写接口中的方法作为事件处理 public void actionPerformed(ActionEvent e) { //获取 文本框1和文本框4中的数据 // 即获取到了 学号 和 更改后的成绩 String s1=jt1.getText(); String s2=jt4.getText(); //调用函数changeSgrade() sql.changeSgrade(s1, s2); //执行完修改操作后 将文本框4的值清空 jt4.setText("");//此时点击查询按钮可以看见更改后的数据 } }); //删除按钮 监视器 jb3.addActionListener(new ActionListener(){ //重写接口中的方法作为事件处理 public void actionPerformed(ActionEvent e) { //获取文本框1的数据 即学号信息 String s1=jt1.getText(); //调用delete函数 删掉学号为s1时的这一条记录 sql.delete(s1); } }); //退出按钮 监视器 jb4.addActionListener(new ActionListener() { //重写接口中的方法作为事件处理 public void actionPerformed(ActionEvent e) { //直接弹出提示框 提示确定是否要退出 JOptionPane.showMessageDialog(null, "确定退出?"); //关闭窗体,释放资源 jf.dispose(); } }); } } SqlConnect类: package shiyanbaogao_qi; import java.lang.invoke.StringConcatFactory; import java.sql.*; public class SqlConnect { Connection con=null; Statement sql; PreparedStatement sql1; ResultSet rs;//用于select语句的返回值 int rs1;//用于update delete语句的返回值 SqlConnect() { //加载驱动 String driverName="com.mysql.cj.jdbc.Driver"; try { Class.forName(driverName); } catch (Exception e) { // TODO: handle exception e.printStackTrace(); } //和数据库建立连接 ip port deptnme String url="jdbc:mysql://localhost:3306/studentgrade?characterEncoding=utf-8"; String user="root"; String password="000000"; try { con=DriverManager.getConnection(url,user,password); } catch (Exception e) { // TODO: handle exception e.printStackTrace(); } } //插入 学号 姓名 学号 的函数 public void insert(String s1,String s2,String s3) { try { //通过链接创建一个sql命令发送器PreparedStatement sql1=con.prepareStatement("insert into info values(?,?,?)"); sql1.setString(1, s1); sql1.setString(2, s2); sql1.setString(3, s3); //使用sql命令发送器向数据库发送sql命令 //这里用的时rs1,因为executeUpdate返回值是int类型 rs1=sql1.executeUpdate(); //执行预处理语句 System.out.println("insert successfully!"); } catch(SQLException e) { System.out.println(e); } } //查询 姓名 的函数 public String findSname(String s) { // 设置初始值 用来确定返回值是否有内容 若无 会弹出提示框 String name=" "; try { //设置sql语句中的where语句后面的内容 //where number=s; //通过链接创建一个sql命令发送器PreparedStatement sql1=con.prepareStatement("select * from info where sno=?"); sql1.setString(1, s);//设置参数 //使用sql命令发送器向数据库发送sql命令 rs=sql1.executeQuery();//执行预处理语句 //处理结果 while(rs.next()) { //name赋值为mess表中的第二列的sname的一个值 name=rs.getString(2); } } catch(SQLException e) { System.out.println(e); } //返回name return name; } //查询 成绩 的函数 public String findSgrade(String s) { // 设置初始值 用来确定返回值是否有内容 //但是 这个为空不设置 弹出提示框 因为已经利用findSname()函数已经设置这样的功能 String grade=" "; try { //设置sql语句中的where语句后面的内容 //where number=s; //通过链接创建一个sql命令发送器PreparedStatement sql1=con.prepareStatement("select * from info where sno=?"); sql1.setString(1, s); //使用sql命令发送器向数据库发送sql命令 rs=sql1.executeQuery(); //执行预处理语句 //处理结果 while(rs.next()) { //name赋值为mess表中的第三列的sgrade的一个值 grade=rs.getString(3); } } catch(SQLException e) { System.out.println(e); } //返回grade return grade; } //修改 成绩 的函数 public void changeSgrade(String s1,String s2) { try { //设置sql语句中的where语句后面的内容 //where number=s1; //设置sql语句中的set语句后面的内容 //set grade=s2; //通过链接创建一个sql命令发送器PreparedStatement sql1=con.prepareStatement("update info set sgrade=? where sno=?"); sql1.setString(1, s2); sql1.setString(2, s1); //使用sql命令发送器向数据库发送sql命令 //这里用的时rs1,因为executeUpdate返回值是int类型 rs1=sql1.executeUpdate(); //执行预处理语句 } catch(SQLException e) { System.out.println(e); } } //删除 一条记录 的函数 public void delete(String s) { try { //设置sql语句中的where语句后面的内容 //where number=s; //通过链接创建一个sql命令发送器PreparedStatement sql1=con.prepareStatement("delete from info where sno=?"); sql1.setString(1, s); //使用sql命令发送器向数据库发送sql命令 //这里用的时rs1,因为executeUpdate返回值是int类型 rs1=sql1.executeUpdate(); //执行预处理语句 System.out.println("delete succeessfully!");//打印语句用来显示删除成功 } catch(SQLException e) { System.out.println(e); } } }