该项目实现了图形化界面的数据库的登录,以及对数据库中表的增删查改。
正好老师布置了相关作业,通过Java 连接 SQL Server 数据库,就写一个学生管理系统。
jdk8
数据库连接通过sqljdbc6.0
图形化界面用swing
目录
1、包含与SQLServer的连接,所属数据库名,表名,表的列名,表的列数据,表的总数据等属性。
2、提供以与SQLServer的连接,所属数据库名,表名,表的列名为参数的构造函数
3、 实现监听器,通过更改单元格数据,同步更改数据库中数据的功能
1、Java 连接SQL Server数据库
这里已经写过了,可以去看文章了解。
通过Java连接Sql Server数据库:http://t.csdn.cn/glB2w
2、准备数据库
该数据库名为学生管理,包含"班级信息", "教师信息", "课程信息", "身份证", "学生成绩", "学生信息", "学院信息"七张表,每张表分别有以下属性。
{"班级编号", "班级名称", "学院编码"},
{"教师编号", "姓名", "性别", "参加工作时间", "政治面貌", "学历", "职称", "学院编码", "毕业院校", "婚否"},
{"课程号", "课程名", "学分", "先修课"},
{"学号", "身份证号"},
{"学号", "课程号", "学期", "成绩"},
{"学号", "姓名", "性别", "出生日期", "籍贯", "政治面貌", "班级编号", "入学分数", "简历", "照片"},
{"学院编码", "学院名称"}
注册用户,给定相应权限,设置好账号密码。
3、登录界面
要求:
1、服务器名称和数据库路径固定,用户名和密码提前在SQL Server注册号,并给定相应权限
driverName = "com.microsoft.sqlserver.jdbc.SQLServerDriver";
dbURL = "jdbc:sqlserver://localhost:1433;DatabaseName=学生管理";
2、可以检测用户名和密码,并在错误时返回错误信息提醒用户
3、用户名和密码正确后跳转到学生管理界面
登录界面的实现主要参考这篇文章,写的简洁
import java.awt.Dimension; //封装了一个构件的高度和宽度 import java.awt.FlowLayout; import java.awt.Font; import javax.swing.*; public class Login { //在类中定义主函数 public static void main(String[] args) { // TODO Auto-generated method stub //在主函数中,实例化Login类的对象,调用初始化界面的方法 Login login = new Login(); login.initUI(); } //在类中定义初始化界面的方法 public void initUI() { //在initUI中实例化JFrame类的对象 JFrame frame = new JFrame(); //设置窗体对象的属性值 frame.setTitle("Login");//设置窗体标题 frame.setSize(400, 200);//设置窗体大小,只对顶层容器生效 frame.setDefaultCloseOperation(3);//设置窗体关闭操作,3表示关闭窗体退出程序 frame.setLocationRelativeTo(null);//设置窗体相对于另一组间的居中位置,参数null表示窗体相对于屏幕的中央位置 frame.setResizable(false);//禁止调整窗体大小 frame.setFont(new Font("宋体",Font.PLAIN,14));//设置字体,显示格式正常,大小 //实例化FlowLayout流式布局类的对象,指定对齐方式为居中对齐组件之间的间隔为10个像素 FlowLayout fl = new FlowLayout(FlowLayout.CENTER,10,10); //实例化流式布局类的对象 frame.setLayout(fl); JLabel labname = new JLabel("用户名:"); labname.setFont(new Font("宋体",Font.PLAIN,14)); //将labname标签添加到窗体上 frame.add(labname); JTextField text_name = new JTextField(); Dimension dim1 = new Dimension(300,30); text_name.setPreferredSize(dim1);//设置除顶级容器组件以外其他组件的大小 //将textName标签添加到窗体上 frame.add(text_name); JLabel labpass = new JLabel("密码: "); labpass.setFont(new Font("宋体",Font.PLAIN,14)); //将labpass添加到窗体上 frame.add(labpass); JPasswordField text_password = new JPasswordField(); //设置大小 text_password.setPreferredSize(dim1); //添加到窗体 frame.add(text_password); //实例化JButton组件 JButton button1 = new JButton(); //设置按键的显示内容 Dimension dim2 = new Dimension(100,30); button1.setText("登录"); button1.setFont(new Font("宋体",Font.PLAIN,14)); //设置按键大小 button1.setSize(dim2); frame.add(button1); frame.setVisible(true);//窗体可见,一定要放在所有组件加入窗体后 LoginListener ll = new LoginListener(frame,text_name,text_password); button1.addActionListener(ll); } }
在监听器中实现对用户名和密码的检测,并使用消息提示框向用户提示错误信息。检测无误后进入管理界面
import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.sql.Connection; import java.sql.DriverManager; import javax.swing.*; public class LoginListener implements ActionListener{ private javax.swing.JTextField text_name; private javax.swing.JPasswordField text_password; private javax.swing.JFrame login; private String driverName = "com.microsoft.sqlserver.jdbc.SQLServerDriver"; private String dbURL = "jdbc:sqlserver://localhost:1433;DatabaseName=学生管理"; public LoginListener(javax.swing.JFrame login,javax.swing.JTextField text_name,javax.swing.JPasswordField text_password) { //获取登录界面、账号密码输入框对象 this.login=login; this.text_name=text_name; this.text_password=text_password; } public void actionPerformed(ActionEvent actionevent) { Connection dbConn = null; try{ // 注册 Class.forName(driverName); // 进行数据库的连接 dbConn = DriverManager.getConnection(dbURL, text_name.getText(), text_password.getText()); // 登陆成功,删除页面 login.dispose(); // 管理界面 JFrame MF = new ManageFrame(dbConn); }catch (Exception e){ // 连接失败,包括密码不正确,配置错误等,提示错误信息 JOptionPane.showMessageDialog(null,e.getMessage()); } } }
效果:
错误信息提示:
4、定义DBTable类
要求:
1、包含与SQLServer的连接,所属数据库名,表名,表的列名,表的列数据,表的总数据等属性。
2、提供以与SQLServer的连接,所属数据库名,表名,表的列名为参数的构造函数
3、提供获取表的列数据,获取表的总数据,表的增删改的方法
实现:
1、包含与SQLServer的连接,所属数据库名,表名,表的列名,表的列数据,表的总数据等属性。
并提供获取各列数据和,获取String[][]类型总数据【用于JTable展示】的接口
private Connection dbConn; private String DataBase; private String TableName; private String[] Columns; private Map<String, ArrayList<String>> ColumnData; private List<String[]> data; public String[] getColumns() { return Columns; } public String[][] getBiDimData() { return (String[][]) data.toArray(new String[0][]); }
2、提供以与SQLServer的连接,所属数据库名,表名,表的列名为参数的构造函数
public DBTable(Connection dbConn, String dataBase, String tableName, String[] columns) throws SQLException { this.dbConn = dbConn; DataBase = dataBase; TableName = tableName; this.Columns = columns; getDataFromdbConn(); }
3、提供获取表的列数据和总数据的方法
使用查询语句,通过迭代器遍历,获得相应数据,并存储在列数据[Map<String,ArrayList<String>>]和总数据[List<String[]>]中。
public void getDataFromdbConn() throws SQLException { data = new ArrayList<>(); ColumnData = new Hashtable<>(); // 使用查询语句,获取相应数据 Statement statement = dbConn.createStatement(); ResultSet rs = statement.executeQuery("select * from "+DataBase+".dbo."+TableName); ColumnData = new Hashtable<>(); for (int i = 0; i < Columns.length; i++) { ColumnData.put(Columns[i],new ArrayList<>()); } while (rs.next()) { List<String> data_row = new ArrayList<>(); for (int i = 0; i < Columns.length; i++) { String value = rs.getString(Columns[i]); ColumnData.get(Columns[i]).add(value); data_row.add(value); } data.add((String[])data_row.toArray(new String[0])); } }
4、提供表数据的插入方法
以插入的列名序列何对应值为传入参数,默认为数据库.dbo.表名的路径,可更改,但此处未提供相关方法,可增加架构名属性。
public void InsertData(String[] columns,String[] values) throws SQLException { String value_str = ""; String column_str = ""; for (int i = 0; i < columns.length; i++) { value_str = value_str + "\'" + values[i] + "\',"; column_str = column_str + columns[i] + ","; } // 去除多余的逗号 value_str = value_str.substring(0, value_str.length() - 1); column_str = column_str.substring(0, column_str.length() - 1); // 构建sql语句 Statement statement = dbConn.createStatement(); String sql = "insert into " + DataBase+".dbo."+TableName + "(" + column_str + ") values(" + value_str + ")"; // 输出执行语句 System.out.println("语句:" + sql); // 执行语句 statement.executeUpdate(sql); // 重新获取数据 getDataFromdbConn(); }
5、提供表数据的删除方法
以对删除行的判断条件为传入参数,删除符合条件的第一数据(不会一次性删掉全部重复数据),默认为数据库.dbo.表名的路径。
public void DeleteData(String where) throws SQLException { // 构建sql语句 Statement statement = dbConn.createStatement(); String sql = "delete top(1) from " + DataBase+".dbo."+TableName + " where " + where; // 执行语句 statement.executeUpdate(sql); // 输出执行语句 System.out.println("语句:" + sql); //重新获取数据 getDataFromdbConn(); }
5、提供表数据的更新方法
以要修改的数据的列,修改后的值,和该行的判断条件为传入参数,默认为数据库.dbo.表名的路径。
public void UpdateData(String column,String value,String where) throws SQLException { Statement statement = dbConn.createStatement(); String sql = "update "+DataBase+".dbo."+TableName+" set "+column+"="+"\'"+value+"\'"+" where "+where; // 执行语句 statement.executeUpdate(sql); // 输出执行语句 System.out.println("语句:" + sql); // 重新获取数据 getDataFromdbConn(); }
5、学生管理界面
功能要求:
1、能对表内的数据进行增删查改,同时与服务端数据库数据同步
2、能通过表格对多张表的数据进行切换查看
3、能通过单元格直接修改表的某一个数据
4、能够删除选中的行数据
5、通过文本框输入数据进行数据插入
页面要求:
效果展示图:
1、 一个输入文本框集合,对每个表有着对应其列数的输入框
2、 两个按钮,插入数据和删除选中行
3、 一个按钮集合,对每个表有一个按钮,负责下面表格的切换
4、 一个表格,超出一定数量数据时可滚动,能够选择一行数据进行删除,能够直接更改单元格内的数据并同步到服务端
页面实现:
1、注册控件,声明属性,构造函数
注册控件,方便全局管理。声明属性,方便调用。并以数据库连接和相应数据库结构做参数进行构造。
// 声明控件,方便管理 private JFrame base; private JPanel TableJP; private JTable TableJT; private JPanel InputTextJP; private List<JTextField> inputTexts;// 当前的输入框列表 //数据库连接 private Connection dbConn; //存储数据库内所有表 private Map<String, DBTable> dbTables; //当前选中的表 private String Table_selected = "班级信息"; // 用于初始化页面的数据库结构 private String[] TablesNameList = {"班级信息", "教师信息", "课程信息", "身份证", "学生成绩", "学生信息", "学院信息"};// 用于存储所有的表名 private String[][] TableColumnList = {{"班级编号", "班级名称", "学院编码"}, {"教师编号", "姓名", "性别", "参加工作时间", "政治面貌", "学历", "职称", "学院编码", "毕业院校", "婚否"}, {"课程号", "课程名", "学分", "先修课"}, {"学号", "身份证号"}, {"学号", "课程号", "学期", "成绩"}, {"学号", "姓名", "性别", "出生日期", "籍贯", "政治面貌", "班级编号", "入学分数", "简历", "照片"}, {"学院编码", "学院名称"}}; private String DataBaseName = "学生管理"; public ManageFrame(Connection dbConn) throws Exception { try { this.dbConn = dbConn; initFrame(); } catch (Exception e) { e.printStackTrace(); } } public ManageFrame(Connection dbConn,String table_selected, String[] tablesNameList, String[][] tableColumnList, String dataBaseName) throws HeadlessException { try { this.dbConn = dbConn; Table_selected = table_selected; TablesNameList = tablesNameList; TableColumnList = tableColumnList; DataBaseName = dataBaseName; initFrame(); } catch (Exception e) { e.printStackTrace(); } }
2、 根据数据库结构初始化相关数据
dbTables = new Hashtable<>(); // 初始化各表,并获取数据 for (int i = 0; i < TablesNameList.length; i++) { DBTable dbtable = new DBTable(dbConn, DataBaseName, TablesNameList[i], TableColumnList[i]); dbTables.put(TablesNameList[i], dbtable); // 获取数据 dbTables.get(TablesNameList[i]).getDataFromdbConn(); }
3、 创建窗口
// 创建窗口 base = new JFrame("学生管理客户端"); base.setSize(1000, 800); base.setLayout(new FlowLayout(FlowLayout.CENTER)); base.setDefaultCloseOperation(3);//设置窗体关闭操作,3表示关闭窗体退出程序 base.setResizable(false);//禁止调整窗体大小
4、 创建包含输入框的面板
通过更新函数,更新当前不同表的输入框,更新功能写在功能实现里。
// 该面板包含输入框 InputTextJP = new JPanel(); InputTextJP.setLayout(new GridLayout(2, 5)); InputTextJP.setSize(1000, 100); inputTexts = new ArrayList<>(); ChangeInputT();
5、 创建插入和删除按钮
用于插入当前输入框中的数据,和删除在表中选中的行数据
// 放置按钮 JPanel FuncJP = new JPanel(); FuncJP.setSize(800, 50); Dimension btnSize = new Dimension(100, 40); Font btnfont = new Font("宋体", Font.BOLD, 12);//设置字体 JButton add = new JButton("插入输入行"); JButton delete = new JButton("删除选中行"); add.setPreferredSize(btnSize); add.setFont(btnfont); delete.setPreferredSize(btnSize); delete.setFont(btnfont); FuncJP.add(add); FuncJP.add(delete); // 插入数据 add.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { try { InsertData(); } catch (SQLException throwables) { throwables.printStackTrace(); } } }); // 删除数据 delete.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { try { DeleteData(); } catch (SQLException throwables) { throwables.printStackTrace(); } } });
6、 创建表名选择面板
通过循环表名列表创建多个按钮,并为其绑定相应的监听器。因其监听器结构详细,所以一并写在循环中,简洁明了。
选择不同的表,会同步更新输入框面板和表格数据展示面板。
!!注意repaint()并不是实时的,他是会放入一个列表等待,一个一个来。会导致两个控件变换不同时,需要通过多线程解决
// 该面板用于展示表名 JPanel TabListJP = new JPanel(); TabListJP.setSize(770, 50); FlowLayout fl = new FlowLayout(FlowLayout.CENTER); fl.setHgap(12); TabListJP.setLayout(fl); List<JButton> btnTables = new ArrayList<>(); // 有序展示表名 String[] TableNames = dbTables.keySet().toArray(new String[0]); for (int i = 0; i < TableNames.length; i++) { JButton btnTable = new JButton(TableNames[i]); btnTable.setPreferredSize(btnSize); btnTable.setFont(btnfont); btnTables.add(btnTable); TabListJP.add(btnTable); int index = i; // 按钮用于切换表,表内数据以及输入框,方便插入数据 btnTable.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { Table_selected = TableNames[index]; // 注意repaint()并不是实时的,他是会放入一个列表等待,一个一个来。会导致两个控件变换不同时,需要通过多线程解决 new Thread(new Runnable() { @Override public void run() { ChangeInputT(); } }).start(); new Thread(new Runnable() { @Override public void run() { ChangeTable(); } }).start(); } }); }
7、 创建表格数据展示面板
通过更新函数,更新当前不同表的数据,更新功能写在功能实现里。
// 该面板用于展示表及数据 TableJP = new JPanel(); TableJP.setLayout(new FlowLayout(FlowLayout.CENTER)); TableJP.setSize(1000, 650); ChangeTable();
8、将各面板加入窗口中
base.add(InputTextJP); base.add(FuncJP); base.add(TabListJP); base.add(TableJP); base.setVisible(true);
功能实现:
1、 输入框面板更新功能
更新时,删除所有原内容。根据当前选中的表,通过循环表名列表创建多个面板,在其中添加标签和文本输入框,并将这些文本输入框添加到相应控件集合中,方便管理使用。
private void ChangeInputT() { // 删除原面板内容 InputTextJP.removeAll(); Dimension textSize = new Dimension(100, 30); // 重绘输入框 inputTexts = new ArrayList<>(); String[] columns = dbTables.get(Table_selected).getColumns(); for (int i = 0; i < columns.length; i++) { JPanel jp = new JPanel(); String columnName = columns[i]; JLabel jl = new JLabel(columnName + ":"); jl.setFont(new Font("宋体", Font.PLAIN, 12)); JTextField jtf = new JTextField(); jtf.setPreferredSize(textSize); inputTexts.add(jtf); jp.add(jl); jp.add(jtf); InputTextJP.add(jp); } base.revalidate(); base.repaint(); }
2、 表格数据展示面板更新功能
更新时,删除所有原内容。根据当前选中的表,重新以当前表数据构建表格
private void ChangeTable() { //删除原面板内容 TableJP.removeAll(); //重绘表 String[] columns = dbTables.get(Table_selected).getColumns(); String[][] data = dbTables.get(Table_selected).getBiDimData(); TableJT = new JTable(data, columns); // jt.setPreferredSize(new Dimension(1000,650)); TableJT.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS); JScrollPane scrolljt = new JScrollPane(TableJT); scrolljt.setPreferredSize(new Dimension(850, 550)); TableJP.add(scrolljt); // 添加监听器,实现通过更改表格数据同步更改数据库的操作 TableJT.getModel().addTableModelListener }
3、 实现监听器,通过更改单元格数据,同步更改数据库中数据的功能
通过TableModelListener监听表格操作,判断单元格内部数据前后是否一致。数据改变则使用DBTable提供的更新方法进行更新操作。更新失败,则提示错误信息。
// 通过JTable直接更新数据 TableJT.getModel().addTableModelListener(new TableModelListener() { @Override public void tableChanged(TableModelEvent e) { int row = e.getLastRow(); int col = e.getColumn(); String colName = TableJT.getColumnName(col); String newvalue = TableJT.getValueAt(row, col).toString(); String oldvalue = dbTables.get(Table_selected).getColumnData().get(colName).get(row); if (!newvalue.equals(oldvalue)) { String[] columns = dbTables.get(Table_selected).getColumns(); String column_str; String value; String where = ""; // 判断条件 // 获取选中行的数据,构造判断条件 for (int i = 0; i < columns.length; i++) { if (i != col) value = "\'" + (String) TableJT.getValueAt(row, i) + "\'"; else value = "\'" + oldvalue + "\'"; column_str = columns[i]; where = where + column_str + "=" + value + " and "; } where = where.substring(0, where.length() - 4); value = newvalue; try { dbTables.get(Table_selected).UpdateData(colName, value, where); } catch (SQLException throwables) { // 展示提示信息 JOptionPane.showMessageDialog(null, throwables.getMessage()); } } } });
4、 插入数据功能
通过输入文本框集合获取当前的输入文本内容,以其和列名为参数,构造字符串参数,使用DBTable提供的插入功能进行插入操作。
插入成功后,重绘表格。插入失败,则提示错误信息。
private void InsertData() throws SQLException { List<String> values = new ArrayList<>(); String[] columns = dbTables.get(Table_selected).getColumns(); for (int i = 0; i < inputTexts.size(); i++) { values.add(inputTexts.get(i).getText()); } try { dbTables.get(Table_selected).InsertData(columns, (String[]) values.toArray(new String[0])); } catch (SQLException throwables) { // 展示提示信息 JOptionPane.showMessageDialog(null, throwables.getMessage()); } // 重绘图 ChangeTable(); }
5、 删除数据功能
从表格中获取当前选中的行数,根据其内容构造判断条件参数,使用DBTable提供的数据删除功能进行删除操作。
删除成功后,重绘表格。删除失败,则提示错误信息。
private void DeleteData() throws SQLException { // 获取选中行 int serow = TableJT.getSelectedRow(); String[] columns = dbTables.get(Table_selected).getColumns(); String column_str; String value; String where = ""; // 判断条件 // 获取选中行的数据,构造判断条件 for (int i = 0; i < columns.length; i++) { value = "\'" + (String) TableJT.getValueAt(serow, i) + "\'"; column_str = columns[i]; where = where + column_str + "=" + value + " and "; } where = where.substring(0, where.length() - 4); try { dbTables.get(Table_selected).DeleteData(where); } catch (SQLException throwables) { // 展示提示信息 JOptionPane.showMessageDialog(null, throwables.getMessage()); } ChangeTable(); }