、私の代わりにシリアライズのデータベースを使用するように傾斜させることだろう。あなたのニーズに応じて、選ぶべきものがたくさんあります。小さな組み込みデータベースの場合、H2のようなものが合理的な選択肢になります。 JavaFX and H2を統合する例をここに示します。
各エンティティ(ユーザー、アカウント、受信者、トランザクション)ごとに個別のテーブルを定義します。各エンティティエントリに一意のIDキーを割り当てます。 ObservableListsに保存したアイテム参照をリンクするにはrelationsを使用してください。
リモートロケーションからデータベースにアクセスしたいが、直接ポート接続を開くことができない場合は、データを提供するサーバー上のサービスを提供する必要があります(例えば、RESTベースのサーバーデータベースアクセスを実行し、JavaFXクライアントがRESTクライアントを介してアクセスするJSON over HTTPとして必要なデータを公開し、REST呼び出し応答をクライアントJavaFXプロパティベースのデータ構造に処理します)。このような実装はすばやく多くの仕事になります:-)
ゴットチャ、それは完全に意味します。私は前にSpringBootとJavaFXを統合しましたが、残念ながらそれらの実装のソースを公開することはできません。
デモプログラムでは、JAXBまたはジャクソンによる永続性で十分です。 Makeryは、JavaFXのJAXBベースの永続性の良い例を提供します。
JAXBベースの手法のトリックは、ネストされたデータモデルで動作するものを得ることです。
JAXBベースのストレージ・アプローチの例
この例はMakery JavaFX tutorialのアイデアに基づいています。それをよりよく理解するには、チュートリアルを参照してください。入れ子にされた観測可能リストの持続性は、JAXB: How to marshal objects in lists?の概念を使用して達成されます。
解決策の鍵は、User
クラスのこのコードビットです。アカウントリストをネストされたObservableListとして提供し、標準アクセッサーaccounts()
を提供して、JavaFXの規則に従ってObservableList
を取得します。 ObservableListを標準Javaリストにコピーして、標準Javaリストにコピーし、JAXB @Xml...
注釈を使用してゲッターに通知して、JAXBがユーザーにリンクされたアカウントのシリアライズとデシリアライズを処理できるようにする方法も提供しています(getAccounts()
とsetAccounts()
)。
private final ObservableList<Account> accounts = FXCollections.observableArrayList();
public ObservableList<Account> accounts() { return accounts; }
@XmlElementWrapper(name="accounts")
@XmlElement(name = "account")
public List<Account> getAccounts() {
return new ArrayList<>(accounts);
}
public void setAccounts(List<Account> accounts) {
this.accounts.setAll(accounts);
}
UserAccountPersistence.java
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.util.prefs.Preferences;
import java.util.stream.Collectors;
public class UserAccountPersistence {
private ObservableList<User> users = FXCollections.observableArrayList();
public UserAccountPersistence() throws JAXBException, IOException {
File dbFile = getDatabaseFilePath();
if (dbFile == null) {
setDatabaseFilePath(new File(System.getProperty("user.home") + "/" + "user-account.xml"));
dbFile = getDatabaseFilePath();
}
if (!dbFile.exists()) {
createTestData();
saveData(dbFile);
} else {
loadData(dbFile);
}
System.out.println("Persisted Data: ");
System.out.println(
Files.lines(dbFile.toPath())
.collect(Collectors.joining("\n"))
);
System.out.println("Database File: " + dbFile);
}
private void createTestData() {
users.add(new User("Hans", "Muster"));
users.add(new User("Ruth", "Mueller"));
users.add(new User("Heinz", "Kurz"));
users.get(0).accounts().addAll(
new Account(10),
new Account(20)
);
users.get(2).accounts().addAll(
new Account(15)
);
}
public File getDatabaseFilePath() {
Preferences prefs = Preferences.userNodeForPackage(UserAccountPersistence.class);
String filePath = prefs.get("filePath", null);
if (filePath != null) {
return new File(filePath);
} else {
return null;
}
}
public void setDatabaseFilePath(File file) {
Preferences prefs = Preferences.userNodeForPackage(UserAccountPersistence.class);
if (file != null) {
prefs.put("filePath", file.getPath());
} else {
prefs.remove("filePath");
}
}
public void loadData(File file) throws JAXBException {
JAXBContext context = JAXBContext
.newInstance(UserListWrapper.class);
Unmarshaller um = context.createUnmarshaller();
UserListWrapper wrapper = (UserListWrapper) um.unmarshal(file);
users.clear();
users.addAll(wrapper.getPersons());
setDatabaseFilePath(file);
}
public void saveData(File file) throws JAXBException {
JAXBContext context = JAXBContext
.newInstance(UserListWrapper.class);
Marshaller m = context.createMarshaller();
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
UserListWrapper wrapper = new UserListWrapper();
wrapper.setPersons(users);
m.marshal(wrapper, file);
setDatabaseFilePath(file);
}
public static void main(String[] args) throws JAXBException, IOException {
UserAccountPersistence userAccountPersistence = new UserAccountPersistence();
}
}
UserListWrapper.java
import java.util.List;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement(name = "users")
public class UserListWrapper {
private List<User> persons;
@XmlElement(name = "user")
public List<User> getPersons() {
return persons;
}
public void setPersons(List<User> persons) {
this.persons = persons;
}
}
User.java
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
public class User {
private final StringProperty id;
private final StringProperty firstName;
private final StringProperty lastName;
private final ObservableList<Account> accounts = FXCollections.observableArrayList();
public User() {
this(UUID.randomUUID().toString(), null, null);
}
public User(String firstName, String lastName) {
this(UUID.randomUUID().toString(), firstName, lastName);
}
public User(String id, String firstName, String lastName) {
this.id = new SimpleStringProperty(id);
this.firstName = new SimpleStringProperty(firstName);
this.lastName = new SimpleStringProperty(lastName);
}
public String getId() {
return id.get();
}
public void setId(String id) {
this.id.set(id);
}
public StringProperty idProperty() {
return id;
}
public String getFirstName() {
return firstName.get();
}
public void setFirstName(String firstName) {
this.firstName.set(firstName);
}
public StringProperty firstNameProperty() {
return firstName;
}
public String getLastName() {
return lastName.get();
}
public void setLastName(String lastName) {
this.lastName.set(lastName);
}
public StringProperty lastNameProperty() {
return lastName;
}
public ObservableList<Account> accounts() { return accounts; }
@XmlElementWrapper(name="accounts")
@XmlElement(name = "account")
public List<Account> getAccounts() {
return new ArrayList<>(accounts);
}
public void setAccounts(List<Account> accounts) {
this.accounts.setAll(accounts);
}
}
Account.java
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import java.util.UUID;
public class Account {
private final StringProperty id;
private final IntegerProperty balance;
public Account() {
this(UUID.randomUUID().toString(), 0);
}
public Account(int balance) {
this(UUID.randomUUID().toString(), balance);
}
public Account(String id, int balance) {
this.id = new SimpleStringProperty(id);
this.balance = new SimpleIntegerProperty(balance);
}
public String getId() {
return id.get();
}
public void setId(String id) {
this.id.set(id);
}
public StringProperty idProperty() {
return id;
}
public int getBalance() {
return balance.get();
}
public IntegerProperty balanceProperty() {
return balance;
}
public void setBalance(int balance) {
this.balance.set(balance);
}
}
出力
$ cat /Users/jewelsea/user-account.xml
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<users>
<user>
<accounts>
<account>
<balance>10</balance>
<id>a17b8244-5d3a-4fb4-a992-da26f4e14917</id>
</account>
<account>
<balance>20</balance>
<id>f0b23df5-3cc0-418c-9840-633bc0f0b3ca</id>
</account>
</accounts>
<firstName>Hans</firstName>
<id>078dad74-ea9d-407d-9be5-d36c52c53b0d</id>
<lastName>Muster</lastName>
</user>
<user>
<accounts/>
<firstName>Ruth</firstName>
<id>78513f1b-75ee-4ca9-a6f0-444f517e3377</id>
<lastName>Mueller</lastName>
</user>
<user>
<accounts>
<account>
<balance>15</balance>
<id>77c4fd3c-5f7a-46cf-a806-da1e6f93baab</id>
</account>
</accounts>
<firstName>Heinz</firstName>
<id>651d9206-42a5-4b76-b89e-be46dce8df74</id>
<lastName>Kurz</lastName>
</user>
</users>
あなたの迅速な答えをありがとうございました!私は実際にDAOとHibernateがうまく動作しているspring-bootベースのWebアプリケーションを既に持っており、このJavaFX AppはそのWebアプリケーションに接続する予定です。私は現在、ローカルに保存されたファイルを、プログラムの少しデモとして必要としています。私はあなたが提供したH2の例を確かにチェックします! – UniqUnicorn
あなたが提供した新しいJAXBサンプルで質問を更新しました! – UniqUnicorn
@ UnniUnicornあなたのバージョンのコードでアンマーシャリングがうまくいかない理由がわかりません。私は私の答えでコードをダブルチェックし、アンマーシャリングは私が提供したコードのために働いています。私はあなたの実装のために経験する動作の違いの理由を知らない。 – jewelsea