1

I'm working on a program with which I can search through a database and display the results.

I'm stuck at the displaying part at the moment. My SQL query already works and returns the results. I'm using a PreparedStatement to fill my ResultSet. However I don't know how I can return the data of the ResultSet to a JTable which I want to use to display the data. Can anyone explain to me in detail how to do this or if there is a better way instead of a JTable I'm not seeing?

I'm using the MVC model and the DAO pattern, but I'm still pretty new to programming. So far from researching it I found the best solution to be to make a custom table class, but from there on I don't know how to progress.

My custom table class:

import java.sql.ResultSet;
import java.sql.ResultSetMetaData;

import java.util.Vector;

import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableModel;


public class ResultSetTable {
 public static TableModel resultSetToTableModel(ResultSet rs) {
    try {
        ResultSetMetaData metaData = rs.getMetaData();
        int numberOfColumns = metaData.getColumnCount();
        Vector columnNames = new Vector();

        //Spaltennamen
        for (int column = 0; column < numberOfColumns; column++) {
            columnNames.addElement(metaData.getColumnLabel(column + 1));
        }

        //Alle Zeilen
        Vector rows = new Vector();

        while (rs.next()) {
            Vector newRow = new Vector();

            for (int i = 1; i <= numberOfColumns; i++) {
                newRow.addElement(rs.getObject(i));
            }

            rows.addElement(newRow);
        }

        return new DefaultTableModel(rows, columnNames);
    } catch (Exception e) {
        e.printStackTrace();

        return null;
    }
}
}

And the relevant part of my View class:

import java.awt.FlowLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTable;
import javax.swing.JTextField;

import dbconnect.dao.impl.BTRDaoImpl;

