元数据:描述数据库或其组成部分的数据
package dbcconnection;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Panel;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.*;
import java.nio.file.*;
import java.sql.*;
import java.util.*;
import javax.sql.*;
import javax.sql.rowset.*;
import javax.swing.*;//Frame 框架
public class ViewDB
{
public static void main(String[] args)
{
// TODO Auto-generated method stub
EventQueue.invokeLater(new Runnable()
{
//EventQueue 是一个与平台无关的类,它将来自于底层同位体类和受信任的应用程序类的事件列入队列。运行后可以自动销毁,顺序加入队列
@Override
public void run()
{
// TODO Auto-generated method stub
JFrame frame=new ViewDBFrame();
frame.setTitle("ViewDB");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
});
}
}
class ViewDBFrame extends JFrame
{
private JButton previousButton;
private JButton nextButton;
private JButton deleteButton;
private JButton saveButton;
private DataPanel dataPanel;
private Component scrollPane;//属于awt包,所有组件的父类
private JComboBox<String> tableNames;//选择框的组件
private Properties props;
private CachedRowSet crs;
public ViewDBFrame()
{
tableNames=new JComboBox<String>();//组合框,下拉菜单
tableNames.addActionListener(new ActionListener()
{
@Override
public void actionPerformed(ActionEvent e)
{
// TODO Auto-generated method stub
showTable((String) tableNames.getSelectedItem());//返回当前的选项
}
});
add(tableNames,BorderLayout.NORTH);
try
{
readDatabaseProperties();
try(Connection conn=getConnection())
{
DatabaseMetaData meta=conn.getMetaData();
ResultSet mrs=meta.getTables(null, null, null, new String[] {"TABLE"});
while(mrs.next())
tableNames.addItem(mrs.getString(3));//获取表的信息,第三列是表的名称
}
}
catch(SQLException e)
{
JOptionPane.showMessageDialog(this, e);
}
catch(IOException e)
{
JOptionPane.showMessageDialog(this, e);
}
JPanel buttonPanel=new JPanel();//面板
add(buttonPanel, BorderLayout.SOUTH);
previousButton=new JButton("Previous");
previousButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
showPreviousRow();
}
});
buttonPanel.add(previousButton);
nextButton=new JButton("Next");
nextButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
showNextRow();
}
});
buttonPanel.add(nextButton);
deleteButton=new JButton("Delete");
deleteButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
deleteRow();
}
});
buttonPanel.add(deleteButton);
saveButton=new JButton("Save");
saveButton.addActionListener(new ActionListener() {
//传入一个ActionListner接口的实现类,但这个类没有名字(匿名类),这个类实现了ActionListner接口.它和普通地定义一个类,
//实现ActionListner接口,然后实例化它,再把它作为参数传给这个方法.如此而已,没有其它区别.
@Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
saveChanges();
}
});
buttonPanel.add(saveButton);
pack();//调整此窗口的大小,以适合其子组件的首选大小和布局。如果该窗口和/或其所有者仍不可显示,则两者在计算首选大小之前变得可显示。在计算首选大小之后,将会验证该 Window。
//窗口自动适应大小,使窗口能正好显示里面所有的控件。
}
public void showTable(String tableName)
{
try
{
try(Connection conn=getConnection())
{
Statement stat=conn.createStatement();
ResultSet rs=stat.executeQuery("SELECT *FROM "+tableName);
RowSetFactory factory=RowSetProvider.newFactory();//获取标准行集
crs=factory.createCachedRowSet();//被缓冲的行集
crs.setTableName(tableName);
crs.populate(rs);//将指定的结果集中的数据填充到被缓冲的行集中
}
if(scrollPane!=null) remove(scrollPane);
dataPanel=new DataPanel(crs);
scrollPane=new JScrollPane(dataPanel);//把dataPanel插入到滚动窗格中
add(scrollPane, BorderLayout.CENTER);//添加约束
validate();//使用 validate 方法会使容器再次布置其子组件。已经布置容器后,在修改此容器的子组件的时候应该调用上述方法。
showNextRow();
}catch(SQLException e)
{
JOptionPane.showMessageDialog(this, e);
}
}
public void showPreviousRow()
{
try
{
if(crs==null||crs.isFirst()) return;
crs.previous();
dataPanel.showRow(crs);
}
catch(SQLException e)
{
for(Throwable t:e)
t.printStackTrace();
}
}
public void showNextRow()
{
try
{
if(crs==null||crs.isLast()) return;
crs.next();
dataPanel.showRow(crs);
}catch(SQLException e)
{
JOptionPane.showMessageDialog(this, e);
}
}
public void deleteRow()
{
try
{
try(Connection conn=getConnection())
{
conn.setAutoCommit(false);
crs.deleteRow();
crs.acceptChanges(conn);
if(crs.isAfterLast())
if(!crs.last()) crs=null;
dataPanel.showRow(crs);
}
}
catch(SQLException e)
{
JOptionPane.showMessageDialog(this, e);
}
}
public void saveChanges()
{
try
{
try(Connection conn=getConnection())
{
conn.setAutoCommit(false);
/*
* 事务默认情况下是自动提交
* conn.setAutoCommit()的功能是每执行一条SQL语句,就作为一次事务提交。但一般在项目中很有可能需要执行多条SQL语句作为一个事务。
* 若有一个执行不成功,就会rollback();
*/
dataPanel.setRow(crs);
crs.acceptChanges(conn);//如果修改了 行集中的内容,必须调用此方法将修改写回到数据库
}
}catch(SQLException e)
{
JOptionPane.showMessageDialog(this, e);
}
}
private void readDatabaseProperties() throws IOException
{
props=new Properties();
try(InputStream in=Files.newInputStream(Paths.get("sof/database.properties")))
{
props.load(in);
}
String drivers=props.getProperty("mysql.driver");
if(drivers!=null)
System.setProperty("mysql.driver", drivers);
}
private Connection getConnection() throws SQLException
{
String url=props.getProperty("mysql.url");
String username=props.getProperty("mysql.user");
String password=props.getProperty("mysql.pwd");
return DriverManager.getConnection(url, username, password);
}
}
class DataPanel extends JPanel
{
private java.util.List<JTextField> fields;
// JTextField(文本框)组件 JTextField组件实现一个文本框,用来接受用户输入的单行文本信息,JTextField类提供的常用构造方法如表1所示。
/*
* 在运行是需要设置列数时,可以使用setColumns方法,使用之后,调用包含这个文本框的容器revalidate
* revalidate会重新计算容器内所有组件大小,进行重新布局
*/
public DataPanel(RowSet rs)throws SQLException
{
fields=new ArrayList<>();
setLayout(new GridBagLayout());//设置布局格式,GridBagLayout组件在容器中可以占据任意大小的位置
GridBagConstraints gbc=new GridBagConstraints();//对组件进行约束
gbc.gridwidth=1;//组件的横向宽度,占几列
gbc.gridheight=1;
ResultSetMetaData rsmd=rs.getMetaData();
for(int i=1;i<rsmd.getColumnCount();i++)
{
gbc.gridy=i-1;//设置组件的位置
String columnName=rsmd.getColumnLabel(i);
gbc.gridx=0;
gbc.anchor=GridBagConstraints.EAST;//当组件空间大于组件本身时,要将组件置于何处
add(new JLabel(columnName),gbc);
int columnWidth=rsmd.getColumnDisplaySize(i);//字段宽度
JTextField tb=new JTextField(columnWidth);
if(!rsmd.getColumnClassName(i).equals("java.lang.String"))
tb.setEditable(false);
fields.add(tb);
gbc.gridx=1;
gbc.anchor=GridBagConstraints.WEST;
add(tb, gbc);
}
}
public void showRow(ResultSet rs) throws SQLException
{
for(int i=1;i<=fields.size();i++)
{
String filed=rs==null?"":rs.getString(i);
JTextField tb=fields.get(i-1);
tb.setText(filed);
}
}
public void setRow(RowSet rs)throws SQLException
{
for(int i=1;i<=fields.size();i++)
{
String field=rs.getString(i);
JTextField tb=fields.get(i-1);
if(!field.equals(tb.getText()))
rs.updateString(i, tb.getText());
}
rs.updateRow();
}
}