使用元数据来浏览数据库中的所有表


元数据:描述数据库或其组成部分的数据
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();
			}
		}
	


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值