Lekce 4 - Práce s CSV soubory v Kotlin - Uložení objektů
V minulé lekci, Práce s textovými soubory v Kotlin, jsme si ukázali zápis do textových souborů i jejich čtení.
V dnešním Kotlin tutoriálu si vytvoříme formulářovou aplikaci s databází uživatelů, která bude ukládat instance do textových souborů ve formátu CSV. Do CSV (jako Comma Separated Values) souborů ukládáme hodnoty oddělené čárkou, případně středníkem. Každý řádek bude uchovávat hodnoty jednoho uživatele.
JavaFX aplikace
K tvorbě formuláře využijeme framework JavaFX. Jednoduchý formulář pak díky tomu budeme moci naklikat v nástroji Scene Builder, který za nás vygeneruje XML kód. Zájemce odkážu na kurz v sekci Java, kde je sice jako vývojové prostředí použito NetBeans, ale postup v IntelliJ bude velmi podobný.
Nejprve si založíme v IntelliJ nový Kotlin projekt. V dalším okně
vybereme položku JavaFX a doplníme název aplikace. Programovacím
jazykem bude Kotlin, správu balíčků necháme na Maven, v
políčku Group nastavujeme název package, který jsme
přepsali na itnetwork
:

Pokračujeme tlačítkem Next do dalšího okna, ve kterém nic měnit nebudeme a pouze klikneme na tlačítko Create.
IntelliJ nám vygenerovalo a otevřelo soubor pom.xml
, jeden
.fxml
soubor pro vzhled formuláře, k němu kontroler a hlavní
třídu, vše ve stylu "Hello world" aplikací.
Konfigurační soubor pom.xml
měnit nebudeme,
ostatní si můžeme smazat a postupně nahradit vlastními, případně si je
přejmenujeme a upravíme jejich obsah.
Zaměřme se ale nejdříve na logickou vrstvu aplikace.
Třída Uzivatel
Pojďme se shodnout na tom, jak bude naše třída uživatele vypadat. Následně si ukážeme, jak její instance do CSV uložíme.
Do vytvořeného projektu si přidáme třídu Uzivatel
. U
uživatele budeme evidovat jeho jméno, věk a
datum, kdy byl registrován. Konstruktor bude instanci
inicializovat na základě těchto tří vlastností.
Přepíšeme si metodu toString()
tak, aby vrátila jméno
uživatele. Třída tedy bude vypadat takto:
class Uzivatel(val jmeno: String, val vek: Int, val registrovan: LocalDate) { override fun toString(): String { return jmeno } }
Naimportujeme si balíček java.time.LocalDate
.
Třída Databáze
Třídu uživatele Uzivatel
máme. Vytvoříme
si i třídu pro naši databázi, kterou nazveme
Databaze
. Ta bude obsahovat kolekci uživatelů,
které budeme ukládat do generického
mutableListOf<Uzivatel>
. Kolekce bude
privátní a přidávání uživatelů (případně jejich
mazání, vyhledávání a podobně) bude realizováno veřejnými
metodami. Databáze bude obsahovat metody k načtení
CSV souboru, a také k uložení obsahu databáze do souboru.
Pro jméno souboru budeme mít privátní atribut
soubor
ve třídě Databaze
.
Přidejme si tedy k projektu třídu Databaze
a předepišme si
do ní i zmíněné metody:
class Databaze(soubor: Path) { private val uzivatele = mutableListOf<Uzivatel>() private val soubor: Path init { this.soubor = soubor } fun pridejUzivatele(jmeno: String, vek: Int, registrovan: LocalDate) { } fun vratVsechny(): List<Uzivatel> { } val model: MutableList<Uzivatel> @Throws(IOException::class) fun uloz() { } @Throws(IOException::class) fun nacti() { } }
IntelliJ nám u metody vratVsechny()
vyhubuje,
protože nevrací hodnotu, ale toho si zatím nebudeme všímat. Jednotlivé
metody vzápětí postupně naimplementujeme.
Metoda pridejUzivatele()
Pojďme si ukázat, jak budou uživatelé ve formátu CSV vypadat. Každý řádek bude reprezentovat jednoho uživatele. Vlastnosti uživatele budou odděleny středníky.
Například uživatel Pavel Slavík, kterému je 22 let a zaregistroval se 21.3.2000 by ve formátu CSV vypadal takto:
Pavel Slavík;22;21.3.2000
Na první pohled vidíme, že je soubor relativně jednoduše
čitelný, i když nezasvěcený se může jen domnívat, co je číslo
22
a k čemu se váže ono datum. V souboru může být
samozřejmě více uživatelů, tedy více řádků.
Přidáme si metodu pridejUzivatele()
:
fun pridejUzivatele(jmeno: String, vek: Int, registrovan: LocalDate) {
uzivatele.add(Uzivatel(jmeno, vek, registrovan))
}
Metoda getModel()
Dále si přidáme metodu model()
, která vrátí
kolekci uživatelů:
val model: MutableList<Uzivatel> get() = uzivatele
Metoda vratVsechny()
Nakonec si napíšeme metodu vratVsechny()
, která nám vrátí
kolekci uživatelů List<Uzivatel>
:
fun vratVsechny(): List<Uzivatel> { return uzivatele }
Uložení uživatelů do CSV
Nyní se již dostáváme k práci s CSV souborem.
Proiterujeme náš list uživatelů a pro každého uživatele vytvoříme
proměnnou radek
typu String
, ve které budou
jednotlivé vlastnosti uživatele oddělené středníkem.
Obsah proměnné radek
pak zapíšeme do souboru
soubor
:
@Throws(IOException::class) fun uloz() { // Nejprve soubor vytvoříme, pokud již existuje tak jej vyprázdníme. Files.writeString(soubor, "", StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING) for (u in vratVsechny()) { val radek: String = u.jmeno + ";" + u.vek + ";" + u.registrovan.toString() + System.lineSeparator() Files.writeString(soubor, radek, StandardOpenOption.APPEND) } }
FXML formulář
Nyní budeme potřebovat vytvořit samotný formulář. FXML soubory
ukládáme ve složce main/
do podsložky resource/
a
vnořeného balíčku. Na ten klikneme pravým tlačítkem myši a přidáme
novou položku FXML File s názvem formular.fxml
. Soubor
si najdeme ve svém počítači a otevřeme jej v Scene Builderu.
Prozatím do něj vložíme kontejner VBox
a do něj přidáme
jeden Label
a jeden Button
. Kontejneru ve vlastnostech
nastavíme centrování na střed, a v nabídce Controller
vyplníme název kontroleru: itnetwork.uzivatele.DatabazeKontroler
.
Položce Label
vymažeme defaultní text a do fx:id
vyplníme errorText
, aby se nám zde zobrazovaly případné
chybové hlášky. Button
necháme zobrazovat text
Ulož
a v nabídce Code vyplníme políčko On
Action textem uloz
. Tím zajistíme, že po kliknutí na
tlačítko bude zavolána metoda uloz()
.
Máme hotovo, změny uložíme a vrátíme se do IntelliJ.
Kontroler
DatabazeKontroler
Do projektu přidáme další Kotlin třídu DatabazeKontroler
.
V té vytvoříme privátní atribut databaze
, do kterého v
konstruktoru formuláře uložíme novou instanci naší databáze:
class DatabazeKontroler { private var databaze: Databaze? = null init { try { val path = Path.of(System.getProperty("user.home"), "itnetwork", "uzivatele.csv") Files.createDirectories(path.getParent()) databaze = Databaze(path) } catch (ex: IOException) { Logger.getLogger(DatabazeKontroler::class.java.name).log(Level.SEVERE, null, ex) } } }
Pokud vám IntelliJ podtrhne poslední řádek, otevřete si
soubor modules-info.java
a doplňte do něj řádek
requires java.logging;
, kterým zavoláte potřebný modul.
Dále si doplníme obsluhu formuláře:
@FXML private lateinit var errorText: Label
Nejprve deklarujeme privátní proměnnou errorText
pro
zobrazení chybových hlášek v naší Label
komponentě.
Dále doplníme obsluhu tlačítka Ulož, které zajistí uložení
dvou níže uvedených uživatelů. Toto řešení je
provizorní, abychom mohli vše vyzkoušet, později bude aplikace vypadat
lépe. Dále celou databázi metoda uloz()
uloží do souboru:
@FXML private fun uloz() { try { databaze!!.pridejUzivatele("Pavel Slavík", 22, LocalDate.of(2000, 3, 21)) databaze!!.pridejUzivatele("Jan Novák", 31, LocalDate.of(2012, 10, 30)) databaze!!.uloz() } catch (ex: IOException) { errorText.text = "Databázi se nepodařilo uložit, zkontrolujte přístupová práva k souboru." println("Databázi se nepodařilo uložit, zkontrolujte přístupová práva k souboru.") } }
Položky k obsluze FXML formuláře nezapomeneme označit
anotací @FXML
.
Hlavní třída
Na závěr nám dnes zbývá doplnit hlavní třídu s main()
metodou. Její kód bude dost podobný vygenerované třídě
HelloApplication
. My si třídu nazveme Main.kt
a
doplníme kód:
class Aplikace : Application() { override fun start(stage: Stage) { val fxmlLoader = FXMLLoader(Aplikace::class.java.getResource("formular.fxml")) val scene = Scene(fxmlLoader.load(), 320.0, 240.0) stage.title = "Databáze uživatelů!" stage.scene = scene stage.show() } } fun main() { Application.launch(Aplikace::class.java) }
V hlavní třídě voláme pomocí fxmlLoader
patřičný
formulář, nastavujeme jeho velikost a titulek a necháme vše zobrazit.
Testování
Aplikaci spustíme a klikneme na tlačítko. Nyní otevřeme (např. v
NotePadu) soubor uzivatele.csv
a vidíme, že má následující
obsah:
Pavel Slavík;22;21.3.2000 Jan Novák;31;30.10.2012
Vše tedy funguje, jak má .
V příští lekci, Práce s CSV soubory v Kotlin - Načtení objektů, dokončíme naši objektovou formulářovou aplikaci s databází uživatelů s použitím textových souborů ve formátu CSV.
Měl jsi s čímkoli problém? Stáhni si vzorovou aplikaci níže a porovnej ji se svým projektem, chybu tak snadno najdeš.
Stáhnout
Stažením následujícího souboru souhlasíš s licenčními podmínkami
Staženo 7x (35.43 kB)
Aplikace je včetně zdrojových kódů v jazyce Kotlin