JDBC适用任意表的数据库查询以及结果美化输出

Java JDBC通用数据库表查询&查询结果美化输出

当你使用cmd查询数据库时结果是这样的 ↓

cmd查询数据库结果

而你自己用JDBC写java程序输出结果是这样的 ↓
你自己的程序输出结果
除了第一列其他参差不齐2333,那么我们该如何输出像cmd那样华丽整齐高端大气的样子呢,针对这个问题我在网上搜了好久,结果找到的都是教你怎么把结果打包为list的教程,真是脑壳疼,那么只好自己来写了。

解决方法构思

我们这次要完成的是一个适用于任意表的查询方法,也就是说查询之前我们并不知道表里有多少列以及每一列的数值类型。

首先在这里再啰嗦一遍JDBC的使用:

Class.forName("com.mysql.jdbc.Driver");
//这里我的编辑器会给一个小提示,说上面这个可以改成新的com.mysql.cj.jdbc.Driver
//因为我用的是新版的jdbc,这里为了兼容性依旧使用旧版,不影响使用
static String url = "jdbc:mysql://localhost:3306/text";//text是我的数据库名,这里改成你自己的数据库名
private String username = "????";你的数据库用户名
private String password = "****";你的数据库密码
static Connection conn = DriverManager.getConnection(url, username, password);//建立数据库连接
static Statement st = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE);
//这里加上ResultSet.TYPE_SCROLL_INSENSITIVE和ResultSet.CONCUR_UPDATABLE是为了让查询结果集rs的光标可以任意移动
//如果不加的话执行完rs.next()光标后移之后就无法返回,这样做的目的后面会说
static ResultSet rs =null;//查询结果集
String s = "???";//你要查询的表名
String com = "SELECT * FROM " + s + ";";
rs = st.executeQuery(com);//执行查询命令得到结果集rs

到这里为止是得到数据库查询结果集rs的过程,其实这些都大同小异,真正的区别之处在于对结果集rs的处理以及输出,我们接着往下看。

这里可以先想一想,我们想要得到cmd那样的整齐输出需要什么?首先是知道每一列查询结果的长度,就是字面意思的显示长度,因为导致输出结果对不齐的根本原因就是每行查询结果的长度不一致,知道了长度之后就可以通过程序自动加空格补齐,使每一列中每行元素长度相等。第二,得知了输出结果长度这一关键信息就可以加上+ -------- + ---------------- + 这样的分隔线。第三,想要结果整齐还需要一个字符等宽字体,你可以观察一下你的编辑器的集成控制台和你电脑的命令行,它们显示的每一个字符都是等宽的,中文汉字宽度正好是英文字母的两倍,电脑上的带的黑体Consolas字体都是字符等宽字体,当然你也可以自己下载。我最近写Java GUI程序用到JTextArea发现自己下载的字体设置font后使用不了,只能用系统带的等宽字体,有大神有解决方法麻烦告诉我一声。

解决方法实现

我们先来写一个可以得到字符串长度的方法

public static int getLength(String s){
    int length=0;//保存字符串长度
    String chinese="[\u0391-\uFFE5]";//用来判断字符是否为中文字符
    for (int i = 0; i < s.length(); i++){
        String temp = s.substring(i, i + 1);//拆分字符串得到第i个字符
        if (temp.matches(chinese)){
            length=length+2;//判断为中文字符,记录字符串总长度加二
        }else{
            length=length+1;//判断非中文字符,记录字符串总长度加一
        }
    }
    return length;//返回字符串长度
}

在其他地方调用此方法来获得字符串长度

接下来就是对rs结果集的处理了,这个方法有那么一丢丢复杂,但是为了得到整齐的输出结果也是值得的,我会在代码中加入详细的注释。

