
- •3.1 Лабораторна робота № 1. Створення JavaFx додатку. Авторизація користувачів.
- •Java Persistence api
- •3.1.1. Необхідне програмне забезпечення
- •3.1.2. Налаштування проекту JavaFx-додатку
- •3.1.3. Підключення бази даних
- •3.1.4. Створення моделей та їх маппінг за допомогою jpa
- •3.1.5. Створення допоміжного класу для роботи з моделями
- •3.1.6. Впровадження логіки авторизації користувача
- •3.2 Лабораторна робота № 2. Робота з медіа. Реалізація crud за допомогою jpa та TableView.
- •Медіа-програвач
- •Табличне представлення данних
- •3.2.1 Вдосконалення коду додатка
- •3.2.2 Створення інтерфейсу додатка
- •3.2.3 Створення медіа програвача
- •3.2.4 Впровадження можливості адміністрування користувачів
- •3.3 Лабораторна робота № 3. Використання вбудованого браузеру, будування графіків та створення анімації.
- •Акордеон
- •Анімація у JavaFx
- •Графіки
- •3.3.1 Інтегрування веб-браузеру до проекту
- •3.3.2 Створення графіків
- •3.3.3 Використання елементу акордіон для створення альтернативного варіанту панелі інструментів
- •3.3.4 Створення анімації кнопок
- •3.4 Лабораторна робота № 4. Технологія drag-and-drop у JavaFx-додатках. Використання стилів.
- •Drag-and-Drop
- •Стилювання додатку за допомогою css
- •3.4.1 Drag-and-Drop
- •3.4.2 Додавання можливості стилювання додатку
- •3.4.3 Створення стилів
- •3.5 Лабораторна робота № 5. Робота з JavaFx Scene Builder. 3-d трансформація у JavaFx. Розгортання додатку.
- •JavaFx Scene Builder
- •Трансформація у JavaFx
- •Розгортання JavaFx додатків
- •3.5.1 JavaFx Scene Builder
- •3.5.2 Створення логіки додатка
- •3.5.3 Розгортання додатка
3.1.5. Створення допоміжного класу для роботи з моделями
Для всіх моделей, які будуть створюватися, необхідно забезпечити мінімальну спільну кількість функціоналу. Наприклад CRUD (create, remove, update, delete). Щоб не дублювати код для кожної моделі, необхідно створити один клас, який зможе виконувати CRUD-дії зі всіма моделями.
Для цього необхідно створити новий пакет managers (javafxapp.managers), та в ньому клас GenericDAO з наступним кодом:
public class GenericDAO<T extends Serializable> {
private EntityManagerFactory emf = JavafxApp.emf;
private EntityManager em;
private Class<T> clazz;
public EntityTransaction entityTransaction;
public GenericDAO(Class<T> clazz) {
this.clazz = clazz;
em = emf.createEntityManager();
entityTransaction = em.getTransaction();
entityTransaction.begin();
}
@Override
protected void finalize() throws Throwable{
entityTransaction.commit();
em.close();
super.finalize();
}
public void create(T t) {
em.persist(t);
}
public T getByField(String fieldname, String value){
try{
Query q = em.createQuery("SELECT u FROM "+ clazz.getSimpleName() +" u WHERE u."+ fieldname +" = ?1");
return (T)q.setParameter(1, value).getSingleResult();
}catch(Exception ex){
return null;
}
}
public T read(long id) {
return em.find(clazz, id);
}
public void update(T t) {
em.merge(t);
entityTransaction.commit();
entityTransaction.begin();
}
public void delete(T t) {
t = em.merge(t);
em.remove(t);
}
public List getAll() {
return em.createQuery("SELECT u FROM "+ clazz.getSimpleName() +" u").getResultList();
}
public void updateList(){
entityTransaction.commit();
entityTransaction.begin();
}
}
Потрібна гнучкість забезпечується за допомогою generic types. При створенні менеджеру необхідно буде передати конкретну модель, з якою він буде працювати. І під час виконання програми JVM підставить цей клас на місце T.
3.1.6. Впровадження логіки авторизації користувача
Все пов’язане з авторизацією користувачів буде знаходитися в окремому пакеті. Це забезпечує легке перенесення логіки та структурує додаток. Отже створіть пакет login (javafxapp.login). До нього перенесіть Sample.fxml та Sample.java та змініть імена на Login.fxml та Login.java (або видаліть їх з проекту і створіть в пакеті javafxapp.login нові).
Вміст файлу Sample.fxml повинен бути таким:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.*?>
<BorderPane fx:controller ="javafxapp.login.Login" xmlns:fx="http://javafx.com/fxml">
<top>
<StackPane>
<Label text="Authorization" style="-fx-font: NORMAL 20 Tahoma;"/>
</StackPane>
</top>
<center>
<GridPane alignment="top_center" hgap="8" vgap="8"
style="-fx-padding: 40 0 0 0">
<children>
<Label text="Sign in:"
style="-fx-font: NORMAL 14 Tahoma;"
GridPane.columnIndex="0" GridPane.rowIndex="0"/>
<Label text="Username:"
GridPane.columnIndex="0" GridPane.rowIndex="1"
labelFor="$usernameField"/>
<TextField fx:id="usernameField" prefColumnCount="15"
GridPane.columnIndex="1" GridPane.rowIndex="1"/>
<Label text="Password:"
GridPane.columnIndex="0" GridPane.rowIndex="2"
labelFor="$passwordField"/>
<PasswordField fx:id="passwordField" prefColumnCount="15"
GridPane.columnIndex="1" GridPane.rowIndex="2"
onAction="#processLogin"/>
<Button fx:id="submitButton" text="Submit"
GridPane.columnIndex="1" GridPane.rowIndex="3"
onAction="#processLogin"/>
<Label fx:id="errorText"
GridPane.columnIndex="1" GridPane.rowIndex="4"
style="-fx-text-fill: #ff0000;"/>
</children>
</GridPane>
</center>
</BorderPane>
Отже fx:controller ="javafxapp.login.Login" вказує на клас, який буде контролером для цього fxml файлу. Hgap та vgap вказують кількість пропусків між елементами GridPane. Властивість prefColumnCount="15" у TextField та PasswordField вказує довжину цих елементів. Властивість onAction="#processLogin" вказує на метод контролера, який буде викликатися при певній події. А за допомогою fx:id (наприклад fx:id="errorText") можна звертатися до елементу з класу контролера.
Вміст файлу Login.java повинен бути таким:
package javafxapp.login;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.Label;
import javafx.scene.control.PasswordField;
import javafx.scene.control.TextField;
import javafxapp.JavafxApp;
public class Login {
@FXML private Label errorText;
@FXML private TextField usernameField;
@FXML private PasswordField passwordField;
@FXML protected void processLogin(ActionEvent event) {
errorText.setText("Hello!");
}
}
Отже в контролері поки що буде знаходитися заглушка. Наступні зміни потрібно зробити у класі JavafxApp:
package javafxapp;
import java.util.logging.FileHandler;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
import javafx.stage.WindowEvent;
import javafxapp.models.UserFx;
import javafxapp.login.Auth;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
public class JavafxApp extends Application {
private static JavafxApp instance;
public static EntityManagerFactory emf = Persistence.createEntityManagerFactory("JavafxAppPU");
public Logger logger;
public UserFx loggedUser = null;
public JavafxApp(){
try{
FileHandler hand = new FileHandler("log_info.log");
logger = Logger.getLogger("log_file");
logger.addHandler(hand);
}catch(Exception ex){
ex.printStackTrace();
}
instance = this;
}
public static JavafxApp getInstance() {
return instance;
}
public static void main(String[] args) {
Application.launch(JavafxApp.class, args);
}
@Override
public void start(Stage stage) throws Exception {
stage.setTitle("Login");
Parent root = FXMLLoader.load(this.getClass().getResource("login/Login.fxml"));
stage.setScene(new Scene(root, 500, 200));
stage.show();
}
public boolean userLogging(String username, String password){
//TODO
}
public void userLogout(){
this.loggedUser = null;
}
}
В класі поле public static EntityManagerFactory emf зберігає фабрику, через яку в GenericDAO отримуємо EntityManager для роботи з базою даних. public UserFx loggedUser — буде зберігати активного користувача (той, що зайшов в систему). В конструкторі класу ініціалізується logger для запису помилок та виняткових ситуацій у файл. В цьому файлі метод userLogging поки що теж потрібно зробити заглушкою. На цьому етапі можна запустити додаток та подивитись на те, що вже зроблено (рис. 3.5).
Тепер потрібно в пакеті javafxapp.login створити файл Auth.java, який буде зберігати логіку аутентефікації користувача.
import javafxapp.managers.GenericDAO;
import javafxapp.models.UserFx;
public class Auth {
public static UserFx validate(String username, String password){
GenericDAO<UserFx> userManager = new GenericDAO(UserFx.class);
UserFx ufx = userManager.getByField("username", username);
if (ufx != null && ufx.getPassword().equals(password))
return ufx;
else
return null;
}
}
Рис. 3.5. Вигляд додатку після натиснутої кнопки Submit
За допомогою GenericDAO виконується пошук по базі даних. Якщо логін і пароль співпадають — повертається юзер, якщо ні — null.
Тепер потрібно позбавитися заглушок. В класі JavafxApp потрібно написати:
public boolean userLogging(String username, String password){
this.loggedUser = Auth.validate(username, password);
return loggedUser != null;
}
В класі Login потрібно написати:
@FXML protected void processLogin(ActionEvent event) {
if(!JavafxApp.getInstance().userLogging(usernameField.getText(), passwordField.getText()))
errorText.setText("Invalid username or password.");
else{
errorText.setText("It's ok!");
}
}
Тепер потрібно переконатися, що все працює вірно. Запускаємо додаток та вводимо валідні дані, які є у базі даних, а потім дані, яких немає. Це зображено на рис. 3.6 та 3.7 відповідно.
Рис. 3.6. Вигляд додатка з введеними валідними даними
Рис. 3.7. Вигляд додатка з введеними не валідними даними
Практичне завдання
Зробити на формі авторизації перевірку на пусті значення полів та вивести відповідне повідомлення.
Добавити в модель UserFx поле banned і якщо banned = true, то не пускати користувача в систему і написати відповідне повідомлення. (Якщо змінюється модель, то необхідно видалити змінені таблиці з бази даних, щоб JPA створив нові).
Контрольні питання
Що таке FXML?
Для чого використовують JavaFx?
Що таке JPA? Чому розробники використовують JPA?
Для чого використовують IDE?