Omdat JavaFX terrein wint als Java's de-facto GUI-framework, zal het vroeg of laat Swing vervangen. JavaFX UI en JDBC kunnen een effectieve combinatie zijn bij het maken van een databasegestuurde applicatie, vooral in een offline of embedded systeem. Dit artikel laat in wezen zien hoe dit kan worden gedaan met een voorbeeldscenario.
Een overzicht van JDBC-applicaties
De evolutie van het Java GUI-framework berust nu op de JavaFX-bibliotheek. Het biedt een krachtig maar flexibel alternatief voor GUI-ontwikkeling, in tegenstelling tot het bestaande Swing- en AWT-framework. JavaFX levert een groot aantal bedieningselementen en componenten die helpen bij het snel en effectief bouwen van een GUI-interface. Het is heel eenvoudig om een desktoptoepassing te ontwikkelen die samenwerkt met de back-enddatabase. Een JDBC (Java Database Connectivity) applicatie heeft voornamelijk een back-end databasesysteem zoals MySQL, Derby, Oracle of een andere database. Java-code wordt geschreven om records op te halen uit een of meer tabellen in de database. De SQL (Structured Query Language) query's worden gestart vanuit Java-code en verzonden naar de database-engine voor verwerking. De JDBC-driver fungeert als intermediair tussen het Java-programma en de database en interpreteert de stroom van informatie heen en weer, zodat zowel de ongeëvenaarde partij, zoals de database, als het Java-programma zich kunnen verzoenen tot een werkbare oplossing. De database heeft absoluut geen idee van Java-code, de syntaxis ervan of wat dan ook. Het begrijpt eenvoudig SQL en kan er alleen mee communiceren. Java daarentegen is een OOP (Object Oriented Programming) taal en heeft ook geen idee van SQL of zijn syntaxis. Om communicatie mogelijk te maken, levert de databaseleverancier native drivers samen met de database. Dit wordt het JDBC-stuurprogramma genoemd. Merk op dat er vier soorten stuurprogramma's beschikbaar zijn. Ze worden in de volksmond Type-1, Type-2, Type-3 en Type-4 drivers genoemd. De native stuurprogramma's zijn Type-4-stuurprogramma's en worden het meest gebruikt. Ze zijn ook efficiënter dan andere typen. Een Java-programma kan deze JDBC-stuurprogramma's als een externe bibliotheek in het Java-programma opnemen, aangezien ze gewoonlijk voorkomen in JAR-archiefbestanden.
JavaFX in de scene
Elke databasetoepassing vereist een interface zodat de gebruiker kan communiceren met de database-informatie. Beter, als het een GUI-interface is waar we ons niet hoeven te verlagen tot een laagdrempelige, intimiderende commando-interface, maar met een klik op een knop krijgen wat we willen. In dit opzicht kan JavaFX met JDBC een geweldige combinatie zijn, omdat het een behoorlijk aantal visueel opwindende GUI-componenten heeft die kunnen worden gebruikt om databaserecords op een meer betekenisvolle manier weer te geven. Records kunnen bijvoorbeeld in tabelvorm worden weergegeven met de TableView controle. Of we kunnen een formulier maken om nieuwe records toe te voegen aan de databasetabel. De gegevens die door de gebruiker zijn ingevoerd, kunnen worden geverifieerd via Java-code voordat ze naar de database worden verzonden. De back-end database-engine krijgt een onderbreking van het valideren van gegevens en een vastgelopen verwerking als gevolg van een invoerfout. Bovendien kan de eindgebruiker een leek zijn die weinig of geen idee heeft van de beperkingen van invoergegevens. Dit wordt idealiter gedaan wanneer een invoerformulier wordt gemaakt met TextField , Label , ComboBox , en ListView bedieningselementen in JavaFX. De gebeurtenissen gegenereerd door Button en andere bedieningselementen worden op zo'n manier afgehandeld dat de gebruiker zich op zijn gemak voelt tijdens interactie met de GUI-interface.
Naar een voorbeeldscenario
In het volgende geïllustreerde voorbeeld implementeren we een ListView zoekbewerking door invoertekst in een TextField . Het geselecteerde item in de ListView wordt dienovereenkomstig opgehaald uit de back-enddatabase en weergegeven in de TableView controle. Het is dus in de eerste plaats een app voor ophalen en weergeven. Andere databasebewerkingen, zoals het invoegen, verwijderen en bijwerken van records, worden niet geïmplementeerd vanwege beperkingen in de grootte. Het zou een mooie oefening zijn om ze zelf te implementeren.
Dus, voordat we beginnen, moeten we een databasetabel en een Java-project maken. We gebruiken MySQL als de back-enddatabase; u kunt een andere kiezen, maar zorg ervoor dat u de juiste stuurprogramma's opneemt in uw pom.xml het dossier. Hier is een deel van de SQL-code om de tabel te maken, enkele dummy-gegevens in te voegen en enkele andere bewerkingen.
CREATE DATABASE addressbook; USE DATABASE addressbook; DROP TABLE IF EXISTS contact; CREATE TABLE contact( id INT UNSIGNED NOT NULL AUTO_INCREMENT, name VARCHAR(100) NOT NULL, nick_name VARCHAR(20), address VARCHAR(128), home_phone VARCHAR(10), work_phone VARCHAR(10), cell_phone VARCHAR(10), email VARCHAR(100), birthday date, web_site VARCHAR(100), profession VARCHAR(100), PRIMARY KEY (id) ); INSERT INTO contact (name, nick_name, address, home_phone, work_phone, cell_phone, email, birthday, web_site,profession) VALUES ('Bruce Wayne', 'batman', 'XYZ Batcave', '9876543210', '6278287326', '9182872363', '[email protected]', '1976/02/03', 'batblog.com', 'Super Hero'); ... INSERT INTO contact (...) VALUES (...); Maven Project: pom.xml <project xmlns_xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.mano.jdbc.examples</groupId> <artifactId>JavaFXJDBCApp</artifactId> <version>1.0-SNAPSHOT</version> <packaging>jar</packaging> <name>JavaFXJDBCApp</name> <url>http://maven.apache.org</url> <properties> <project.build.sourceEncoding> UTF-8 </project.build.sourceEncoding> </properties> <build> <plugins> <plugin> <groupId> org.apache.maven.plugins </groupId> <artifactId> maven-compiler-plugin </artifactId> <version>2.5.1</version> <configuration> <source>1.8</source> <target>1.8</target> </configuration> </plugin> </plugins> </build> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> <!-- https://mvnrepository.com/artifact/mysql/ mysql-connector-java --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.6</version> </dependency> </dependencies> </project>
Laten we nu een domeinobject maken dat we zullen gebruiken in zowel ListView en TableView omdat ze allebei verwant zijn, zoals in ons geval vermeld. De TableView zal een waarneembare lijst van mensen bevatten (ContactPerson ) op basis van de naam van de geselecteerde persoon uit de ListView controle. We hebben ook een TextField om snel naar items te zoeken (ContactPerson naam) in de ListView . Bij selectie van een specifiek item uit de ListView , wordt een SQL-query gestart en worden relevante records opgehaald om de TableView te vullen dienovereenkomstig regelen.
Domeinobject:Contactpersoon
De Contactpersoon klasse is niets anders dan de POJO-representatie van de contact tabel attributen. Het bevat de constructor en eenvoudige getter-setter methoden.
package org.mano.jdbc.examples; import java.util.Date; public class ContactPerson { private int id; private String name; private String nickName; private String address; private String homePhone; private String workPhone; private String cellPhone; private String email; private Date birthDate; private String webSite; private String profession; public ContactPerson() { } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getNickName() { return nickName; } public void setNickName(String nickName) { this.nickName = nickName; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } public String getHomePhone() { return homePhone; }< public void setHomePhone(String homePhone) { this.homePhone = homePhone; } public String getWorkPhone() { return workPhone; } public void setWorkPhone(String workPhone) { this.workPhone = workPhone; } public String getCellPhone() { return cellPhone; } public void setCellPhone(String cellPhone) { this.cellPhone = cellPhone; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public Date getBirthDate() { return birthDate; } public void setBirthDate(Date birthDate) { this.birthDate = birthDate; } public String getWebSite() { return webSite; } public void setWebSite(String webSite) { this.webSite = webSite; } public String getProfession() { return profession; } public void setProfession(String profession) { this.profession = profession; } }
Gegevenstoegangsobject:ContactDAO
De ContactDAO is een gegevenstoegangsobjectklasse die voornamelijk databasetoegangsbewerkingen omvat. Het implementeert de DAO koppel. Deze interface is misschien niet belangrijk in ons voorbeeld, maar kan goed worden gebruikt als de toepassing wordt uitgebreid met meer gegevenstoegangsobjectklassen. Hier, de DAO interface bevat een verbindingsreeks, stuurprogramma en gebruikersnaam en wachtwoord om toegang te krijgen tot de MySQL-database.
DAO.java
package org.mano.jdbc.examples; public interface DAO { public static final String DB_URL = "jdbc:mysql://localhost:3306/"+ "addressbook?zeroDateTimeBehavior=convertToNull"; public static final String DRIVER = "com.mysql.jdbc.Driver"; public static final String USER = "root"; public static final String PASS = "secret"; }
ContactDAO.java
package org.mano.jdbc.examples; import java.sql.*; import java.util.ArrayList; import java.util.List; public class ContactDAO implements DAO { private ontactPerson createContactPerson(ResultSet rs) { ContactPerson p = new ContactPerson(); try { p.setId(rs.getInt("id")); p.setName(rs.getString("name")); p.setNickName(rs.getString("nick_name")); p.setAddress(rs.getString("address")); p.setHomePhone(rs.getString("home_phone")); p.setWorkPhone(rs.getString("work_phone")); p.setCellPhone(rs.getString("cell_phone")); p.setEmail(rs.getString("email")); p.setBirthDate(rs.getDate("birthday")); p.setWebSite(rs.getString("web_site")); p.setProfession(rs.getString("profession")); } catch (SQLException ex) { } return p; } public List<ContactPerson> getContacts() { String sql = "Select * from contact order by name"; List<ContactPerson> list = new ArrayList<>(); try { Class.forName(DRIVER); Connection con = DriverManager.getConnection (DB_URL, USER, PASS); Statement stmt = con.createStatement(); ResultSet rs = stmt.executeQuery(sql); while (rs.next()) { ContactPerson p = createContactPerson(rs); list.add(p); } rs.close(); con.close(); } catch (ClassNotFoundException | SQLException ex) { } return list; } public List<ContactPerson> getContactsForName(String name) { String sql = "Select * from contact where name like '%" + name + "%'"; List<ContactPerson> list = new ArrayList<>(); try { Class.forName(DRIVER); Connection con = DriverManager.getConnection (DB_URL, USER, PASS); Statement stmt = con.createStatement(); ResultSet rs = stmt.executeQuery(sql); while (rs.next()) { ContactPerson p = createContactPerson(rs); list.add(p); } rs.close(); con.close(); } catch (ClassNotFoundException | SQLException ex) { } return list; } }
JavaFX GUI-interface:ContactBrowser
In de JavaFX-toepassing genaamd ContactBrowser , hebben we alle bedieningselementen programmatisch ingesteld. Dit kan ook worden ingesteld met behulp van FXML of hulpprogramma's voor builders, zoals Scene Builder. Maar, naar de mening van de schrijver, kunnen ze worden gebruikt zodra iemand voldoende ervaring heeft opgedaan met wat er achter de schermen gebeurt in JavaFX. De GUI is in de eerste plaats een samenspel van drie bedieningselementen, zoals een TextField (zoekveld ), een ListView (listView ), en TableView (contactTableView ). De code spreekt voor zich, met opmerkingen op de juiste plaatsen. Lambda-expressie wordt waar van toepassing gebruikt om de code kort te houden. Raadpleeg waar nodig de JavaFX API-documentatie.
package org.mano.jdbc.examples; import javafx.application.Application; import javafx.beans.value.*; import javafx.collections.*; import javafx.collections.transformation.*; import javafx.geometry.Insets; import javafx.scene.Scene; import javafx.scene.control.*; import javafx.scene.control.cell.PropertyValueFactory; import javafx.scene.layout.*; import javafx.scene.paint.Color; import javafx.stage.Stage; public class ContactBrowser extends Application { // List of contact table properties private String[] propertyName = {"id", "name", "nickName", "address", "homePhone", "workPhone", "cellPhone", "email", "birthDate", "webSite", "profession"}; private String[] propertyLabel = {"ID", "Name", "Nick Name", "Address", "Home Phone", "Work Phone", "Cell Phone", "Email", "Birth Date", "Website", "Profession"}; private ContactDAO contact = new ContactDAO(); private final GridPane gridPane = new GridPane(); private final Label lblName = new Label("Search by Name"); private final TextField searchField = new TextField(); private ObservableList<ContactPerson> observableNames; private FilteredList<ContactPerson> filteredData; private SortedList<ContactPerson> sortedData; private final ListView<ContactPerson> listView; TableView<ContactPerson> contactTableView = new TableView<>(); public ContactBrowser2() { lblName.setTextFill(Color.web("#0076a3")); observableNames = FXCollections.observableArrayList (contact.getContacts()); filteredData = new FilteredList<> (observableNames, p -> true); sortedData = new SortedList<>(filteredData); listView = new ListView<>(sortedData); } @Override public void start(Stage primaryStage) { primaryStage.setTitle("Address Book"); primaryStage.setMaximized(true); BorderPane borderPane = new BorderPane(); Scene scene = new Scene(borderPane,650,400,true); gridPane.setPadding(new Insets(10)); gridPane.setHgap(5); gridPane.setVgap(5); gridPane.add(lblName, 0, 0); gridPane.add(searchField, 0, 1); // Search TextField event handling searchField.textProperty() .addListener((observable, oldValue, newValue) -> filteredData.setPredicate(str -> { if (newValue == null || newValue.isEmpty()) return true; if (str.getName().toLowerCase().contains (newValue.toLowerCase())) return true; return false; })); listView.getSelectionModel().setSelectionMode (SelectionMode.SINGLE); listView.setPrefHeight(Integer.MAX_VALUE); // Sets a new cell factory to use in the ListView. // This throws away all old list cells and new ListCells // created with the new cell factory. listView.setCellFactory(listView-> { Tooltip tooltip = new Tooltip(); ListCell<ContactPerson> cell = new ListCell<ContactPerson>() { @Override public voidupdateItem(ContactPerson contactPerson, Boolean empty) { super.updateItem(contactPerson, empty); if (contactPerson != null) { setText(contactPerson.getName()); tooltip.setText(contactPerson.getNickName()); setTooltip(tooltip); } else setText(null); } }; return cell; }); gridPane.add(listView, 0, 2); // Create and initializing TableView ObservableList<ContactPerson> contactPeopleList = FXCollections.observableArrayList(); contactTableView.setItems(contactPeopleList); contactTableView.setColumnResizePolicy( TableView.CONSTRAINED_RESIZE_POLICY); for (int i = 0; i < propertyLabel.length; i++) { TableColumn<ContactPerson, Object> col = new TableColumn<>(propertyLabel[i]); col.setCellValueFactory(new PropertyValueFactory<>(propertyName[i])); contactTableView.getColumns().add(col); } borderPane.setCenter(contactTableView) borderPane.setLeft(gridPane); // TableView will populate from the contactPeopleList // contactPeopleList will have value according to the // item selected in the ListView listView.getSelectionModel() .selectedItemProperty() .addListener(new ChangeListener<ContactPerson>() { @Override public void changed( ObservableValue<? extends ContactPerson> observable, ContactPerson oldValue, ContactPerson newValue) { if (observable != null && observable.getValue() != null) { contactPeopleList.clear(); contactPeopleList.addAll( contact.getContactsForName (newValue.getName())); } } }); primaryStage.setScene(scene); primaryStage.show(); } public static void main(String[] args) { launch (args); } }
Uitvoer
Figuur 1: Code-uitvoer
Conclusie
Een JDBC-toepassing met JavaFX betekent in wezen dat het JavaFX GUI-framework werd gebruikt als de front-end ontwikkelingsengine en JDBC werd gebruikt voor de back-end database-interactie. Ze kunnen van verschillende typen zijn met N aantal functionaliteiten dat daarin is gedefinieerd. De basis is de CRUD-applicatie. We hebben een deel van de zoek- en weergavebewerking geïmplementeerd. Hier is wat je kunt doen om het uit te breiden:implementeer Creëren , Verwijderen , en Bijwerken activiteiten; u kunt ook namen met afbeeldingen toevoegen in de ListView . Veel plezier met coderen 😉