Как реализовать получение и отображение данных с сервера в таблицах TableView?
Помогите понять, что я делаю не так. Создаю на JavaFX приложение для отображения БД на MySQL-сервере. Настраиваю внешний вид страниц с помощью SceneBuilder. Соответственно вот код по классам, которые необходимы для реализации получения данных с сервера и размещения их в таблице TableView.
Проблема в том, что мне удаётся получить данные с сервера и передать их построчно в сущности созданного класса Client, в цикле добавляя их к списку clients. Но данный список я никак не могу поместить/отобразить в TableView.
DBConnection.java
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import sample.Clients.Client;
import java.sql.*;
import java.util.Date;
public class DBConnection {
private final Connection connection;
public DBConnection() throws SQLException {
String host = "";
String port = "";
String name = "";
String url = "jdbc:mysql://" + host + ":" + port + "/" + name;
String login = "";
String password = "";
connection = DriverManager.getConnection(url, login, password);
}
public ObservableList<Client> getClients() throws SQLException, ClassNotFoundException {
String sql = "SELECT * FROM Clients";
Statement statement = connection.createStatement();
ResultSet res = statement.executeQuery(sql);
ObservableList<Client> clients = FXCollections.observableArrayList();
while (res.next()) {
int id = res.getInt("id");
String legal_entity_name = res.getString("legal_entity_name");
String bank_details = res.getString("bank_details");
// переход от реляционной модели к объектной
clients.add(new Client(id, legal_entity_name, bank_details));
System.out.println(id + " " + legal_entity_name + " " + bank_details);
}
return clients;
}
}
ClientsController.java
import javafx.beans.property.SimpleIntegerProperty;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.stage.Stage;
import sample.DBConnection;
import java.io.IOException;
import java.net.URL;
import java.sql.SQLException;
import java.util.ResourceBundle;
public class ClientsController {
@FXML
private ResourceBundle resources;
@FXML
private URL location;
@FXML
private TableColumn<Client, SimpleIntegerProperty> id;
@FXML
private TableColumn<Client, String> legal_entity_name;
@FXML
private TableColumn<Client, String> bank_details;
@FXML
private TableView<Client> Clients;
@FXML
private Button delete;
@FXML
private Button update;
@FXML
private Button add;
DBConnection connection = null;
@FXML
void initialize() throws SQLException, ClassNotFoundException {
connection = new DBConnection();
loadInfo();
}
void loadInfo() throws SQLException, ClassNotFoundException {
for (int i = 0; i < Clients.getItems().size(); i++)
Clients.getItems().clear();
id.setCellValueFactory(new PropertyValueFactory<>("id"));
legal_entity_name.setCellValueFactory(new PropertyValueFactory<>("legal_entity_name"));
bank_details.setCellValueFactory(new PropertyValueFactory<>("bank_details"));
// определяем таблицу и устанавливаем данные
ObservableList<Client> clients = connection.getClients();
//System.out.println(clients.get(1).getLegalEntityName());
Clients = new TableView<>(clients);
Clients.setItems(clients);
Clients.getColumns().addAll(id, legal_entity_name, bank_details);
}
}
//System.out.println(clients.get(1).getLegalEntityName());
Если раскомментировать данную строчку, то можно понять, что список clients непустой и верно заполнен передаваемыми данными. Из чего я делаю вывод, что ошибка где-то здесь:
Clients = new TableView<>(clients);
Clients.setItems(clients);
Clients.getColumns().addAll(id, legal_entity_name, bank_details);
Или ещё до получения данных с сервера здесь:
id.setCellValueFactory(new PropertyValueFactory<>("id"));
legal_entity_name.setCellValueFactory(new PropertyValueFactory<>("legal_entity_name"));
bank_details.setCellValueFactory(new PropertyValueFactory<>("bank_details"));
Подскажите, пожалуйста, в чём тут дело? Вроде прописываю по руководствам всё, а данные не выводятся :(
Ответы (1 шт):
Я попробую ответить, возможно в чем-то могу ошибаться но Ваш результат я получил. Я использовал паттерн DAO. У Вас не совсем хорошо реализован DBConnection. Он по логике предназначен для организации соединения с БД, а у Вас там и сразу запросы... Даже небольшая программа вскоре доставит при таком подходе массу проблем. DAO (Data Access Objects) - шаблон проектирования, определяющий механизм доступа к данным (ссылка на вики). Грубо говоря, в классах дао (UserDao итд) вы должны организовать методы получения определенных объектов или коллекций этих объектов, а также методы для работы с этими объектами (CRUD-операции)(Evgeny Lazarev). Можете использовать другие паттерны, но это Ваше уже дело. Класс Client для формирования записей
public class Client {
private Integer id;
private String legalEntityName;
private String bankDetails;
public Client(Integer id, String legalEntityName, String bankDetails) {
this.id = id;
this.legalEntityName = legalEntityName;
this.bankDetails = bankDetails;
}
public Integer getId() {return id;}
public String getLegalEntityName() {return legalEntityName;}
public String getBankDetails() {return bankDetails;}
@Override
public String toString() {
return this.legalEntityName;
}
}
FXML
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<AnchorPane prefHeight="400.0" prefWidth="600.0"
xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1"
fx:controller="ПутьКВашемуКонтроллеру.ClientsController">
<children>
<TableView fx:id="Clients" layoutX="59.0" layoutY="84.0" prefHeight="200.0" prefWidth="514.0">
<columns>
<TableColumn fx:id="id" prefWidth="150.0" text="id" />
<TableColumn fx:id="legalEntityName" minWidth="0.0" prefWidth="180.0" text="legal_entity_name" />
<TableColumn fx:id="bankDetails" minWidth="0.0" prefWidth="180.0" text="bank_details" />
</columns>
</TableView>
</children>
</AnchorPane>
Контроллер
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import java.net.URL;
import java.util.ResourceBundle;
public class ClientsController implements Initializable {
private static ObservableList<Client> clientData = FXCollections.observableArrayList();
@FXML
private TableColumn<Client, String> bankDetails, legalEntityName;
@FXML
private TableColumn<Client, Integer> id;
@FXML
private TableView<Client> Clients;
@Override
public void initialize(URL location, ResourceBundle resources) {
initData();
// устанавливаем тип и значение которое должно хранится в колонке
id.setCellValueFactory(new PropertyValueFactory<Client, Integer>("id"));
legalEntityName.setCellValueFactory(new PropertyValueFactory<Client, String>("legalEntityName"));
bankDetails.setCellValueFactory(new PropertyValueFactory<Client, String>("bankDetails"));
// заполняем таблицу данными
Clients.setItems(clientData);
}
private void initData() {
var clients = ClientDAO.getInstance().findAll();
for (Client client : clients) {
clientData.add(new Client(
client.getId(),
client.getLegalEntityName(),
client.getBankDetails()
));
}
}
}
Слой DAO с одной реализацией вывода всех записей
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
public class ClientDAO {
private static final String FIND_ALL_SQL = """
SELECT id,
legal_entity_name,
bank_details
FROM "Clients"
""";
public List<Client> findAll() {
try (var connection = DBConnection.getInstance().getConnection();
var preparedStatement = connection.prepareStatement(FIND_ALL_SQL)) {
var resultSet = preparedStatement.executeQuery();
List<Client> clients = new ArrayList<>();
while (resultSet.next()) {
clients.add(buildClient(resultSet));
}
return clients;
} catch (SQLException throwable) {
throwable.printStackTrace();
throw new DaoException(throwable);
}
}
private static final ClientDAO INSTANCE = new ClientDAO();
public static ClientDAO getInstance() {
return INSTANCE;
}
private Client buildClient(ResultSet resultSet) throws SQLException {
return new Client(
resultSet.getInt("id"),
resultSet.getString("legal_entity_name"),
resultSet.getString("bank_details")
);
}
}
Вспомогательный класс DaoException
public class DaoException extends RuntimeException {
public DaoException(Throwable throwable) {
super(throwable);
}
}
DBConnection
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class DBConnection {
private static DBConnection instance = null;
public static DBConnection getInstance() throws SQLException {
if(null == instance)
instance = new DBConnection();
return instance;
}
public Connection getConnection() {
Connection connection = null;
try{
connection = DriverManager.getConnection("jdbc:postgresql://localhost:5432/bd","login","pass");
}catch(SQLException e){
e.printStackTrace();
}
return connection;
}
}
