应数据库课程作业要求,用Java编写了一个简单的图形界面化数据库查询程序,实际用于数据库编程的时间并不多,大部分时间都在做界面开发了。下面就分享一下开发经历和其中的一些坑。
1. 数据库服务器操作系统: Windows10(把自己的笔记本当做数据库服务器,然后用数据库客户端连接localhost)
2. 数据库服务器: MySQL 8.0.13
3. 图形界面框架: Java Swing(jdk1.8)
4. JDBC: mysql-connector-java-8.0.12.jar
环境配置中的坑主要在于MySQL的安装。安装过程我主要参考的是菜鸟教程 | MySQL 安装。
mysqld --initialize-inseure
mysql -u -p
然后按要求输入密码即可。
以下例子比较完整的展示了Java数据库编程的要点:
package testsql;
import java.sql.*;
public class Test {
static final String JDBC_DRIVER = "com.mysql.cj.jdbc.Driver"; // jdbc driver name
static final String DB_URL =
"jdbc:mysql://localhost:3306/DATABASE_HOMEWORK?useSSL=false&serverTimezone=UTC";
// url = jdbc:mysql://$IP:$PORT/$DATABASENAME?useSSL=false&serverTimezone=UTC (for connector-java-8.0)
static final String USER = "root"; // mysql username
static final String PASS = ""; // mysql password
public static void main(String[] args) {
Connection conn = null;
Statement stmt = null;
try{
// register jdbc driver
Class.forName(JDBC_DRIVER);
// open connection
System.out.println("Connecting database...");
conn = DriverManager.getConnection(DB_URL,USER,PASS);
// execute query
System.out.println(" create statement object...");
stmt = conn.createStatement();
String sql;
sql = "SELECT SNO, SNAME, SADDRESS FROM SUPPLIER";
ResultSet rs = stmt.executeQuery(sql);
// show query response
while(rs.next()){
// fetch by field
int sno = rs.getInt("SNO");
String sname = rs.getString("SNAME");
String saddress = rs.getString("SADDRESS");
// print data
System.out.print("SNO: " + sno);
System.out.print(", Name: " + sname);
System.out.print(", Address: " + saddress);
System.out.print("\n");
}
// close
rs.close();
stmt.close();
conn.close();
}catch(SQLException se){
// handle jdbc error
se.printStackTrace();
}catch(Exception e){
// handle Class.forName error
e.printStackTrace();
}finally{
// free resource
try{
if(stmt!=null) stmt.close();
}catch(SQLException se2){
}// do nothing
try{
if(conn!=null) conn.close();
}catch(SQLException se){
se.printStackTrace();
}
}
System.out.println("Goodbye!");
}
}
其中的坑点在于mysql-connector-java-8.0以上版本在DB_URL中需要指定useSSL和serverTimezone,即代码中的
static final String DB_URL = "jdbc:mysql://localhost:3306/DATABASE_HOMEWORK?useSSL=false&serverTimezone=UTC";
图形界面编程使用Java Swing。目前Java已有一些工具支持图形化界面编程,但本文仍然通过调用Swing库的各个控件类和布局类编写界面。为控件添加事件监听器(ActionListener)可以实现事件响应。
整体思路是用两个下拉菜单控件(JComboBox)控制查询的类型和查询条件,组合成SQL语句通过JDBC得到查询结果,用表格(JTable)展示查询结果。将JTable绑定到DefaultTableModel类的实例dataModel,当dataModel发生变化时,表格(JTable)会自动刷新显示。
package gui;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Vector;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;
public class DBGUI extends JFrame {
private static final long serialVersionUID = 1L; // default serial version UID
private Vector t_title = new Vector(); // data title for dataModel
private Vector> t_data = new Vector>(); // data list for dataModel
DefaultTableModel dataModel = new DefaultTableModel(); // dataModel for table_viewer
private JLabel label_query_item = new JLabel("Query item: ");
private JLabel label_query_content = new JLabel("Query content: ");
private final String[] str_query_item = {"查询1", "查询2", "查询3", "查询4", "查询5"};
private JComboBox combo_query_item = new JComboBox(str_query_item);
private JComboBox combo_query_content = new JComboBox();
private JButton btn_query = new JButton("Query!");
private JTable table_viewer = new JTable(dataModel);
private Connection conn = null;
public static void main(String args[])
{
DBGUI myapp = new DBGUI();
myapp.setMinimumSize(new Dimension(750, 500));
myapp.setVisible(true);
myapp.setResizable(false);
}
public DBGUI()
{
super("Database Query GUI by weiyuxuan");
// top: ComboBoxes and button
JPanel control_panel = new JPanel();
control_panel.setLayout(new FlowLayout());
control_panel.add(label_query_item);
control_panel.add(combo_query_item);
control_panel.add(label_query_content);
control_panel.add(combo_query_content);
control_panel.add(btn_query);
// Medium: Static text field
JPanel text_panel = new JPanel();
String[] texts = {"查询1:给出为工程(Query content)提供零件的全部供应商名",
"查询2:给出使用供应商(Query content)所供零件的全部工程名",
"查询3:给出使用颜色(Query content)零件的工程名",
"查询4:给出住在某地(Query content)而为不在该地、且不使用红色零件的工程提供零件的供应商名",
"查询5:给出使用供应商(Query content)供应的全部零件的工程名"
};
StringBuilder sb = new StringBuilder(); // use StringBuilder to concatenate strings
sb.append(""); // use html in JLabel
for (String text : texts)
{
sb.append(text);
sb.append("
");
}
sb.append("");
text_panel.add(new JLabel(sb.toString()));
// Bottom: Table viewer
JPanel table_panel = new JPanel();
table_panel.add(table_viewer.getTableHeader());
table_panel.add(new JScrollPane(table_viewer));
// Whole
JPanel container = new JPanel();
container.setLayout(new BoxLayout(container, BoxLayout.Y_AXIS));
container.add(control_panel);
container.add(text_panel);
container.add(table_panel);
this.add(container);
connectDB();
// close sql connection when window closed
this.addWindowListener(new WindowAdapter( ) {
public void windowClosing(WindowEvent e)
{
try {
if (conn != null)
{
conn.close();
}
} catch (SQLException se)
{
se.printStackTrace();
}
System.exit(0);
}
});
setActionListener();
}
private void connectDB()
{
final String JDBC_DRIVER = "com.mysql.cj.jdbc.Driver"; // jdbc driver name
final String DB_URL =
"jdbc:mysql://localhost:3306/DATABASE_HOMEWORK?useSSL=false&serverTimezone=UTC";
final String USER = "root";
final String PASSWORD = "";
try {
Class.forName(JDBC_DRIVER);
conn = DriverManager.getConnection(DB_URL,USER, PASSWORD);
}
catch (SQLException se) {
System.out.println("SQLException encountered when creating connection");
se.printStackTrace();
}
catch (ClassNotFoundException cnfe)
{
cnfe.printStackTrace();
}
}
private void setActionListener()
{
combo_query_item.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e)
{
String sql = "SELECT PNO FROM PROJECT";
String key;
combo_query_content.removeAllItems();
switch(combo_query_item.getSelectedIndex())
{
case 0:
System.out.println("查询1");
sql = "SELECT DISTINCT PNO FROM PROJECT";
break;
case 1:
System.out.println("查询2");
sql = "SELECT DISTINCT SNO FROM SUPPLIER";
break;
case 2:
System.out.println("查询3");
sql = "SELECT DISTINCT COLOR FROM COMPONENT";
break;
case 3:
System.out.println("查询4");
sql = "SELECT DISTINCT SADDRESS FROM SUPPLIER";
break;
case 4:
System.out.println("查询5");
sql = "SELECT DISTINCT SNO FROM SUPPLIER";
break;
default:
System.out.println("查询1");
sql = "SELECT DISTINCT PNO FROM PROJECT";
break;
}
try {
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(sql);
while (rs.next())
{
key = rs.getString(1); // 1 refers to the first column
combo_query_content.addItem(key);
}
rs.close();
stmt.close();
} catch (SQLException e_stmt)
{
System.out.println("SQLException encountered when using SQL Statement");
e_stmt.printStackTrace();
}
}
});
btn_query.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e)
{
int line = 0;
String sql = "SELECT PNO FROM PROJECT";
String key = (String) combo_query_content.getSelectedItem();
switch(combo_query_item.getSelectedIndex())
{
case 0:
sql = "SELECT DISTINCT SNAME "
+ "FROM SUPPLIER, SUPPLY "
+ "WHERE SUPPLIER.SNO=SUPPLY.SNO AND SUPPLY.PNO=" + key;
break;
case 1:
sql = " SELECT DISTINCT PNAME "
+ "FROM PROJECT,SUPPLY "
+ "WHERE PROJECT.PNO=SUPPLY.PNO AND SUPPLY.SNO=" + key;
break;
case 2:
sql = "SELECT DISTINCT PNAME "
+ "FROM PROJECT,SUPPLY,COMPONENT "
+ "WHERE PROJECT.PNO=SUPPLY.PNO AND COMPONENT.CNO=SUPPLY.CNO AND COLOR="
+ "\"" + key + "\"";
break;
case 3:
sql = "SELECT SNAME FROM SUPPLIER WHERE SADDRESS="
+ "\"" + key + "\"" + " AND SNO IN " +
"(SELECT SNO FROM SUPPLY WHERE PNO IN " +
"(SELECT PNO FROM PROJECT WHERE PADDRESS!="
+ "\"" + key + "\""
+ " AND NOT EXISTS "
+ "(SELECT * FROM SUPPLY, COMPONENT "
+ "WHERE PROJECT.PNO=SUPPLY.PNO AND COMPONENT.CNO=SUPPLY.CNO AND COLOR=\"red\")));";
break;
case 4:
sql = "SELECT PNAME FROM PROJECT WHERE NOT EXISTS " +
"(SELECT CNO FROM SUPPLY WHERE SNO=" + key + " AND NOT EXISTS " +
"(SELECT * FROM SUPPLY WHERE SUPPLY.PNO=PROJECT.PNO));";
break;
default:
sql = "SELECT DISTINCT SNAME "
+ "FROM SUPPLIER, SUPPLY "
+ "WHERE SUPPLIER.SNO=SUPPLY.SNO AND SUPPLY.PNO=" + key;
break;
}
try {
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(sql);
t_title.clear();
t_title.add(rs.getMetaData().getColumnName(1));
t_data.clear();
while (rs.next())
{
key = rs.getString(1); // 1 refers to the first column
t_data.add(new Vector());
t_data.get(line++).add(key);
}
rs.close();
stmt.close();
System.out.println(t_title);
System.out.println(t_data);
dataModel.setDataVector(t_data, t_title); // refresh dataModel
} catch (SQLException e_stmt)
{
System.out.println("SQLException encountered when using SQL Statement");
e_stmt.printStackTrace();
}
}
});
}
}