public class View extends JFrame{
public View() {

    JTable table = new JTable(new ResultSetTable(BTRDaoImpl.resultset);

    this.setSize(600, 400);
    setResizable(false);
}

My BTRDaoImpl class with the sql query and resultset:

import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import mvc.View;
import dao.BTRbDao;
import business.BTRBean;

public class BTRDaoImpl extends AbstractDao implements BTRDao {

private Connection dbConnection = null;
private PreparedStatement preparedStatement = null;

public void sqlquery() {
    try {

        String btrname = View.searchbbtrname.getText();
        String btrplz = View.searchbtrplz.getText();
        btrname = btrname.trim().toUpperCase();
        btrplz = btrplz.trim().toUpperCase();

        if (btrplz.isEmpty()) {
            String btrResult = "SELECT BBSTBBNR, BBSTNABE, BBSTPLZ FROM BP.TBBBST WHERE BBSTNABEG = ?";

            dbConnection = AbstractDao.getConnection();
            preparedStatement = dbConnection.prepareStatement(btrResult);
            preparedStatement.setString(1, btrname);


        } else {
            String btrResult = "SELECT BBSTBBNR, BBSTNABE, BBSTPLZ FROM BP.TBBBST WHERE BBSTNABEG = ? AND BBSTPLZ = ?";

            dbConnection = AbstractDao.getConnection();
            preparedStatement = dbConnection.prepareStatement(btrResult);
            preparedStatement.setString(1, btrname);
            preparedStatement.setString(2, btrplz);

        }
    } catch (SQLException e1) {
        System.out.println("An error with the SQL query occured: ");
        e1.printStackTrace();
    } 
}

public Collection<BtrBean> getBTR() throws SQLException,
        IOException {
    sqlquery();
    final Collection<BtrBean> result = new ArrayList<BtrBean>();

    ResultSet resultset = null;
    try {
        resultset = preparedStatement.executeQuery();

        // while loop to get data
        while (resultset.next()) {
            BtrBean btr = new BtrBean();
            int btrid = resultset.getInt(1);
            String btrplz = resultset.getString(3);
            String btrname = resultset.getString(2);
            btr.setBetriebnr(btrid);
            btr.setBetriebplz(btrplz);
            btr.setBetriebname(btrname);
            result.add(btr);
        //  System.out.println("BTR-ID: " + btrid + " BTR PLZ: " + btrplz + " BTR: " + btrname);
        }

    } catch (SQLException e) {
        e.printStackTrace();
        System.out.println("An error processing the SQL occured: ");
        e.printStackTrace();
    } catch (NullPointerException npe) {
        System.out.println("NullPointerException: ");
        npe.printStackTrace();
    } finally {
        if (preparedStatement != null) preparedStatement.close();
        closeConnection(resultset);
    }
    return result;
}

}

My BTRBean class:

public class BetriebBean {

private String betriebname;
private int betriebnr;
private String betriebplz;

public BetriebBean() {

}

public BetriebBean(String betriebname, int betriebnr, String betriebplz) {
    super();
    this.betriebname = betriebname;
    this.betriebnr = betriebnr;
    this.betriebplz = betriebplz;
}
public String getBetriebname() {
    return betriebname;
}
public void setBetriebname(String betriebname) {
    this.betriebname = betriebname;
}
public int getBetriebnr() {
    return betriebnr;
}
public void setBetriebnr(int betriebnr) {
    this.betriebnr = betriebnr;
}
public String getBetriebplz() {
    return betriebplz;
}
public void setBetriebplz(String betriebplz) {
    this.betriebplz = betriebplz;
}

}

//edit:

My whole View.class:

import java.awt.FlowLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTable;
import javax.swing.JTextField;

public class View extends JFrame{

private static final long serialVersionUID = 1L;

public static final String SEARCH = "SEARCH";

private JLabel searchbtrlabel = new JLabel("BTR name:");
public static JTextField searchbtrname = new JTextField(10);
private JLabel searchbtrlabel = new JLabel("PLZ:");
public static JTextField searchbtrplz = new JTextField(10);
private JButton searchbutton = new JButton();

public View() {
    this.setTitle("BTR search TBBBST");

    this.setDefaultCloseOperation(EXIT_ON_CLOSE);

    this.setLayout(new FlowLayout());

    this.add(searchbtrlabel);
    this.add(searchbtrname);
    this.add(searchbtrplzlabel);
    this.add(searchbtrplz);

    searchbutton.setText("Search");
    searchbutton.setActionCommand(View.SEARCH);
    this.add(searchbutton);

    JTable table = new JTable();
    this.add(table);

    this.setSize(600, 400);
    setResizable(false);
    //this.pack();
}

public JTextField getSearchbtrname() {
    return searchbetriebname;
}

public JTextField getSearchbbtrplz() {
    return searchbetriebplz;
}

public JButton getSearchbutton() {
    return searchbutton;
}
}

My Controller class:

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Observable;
import java.util.Observer;

import mvc.Model;
import dbconnect.dao.impl.BTRDaoImpl;

public class Controller implements Observer, ActionListener{

private Model model;
@SuppressWarnings("unused")
private View view;

public Controller(Model model, View view) {
    this.model = model;
    this.view = view;

    model.addObserver(this);
    view.getSearchbutton().addActionListener(this);
    view.setVisible(true);
}

@Override
public void actionPerformed(ActionEvent e) {
    switch (e.getActionCommand()) {
    case View.SEARCH:
        model.search();
        view.table.setModel(ResultSetToTable.buildTableModel(BTRDaoImpl.resultset));
        break;

    default:
        System.out.println("Error : " + e.getActionCommand());
        break;
    }

}

@Override
public void update(Observable o, Object arg) {
    // TODO Auto-generated method stub

}

}
APL
  • 101
  • 1
  • 3
  • 14

2 Answers2

1

Firstly, include rs2xml.jar in your libraries. You can find it here

In whatever action to populate your MySQL query in your JTable use following general idea:

public void sqlquery() {
    try {
        String btrResult = "SELECT BBSTBBNR, BBSTNABE, BBSTPLZ FROM BP.TBBBST WHERE BBSTNABEG = ?";
        preparedStatement = dbConnection.prepareStatement(btrResult);
        dbConnection.setString(1, btrname);
        ResultSet rs =dbConnection.executeQuery();
        Ur_table_name.setModel(DbUtils.resultSetToTableModel(DbUtils.resultSetToel(rs));  //this line of code will show it in your JTable
    }catch(Exception e){

    }
Abra
  • 19,142
  • 7
  • 29
  • 41
JBALI
  • 89
  • 6
  • Thanks! I have two questions for that though. I don't have a resultSetToel method, haven't seen it in the example from which I learned about the custom tables either. What would this method look like / what does it do? And as far as I see it, I need to replace the "rs" in this example with my ResultSet which would be "BTRDaoImpl.resultset", right? – APL Dec 03 '15 at 12:31
  • What about the `resultSeToel` method? I haven't seen it in an example so far and apparently it is crucial, because right now without it, it doesn't work. With the error _"resultset cannot be resolved or is not a field"_ pointing at the `BTRDaoImpl.resultset` in said method. – APL Dec 03 '15 at 12:46
  • resultset is imported from sql library `import java.sql.ResultSet` it will be used inside `resultSetToTableModel())` by adding the object rs, this way u will populate ur results to jtabel, do not forget to get ur js2Xml jar from sourceforge – JBALI Dec 03 '15 at 12:48
  • So do I need to change the arguement for this method, which is in my case: `table.setModel(DbUtils.resultSetToTableModel(rs);`, into something or do I need to declare rs in my View class as well first? Because like this it gives me an error, that it obviously doesn't know the variable. – APL Dec 03 '15 at 13:02
  • in my answer I have defined rs as an `ResultSet` object and the way u see it in my answer works fine for me, what kind of error u get? – JBALI Dec 03 '15 at 13:15
  • Mmh well I thought I could use my resultset from my other class, so `BTRDaoImpl.resultset`, but with that it gives me the error _"resultset cannot be resolved or is not a field"_. – APL Dec 03 '15 at 13:25
0

What is your question? Try being more specific than "[...] but from there on I don't know how to progress." What do you want to do? Are the results from your query visible in the table?

Using the answer from Paul Vargas over here Most simple code to populate JTable from ResultSet, you could start with something like this (using Java 8):

import java.sql.*;
import java.util.Vector;
import javax.swing.*;
import javax.swing.table.*;

public class ResultSetToTable {
    public static void main(final String[] arguments) {
        SwingUtilities.invokeLater(() -> {
            try {
                new ResultSetToTable().createAndShowGui();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        });
    }

    private void createAndShowGui() throws SQLException {
        final JFrame frame = new JFrame("Stack Overflow");
        frame.setBounds(100, 100, 800, 600);
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);

        final JPanel panel = new JPanel();
        final TableModel tableModel = buildTableModel(getData("Audi"));
        final JTable table = new JTable(tableModel);
        panel.add(new JScrollPane(table));
        frame.getContentPane().add(panel);

        frame.setVisible(true);
    }

    private ResultSet getData(final String btrName) throws SQLException {
        final String url = "jdbc:h2:/Freek/TBBBST";
        final Connection connection = DriverManager.getConnection(url, "me", "123");
        final String sql = "SELECT BBSTBBNR, BBSTNABE, BBSTPLZ " +
                           "FROM BP.TBBBST " +
                           "WHERE BBSTNABEG = ?";
        final PreparedStatement preparedStatement = connection.prepareStatement(sql);
        preparedStatement.setString(1, btrName);
        return preparedStatement.executeQuery();
    }

    /**
     * See https://stackoverflow.com/a/10625471/1694043
     */
    public static TableModel buildTableModel(final ResultSet resultSet)
            throws SQLException {
        int columnCount = resultSet.getMetaData().getColumnCount();

        // Column names.
        Vector<String> columnNames = new Vector<>();
        for (int columnIndex = 1; columnIndex <= columnCount; columnIndex++) {
            columnNames.add(resultSet.getMetaData().getColumnName(columnIndex));
        }

        // Data of the table.
        Vector<Vector<Object>> dataVector = new Vector<>();
        while (resultSet.next()) {
            Vector<Object> rowVector = new Vector<>();
            for (int columnIndex = 1; columnIndex <= columnCount; columnIndex++) {
                rowVector.add(resultSet.getObject(columnIndex));
            }
            dataVector.add(rowVector);
        }

        return new DefaultTableModel(dataVector, columnNames);
    }
}

For older versions of Java, you should be able to use this version of the main method:

public static void main(final String[] arguments) {
    SwingUtilities.invokeLater(new Runnable() {
        @Override
        public void run() {
            try {
                new ResultSetToTable().createAndShowGui();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    });
}

Edit: connecting controller and table

To make the table available outside the view, you need to convert the table variable in the View() constructor into a field (like you have done with searchbtrname) and create a getTable getter method for it (like you have done with getSearchbtrname). In the Controller.actionPerformed method you can now change view.table into view.getTable().

Community
  • 1
  • 1
Freek de Bruijn
  • 3,552
  • 2
  • 22
  • 28
  • Wouldn't that mean I'd have to execute the PreparedStatement with the SQL query a second time and therefore slowing down my program a lot? – APL Dec 04 '15 at 07:18
  • I think the `getData` method is only called once and therefore the query is not executed a second time. You can add a println to check that. Is the example above having the same issue as your code? If the example above has issues for you, which issues do you run into? – Freek de Bruijn Dec 04 '15 at 07:26
  • I got a problem with the `invokeLater`-method. It is not working like in your example telling me that it needs an arguement, so Iassumed that the try-catch block should be the parameter of that method, but that doesn't seem to work either. – APL Dec 04 '15 at 08:22
  • Are you using Java 8 or an older version of Java? ["Since April 2015, Oracle is no longer post updates of Java SE 7 to its public download sites."](https://java.com/en/download/faq/java_7.xml) – Freek de Bruijn Dec 04 '15 at 09:29
  • See the alternative `main` method above for older versions of Java. – Freek de Bruijn Dec 04 '15 at 09:34
  • Ah yes I'm still using Java 7 at the moment. The alternative method seems to work. Well kind of, it doesn't throw me any errors. – APL Dec 04 '15 at 09:46
  • In that case, you can also try to call `new ResultSetToTable().createAndShowGui();` directly (so remove the 9 lines around that statement). – Freek de Bruijn Dec 04 '15 at 09:48
  • Ah thanks. That seemed to work. However how could I add the filled JTable to my GUI after a successful search then? As in how do I update the view with this? I know that I can't do it in my View class since that would lead to a Nullpointer exception, because no resultset exists before the search. – APL Dec 04 '15 at 09:50
  • During initialization, you can fill the `JTable` with the results of a query. Whenever you want to update your table, you can replace the table model with a call to `table.setModel([new table model])` and your table should update automatically. – Freek de Bruijn Dec 04 '15 at 09:56
  • When trying to access my JTable from my Controller class however it tells me that my JTable "table" doesn't exist. – APL Dec 04 '15 at 10:01
  • Share the code of your controller and viewer and explain your issue. It sounds like you need to make your table available to your controller, but I'm not sure. – Freek de Bruijn Dec 04 '15 at 10:05
  • Alright, I added the code to the end of my main post. – APL Dec 04 '15 at 10:21