public static void printResults(ResultSet rs) {
        try {
            ResultSetMetaData md = rs.getMetaData();
            //为了使该方法适用于任意表,所以需要程序自己读取列信息,ResultSetMetaData 正是服务于此
            int columnCount = md.getColumnCount(); // 获取查询结果集的列数
            int maxlength[] = new int[100];// 保存每一列的最大长度,一般情况下不会有超过100列的表吧。。。

            while (rs.next()) {//遍历查询结果,获取每一列字符串长度的最大值,保存在数组中
                for (int i = 0; i < columnCount; i++) {
                    int n = getLength(String.valueOf(rs.getObject(i + 1)));//getLenght为自定义方法
                    if (n > maxlength[i]) {
                        maxlength[i] = n;
                    }
                }
            }
            rs.first();//遍历一遍得到每一列的最大长度之后将光标移至起始位置,接下来输出还要遍历一遍
            
            String colname = "";// 保存每一列的列名
            String line="";//用于构造分隔线
            for (int i = 0; i < columnCount; i++) {
                String name = md.getColumnName(i + 1);//获取列名
                int n1 = getLength(name);//获取列名的长度,与该列最大长度对比
                if (n1 > maxlength[i]) {
                    maxlength[i] = n1;//如果列名长度比该列最大长度还大,则该列最大长度设为列名长度
                }
                int n2 = maxlength[i] - getLength(name) + 3;//最大长度减去列名长度加3作为补充空格的数量
                for (int k = 1; k <= n2; k++) {//循环来补充空格
                    name = name + " ";
                }
                int n3=maxlength[i]+3;//分隔线补充减号的数量
                String subline="";
                for(int k=1;k<=n3;k++){
                    subline = subline + "-";
                }
                colname = colname + "| " + name;//每行的每个元素之间用竖线分隔
                line=line+"+-"+subline;//分隔线在与竖线对齐处添加“+”
            }
            
            System.out.println("\nReturn Massage :");//输出内容提示
            System.out.println(line+"+");//输出第一行分隔线
            System.out.println(colname+"|");//输出列名
            System.out.println(line+"+");//输出第二行分隔线
            
            while (true) {//遍历输出所有元素,每次循环读取一整行
                String out = "";//用于构造每行的输出内容
                String row = null;//用于在循环中临时保存新得到的内容
                for (int i = 0; i < columnCount; i++) {//每次循环读取该行下一列的元素
                    row = String.valueOf(rs.getObject(i + 1));//获取内容并转为字符串
                    int n = maxlength[i] - getLength(row) + 3;//添加空格的数量
                    for (int k = 1; k <= n; k++) {//循环添加空格
                        row = row + " ";
                    }
                    out = out + "| " + row;//构造该行输出内容
                }
                System.out.println(out+"|");//输出该行所有内容
                if(!rs.next())break;//当读取完所有行之后结束循环
                //注:此处的rs.next()不能放到 while 的括号里,因为上面rs.first()光标移动到首位
                //如果 while 执行一次括号里的条件,光标会变到第二行,第一行会被忽略
            }
            System.out.println(line+"+");//输出最后的分隔线
        } catch (Exception e) {
            //添加你对错误消息的处理,我这里省略了
        }
    }

到此为止,查询结果集的美化输出也完成了,我们来跑一下程序看看效果
在这里插入图片描述

完美还原cmd命令行的输出效果,瞬间变得整齐了有木有,这样的输出看着才舒坦。那么本次分享也该到此为止了,有帮助的小伙伴记得点个赞,谢谢!

Java数据库查询结果的输出 摘自:北京海脉信息咨询有限公司   利用Java开发数据库应用时,经常需要在用户界面上显示查询结果。我们可以利用Vector、JTable、AbstractTableModel等三个类较好地解决这一问题。 类Vector:   定义如下: public class Vector extends AbstractList implements List , Cloneable , Serializable{…} 类JTable:   JTable组件是Swing组件中比较复杂的小件,隶属于javax.swing包,它能以二维的形式显示数据。类Jtable: 定义如下: public class JTable extends JComponent implements TableModelListener, Scrollable, TableColumnModelListener, ListSelectionListener, CellEditorListener, Accessible{…} 类AbstractTableModel:   定义如下: public abstract class AbstractTableModel extends Object implements TableModel, Serializable{…}   生成一个具体的TableModel作为AbstractTableMode的子类,至少必须实现下面三个方法: public int getRowCount(); public int getColumnCount(); public Object getValueAt(int row, int column);   我们可以建立一个简单二维(5×5): TableModel dataModel = new AbstractTableModel() { public int getColumnCount() { return 5; } public int getRowCount() { return 5;} public Object getValueAt(int row, int col) { return new Integer(row*col); } }; JTable table = new JTable(dataModel); JScrollPane scrollpane = new JScrollPane(table); 数据库及其连接方法:   我们采用Sybase数据库数据库存放在数据库服务器中。路径为:D:WORKER,数据库名为:worker.dbf。具有以下字段: 字段名 类型 Wno(职工号) VARCHAR Wname(职工名) VARCHAR Sex(性别) VARCHAR Birthday(出生日期) DATE Wage(工资) FLOAT   要连接此数据库,需使用java.sql包中的类DriverManager。此类是用于管理JDBC驱动程序的实用程序类。它提供了通过驱动程序取得连接、注册,撤消驱动程序,设置登记和数据库访问登录超时等方法。   具体连接方法如下:   定位、装入和链接SybDriver类。 driver="com.sybase.jdbc.SybDriver"; SybDriver sybdriver=(SybDriver) Class.forName(driver).newInstance();   注册SybDriver类。 DriverManager.registerDriver(sybdriver);   取得连接(SybConnection)对象引用。 user="sa"; password=""; url="jdbc:sybase:Tds:202.117.203.114:5000/WORKER"; SybConnection connection= (SybConnection)DriverManager.getConnection (url,user,password); 建立完连接后,即可通过Statement接口进行数据库的查询与更改。 实现方法:   对象声明。   AbstractTableModel tm;   //声明一个类AbstractTableModel对象   JTable jg_table;//声明一个类JTable对象   Vector vect;//声明一个向量对象   JScrollPane jsp;//声明一个滚动杠对象   String title[]={"职工号","职工名",   "性别","出生日期","工资"};   //二维列名   定制表格。   实现抽象类AbstractTableModel对象tm中的方法:   vect=new Vector();//实例化向量   tm=new AbstractTableModel(){   public int getColumnCount(){   return title.length;}//取得表格列数   public int getRowCount(){   return vect.size();}//取得表格行数   public Object getValueAt(int row,int column){   if(!vect.isEmpty())   return   ((Vector)vect.elementAt(row)).elementAt(column);   else   return null;}//取得单元格中的属性值   public String getColumnName(int column){   return title[column];}//设置表格列名   public void setValueAt   (Object value,int row,int column){}   //数据模型不可编辑,该方法设置为空   public Class getColumnClass(int c){   return getValueAt(0,c).getClass();   }//取得列所属对象类   public boolean isCellEditable(int row,int column){   return false;}//设置单元格不可编辑,为缺省实现   };   定制表格:   jg_table=new JTable(tm);//生成自己的数据模型   jg_table.setToolTipText("显示全部查询结果");   //设置帮助提示   jg_table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);   //设置表格调整尺寸模式   jg_table.setCellSelectionEnabled(false);   //设置单元格选择方式   jg_table.setShowVerticalLines(true);//   设置是否显示单元格间的分割线   jg_table.setShowHorizontalLines(true);   jsp=new JScrollPane(jg_table);//给表格加上滚动杠   显示查询结果。   连接数据库:已给出。   数据库查询:   Statement stmt=connection.createStatement();   ResultSet rs=stmt.executeQuery   ("select * from worker");   显示查询结果:   vect.removeAllElements();//初始化向量对象   tm.fireTableStructureChanged();//更新表格内容   while(rs.next()){   Vector rec_vector=new Vector();   //从结果集中取数据放入向量rec_vector中   rec_vector.addElement(rs.getString(1));   rec_vector.addElement(rs.getString(2)); rec_vector.addElement(rs.getString(3)); rec_vector.addElement(rs.getDate(4));   rec_vector.addElement(new Float(rs.getFloat(5)));   vect.addElement(rec_vector);   //向量rec_vector加入向量vect中   }   tm.fireTableStructureChanged();   //更新表格,显示向量vect的内容   实现示图中记录前翻、后翻的效果,有两种方法:   如果软件环境支持JDBC2.0,可直接利用rs.prevoius()和rs.next()获得记录,然后通过类JTextField中的setText()方法,显示出各个字段值。   如果不支持JDBC2.0,则可利用向量Vector按行取出JTable中数据。自定义一个指针,用来记录位置。当指针加1时,取出上一行数据放入Vector中显示;指针减1时,取出下一行数据显示。显示方法同上。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

NEKO!

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值