From 033188dc558ba133d67cc64afb39b0db6df27ef7 Mon Sep 17 00:00:00 2001 From: Alexander Kim Date: Sun, 6 Apr 2025 18:40:07 +0300 Subject: [PATCH 1/6] feat: implement spring boot + DI; add .env logic; refactor: delete javadoc; fix: delete excess migration --- .gitignore | 4 + Application/pom.xml | 6 + .../Application/Managers/UserManager.java | 58 +-------- .../Models/Entities/BankAccount.java | 18 +-- .../Models/Entities/Operation.java | 19 +-- .../Application/Models/Entities/User.java | 50 ++++---- .../Application/Models/Enums/HairColor.java | 3 - .../Models/Enums/OperationType.java | 3 - .../java/Application/Models/Enums/Sex.java | 3 - .../ResultTypes/BankAccountResult.java | 4 - .../ResultTypes/OperationResult.java | 4 - .../Application/ResultTypes/UserResult.java | 4 - DataAccess/pom.xml | 35 +----- .../java/DAO/HibernateBankAccountDAO.java | 115 ------------------ .../main/java/DAO/HibernateOperationDAO.java | 92 -------------- .../src/main/java/DAO/HibernateUserDAO.java | 103 ---------------- .../java/DAO/Interfaces/IBankAccountDAO.java | 12 -- .../java/DAO/Interfaces/IOperationDAO.java | 13 -- .../main/java/DAO/Interfaces/IUserDAO.java | 12 -- .../DataAccess/Configs/DataAccessConfig.java | 9 ++ .../java/DataAccess/Configs/JPAConfig.java | 11 ++ .../Repositories/IBankAccountRepository.java | 8 ++ .../Repositories/IOperationRepository.java | 12 ++ .../Repositories/IUserRepository.java | 8 ++ .../Services/BankAccountService.java | 84 +++++++++++++ .../Interfaces/IBankAccountService.java | 3 +- .../Interfaces/IOperationService.java | 2 +- .../Services/Interfaces/IUserService.java | 6 +- .../DataAccess/Services/OperationService.java | 39 ++++++ .../java/DataAccess/Services/UserService.java | 39 ++++++ .../java/Services/BankAccountService.java | 42 ------- .../main/java/Services/OperationService.java | 35 ------ .../src/main/java/Services/UserService.java | 28 ----- .../Utils/HibernateSessionFactoryUtil.java | 35 ------ DataAccess/src/main/resources/application.yml | 17 +++ .../src/main/resources/hibernate.cfg.xml | 27 ---- Presentation/pom.xml | 6 + .../java/Presentation/Configs/AppConfig.java | 38 ++++++ .../Presentation/Configs/AppInitializer.java | 27 ++++ .../Configs/DotenvInitializer.java | 20 +++ .../main/java/Presentation/Console/Main.java | 14 +-- .../main/java/Presentation/Console/Menu.java | 90 ++------------ .../Controllers/FlywayController.java | 23 ++++ .../Controllers/UserController.java | 107 ++++++++-------- .../Interfaces/IFlywayController.java | 6 + .../java/Presentation/Interfaces/IMenu.java | 9 -- .../Interfaces/IUserController.java | 95 --------------- .../src/main/resources/application.yml | 8 +- .../main/resources/db/migration/V1__init.sql | 60 +++++---- .../main/resources/db/migration/V2__drop.sql | 4 + .../db/migration/V2__drop_tables.sql | 4 - .../main/resources/db/migration/V3__init.sql | 56 --------- Presentation/src/test/java/BankTests.java | 8 +- pom.xml | 77 +++++++++++- 54 files changed, 597 insertions(+), 1018 deletions(-) delete mode 100644 DataAccess/src/main/java/DAO/HibernateBankAccountDAO.java delete mode 100644 DataAccess/src/main/java/DAO/HibernateOperationDAO.java delete mode 100644 DataAccess/src/main/java/DAO/HibernateUserDAO.java delete mode 100644 DataAccess/src/main/java/DAO/Interfaces/IBankAccountDAO.java delete mode 100644 DataAccess/src/main/java/DAO/Interfaces/IOperationDAO.java delete mode 100644 DataAccess/src/main/java/DAO/Interfaces/IUserDAO.java create mode 100644 DataAccess/src/main/java/DataAccess/Configs/DataAccessConfig.java create mode 100644 DataAccess/src/main/java/DataAccess/Configs/JPAConfig.java create mode 100644 DataAccess/src/main/java/DataAccess/Repositories/IBankAccountRepository.java create mode 100644 DataAccess/src/main/java/DataAccess/Repositories/IOperationRepository.java create mode 100644 DataAccess/src/main/java/DataAccess/Repositories/IUserRepository.java create mode 100644 DataAccess/src/main/java/DataAccess/Services/BankAccountService.java rename DataAccess/src/main/java/{ => DataAccess}/Services/Interfaces/IBankAccountService.java (81%) rename DataAccess/src/main/java/{ => DataAccess}/Services/Interfaces/IOperationService.java (88%) rename DataAccess/src/main/java/{ => DataAccess}/Services/Interfaces/IUserService.java (53%) create mode 100644 DataAccess/src/main/java/DataAccess/Services/OperationService.java create mode 100644 DataAccess/src/main/java/DataAccess/Services/UserService.java delete mode 100644 DataAccess/src/main/java/Services/BankAccountService.java delete mode 100644 DataAccess/src/main/java/Services/OperationService.java delete mode 100644 DataAccess/src/main/java/Services/UserService.java delete mode 100644 DataAccess/src/main/java/Utils/HibernateSessionFactoryUtil.java create mode 100644 DataAccess/src/main/resources/application.yml delete mode 100644 DataAccess/src/main/resources/hibernate.cfg.xml create mode 100644 Presentation/src/main/java/Presentation/Configs/AppConfig.java create mode 100644 Presentation/src/main/java/Presentation/Configs/AppInitializer.java create mode 100644 Presentation/src/main/java/Presentation/Configs/DotenvInitializer.java create mode 100644 Presentation/src/main/java/Presentation/Controllers/FlywayController.java create mode 100644 Presentation/src/main/java/Presentation/Interfaces/IFlywayController.java create mode 100644 Presentation/src/main/resources/db/migration/V2__drop.sql delete mode 100644 Presentation/src/main/resources/db/migration/V2__drop_tables.sql delete mode 100644 Presentation/src/main/resources/db/migration/V3__init.sql diff --git a/.gitignore b/.gitignore index 343d1cc..026a978 100644 --- a/.gitignore +++ b/.gitignore @@ -27,9 +27,13 @@ bin/ /.nb-gradle/ DataAccess.iml Presentation.iml +Application.iml ### VS Code ### .vscode/ ### Mac OS ### .DS_Store + +# Environment +.env diff --git a/Application/pom.xml b/Application/pom.xml index bf8075d..0563460 100644 --- a/Application/pom.xml +++ b/Application/pom.xml @@ -8,6 +8,12 @@ Application 1.0-SNAPSHOT + + com.example + lim0sha + 1.0-SNAPSHOT + + 17 17 diff --git a/Application/src/main/java/Application/Managers/UserManager.java b/Application/src/main/java/Application/Managers/UserManager.java index ec4f438..af4305c 100644 --- a/Application/src/main/java/Application/Managers/UserManager.java +++ b/Application/src/main/java/Application/Managers/UserManager.java @@ -4,33 +4,20 @@ import Application.Models.Entities.BankAccount; import Application.Models.Entities.Operation; import Application.Models.Entities.User; +import org.springframework.stereotype.Component; -import java.util.ArrayList; import java.util.List; -/** - * Класс-менеджер для управления данными пользователей, их банковскими счетами и друзьями. - * Предоставляет методы для получения информации о пользователе, добавления/удаления друзей, - * управления банковскими счетами и вывода истории операций. - */ +@Component public class UserManager { - /** - * Выводит информацию о пользователе, включая его данные и банковские счета. - * - * @param user объект пользователя, информацию о котором нужно вывести. - */ public void GetUserInfo(User user) { if (user == null) { - System.out.println("Пользователь с ID " + user.getId() + " не найден."); + System.out.println("Пользователь с ID: [null] не найден."); return; } -// // Инициализация ленивых коллекций -// Hibernate.initialize(user.getBankAccounts()); -// Hibernate.initialize(user.getFriends()); - System.out.println("ID: " + user.getId()); System.out.println("Логин: " + user.getLogin()); System.out.println("Имя: " + user.getName()); @@ -38,7 +25,6 @@ public void GetUserInfo(User user) { System.out.println("Пол: " + user.getSex()); System.out.println("Цвет волос: " + user.getHairType()); - // Вывод банковских счетов System.out.println("\nБанковские счета:"); if (user.getBankAccounts().isEmpty()) { System.out.println("Нет привязанных счетов."); @@ -48,7 +34,6 @@ public void GetUserInfo(User user) { } } - // Вывод друзей System.out.println("\nДрузья:"); if (user.getFriends().isEmpty()) { System.out.println("Нет друзей."); @@ -59,67 +44,30 @@ public void GetUserInfo(User user) { } } - /** - * Добавляет друга пользователю и другому пользователю. - * - * @param user текущий пользователь, добавляющий друга. - * @param other пользователь, который будет добавлен в друзья. - */ public void AddFriend(User user, User other) { user.getFriends().add(other); other.getFriends().add(user); } - /** - * Удаляет друга у пользователя и другого пользователя. - * - * @param user текущий пользователь, у которого будет удален друг. - * @param other пользователь, который будет удален из друзей. - */ public void RemoveFriend(User user, User other) { user.getFriends().remove(other); other.getFriends().remove(user); } - /** - * Добавляет банковский счет пользователю. - * - * @param user пользователь, которому добавляется банковский счет. - * @param bankAccount банковский счет для добавления. - */ public void AddBankAccount(User user, BankAccount bankAccount) { user.getBankAccounts().add(bankAccount); } - /** - * Удаляет банковский счет у пользователя. - * - * @param user пользователь, у которого будет удален банковский счет. - * @param bankAccount банковский счет для удаления. - */ public void RemoveBankAccount(User user, BankAccount bankAccount) { user.getBankAccounts().remove(bankAccount.getId()); } - /** - * Проверяет баланс банковского счета пользователя. - * - * @param user пользователь, чей баланс проверяется. - * @param bankAccount банковский счет для проверки баланса. - */ public void CheckBalance(User user, BankAccount bankAccount) { System.out.println("User: " + user.getId()); System.out.println("BankAccount: " + bankAccount.getId()); System.out.println("Balance: " + bankAccount.getBalance()); } - /** - * Выводит историю операций по банковскому счету. - * - * @param account банковский счет, для которого нужно вывести историю. - * @param operations список операций, связанных с этим счетом. - * @return результат операции (успех или ошибка). - */ public OperationResult PrintHistory(BankAccount account, List operations) { if (operations == null) { return new OperationResult.OperationError("Operations can not be null."); diff --git a/Application/src/main/java/Application/Models/Entities/BankAccount.java b/Application/src/main/java/Application/Models/Entities/BankAccount.java index 7fd15b4..84a2a27 100644 --- a/Application/src/main/java/Application/Models/Entities/BankAccount.java +++ b/Application/src/main/java/Application/Models/Entities/BankAccount.java @@ -3,36 +3,28 @@ import jakarta.persistence.*; import lombok.*; -/** - * Класс, представляющий банковский счет пользователя. - * Хранит информацию о счете, балансе и привязанном пользователе. - */ @Entity -@Table(name = "BankAccounts") @Getter @NoArgsConstructor +@Table(name = "bankaccounts") public class BankAccount { @Id @Setter @GeneratedValue(strategy = GenerationType.IDENTITY) private Integer id; + @Column(name = "balance", nullable = false) @Setter private Double balance; - @Column(name = "userLogin") + @Column(name = "userlogin", nullable = false) private String userLogin; @ManyToOne - @JoinColumn(name = "userId", nullable = false) + @Setter + @JoinColumn(name = "user_id", nullable = false) private User user; - /** - * Конструктор для создания нового банковского счета. - * Генерирует уникальный идентификатор счета и связывает его с пользователем. - * - * @param user пользователь, к которому будет привязан новый счет. - */ public BankAccount(User user) { this.balance = 0.0; this.userLogin = user.getLogin(); diff --git a/Application/src/main/java/Application/Models/Entities/Operation.java b/Application/src/main/java/Application/Models/Entities/Operation.java index 9a7664e..50aeba4 100644 --- a/Application/src/main/java/Application/Models/Entities/Operation.java +++ b/Application/src/main/java/Application/Models/Entities/Operation.java @@ -4,37 +4,26 @@ import lombok.*; import Application.Models.Enums.OperationType; -/** - * Класс, представляющий операцию с банковским счетом. - * Хранит информацию о типе операции, сумме и счете, на котором она была проведена. - */ @Getter @Setter @NoArgsConstructor @Entity -@Table(name = "Operations") +@Table(name = "operations") public class Operation { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Integer id; @ManyToOne - @JoinColumn(name = "accountId", nullable = false) + @JoinColumn(name = "account_id", nullable = false) private BankAccount bankAccount; - @Column(nullable = false) + @Column(name = "amount", nullable = false) private Double amount; - @Column(nullable = false) + @Column(name = "type", nullable = false) private String type; - /** - * Конструктор для создания новой операции. - * - * @param bankAccount банковский счет, на котором выполнена операция. - * @param type тип операции (например, депозит или снятие). - * @param amount сумма, участвующая в операции. - */ public Operation(BankAccount bankAccount, OperationType type, Double amount) { this.bankAccount = bankAccount; this.type = type.toString(); diff --git a/Application/src/main/java/Application/Models/Entities/User.java b/Application/src/main/java/Application/Models/Entities/User.java index dffba50..356ffcb 100644 --- a/Application/src/main/java/Application/Models/Entities/User.java +++ b/Application/src/main/java/Application/Models/Entities/User.java @@ -4,66 +4,58 @@ import lombok.*; import Application.Models.Enums.HairColor; import Application.Models.Enums.Sex; + import java.util.*; -/** - * Класс, представляющий пользователя системы. - * Хранит информацию о пользователе, включая личные данные, список банковских счетов и друзей. - */ @Entity @Getter -@Table(name = "Users") @NoArgsConstructor +@Table(name = "users") public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Integer id; - @Column(nullable = false, unique = true) + @Column(name = "login", nullable = false, unique = true) private String login; - @Column(nullable = false) + @Column(name = "name", nullable = false) private String name; - @Column(nullable = false) + @Column(name = "age", nullable = false) private Integer age; @Enumerated(EnumType.STRING) + @Column(name = "sex", nullable = false) private Sex sex; @Enumerated(EnumType.STRING) - @Column(name = "hairColor") + @Column(name = "haircolor") private HairColor hairType; - @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER) - private List bankAccounts; + @OneToMany(mappedBy = "user", cascade = CascadeType.REMOVE, orphanRemoval = true, fetch = FetchType.EAGER) + private List bankAccounts = new ArrayList<>(); - @ManyToMany(fetch = FetchType.LAZY) + @ManyToMany(fetch = FetchType.EAGER) @JoinTable( - name = "Friends", - joinColumns = @JoinColumn(name = "userId"), - inverseJoinColumns = @JoinColumn(name = "friendId") + name = "friends", + joinColumns = @JoinColumn(name = "user_id"), + inverseJoinColumns = @JoinColumn(name = "friend_id") ) - private List friends; + private List friends = new ArrayList<>(); - /** - * Конструктор для создания нового пользователя. - * Генерирует уникальный идентификатор для пользователя и инициализирует его данные. - * - * @param login логин пользователя. - * @param name имя пользователя. - * @param age возраст пользователя. - * @param sex пол пользователя. - * @param hairType цвет волос пользователя. - */ public User(String login, String name, Integer age, Sex sex, HairColor hairType) { this.login = login; this.name = name; this.age = age; this.sex = sex; this.hairType = hairType; - this.bankAccounts = new ArrayList<>(); - this.friends = new ArrayList<>(); } -} + public void addBankAccount(BankAccount bankAccount) { + if (!bankAccounts.contains(bankAccount)) { + bankAccounts.add(bankAccount); + bankAccount.setUser(this); + } + } +} diff --git a/Application/src/main/java/Application/Models/Enums/HairColor.java b/Application/src/main/java/Application/Models/Enums/HairColor.java index b1768fb..532ce53 100644 --- a/Application/src/main/java/Application/Models/Enums/HairColor.java +++ b/Application/src/main/java/Application/Models/Enums/HairColor.java @@ -1,8 +1,5 @@ package Application.Models.Enums; -/** - * Перечисление возможных цветов волос пользователя. - */ public enum HairColor { Blond, Ash, diff --git a/Application/src/main/java/Application/Models/Enums/OperationType.java b/Application/src/main/java/Application/Models/Enums/OperationType.java index fba1823..99ef7e2 100644 --- a/Application/src/main/java/Application/Models/Enums/OperationType.java +++ b/Application/src/main/java/Application/Models/Enums/OperationType.java @@ -1,8 +1,5 @@ package Application.Models.Enums; -/** - * Перечисление возможных типов операций с банковским счётом. - */ public enum OperationType { Deposit, Withdraw, diff --git a/Application/src/main/java/Application/Models/Enums/Sex.java b/Application/src/main/java/Application/Models/Enums/Sex.java index 3ab3aac..6ec0f67 100644 --- a/Application/src/main/java/Application/Models/Enums/Sex.java +++ b/Application/src/main/java/Application/Models/Enums/Sex.java @@ -1,8 +1,5 @@ package Application.Models.Enums; -/** - * Перечисление возможных вариантов пола пользователя. - */ public enum Sex { Undefined, Male, diff --git a/Application/src/main/java/Application/ResultTypes/BankAccountResult.java b/Application/src/main/java/Application/ResultTypes/BankAccountResult.java index 321b999..f753677 100644 --- a/Application/src/main/java/Application/ResultTypes/BankAccountResult.java +++ b/Application/src/main/java/Application/ResultTypes/BankAccountResult.java @@ -3,10 +3,6 @@ import lombok.AllArgsConstructor; import lombok.Getter; -/** - * Абстрактный класс, представляющий result-type операций с банковским счетом. - * Включает различные типы результатов, такие как успешное выполнение операции или ошибка при создании, обновлении или удалении банковского счета. - */ public abstract sealed class BankAccountResult permits BankAccountResult.Success, BankAccountResult.BankAccountCreationError, BankAccountResult.BankAccountUpdateError, BankAccountResult.BankAccountDeletionError { diff --git a/Application/src/main/java/Application/ResultTypes/OperationResult.java b/Application/src/main/java/Application/ResultTypes/OperationResult.java index c834d01..e42903d 100644 --- a/Application/src/main/java/Application/ResultTypes/OperationResult.java +++ b/Application/src/main/java/Application/ResultTypes/OperationResult.java @@ -4,10 +4,6 @@ import lombok.Getter; import lombok.NoArgsConstructor; -/** - * Абстрактный класс, представляющий result-type операции с деньгами. - * Включает два типа результатов: успешное выполнение операции и ошибка при выполнении. - */ public abstract sealed class OperationResult permits OperationResult.Success, OperationResult.OperationError { @NoArgsConstructor diff --git a/Application/src/main/java/Application/ResultTypes/UserResult.java b/Application/src/main/java/Application/ResultTypes/UserResult.java index 95355bd..e248208 100644 --- a/Application/src/main/java/Application/ResultTypes/UserResult.java +++ b/Application/src/main/java/Application/ResultTypes/UserResult.java @@ -3,10 +3,6 @@ import lombok.AllArgsConstructor; import lombok.Getter; -/** - * Абстрактный класс, представляющий result-type операций с пользователями. - * Включает различные типы результатов, такие как успешное выполнение операции или ошибка при создании, обновлении или удалении пользователя. - */ public abstract sealed class UserResult permits UserResult.Success, UserResult.UserCreationError, UserResult.UserUpdateError, UserResult.UserDeletionError { diff --git a/DataAccess/pom.xml b/DataAccess/pom.xml index bf37e2d..494103d 100644 --- a/DataAccess/pom.xml +++ b/DataAccess/pom.xml @@ -8,6 +8,12 @@ DataAccess 1.0-SNAPSHOT + + com.example + lim0sha + 1.0-SNAPSHOT + + 17 17 @@ -29,35 +35,6 @@ Application 1.0-SNAPSHOT - - org.hibernate - hibernate-core - 6.4.4.Final - - - - org.hibernate - hibernate-ehcache - 4.3.0.Beta3 - - - - org.postgresql - postgresql - 42.7.2 - - - - net.bytebuddy - byte-buddy - 1.14.7 - - - - org.flywaydb - flyway-core - 9.22.0 - diff --git a/DataAccess/src/main/java/DAO/HibernateBankAccountDAO.java b/DataAccess/src/main/java/DAO/HibernateBankAccountDAO.java deleted file mode 100644 index f2c2d21..0000000 --- a/DataAccess/src/main/java/DAO/HibernateBankAccountDAO.java +++ /dev/null @@ -1,115 +0,0 @@ -package DAO; - -import Application.Models.Entities.BankAccount; -import DAO.Interfaces.IBankAccountDAO; -import org.hibernate.Session; -import org.hibernate.SessionFactory; -import org.hibernate.Transaction; - -public class HibernateBankAccountDAO implements IBankAccountDAO { - private final SessionFactory sessionFactory; - - public HibernateBankAccountDAO(SessionFactory sf) { - this.sessionFactory = sf; - } - - public BankAccount GetBankAccountByID(int id) { - try (Session session = sessionFactory.openSession()) { - return session.get(BankAccount.class, id); - } catch (Exception e) { - e.printStackTrace(); - return null; - } - } - - public void SaveBankAccount(BankAccount account) { - try (Session session = sessionFactory.openSession()) { - Transaction tx = null; - try { - tx = session.beginTransaction(); - session.saveOrUpdate(account); - tx.commit(); - } catch (Exception e) { - if (tx != null) { - tx.rollback(); - } - e.printStackTrace(); - } - } - } - - public void DeleteBankAccount(BankAccount bankAccount) { - try (Session session = sessionFactory.openSession()) { - Transaction tx = null; - try { - tx = session.beginTransaction(); - session.delete(bankAccount); - tx.commit(); - } catch (Exception e) { - if (tx != null) { - tx.rollback(); - } - e.printStackTrace(); - } - } - } - - public boolean Deposit ( int accountId, double amount){ - try (Session session = sessionFactory.openSession()) { - Transaction tx = session.beginTransaction(); - BankAccount account = session.get(BankAccount.class, accountId); - if (account != null) { - account.setBalance(account.getBalance() + amount); - session.saveOrUpdate(account); - tx.commit(); - return true; - } - tx.rollback(); - } catch (Exception e) { - e.printStackTrace(); - } - return false; - } - - public boolean Withdraw ( int accountId, double amount){ - try (Session session = sessionFactory.openSession()) { - Transaction tx = session.beginTransaction(); - BankAccount account = session.get(BankAccount.class, accountId); - if (account != null && account.getBalance() >= amount) { - account.setBalance(account.getBalance() - amount); - session.saveOrUpdate(account); - tx.commit(); - return true; - } - tx.rollback(); - return false; - } catch (Exception e) { - e.printStackTrace(); - return false; - } - } - - public boolean Transfer ( int accountFromId, int accountToId, double amount){ - try (Session session = sessionFactory.openSession()) { - Transaction tx = session.beginTransaction(); - - BankAccount accountFrom = session.get(BankAccount.class, accountFromId); - BankAccount accountTo = session.get(BankAccount.class, accountToId); - - if (accountFrom != null && accountTo != null && accountFrom.getBalance() >= amount) { - accountFrom.setBalance(accountFrom.getBalance() - amount); - accountTo.setBalance(accountTo.getBalance() + amount); - session.saveOrUpdate(accountFrom); - session.saveOrUpdate(accountTo); - tx.commit(); - return true; - } - - tx.rollback(); - return false; - } catch (Exception e) { - e.printStackTrace(); - return false; - } - } - } diff --git a/DataAccess/src/main/java/DAO/HibernateOperationDAO.java b/DataAccess/src/main/java/DAO/HibernateOperationDAO.java deleted file mode 100644 index 4cf7954..0000000 --- a/DataAccess/src/main/java/DAO/HibernateOperationDAO.java +++ /dev/null @@ -1,92 +0,0 @@ -package DAO; - -import Application.Models.Entities.Operation; -import DAO.Interfaces.IOperationDAO; -import org.hibernate.Session; -import org.hibernate.SessionFactory; -import org.hibernate.Transaction; - -import java.util.ArrayList; -import java.util.List; - -public class HibernateOperationDAO implements IOperationDAO { - private final SessionFactory sessionFactory; - - public HibernateOperationDAO(SessionFactory sf) { - sessionFactory = sf; - } - - @Override - public Operation GetOperationById(int id) { - try (Session session = sessionFactory.openSession()) { - return session.get(Operation.class, id); - } catch (Exception e) { - e.printStackTrace(); - return null; - } - } - - @Override - public void SaveOperation(Operation operation) { - Session session = null; - Transaction tx = null; - try { - session = sessionFactory.openSession(); - tx = session.beginTransaction(); - session.saveOrUpdate(operation); - tx.commit(); - } catch (Exception e) { - if (tx != null) { - tx.rollback(); - } - e.printStackTrace(); - } finally { - if (session != null) { - session.close(); - } - } - } - - @Override - public void DeleteOperation(Operation operation) { - Session session = null; - Transaction tx = null; - try { - session = sessionFactory.openSession(); - tx = session.beginTransaction(); - session.delete(operation); - tx.commit(); - } catch (Exception e) { - if (tx != null) { - tx.rollback(); - } - e.printStackTrace(); - } finally { - if (session != null) { - session.close(); - } - } - } - - @Override - public List FindAllOperations() { - try (Session session = sessionFactory.openSession()) { - return session.createQuery("FROM Operation", Operation.class).list(); - } catch (Exception e) { - e.printStackTrace(); - return new ArrayList<>(); - } - } - - @Override - public List FindAllOperationsByAccountId(int id) { - try (Session session = sessionFactory.openSession()) { - return session.createQuery("FROM Operation WHERE bankAccount.id = :accountId", Operation.class) - .setParameter("accountId", id) - .getResultList(); - } catch (Exception e) { - e.printStackTrace(); - return new ArrayList<>(); - } - } -} \ No newline at end of file diff --git a/DataAccess/src/main/java/DAO/HibernateUserDAO.java b/DataAccess/src/main/java/DAO/HibernateUserDAO.java deleted file mode 100644 index bded311..0000000 --- a/DataAccess/src/main/java/DAO/HibernateUserDAO.java +++ /dev/null @@ -1,103 +0,0 @@ -package DAO; - -import Application.Models.Entities.User; -import DAO.Interfaces.IUserDAO; -import org.hibernate.Hibernate; -import org.hibernate.Session; -import org.hibernate.SessionFactory; -import org.hibernate.Transaction; - -import java.util.List; - -public class HibernateUserDAO implements IUserDAO { - private final SessionFactory sessionFactory; - - public HibernateUserDAO(SessionFactory sf) { - sessionFactory = sf; - } - - @Override - public void SaveUser(User user) { - if (user == null) { - throw new IllegalArgumentException("Пользователь не может быть null"); - } - Session session = null; - Transaction tx = null; - try { - session = sessionFactory.openSession(); - tx = session.beginTransaction(); - session.saveOrUpdate(user); - tx.commit(); - } catch (Exception e) { - if (tx != null) { - tx.rollback(); - } - e.printStackTrace(); - } finally { - if (session != null) { - session.close(); - } - } - } - - @Override - public void DeleteUser(User user) { - if (user == null || user.getId() == null) { - throw new IllegalArgumentException("Пользователь или его ID не могут быть null"); - } - Session session = null; - Transaction tx = null; - try { - session = sessionFactory.openSession(); - tx = session.beginTransaction(); - session.delete(user); - tx.commit(); - } catch (Exception e) { - if (tx != null) { - tx.rollback(); - } - e.printStackTrace(); - } finally { - if (session != null) { - session.close(); - } - } - } - - @Override - public User FindUserById(int id) { - Session session = null; - try { - session = sessionFactory.openSession(); - User user = session.get(User.class, id); - if (user != null) { - Hibernate.initialize(user.getBankAccounts()); - Hibernate.initialize(user.getFriends()); - } - return user; - } catch (Exception e) { - e.printStackTrace(); - return null; - } finally { - if (session != null) { - session.close(); - } - } - } - - @Override - public List FindAllUsers() { - Session session = null; - try { - session = sessionFactory.openSession(); - return session.createQuery("FROM User", User.class).list(); - } catch (Exception e) { - e.printStackTrace(); - return null; - } finally { - if (session != null) { - session.close(); - } - } - } -} \ No newline at end of file diff --git a/DataAccess/src/main/java/DAO/Interfaces/IBankAccountDAO.java b/DataAccess/src/main/java/DAO/Interfaces/IBankAccountDAO.java deleted file mode 100644 index b535210..0000000 --- a/DataAccess/src/main/java/DAO/Interfaces/IBankAccountDAO.java +++ /dev/null @@ -1,12 +0,0 @@ -package DAO.Interfaces; - -import Application.Models.Entities.BankAccount; - -public interface IBankAccountDAO { - BankAccount GetBankAccountByID(int id); - void SaveBankAccount(BankAccount bankAccount); - void DeleteBankAccount(BankAccount bankAccount); - boolean Deposit(int accountId, double amount); - boolean Withdraw(int accountId, double amount); - boolean Transfer(int accountFromId, int accountToId, double amount); -} diff --git a/DataAccess/src/main/java/DAO/Interfaces/IOperationDAO.java b/DataAccess/src/main/java/DAO/Interfaces/IOperationDAO.java deleted file mode 100644 index deb824a..0000000 --- a/DataAccess/src/main/java/DAO/Interfaces/IOperationDAO.java +++ /dev/null @@ -1,13 +0,0 @@ -package DAO.Interfaces; - -import Application.Models.Entities.Operation; - -import java.util.List; - -public interface IOperationDAO { - Operation GetOperationById(int id); - void SaveOperation(Operation operation); - void DeleteOperation(Operation operation); - List FindAllOperations(); - List FindAllOperationsByAccountId(int id); -} diff --git a/DataAccess/src/main/java/DAO/Interfaces/IUserDAO.java b/DataAccess/src/main/java/DAO/Interfaces/IUserDAO.java deleted file mode 100644 index 8e055fc..0000000 --- a/DataAccess/src/main/java/DAO/Interfaces/IUserDAO.java +++ /dev/null @@ -1,12 +0,0 @@ -package DAO.Interfaces; - -import Application.Models.Entities.User; - -import java.util.List; - -public interface IUserDAO { - void SaveUser(User user); - void DeleteUser(User user); - User FindUserById(int id); - List FindAllUsers(); -} diff --git a/DataAccess/src/main/java/DataAccess/Configs/DataAccessConfig.java b/DataAccess/src/main/java/DataAccess/Configs/DataAccessConfig.java new file mode 100644 index 0000000..8f702bc --- /dev/null +++ b/DataAccess/src/main/java/DataAccess/Configs/DataAccessConfig.java @@ -0,0 +1,9 @@ +package DataAccess.Configs; + +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; + +@Configuration +@ComponentScan(basePackages = "DataAccess.Services") +public class DataAccessConfig { +} \ No newline at end of file diff --git a/DataAccess/src/main/java/DataAccess/Configs/JPAConfig.java b/DataAccess/src/main/java/DataAccess/Configs/JPAConfig.java new file mode 100644 index 0000000..c8d1971 --- /dev/null +++ b/DataAccess/src/main/java/DataAccess/Configs/JPAConfig.java @@ -0,0 +1,11 @@ +package DataAccess.Configs; + +import org.springframework.context.annotation.Configuration; +import org.springframework.data.jpa.repository.config.EnableJpaRepositories; +import org.springframework.boot.autoconfigure.domain.EntityScan; + +@Configuration +@EnableJpaRepositories(basePackages = "DataAccess.Repositories") +@EntityScan(basePackages = "Application.Models.Entities") +public class JPAConfig { +} \ No newline at end of file diff --git a/DataAccess/src/main/java/DataAccess/Repositories/IBankAccountRepository.java b/DataAccess/src/main/java/DataAccess/Repositories/IBankAccountRepository.java new file mode 100644 index 0000000..589ac31 --- /dev/null +++ b/DataAccess/src/main/java/DataAccess/Repositories/IBankAccountRepository.java @@ -0,0 +1,8 @@ +package DataAccess.Repositories; + +import Application.Models.Entities.BankAccount; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface IBankAccountRepository extends JpaRepository { } diff --git a/DataAccess/src/main/java/DataAccess/Repositories/IOperationRepository.java b/DataAccess/src/main/java/DataAccess/Repositories/IOperationRepository.java new file mode 100644 index 0000000..9ce232f --- /dev/null +++ b/DataAccess/src/main/java/DataAccess/Repositories/IOperationRepository.java @@ -0,0 +1,12 @@ +package DataAccess.Repositories; + +import Application.Models.Entities.Operation; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +public interface IOperationRepository extends JpaRepository { + List findAllByBankAccount_Id(int id); +} diff --git a/DataAccess/src/main/java/DataAccess/Repositories/IUserRepository.java b/DataAccess/src/main/java/DataAccess/Repositories/IUserRepository.java new file mode 100644 index 0000000..df93795 --- /dev/null +++ b/DataAccess/src/main/java/DataAccess/Repositories/IUserRepository.java @@ -0,0 +1,8 @@ +package DataAccess.Repositories; + +import Application.Models.Entities.User; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface IUserRepository extends JpaRepository { } diff --git a/DataAccess/src/main/java/DataAccess/Services/BankAccountService.java b/DataAccess/src/main/java/DataAccess/Services/BankAccountService.java new file mode 100644 index 0000000..9a3b55e --- /dev/null +++ b/DataAccess/src/main/java/DataAccess/Services/BankAccountService.java @@ -0,0 +1,84 @@ +package DataAccess.Services; + +import Application.Models.Entities.BankAccount; +import DataAccess.Repositories.IBankAccountRepository; +import DataAccess.Services.Interfaces.IBankAccountService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Optional; + +@Service +public class BankAccountService implements IBankAccountService { + private final IBankAccountRepository BankAccountRepository; + + @Autowired + public BankAccountService(IBankAccountRepository bankAccountRepository) { + this.BankAccountRepository = bankAccountRepository; + } + + @Override + public BankAccount GetAccount(int id) { + return BankAccountRepository.findById(id).orElse(null); + } + + @Override + public void UpdateAccount(BankAccount account) { + BankAccountRepository.save(account); + } + + @Override + public void DeleteAccount(BankAccount account) { + BankAccountRepository.delete(account); + } + + @Override + @Transactional + public boolean Deposit(int accountId, double amount) { + Optional optional = BankAccountRepository.findById(accountId); + if (optional.isPresent()) { + BankAccount account = optional.get(); + account.setBalance(account.getBalance() + amount); + BankAccountRepository.save(account); + return true; + } + return false; + } + + @Override + @Transactional + public boolean Withdraw(int accountId, double amount) { + Optional optional = BankAccountRepository.findById(accountId); + if (optional.isPresent()) { + BankAccount account = optional.get(); + if (account.getBalance() >= amount) { + account.setBalance(account.getBalance() - amount); + BankAccountRepository.save(account); + return true; + } + } + return false; + } + + @Override + @Transactional + public boolean Transfer(int accountFromId, int accountToId, double amount) { + Optional fromOpt = BankAccountRepository.findById(accountFromId); + Optional toOpt = BankAccountRepository.findById(accountToId); + + if (fromOpt.isPresent() && toOpt.isPresent()) { + BankAccount from = fromOpt.get(); + BankAccount to = toOpt.get(); + + if (from.getBalance() >= amount) { + from.setBalance(from.getBalance() - amount); + to.setBalance(to.getBalance() + amount); + BankAccountRepository.save(from); + BankAccountRepository.save(to); + return true; + } + } + return false; + } +} diff --git a/DataAccess/src/main/java/Services/Interfaces/IBankAccountService.java b/DataAccess/src/main/java/DataAccess/Services/Interfaces/IBankAccountService.java similarity index 81% rename from DataAccess/src/main/java/Services/Interfaces/IBankAccountService.java rename to DataAccess/src/main/java/DataAccess/Services/Interfaces/IBankAccountService.java index eac5e81..329ede3 100644 --- a/DataAccess/src/main/java/Services/Interfaces/IBankAccountService.java +++ b/DataAccess/src/main/java/DataAccess/Services/Interfaces/IBankAccountService.java @@ -1,6 +1,7 @@ -package Services.Interfaces; +package DataAccess.Services.Interfaces; import Application.Models.Entities.BankAccount; +import org.springframework.stereotype.Service; public interface IBankAccountService { BankAccount GetAccount(int id); diff --git a/DataAccess/src/main/java/Services/Interfaces/IOperationService.java b/DataAccess/src/main/java/DataAccess/Services/Interfaces/IOperationService.java similarity index 88% rename from DataAccess/src/main/java/Services/Interfaces/IOperationService.java rename to DataAccess/src/main/java/DataAccess/Services/Interfaces/IOperationService.java index f86fd3e..ec28f93 100644 --- a/DataAccess/src/main/java/Services/Interfaces/IOperationService.java +++ b/DataAccess/src/main/java/DataAccess/Services/Interfaces/IOperationService.java @@ -1,4 +1,4 @@ -package Services.Interfaces; +package DataAccess.Services.Interfaces; import Application.Models.Entities.Operation; diff --git a/DataAccess/src/main/java/Services/Interfaces/IUserService.java b/DataAccess/src/main/java/DataAccess/Services/Interfaces/IUserService.java similarity index 53% rename from DataAccess/src/main/java/Services/Interfaces/IUserService.java rename to DataAccess/src/main/java/DataAccess/Services/Interfaces/IUserService.java index 54e8164..aceb3ae 100644 --- a/DataAccess/src/main/java/Services/Interfaces/IUserService.java +++ b/DataAccess/src/main/java/DataAccess/Services/Interfaces/IUserService.java @@ -1,9 +1,13 @@ -package Services.Interfaces; +package DataAccess.Services.Interfaces; import Application.Models.Entities.User; +import org.springframework.stereotype.Service; + +import java.util.List; public interface IUserService { User GetUser(int id); void SaveUser(User user); void DeleteUser(User user); + List getAllUsers(); } diff --git a/DataAccess/src/main/java/DataAccess/Services/OperationService.java b/DataAccess/src/main/java/DataAccess/Services/OperationService.java new file mode 100644 index 0000000..6f28ae1 --- /dev/null +++ b/DataAccess/src/main/java/DataAccess/Services/OperationService.java @@ -0,0 +1,39 @@ +package DataAccess.Services; + +import Application.Models.Entities.Operation; +import DataAccess.Repositories.IOperationRepository; +import DataAccess.Services.Interfaces.IOperationService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +public class OperationService implements IOperationService { + private final IOperationRepository OperationRepository; + + @Autowired + public OperationService(IOperationRepository operationRepository) { + OperationRepository = operationRepository; + } + + @Override + public Operation GetOperation(int id) { + return OperationRepository.findById(id).orElse(null); + } + + @Override + public void SaveOperation(Operation operation) { + OperationRepository.save(operation); + } + + @Override + public void DeleteOperation(Operation operation) { + OperationRepository.delete(operation); + } + + @Override + public List FindAllOperationsByAccountId(int id) { + return OperationRepository.findAllByBankAccount_Id(id); + } +} diff --git a/DataAccess/src/main/java/DataAccess/Services/UserService.java b/DataAccess/src/main/java/DataAccess/Services/UserService.java new file mode 100644 index 0000000..a465191 --- /dev/null +++ b/DataAccess/src/main/java/DataAccess/Services/UserService.java @@ -0,0 +1,39 @@ +package DataAccess.Services; + +import Application.Models.Entities.User; +import DataAccess.Repositories.IUserRepository; +import DataAccess.Services.Interfaces.IUserService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +public class UserService implements IUserService { + private final IUserRepository UserRepository; + + @Autowired + public UserService(IUserRepository userRepository) { + this.UserRepository = userRepository; + } + + @Override + public User GetUser(int id) { + return UserRepository.findById(id).orElse(null); + } + + @Override + public void SaveUser(User user) { + UserRepository.save(user); + } + + @Override + public void DeleteUser(User user) { + UserRepository.delete(user); + } + + @Override + public List getAllUsers() { + return UserRepository.findAll(); + } +} diff --git a/DataAccess/src/main/java/Services/BankAccountService.java b/DataAccess/src/main/java/Services/BankAccountService.java deleted file mode 100644 index fe291f0..0000000 --- a/DataAccess/src/main/java/Services/BankAccountService.java +++ /dev/null @@ -1,42 +0,0 @@ -package Services; - -import Application.Models.Entities.BankAccount; -import DAO.HibernateBankAccountDAO; -import Services.Interfaces.IBankAccountService; - -public class BankAccountService implements IBankAccountService { - private final HibernateBankAccountDAO BankAccountDAO; - - public BankAccountService(HibernateBankAccountDAO bankAccountDAO) { - BankAccountDAO = bankAccountDAO; - } - @Override - public BankAccount GetAccount(int id) { - return BankAccountDAO.GetBankAccountByID(id); - } - - @Override - public void UpdateAccount(BankAccount account) { - BankAccountDAO.SaveBankAccount(account); - } - - @Override - public void DeleteAccount(BankAccount account) { - BankAccountDAO.DeleteBankAccount(account); - } - - @Override - public boolean Deposit(int accountId, double amount) { - return BankAccountDAO.Deposit(accountId, amount); - } - - @Override - public boolean Withdraw(int accountId, double amount) { - return BankAccountDAO.Withdraw(accountId, amount); - } - - @Override - public boolean Transfer(int accountFromId, int accountToId, double amount) { - return BankAccountDAO.Transfer(accountFromId, accountToId, amount); - } -} diff --git a/DataAccess/src/main/java/Services/OperationService.java b/DataAccess/src/main/java/Services/OperationService.java deleted file mode 100644 index f2920a1..0000000 --- a/DataAccess/src/main/java/Services/OperationService.java +++ /dev/null @@ -1,35 +0,0 @@ -package Services; - -import Application.Models.Entities.Operation; -import DAO.HibernateOperationDAO; -import Services.Interfaces.IOperationService; - -import java.util.List; - -public class OperationService implements IOperationService { - private final HibernateOperationDAO OperationDAO; - - public OperationService(HibernateOperationDAO operationDAO) { - OperationDAO = operationDAO; - } - - @Override - public Operation GetOperation(int id) { - return OperationDAO.GetOperationById(id); - } - - @Override - public void SaveOperation(Operation operation) { - OperationDAO.SaveOperation(operation); - } - - @Override - public void DeleteOperation(Operation operation) { - OperationDAO.DeleteOperation(operation); - } - - @Override - public List FindAllOperationsByAccountId(int id) { - return OperationDAO.FindAllOperationsByAccountId(id); - } -} diff --git a/DataAccess/src/main/java/Services/UserService.java b/DataAccess/src/main/java/Services/UserService.java deleted file mode 100644 index 2339ea4..0000000 --- a/DataAccess/src/main/java/Services/UserService.java +++ /dev/null @@ -1,28 +0,0 @@ -package Services; - -import Application.Models.Entities.User; -import DAO.HibernateUserDAO; -import Services.Interfaces.IUserService; - -public class UserService implements IUserService { - private final HibernateUserDAO UserDAO; - - public UserService(HibernateUserDAO userDAO) { - UserDAO = userDAO; - } - - @Override - public User GetUser(int id) { - return UserDAO.FindUserById(id); - } - - @Override - public void SaveUser(User user) { - UserDAO.SaveUser(user); - } - - @Override - public void DeleteUser(User user) { - UserDAO.DeleteUser(user); - } -} diff --git a/DataAccess/src/main/java/Utils/HibernateSessionFactoryUtil.java b/DataAccess/src/main/java/Utils/HibernateSessionFactoryUtil.java deleted file mode 100644 index 230c5e8..0000000 --- a/DataAccess/src/main/java/Utils/HibernateSessionFactoryUtil.java +++ /dev/null @@ -1,35 +0,0 @@ -package Utils; - -import Application.Models.Entities.BankAccount; -import Application.Models.Entities.Operation; -import Application.Models.Entities.User; -import org.hibernate.SessionFactory; -import org.hibernate.boot.registry.StandardServiceRegistryBuilder; -import org.hibernate.cfg.Configuration; - - -public class HibernateSessionFactoryUtil { - private static SessionFactory SessionFactory; - - private HibernateSessionFactoryUtil() {} - - public static SessionFactory GetSessionFactory() { - if (SessionFactory == null) { - try { - Configuration config = new Configuration().configure(); - - config.addAnnotatedClass(User.class); - config.addAnnotatedClass(BankAccount.class); - config.addAnnotatedClass(Operation.class); - StandardServiceRegistryBuilder builder = new StandardServiceRegistryBuilder() - .applySettings(config.getProperties()); - - SessionFactory = config.buildSessionFactory(builder.build()); - } catch (Exception e) { - System.out.println("Error in getSessionFactory: " + e.getMessage()); - throw new RuntimeException("Failed to create sessionFactory", e); - } - } - return SessionFactory; - } -} diff --git a/DataAccess/src/main/resources/application.yml b/DataAccess/src/main/resources/application.yml new file mode 100644 index 0000000..5f42461 --- /dev/null +++ b/DataAccess/src/main/resources/application.yml @@ -0,0 +1,17 @@ +spring: + datasource: + url: ${DB_URL} + username: ${DB_USERNAME} + password: ${DB_PASSWORD} + driver-class-name: org.postgresql.Driver + + jpa: + database-platform: org.hibernate.dialect.PostgreSQLDialect + hibernate: + ddl-auto: none + show-sql: true + + flyway: + enabled: true + locations: classpath:db/migration + baseline-on-migrate: true diff --git a/DataAccess/src/main/resources/hibernate.cfg.xml b/DataAccess/src/main/resources/hibernate.cfg.xml deleted file mode 100644 index 99e6283..0000000 --- a/DataAccess/src/main/resources/hibernate.cfg.xml +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - org.postgresql.Driver - jdbc:postgresql://localhost:5432/JavaLabsDb - postgres - limosha - - - org.hibernate.dialect.PostgreSQLDialect - - - true - true - - create-drop - - - - - - - diff --git a/Presentation/pom.xml b/Presentation/pom.xml index e799d3e..2a4b04a 100644 --- a/Presentation/pom.xml +++ b/Presentation/pom.xml @@ -8,6 +8,12 @@ Presentation 1.0-SNAPSHOT + + com.example + lim0sha + 1.0-SNAPSHOT + + 17 17 diff --git a/Presentation/src/main/java/Presentation/Configs/AppConfig.java b/Presentation/src/main/java/Presentation/Configs/AppConfig.java new file mode 100644 index 0000000..a9223f2 --- /dev/null +++ b/Presentation/src/main/java/Presentation/Configs/AppConfig.java @@ -0,0 +1,38 @@ +package Presentation.Configs; + +import Application.Managers.UserManager; +import Presentation.Console.Menu; +import Presentation.Controllers.UserController; +import DataAccess.Services.Interfaces.IBankAccountService; +import DataAccess.Services.Interfaces.IOperationService; +import DataAccess.Services.Interfaces.IUserService; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import java.util.Scanner; + +@Configuration +@ComponentScan(basePackages = "Presentation") +@ComponentScan(basePackages = "DataAccess") +@ComponentScan(basePackages = "Application") +public class AppConfig { + + @Bean + public Scanner scanner() { + return new Scanner(System.in); + } + + @Bean + public UserController userController( + UserManager userManager, + IUserService userService, + IBankAccountService bankAccountService, + IOperationService operationService) { + return new UserController(userManager, userService, bankAccountService, operationService); + } + + @Bean + public Menu menu(UserController userController, Scanner scanner) { + return new Menu(userController, scanner); + } +} \ No newline at end of file diff --git a/Presentation/src/main/java/Presentation/Configs/AppInitializer.java b/Presentation/src/main/java/Presentation/Configs/AppInitializer.java new file mode 100644 index 0000000..46ba630 --- /dev/null +++ b/Presentation/src/main/java/Presentation/Configs/AppInitializer.java @@ -0,0 +1,27 @@ +package Presentation.Configs; + +import Presentation.Interfaces.IFlywayController; +import Presentation.Interfaces.IMenu; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.CommandLineRunner; +import org.springframework.stereotype.Component; + +@Component +public class AppInitializer implements CommandLineRunner { + + private final IFlywayController flywayController; + private final IMenu menu; + + @Autowired + public AppInitializer(IFlywayController flywayController, IMenu menu) { + this.flywayController = flywayController; + this.menu = menu; + } + + @Override + public void run(String... args) { + flywayController.FlywayInit(); + flywayController.FlywayMigrate(); + menu.Run(); + } +} \ No newline at end of file diff --git a/Presentation/src/main/java/Presentation/Configs/DotenvInitializer.java b/Presentation/src/main/java/Presentation/Configs/DotenvInitializer.java new file mode 100644 index 0000000..52080ed --- /dev/null +++ b/Presentation/src/main/java/Presentation/Configs/DotenvInitializer.java @@ -0,0 +1,20 @@ +package Presentation.Configs; + +import io.github.cdimascio.dotenv.Dotenv; +import org.springframework.context.ApplicationContextInitializer; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.stereotype.Component; + +@Component +public class DotenvInitializer implements ApplicationContextInitializer { + + public static Dotenv dotenv; + + @Override + public void initialize(ConfigurableApplicationContext applicationContext) { + dotenv = Dotenv.configure().ignoreIfMissing().load(); + System.setProperty("DB_URL", dotenv.get("DB_URL")); + System.setProperty("DB_USERNAME", dotenv.get("DB_USERNAME")); + System.setProperty("DB_PASSWORD", dotenv.get("DB_PASSWORD")); + } +} \ No newline at end of file diff --git a/Presentation/src/main/java/Presentation/Console/Main.java b/Presentation/src/main/java/Presentation/Console/Main.java index 5487063..2a7456d 100644 --- a/Presentation/src/main/java/Presentation/Console/Main.java +++ b/Presentation/src/main/java/Presentation/Console/Main.java @@ -1,14 +1,14 @@ package Presentation.Console; +import Presentation.Configs.DotenvInitializer; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; -import Presentation.Interfaces.IMenu; -import org.flywaydb.core.Flyway; - +@SpringBootApplication public class Main { public static void main(String[] args) { - Flyway flyway = Flyway.configure().dataSource("jdbc:postgresql://localhost:5432/JavaLabsDb", "postgres", "limosha").load(); - flyway.migrate(); - IMenu menu = new Menu(); - menu.Run(); + SpringApplication app = new SpringApplication(Main.class); + app.addInitializers(new DotenvInitializer()); + app.run(args); } } diff --git a/Presentation/src/main/java/Presentation/Console/Menu.java b/Presentation/src/main/java/Presentation/Console/Menu.java index ecda47b..148fcfa 100644 --- a/Presentation/src/main/java/Presentation/Console/Menu.java +++ b/Presentation/src/main/java/Presentation/Console/Menu.java @@ -1,72 +1,34 @@ package Presentation.Console; -import Application.Models.Entities.Operation; import Application.ResultTypes.BankAccountResult; import Application.ResultTypes.OperationResult; import Application.ResultTypes.UserResult; -import Application.Managers.UserManager; import Application.Models.Entities.BankAccount; import Application.Models.Entities.User; import Application.Models.Enums.HairColor; import Application.Models.Enums.Sex; -import DAO.HibernateBankAccountDAO; -import DAO.HibernateOperationDAO; -import DAO.HibernateUserDAO; import Presentation.Controllers.UserController; -import Services.BankAccountService; -import Services.OperationService; -import Services.UserService; import Presentation.Interfaces.IMenu; -import Utils.HibernateSessionFactoryUtil; -import org.hibernate.Hibernate; -import org.hibernate.SessionFactory; -import org.hibernate.cfg.Configuration; +import Presentation.Interfaces.IUserController; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.stereotype.Component; import java.util.Scanner; -/** - * Класс {@code Menu} представляет консольное меню для управления пользователями и банковскими счетами. - * Предоставляет интерфейс для создания пользователей, управления друзьями, работы с банковскими счетами - * и выполнения финансовых операций. - *

- * Реализует интерфейс {@link IMenu}. - *

- * Основные возможности: - *

    - *
  • Создание пользователя
  • - *
  • Просмотр информации о пользователе
  • - *
  • Управление списком друзей пользователя
  • - *
  • Создание банковского счета
  • - *
  • Проверка баланса счета
  • - *
  • Снятие и пополнение средств
  • - *
  • Перевод средств между счетами
  • - *
- * - * Зависимости: - *
    - *
  • {@link UserService} - основной сервис для работы с пользователями и счетами
  • - *
  • {@link Scanner} - для считывания ввода пользователя
  • - *
- * - * @author lim0sha - * @version 1.0 - */ +@Component +@ComponentScan(basePackages = "Presentation") public class Menu implements IMenu { - private final SessionFactory sf = HibernateSessionFactoryUtil.GetSessionFactory(); - private final UserController controller = new UserController( - new UserManager(), new UserService(new HibernateUserDAO(sf)), - new BankAccountService(new HibernateBankAccountDAO(sf)), - new OperationService(new HibernateOperationDAO(sf)) - ); + private final IUserController controller; + private final Scanner scanner; + @Autowired + public Menu(UserController controller, Scanner scanner) { + this.controller = controller; + this.scanner = scanner; + } - private final Scanner scanner = new Scanner(System.in); - - /** - * Запускает основное меню и обрабатывает выбор пользователя. - * Предоставляет доступ к основным функциям системы через консольный интерфейс. - */ @Override public void Run() { while (true) { @@ -103,9 +65,6 @@ public void Run() { } } - /** - * Создает нового пользователя с вводом данных через консоль. - */ private void createUser() { System.out.print("Введите логин: "); String login = scanner.nextLine().trim(); @@ -184,10 +143,8 @@ private void createUser() { return; } - // Создаем пользователя без использования IdGenerator, так как ID генерируется базой данных User user = new User(login, name, age, sex, hairColor); - // Вызываем метод создания пользователя через контроллер UserResult result = controller.CreateUser(user); if (result instanceof UserResult.Success) { System.out.println("Пользователь создан!"); @@ -196,18 +153,12 @@ private void createUser() { } } - /** - * Выводит информацию о пользователе по введенному ID. - */ private void getUserInfo() { System.out.print("Введите ID пользователя: "); int userId = scanner.nextInt(); controller.GetUserInfo(userId); } - /** - * Позволяет добавить или удалить друга из списка друзей пользователя. - */ private void manageFriends() { System.out.print("Введите ID пользователя: "); int userId = scanner.nextInt(); @@ -231,9 +182,6 @@ private void manageFriends() { } } - /** - * Создает банковский счет для существующего пользователя. - */ private void createBankAccount() { System.out.print("Введите ID пользователя: "); int userId = scanner.nextInt(); @@ -252,9 +200,6 @@ private void createBankAccount() { } } - /** - * Проверяет баланс на указанном банковском счете. - */ private void checkBalance() { System.out.print("Введите ID счета: "); int accountId = scanner.nextInt(); @@ -268,9 +213,6 @@ private void checkBalance() { controller.CheckBalance(account.getUser().getId(), accountId); } - /** - * Снимает средства с указанного банковского счета. - */ private void withdraw() { System.out.print("Введите ID счета: "); int accountId = scanner.nextInt(); @@ -291,9 +233,6 @@ private void withdraw() { } } - /** - * Пополняет баланс указанного банковского счета. - */ private void deposit() { System.out.print("Введите ID счета: "); int accountId = scanner.nextInt(); @@ -313,9 +252,6 @@ private void deposit() { } } - /** - * Переводит средства с одного банковского счета на другой. - */ private void transfer() { try { System.out.print("Введите ID счета отправителя: "); diff --git a/Presentation/src/main/java/Presentation/Controllers/FlywayController.java b/Presentation/src/main/java/Presentation/Controllers/FlywayController.java new file mode 100644 index 0000000..8b0c437 --- /dev/null +++ b/Presentation/src/main/java/Presentation/Controllers/FlywayController.java @@ -0,0 +1,23 @@ +package Presentation.Controllers; + +import Presentation.Interfaces.IFlywayController; +import org.flywaydb.core.Flyway; +import org.springframework.stereotype.Component; + +@Component +public class FlywayController implements IFlywayController { + Flyway flyway = null; + + @Override + public void FlywayInit() { + String url = System.getProperty("DB_URL"); + String username = System.getProperty("DB_USERNAME"); + String password = System.getProperty("DB_PASSWORD"); + flyway = Flyway.configure().dataSource(url, username, password).load(); + } + + @Override + public void FlywayMigrate() { + flyway.migrate(); + } +} diff --git a/Presentation/src/main/java/Presentation/Controllers/UserController.java b/Presentation/src/main/java/Presentation/Controllers/UserController.java index 74bee86..f4c6424 100644 --- a/Presentation/src/main/java/Presentation/Controllers/UserController.java +++ b/Presentation/src/main/java/Presentation/Controllers/UserController.java @@ -9,24 +9,30 @@ import Application.ResultTypes.OperationResult; import Application.ResultTypes.UserResult; import Presentation.Interfaces.IUserController; -import Services.BankAccountService; -import Services.OperationService; -import Services.UserService; +import DataAccess.Services.Interfaces.IBankAccountService; +import DataAccess.Services.Interfaces.IOperationService; +import DataAccess.Services.Interfaces.IUserService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.stereotype.Controller; -import java.util.ArrayList; import java.util.List; +@Component +@Controller public class UserController implements IUserController { - private final UserManager UserManager; - private final UserService UserService; - private final BankAccountService BankAccountService; - private final OperationService OperationService; - - public UserController(UserManager userManager, UserService userService, BankAccountService bankAccountService, OperationService operationService) { - UserManager = userManager; - UserService = userService; - BankAccountService = bankAccountService; - OperationService = operationService; + + private final UserManager userManager; + private final IUserService userService; + private final IBankAccountService bankAccountService; + private final IOperationService operationService; + + @Autowired + public UserController(UserManager userManager, IUserService userService, IBankAccountService bankAccountService, IOperationService operationService) { + this.userManager = userManager; + this.userService = userService; + this.bankAccountService = bankAccountService; + this.operationService = operationService; } @Override @@ -34,14 +40,14 @@ public UserResult CreateUser(User user) { if (user == null || user.getLogin() == null || user.getName() == null) { return new UserResult.UserCreationError("Некорректные данные пользователя"); } - UserService.SaveUser(user); + userService.SaveUser(user); return new UserResult.Success(); } @Override public User GetUserById(int id) { try { - return UserService.GetUser(id); + return userService.GetUser(id); } catch (Exception e) { return null; } @@ -50,7 +56,7 @@ public User GetUserById(int id) { @Override public BankAccount GetBankAccountById(int id) { try { - return BankAccountService.GetAccount(id); + return bankAccountService.GetAccount(id); } catch (Exception e) { return null; } @@ -59,7 +65,7 @@ public BankAccount GetBankAccountById(int id) { @Override public UserResult DeleteUser(User user) { try { - UserService.DeleteUser(user); + userService.DeleteUser(user); return new UserResult.Success(); } catch (Exception e) { return new UserResult.UserDeletionError(e.getMessage()); @@ -68,34 +74,34 @@ public UserResult DeleteUser(User user) { @Override public void GetUserInfo(int id) { - UserManager.GetUserInfo(UserService.GetUser(id)); + userManager.GetUserInfo(userService.GetUser(id)); } @Override public void AddFriend(int userId, int otherId) { - User user1 = UserService.GetUser(userId); - User user2 = UserService.GetUser(otherId); - UserManager.AddFriend(user1, user2); - UserService.SaveUser(user1); - UserService.SaveUser(user2); + User user1 = userService.GetUser(userId); + User user2 = userService.GetUser(otherId); + userManager.AddFriend(user1, user2); + userService.SaveUser(user1); + userService.SaveUser(user2); } @Override public void RemoveFriend(int userId, int otherId) { - User user1 = UserService.GetUser(userId); - User user2 = UserService.GetUser(otherId); - UserManager.RemoveFriend(user1, user2); - UserService.SaveUser(user1); - UserService.SaveUser(user2); + User user1 = userService.GetUser(userId); + User user2 = userService.GetUser(otherId); + userManager.RemoveFriend(user1, user2); + userService.SaveUser(user1); + userService.SaveUser(user2); } @Override public BankAccountResult addBankAccount(int userId, BankAccount bankAccount) { try { - User user = UserService.GetUser(userId); - UserManager.AddBankAccount(user, bankAccount); - UserService.SaveUser(user); - BankAccountService.UpdateAccount(bankAccount); + User user = userService.GetUser(userId); + userManager.AddBankAccount(user, bankAccount); + userService.SaveUser(user); + bankAccountService.UpdateAccount(bankAccount); return new BankAccountResult.Success(); } catch (Exception e) { return new BankAccountResult.BankAccountCreationError(e.getMessage()); @@ -105,10 +111,10 @@ public BankAccountResult addBankAccount(int userId, BankAccount bankAccount) { @Override public BankAccountResult RemoveBankAccount(int userId, BankAccount bankAccount) { try { - User user = UserService.GetUser(userId); - UserManager.RemoveBankAccount(user, bankAccount); - UserService.SaveUser(user); - BankAccountService.UpdateAccount(bankAccount); + User user = userService.GetUser(userId); + userManager.RemoveBankAccount(user, bankAccount); + userService.SaveUser(user); + bankAccountService.UpdateAccount(bankAccount); return new BankAccountResult.Success(); } catch (Exception e) { return new BankAccountResult.BankAccountDeletionError(e.getMessage()); @@ -117,7 +123,7 @@ public BankAccountResult RemoveBankAccount(int userId, BankAccount bankAccount) @Override public OperationResult CheckBalance(int userId, int accountId) { - BankAccount account = BankAccountService.GetAccount(accountId); + BankAccount account = bankAccountService.GetAccount(accountId); if (account == null || account.getUser().getId() != userId) { return new OperationResult.OperationError("Счет не найден или принадлежит другому пользователю."); } @@ -128,8 +134,8 @@ public OperationResult CheckBalance(int userId, int accountId) { @Override public OperationResult Deposit(BankAccount bankAccount, Double amount) { try { - BankAccountService.Deposit(bankAccount.getId(), amount); - OperationService.SaveOperation(new Operation(bankAccount, OperationType.Deposit, amount)); + bankAccountService.Deposit(bankAccount.getId(), amount); + operationService.SaveOperation(new Operation(bankAccount, OperationType.Deposit, amount)); return new OperationResult.Success(); } catch (Exception e) { return new OperationResult.OperationError(e.getMessage()); @@ -139,11 +145,11 @@ public OperationResult Deposit(BankAccount bankAccount, Double amount) { @Override public OperationResult Withdraw(BankAccount bankAccount, Double amount) { try { - boolean success = BankAccountService.Withdraw(bankAccount.getId(), amount); + boolean success = bankAccountService.Withdraw(bankAccount.getId(), amount); if (!success) { return new OperationResult.OperationError("Not enough balance."); } - OperationService.SaveOperation(new Operation(bankAccount, OperationType.Withdraw, amount)); + operationService.SaveOperation(new Operation(bankAccount, OperationType.Withdraw, amount)); return new OperationResult.Success(); } catch (Exception e) { return new OperationResult.OperationError(e.getMessage()); @@ -153,8 +159,8 @@ public OperationResult Withdraw(BankAccount bankAccount, Double amount) { @Override public OperationResult Transfer(BankAccount bankAccount1, BankAccount bankAccount2, Double amount) { try { - User user1 = UserService.GetUser(bankAccount1.getUser().getId()); - User user2 = UserService.GetUser(bankAccount2.getUser().getId()); + User user1 = userService.GetUser(bankAccount1.getUser().getId()); + User user2 = userService.GetUser(bankAccount2.getUser().getId()); double commissionRate = user1.getId().equals(user2.getId()) ? 0.00 : user1.getFriends().stream().anyMatch(f -> f.getId().equals(user2.getId())) ? 0.03 @@ -162,13 +168,13 @@ public OperationResult Transfer(BankAccount bankAccount1, BankAccount bankAccoun double commission = amount * commissionRate; double totalAmount = amount + commission; - boolean success = BankAccountService.Transfer(bankAccount1.getId(), bankAccount2.getId(), totalAmount); + boolean success = bankAccountService.Transfer(bankAccount1.getId(), bankAccount2.getId(), totalAmount); if (!success) { return new OperationResult.OperationError("Insufficient funds, including commission."); } - OperationService.SaveOperation(new Operation(bankAccount1, OperationType.Transfer, totalAmount)); - OperationService.SaveOperation(new Operation(bankAccount2, OperationType.Deposit, amount)); + operationService.SaveOperation(new Operation(bankAccount1, OperationType.Transfer, totalAmount)); + operationService.SaveOperation(new Operation(bankAccount2, OperationType.Deposit, amount)); return new OperationResult.Success(); } catch (Exception e) { @@ -179,13 +185,12 @@ public OperationResult Transfer(BankAccount bankAccount1, BankAccount bankAccoun @Override public OperationResult GetOperationHistory(int bankAccountId) { try { - BankAccount account = BankAccountService.GetAccount(bankAccountId); - List operations = OperationService.FindAllOperationsByAccountId(account.getId()); - return UserManager.PrintHistory(account, operations); + BankAccount account = bankAccountService.GetAccount(bankAccountId); + List operations = operationService.FindAllOperationsByAccountId(account.getId()); + return userManager.PrintHistory(account, operations); } catch (Exception e) { e.printStackTrace(); return new OperationResult.OperationError(e.getMessage()); } } - } diff --git a/Presentation/src/main/java/Presentation/Interfaces/IFlywayController.java b/Presentation/src/main/java/Presentation/Interfaces/IFlywayController.java new file mode 100644 index 0000000..0d847ed --- /dev/null +++ b/Presentation/src/main/java/Presentation/Interfaces/IFlywayController.java @@ -0,0 +1,6 @@ +package Presentation.Interfaces; + +public interface IFlywayController { + void FlywayInit(); + void FlywayMigrate(); +} diff --git a/Presentation/src/main/java/Presentation/Interfaces/IMenu.java b/Presentation/src/main/java/Presentation/Interfaces/IMenu.java index 592e4d8..869abd7 100644 --- a/Presentation/src/main/java/Presentation/Interfaces/IMenu.java +++ b/Presentation/src/main/java/Presentation/Interfaces/IMenu.java @@ -1,14 +1,5 @@ package Presentation.Interfaces; -/** - * Интерфейс для меню пользовательского интерфейса в консоли. - * Обеспечивает базовый контракт для запуска меню. - */ public interface IMenu { - - /** - * Запускает отображение и обработку логики меню. - * Отображает доступные опции и обрабатывает пользовательский ввод. - */ void Run(); } diff --git a/Presentation/src/main/java/Presentation/Interfaces/IUserController.java b/Presentation/src/main/java/Presentation/Interfaces/IUserController.java index a59ac15..ffb3ce3 100644 --- a/Presentation/src/main/java/Presentation/Interfaces/IUserController.java +++ b/Presentation/src/main/java/Presentation/Interfaces/IUserController.java @@ -6,128 +6,33 @@ import Application.Models.Entities.BankAccount; import Application.Models.Entities.User; -/** - * Интерфейс, предоставляющий операции для управления пользователями и их банковскими счетами. - * Включает методы для создания, удаления пользователей, управления их друзьями и банковскими счетами, - * а также выполнения различных операций с банковскими счетами. - */ public interface IUserController { - /** - * Создание нового пользователя. - * - * @param user объект пользователя, который должен быть создан. - * @return результат операции создания пользователя. - */ UserResult CreateUser(User user); - /** - * Создание нового пользователя. - * - * @param id идентификатор пользователя, который должен быть найден. - * @return результат операции поиска пользователя. - */ User GetUserById(int id); - /** - * Создание нового пользователя. - * - * @param id идентификатор аккаунта, который должен быть найден. - * @return результат операции поиска аккаунта. - */ BankAccount GetBankAccountById(int id); - /** - * Удаление пользователя. - * - * @param user объект пользователя, который должен быть удален. - * @return результат операции удаления пользователя. - */ UserResult DeleteUser(User user); - /** - * Получение информации о пользователе. - * - * @param id идентификатор пользователя, информацию о котором необходимо получить. - */ void GetUserInfo(int id); - /** - * Добавление пользователя в друзья. - * - * @param userId идентификатор текущего пользователя. - * @param otherId идентификатор пользователя, которого нужно добавить в друзья. - */ void AddFriend(int userId, int otherId); - /** - * Удаление пользователя из списка друзей. - * - * @param userId идентификатор текущего пользователя. - * @param otherId идентификатор пользователя, которого нужно удалить из друзей. - */ void RemoveFriend(int userId, int otherId); - /** - * Добавление нового банковского счета пользователю. - * - * @param userId идентификатор пользователя, которому нужно добавить банковский счет. - * @param bankAccount объект банковского счета, который нужно добавить. - * @return результат операции добавления банковского счета. - */ BankAccountResult addBankAccount(int userId, BankAccount bankAccount); - /** - * Удаление банковского счета пользователя. - * - * @param userId идентификатор пользователя, чей банковский счет должен быть удален. - * @param bankAccount объект банковского счета, который нужно удалить. - * @return результат операции удаления банковского счета. - */ BankAccountResult RemoveBankAccount(int userId, BankAccount bankAccount); - /** - * Проверка баланса банковского счета пользователя. - * - * @param userId идентификатор пользователя, чей баланс нужно проверить. - * @param bankAccountId объект банковского счета, баланс которого нужно проверить. - * @return результат операции проверки баланса. - */ OperationResult CheckBalance(int userId, int bankAccountId); - /** - * Пополнение банковского счета. - * - * @param bankAccount объект банковского счета, на который нужно пополнить средства. - * @param amount сумма, которую нужно внести на счет. - * @return результат операции пополнения. - */ OperationResult Deposit(BankAccount bankAccount, Double amount); - /** - * Снятие средств с банковского счета. - * - * @param bankAccount объект банковского счета, с которого нужно снять средства. - * @param amount сумма, которую нужно снять со счета. - * @return результат операции снятия средств. - */ OperationResult Withdraw(BankAccount bankAccount, Double amount); - /** - * Перевод средств между двумя банковскими счетами. - * - * @param bankAccount1 объект исходного банковского счета. - * @param bankAccount2 объект целевого банковского счета. - * @param amount сумма, которую нужно перевести. - * @return результат операции перевода. - */ OperationResult Transfer(BankAccount bankAccount1, BankAccount bankAccount2, Double amount); - /** - * Получение истории операций для конкретного банковского счета. - * - * @param bankAccountId идентификатор банковского счета, для которого нужно получить историю операций. - * @return результат операции получения истории. - */ OperationResult GetOperationHistory(int bankAccountId); } diff --git a/Presentation/src/main/resources/application.yml b/Presentation/src/main/resources/application.yml index 204317a..d1ec292 100644 --- a/Presentation/src/main/resources/application.yml +++ b/Presentation/src/main/resources/application.yml @@ -1,9 +1,9 @@ spring: datasource: - url: jdbc:postgresql://localhost:5432/JavaLabsDb - username: postgres - password: limosha + url: ${DB_URL} + username: ${DB_USERNAME} + password: ${DB_PASSWORD} flyway: enabled: true locations: classpath:db/migration - baseline-on-migrate: true \ No newline at end of file + baseline-on-migrate: true diff --git a/Presentation/src/main/resources/db/migration/V1__init.sql b/Presentation/src/main/resources/db/migration/V1__init.sql index 26dd68f..6818625 100644 --- a/Presentation/src/main/resources/db/migration/V1__init.sql +++ b/Presentation/src/main/resources/db/migration/V1__init.sql @@ -1,32 +1,40 @@ -CREATE TABLE Users -( - id SERIAL PRIMARY KEY, - login VARCHAR(255) UNIQUE NOT NULL, - name VARCHAR(255) NOT NULL, - age INT NOT NULL, - sex VARCHAR(255) NOT NULL, - hairColor VARCHAR(255) +CREATE SEQUENCE IF NOT EXISTS bankaccounts_id_seq START WITH 1 INCREMENT BY 1; +CREATE SEQUENCE IF NOT EXISTS operations_id_seq START WITH 1 INCREMENT BY 1; +CREATE SEQUENCE IF NOT EXISTS users_id_seq START WITH 1 INCREMENT BY 1; + +CREATE TABLE users ( + id INTEGER GENERATED BY DEFAULT AS IDENTITY NOT NULL, + login VARCHAR(255) NOT NULL, + name VARCHAR(255) NOT NULL, + age INTEGER NOT NULL, + sex VARCHAR(255) NOT NULL, + haircolor VARCHAR(255), + CONSTRAINT users_pkey PRIMARY KEY (id), + CONSTRAINT users_login_key UNIQUE (login) ); -CREATE TABLE BankAccounts -( - id SERIAL PRIMARY KEY, - balance DOUBLE PRECISION NOT NULL, - userLogin VARCHAR(255) NOT NULL, - userId INT NOT NULL REFERENCES Users (id) +CREATE TABLE bankaccounts ( + id INTEGER GENERATED BY DEFAULT AS IDENTITY NOT NULL, + balance DOUBLE PRECISION NOT NULL, + userlogin VARCHAR(255) NOT NULL, + user_id INTEGER NOT NULL, + CONSTRAINT bankaccounts_pkey PRIMARY KEY (id), + CONSTRAINT bankaccounts_userid_fkey FOREIGN KEY (user_id) REFERENCES users (id) ON DELETE NO ACTION ); -CREATE TABLE Operations -( - id SERIAL PRIMARY KEY, - accountId INT NOT NULL REFERENCES BankAccounts (id), - type VARCHAR(255) NOT NULL, - amount DOUBLE PRECISION NOT NULL +CREATE TABLE operations ( + id INTEGER GENERATED BY DEFAULT AS IDENTITY NOT NULL, + account_id INTEGER NOT NULL, + type VARCHAR(255) NOT NULL, + amount DOUBLE PRECISION NOT NULL, + CONSTRAINT operations_pkey PRIMARY KEY (id), + CONSTRAINT operations_accountid_fkey FOREIGN KEY (account_id) REFERENCES bankaccounts (id) ON DELETE NO ACTION ); -CREATE TABLE Friends -( - userId INT NOT NULL REFERENCES Users (id), - friendId INT NOT NULL REFERENCES Users (id), - PRIMARY KEY (userId, friendId) -); \ No newline at end of file +CREATE TABLE friends ( + user_id INTEGER NOT NULL, + friend_id INTEGER NOT NULL, + CONSTRAINT friends_pkey PRIMARY KEY (user_id, friend_id), + CONSTRAINT friends_userid_fkey FOREIGN KEY (user_id) REFERENCES users (id) ON DELETE NO ACTION, + CONSTRAINT friends_friendid_fkey FOREIGN KEY (friend_id) REFERENCES users (id) ON DELETE NO ACTION +); diff --git a/Presentation/src/main/resources/db/migration/V2__drop.sql b/Presentation/src/main/resources/db/migration/V2__drop.sql new file mode 100644 index 0000000..85e8be5 --- /dev/null +++ b/Presentation/src/main/resources/db/migration/V2__drop.sql @@ -0,0 +1,4 @@ +DROP TABLE friends; +DROP TABLE operations; +DROP TABLE bankaccounts; +DROP TABLE users; \ No newline at end of file diff --git a/Presentation/src/main/resources/db/migration/V2__drop_tables.sql b/Presentation/src/main/resources/db/migration/V2__drop_tables.sql deleted file mode 100644 index ea5d75d..0000000 --- a/Presentation/src/main/resources/db/migration/V2__drop_tables.sql +++ /dev/null @@ -1,4 +0,0 @@ -DROP TABLE Friends; -DROP TABLE Operations; -DROP TABLE BankAccounts; -DROP TABLE Users; diff --git a/Presentation/src/main/resources/db/migration/V3__init.sql b/Presentation/src/main/resources/db/migration/V3__init.sql deleted file mode 100644 index 01d855f..0000000 --- a/Presentation/src/main/resources/db/migration/V3__init.sql +++ /dev/null @@ -1,56 +0,0 @@ -CREATE SEQUENCE IF NOT EXISTS bankaccounts_id_seq START WITH 1 INCREMENT BY 1; - -CREATE SEQUENCE IF NOT EXISTS operations_id_seq START WITH 1 INCREMENT BY 1; - -CREATE SEQUENCE IF NOT EXISTS users_id_seq START WITH 1 INCREMENT BY 1; - -CREATE TABLE bankaccounts -( - id INTEGER GENERATED BY DEFAULT AS IDENTITY NOT NULL, - balance DOUBLE PRECISION NOT NULL, - userlogin VARCHAR(255) NOT NULL, - userid INTEGER NOT NULL, - CONSTRAINT bankaccounts_pkey PRIMARY KEY (id) -); - -CREATE TABLE friends -( - userid INTEGER NOT NULL, - friendid INTEGER NOT NULL, - CONSTRAINT friends_pkey PRIMARY KEY (userid, friendid) -); - -CREATE TABLE operations -( - id INTEGER GENERATED BY DEFAULT AS IDENTITY NOT NULL, - accountid INTEGER NOT NULL, - type VARCHAR(255) NOT NULL, - amount DOUBLE PRECISION NOT NULL, - CONSTRAINT operations_pkey PRIMARY KEY (id) -); - -CREATE TABLE users -( - id INTEGER GENERATED BY DEFAULT AS IDENTITY NOT NULL, - login VARCHAR(255) NOT NULL, - name VARCHAR(255) NOT NULL, - age INTEGER NOT NULL, - sex VARCHAR(255) NOT NULL, - haircolor VARCHAR(255), - CONSTRAINT users_pkey PRIMARY KEY (id) -); - -ALTER TABLE users - ADD CONSTRAINT users_login_key UNIQUE (login); - -ALTER TABLE bankaccounts - ADD CONSTRAINT bankaccounts_userid_fkey FOREIGN KEY (userid) REFERENCES users (id) ON DELETE NO ACTION; - -ALTER TABLE friends - ADD CONSTRAINT friends_friendid_fkey FOREIGN KEY (friendid) REFERENCES users (id) ON DELETE NO ACTION; - -ALTER TABLE friends - ADD CONSTRAINT friends_userid_fkey FOREIGN KEY (userid) REFERENCES users (id) ON DELETE NO ACTION; - -ALTER TABLE operations - ADD CONSTRAINT operations_accountid_fkey FOREIGN KEY (accountid) REFERENCES bankaccounts (id) ON DELETE NO ACTION; \ No newline at end of file diff --git a/Presentation/src/test/java/BankTests.java b/Presentation/src/test/java/BankTests.java index a1b0b16..9752158 100644 --- a/Presentation/src/test/java/BankTests.java +++ b/Presentation/src/test/java/BankTests.java @@ -5,9 +5,9 @@ import Application.Models.Enums.HairColor; import Application.Models.Enums.Sex; import Presentation.Controllers.UserController; -import Services.BankAccountService; -import Services.OperationService; -import Services.UserService; +import DataAccess.Services.BankAccountService; +import DataAccess.Services.OperationService; +import DataAccess.Services.UserService; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.InjectMocks; @@ -24,7 +24,7 @@ public class BankTests { private UserManager userManager; @Mock - private UserService userService; + private UserService UserService; @Mock private BankAccountService bankAccountService; diff --git a/pom.xml b/pom.xml index b718579..790b8ce 100644 --- a/pom.xml +++ b/pom.xml @@ -5,9 +5,28 @@ com.example lim0sha 1.0-SNAPSHOT + + + 2.0 + + pom + + org.springframework.boot + spring-boot-starter-parent + 3.4.4 + + + + + io.github.cdimascio + dotenv-java + 3.0.0 + + + org.hibernate hibernate-core @@ -20,24 +39,70 @@ 4.3.0.Beta3 - - org.postgresql - postgresql - 42.7.2 - - net.bytebuddy byte-buddy 1.14.7 + + + org.postgresql + postgresql + 42.7.2 + + + org.flywaydb flyway-core 9.22.0 + + + org.springframework.boot + spring-boot-starter-web + + + + + org.springframework.boot + spring-boot-starter-data-jpa + + + + + org.springframework.boot + spring-boot-starter-validation + + + + + org.springframework.boot + spring-boot-starter-actuator + + + + + org.springframework.boot + spring-boot-starter-security + + + + + org.springframework.boot + spring-boot-starter-test + test + + + + + org.springdoc + springdoc-openapi-starter-webmvc-ui + 2.0.2 + + From ccffc476889dff85d2b448c05a951b2e87706546 Mon Sep 17 00:00:00 2001 From: Alexander Kim Date: Mon, 7 Apr 2025 00:05:25 +0300 Subject: [PATCH 2/6] feat: add REST API + base endpoints for UserController; fix: Spring SecurityConfig methods permission --- .gitignore | 1 + Presentation/pom.xml | 12 +++ .../java/Presentation/Configs/AppConfig.java | 4 +- .../Presentation/Configs/SecurityConfig.java | 24 +++++ .../Presentation/Configs/SwaggerConfig.java | 18 ++++ .../Controllers/UserController.java | 28 +++++- .../Controllers/UserDTOController.java | 94 +++++++++++++++++++ .../main/java/Presentation/DTO/UserDTO.java | 19 ++++ .../Interfaces/IUserController.java | 4 + pom.xml | 13 --- 10 files changed, 199 insertions(+), 18 deletions(-) create mode 100644 Presentation/src/main/java/Presentation/Configs/SecurityConfig.java create mode 100644 Presentation/src/main/java/Presentation/Configs/SwaggerConfig.java create mode 100644 Presentation/src/main/java/Presentation/Controllers/UserDTOController.java create mode 100644 Presentation/src/main/java/Presentation/DTO/UserDTO.java diff --git a/.gitignore b/.gitignore index 026a978..d41fd5e 100644 --- a/.gitignore +++ b/.gitignore @@ -28,6 +28,7 @@ bin/ DataAccess.iml Presentation.iml Application.iml +target ### VS Code ### .vscode/ diff --git a/Presentation/pom.xml b/Presentation/pom.xml index 2a4b04a..03ea269 100644 --- a/Presentation/pom.xml +++ b/Presentation/pom.xml @@ -63,6 +63,18 @@ test + + org.springdoc + springdoc-openapi-starter-webmvc-ui + 2.0.2 + + + + + org.springframework.boot + spring-boot-starter-security + + diff --git a/Presentation/src/main/java/Presentation/Configs/AppConfig.java b/Presentation/src/main/java/Presentation/Configs/AppConfig.java index a9223f2..805e639 100644 --- a/Presentation/src/main/java/Presentation/Configs/AppConfig.java +++ b/Presentation/src/main/java/Presentation/Configs/AppConfig.java @@ -12,9 +12,7 @@ import java.util.Scanner; @Configuration -@ComponentScan(basePackages = "Presentation") -@ComponentScan(basePackages = "DataAccess") -@ComponentScan(basePackages = "Application") +@ComponentScan(basePackages = { "Presentation", "DataAccess", "Application" }) public class AppConfig { @Bean diff --git a/Presentation/src/main/java/Presentation/Configs/SecurityConfig.java b/Presentation/src/main/java/Presentation/Configs/SecurityConfig.java new file mode 100644 index 0000000..27890c3 --- /dev/null +++ b/Presentation/src/main/java/Presentation/Configs/SecurityConfig.java @@ -0,0 +1,24 @@ +package Presentation.Configs; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.Customizer; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.web.SecurityFilterChain; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; + +@Configuration +@EnableWebSecurity +public class SecurityConfig { + + @Bean + public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { + return http + .authorizeHttpRequests(auth -> auth + .anyRequest().permitAll() + ) + .csrf(csrf -> csrf.disable()) // отключаем CSRF + .httpBasic(Customizer.withDefaults()) // можно убрать если не нужен basic auth + .build(); + } +} diff --git a/Presentation/src/main/java/Presentation/Configs/SwaggerConfig.java b/Presentation/src/main/java/Presentation/Configs/SwaggerConfig.java new file mode 100644 index 0000000..d847d6c --- /dev/null +++ b/Presentation/src/main/java/Presentation/Configs/SwaggerConfig.java @@ -0,0 +1,18 @@ +package Presentation.Configs; + +import org.springdoc.core.models.GroupedOpenApi; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class SwaggerConfig { + + @Bean + public GroupedOpenApi publicApi() { + return GroupedOpenApi.builder() + .group("public-api") + .packagesToScan("Presentation.Controllers") + .pathsToMatch("/**") + .build(); + } +} \ No newline at end of file diff --git a/Presentation/src/main/java/Presentation/Controllers/UserController.java b/Presentation/src/main/java/Presentation/Controllers/UserController.java index f4c6424..0db2aae 100644 --- a/Presentation/src/main/java/Presentation/Controllers/UserController.java +++ b/Presentation/src/main/java/Presentation/Controllers/UserController.java @@ -14,12 +14,10 @@ import DataAccess.Services.Interfaces.IUserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; -import org.springframework.stereotype.Controller; import java.util.List; @Component -@Controller public class UserController implements IUserController { private final UserManager userManager; @@ -44,6 +42,16 @@ public UserResult CreateUser(User user) { return new UserResult.Success(); } + @Override + public UserResult UpdateUser(User user) { + try { + userService.SaveUser(user); + return new UserResult.Success(); + } catch (Exception e) { + return new UserResult.UserUpdateError(e.getMessage()); + } + } + @Override public User GetUserById(int id) { try { @@ -193,4 +201,20 @@ public OperationResult GetOperationHistory(int bankAccountId) { return new OperationResult.OperationError(e.getMessage()); } } + + @Override + public UserResult DeleteUserById(int id) { + try { + User user = userService.GetUser(id); + if (user == null) { + return new UserResult.UserDeletionError("Пользователь с данным ID не найден."); + } + + userService.DeleteUser(user); + return new UserResult.Success(); + } catch (Exception e) { + return new UserResult.UserDeletionError("Ошибка при удалении пользователя: " + e.getMessage()); + } + } + } diff --git a/Presentation/src/main/java/Presentation/Controllers/UserDTOController.java b/Presentation/src/main/java/Presentation/Controllers/UserDTOController.java new file mode 100644 index 0000000..0d83b79 --- /dev/null +++ b/Presentation/src/main/java/Presentation/Controllers/UserDTOController.java @@ -0,0 +1,94 @@ +package Presentation.Controllers; + +import Application.Models.Entities.User; +import Application.ResultTypes.UserResult; +import Presentation.DTO.UserDTO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +@RestController +@RequestMapping("/users") +public class UserDTOController { + + private final UserController userController; + + public UserDTOController(UserController userController) { + this.userController = userController; + } + + @Operation(summary = "Получить пользователя по ID", description = "Получает информацию о пользователе по ID") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Пользователь найден", content = @Content(mediaType = "application/json", schema = @Schema(implementation = UserDTO.class))), + @ApiResponse(responseCode = "404", description = "Пользователь не найден") + }) + @GetMapping("/{id}") + public ResponseEntity getUserById(@Parameter(description = "ID пользователя") @PathVariable int id) { + User user = userController.GetUserById(id); + if (user == null) { + return ResponseEntity.notFound().build(); + } + return ResponseEntity.ok(new UserDTO(user)); + } + + @Operation(summary = "Создать нового пользователя", description = "Создает нового пользователя") + @ApiResponses(value = { + @ApiResponse(responseCode = "201", description = "Пользователь создан"), + @ApiResponse(responseCode = "400", description = "Некорректные данные") + }) + @PostMapping + public ResponseEntity createUser(@RequestBody User user) { + UserResult result = userController.CreateUser(user); + if (result instanceof UserResult.Success) { + return ResponseEntity.status(HttpStatus.CREATED).body(result); + } else { + return ResponseEntity.badRequest().body(result); + } + } + + @Operation(summary = "Обновить данные пользователя", description = "Обновляет данные о пользователе по ID") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Пользователь обновлен", content = @Content(mediaType = "application/json", schema = @Schema(implementation = UserDTO.class))), + @ApiResponse(responseCode = "404", description = "Пользователь не найден"), + @ApiResponse(responseCode = "400", description = "Некорректные данные") + }) + @PutMapping("/{id}") + public ResponseEntity updateUser(@Parameter(description = "ID пользователя") @PathVariable int id, @RequestBody User user) { + User existingUser = userController.GetUserById(id); + if (existingUser == null) { + return ResponseEntity.notFound().build(); + } + UserResult result = userController.UpdateUser(user); + if (result instanceof UserResult.Success) { + return ResponseEntity.ok(new UserDTO(user)); + } else { + return ResponseEntity.badRequest().body(result); + } + } + + @Operation(summary = "Удалить пользователя", description = "Удаляет пользователя по ID") + @ApiResponses(value = { + @ApiResponse(responseCode = "204", description = "Пользователь удален"), + @ApiResponse(responseCode = "404", description = "Пользователь не найден") + }) + @DeleteMapping("/{id}") + public ResponseEntity deleteUser(@Parameter(description = "ID пользователя") @PathVariable int id) { + User user = userController.GetUserById(id); + if (user == null) { + return ResponseEntity.notFound().build(); + } + UserResult result = userController.DeleteUser(user); + if (result instanceof UserResult.Success) { + return ResponseEntity.noContent().build(); + } else { + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(result); + } + } +} \ No newline at end of file diff --git a/Presentation/src/main/java/Presentation/DTO/UserDTO.java b/Presentation/src/main/java/Presentation/DTO/UserDTO.java new file mode 100644 index 0000000..0e8e74a --- /dev/null +++ b/Presentation/src/main/java/Presentation/DTO/UserDTO.java @@ -0,0 +1,19 @@ +package Presentation.DTO; + +import Application.Models.Entities.User; +import lombok.AllArgsConstructor; +import lombok.Getter; + +@AllArgsConstructor +@Getter +public class UserDTO { + private final Integer id; + private final String login; + private final String name; + + public UserDTO(User user) { + this.id = user.getId(); + this.login = user.getLogin(); + this.name = user.getName(); + } +} diff --git a/Presentation/src/main/java/Presentation/Interfaces/IUserController.java b/Presentation/src/main/java/Presentation/Interfaces/IUserController.java index ffb3ce3..14ae532 100644 --- a/Presentation/src/main/java/Presentation/Interfaces/IUserController.java +++ b/Presentation/src/main/java/Presentation/Interfaces/IUserController.java @@ -10,6 +10,8 @@ public interface IUserController { UserResult CreateUser(User user); + UserResult UpdateUser(User user); + User GetUserById(int id); BankAccount GetBankAccountById(int id); @@ -35,4 +37,6 @@ public interface IUserController { OperationResult Transfer(BankAccount bankAccount1, BankAccount bankAccount2, Double amount); OperationResult GetOperationHistory(int bankAccountId); + + UserResult DeleteUserById(int id); } diff --git a/pom.xml b/pom.xml index 790b8ce..3b6964c 100644 --- a/pom.xml +++ b/pom.xml @@ -83,12 +83,6 @@ spring-boot-starter-actuator - - - org.springframework.boot - spring-boot-starter-security - - org.springframework.boot @@ -96,13 +90,6 @@ test - - - org.springdoc - springdoc-openapi-starter-webmvc-ui - 2.0.2 - - From c569eb5d84b5ddaaf56284d8bacf866f84794052 Mon Sep 17 00:00:00 2001 From: Alexander Kim Date: Tue, 8 Apr 2025 01:59:41 +0300 Subject: [PATCH 3/6] feat: add REST API filters for users' data, operations and bank accounts --- .../Application/Managers/IUserManager.java | 24 +++++++ .../Application/Managers/UserManager.java | 2 +- .../Services/BankAccountService.java | 6 ++ .../Interfaces/IBankAccountService.java | 10 ++- .../Interfaces/IOperationService.java | 5 ++ .../Services/Interfaces/IUserService.java | 6 +- .../DataAccess/Services/OperationService.java | 5 ++ .../java/DataAccess/Services/UserService.java | 2 +- Presentation/pom.xml | 9 +-- .../java/Presentation/Configs/AppConfig.java | 9 +-- .../main/java/Presentation/Console/Menu.java | 3 +- .../Controllers/UserController.java | 66 +++++++++++++++-- .../Controllers/UserDTOController.java | 6 +- .../Controllers/UserDataController.java | 71 +++++++++++++++++++ .../java/Presentation/DTO/BankAccountDTO.java | 21 ++++++ .../java/Presentation/DTO/OperationDTO.java | 22 ++++++ .../main/java/Presentation/DTO/UserDTO.java | 22 +++++- .../Interfaces/IFlywayController.java | 1 + .../Interfaces/IUserController.java | 16 +++++ Presentation/src/test/java/BankTests.java | 21 +++--- 20 files changed, 288 insertions(+), 39 deletions(-) create mode 100644 Application/src/main/java/Application/Managers/IUserManager.java create mode 100644 Presentation/src/main/java/Presentation/Controllers/UserDataController.java create mode 100644 Presentation/src/main/java/Presentation/DTO/BankAccountDTO.java create mode 100644 Presentation/src/main/java/Presentation/DTO/OperationDTO.java diff --git a/Application/src/main/java/Application/Managers/IUserManager.java b/Application/src/main/java/Application/Managers/IUserManager.java new file mode 100644 index 0000000..70c5ce3 --- /dev/null +++ b/Application/src/main/java/Application/Managers/IUserManager.java @@ -0,0 +1,24 @@ +package Application.Managers; + +import Application.Models.Entities.BankAccount; +import Application.Models.Entities.Operation; +import Application.Models.Entities.User; +import Application.ResultTypes.OperationResult; + +import java.util.List; + +public interface IUserManager { + void GetUserInfo(User user); + + void AddFriend(User user, User other); + + void RemoveFriend(User user, User other); + + void AddBankAccount(User user, BankAccount bankAccount); + + void RemoveBankAccount(User user, BankAccount bankAccount); + + void CheckBalance(User user, BankAccount bankAccount); + + OperationResult PrintHistory(BankAccount account, List operations); +} diff --git a/Application/src/main/java/Application/Managers/UserManager.java b/Application/src/main/java/Application/Managers/UserManager.java index af4305c..d63b859 100644 --- a/Application/src/main/java/Application/Managers/UserManager.java +++ b/Application/src/main/java/Application/Managers/UserManager.java @@ -9,7 +9,7 @@ import java.util.List; @Component -public class UserManager { +public class UserManager implements IUserManager { public void GetUserInfo(User user) { diff --git a/DataAccess/src/main/java/DataAccess/Services/BankAccountService.java b/DataAccess/src/main/java/DataAccess/Services/BankAccountService.java index 9a3b55e..1bf8629 100644 --- a/DataAccess/src/main/java/DataAccess/Services/BankAccountService.java +++ b/DataAccess/src/main/java/DataAccess/Services/BankAccountService.java @@ -7,6 +7,7 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.util.List; import java.util.Optional; @Service @@ -81,4 +82,9 @@ public boolean Transfer(int accountFromId, int accountToId, double amount) { } return false; } + + @Override + public List GetAllAccounts() { + return this.BankAccountRepository.findAll(); + } } diff --git a/DataAccess/src/main/java/DataAccess/Services/Interfaces/IBankAccountService.java b/DataAccess/src/main/java/DataAccess/Services/Interfaces/IBankAccountService.java index 329ede3..708de5a 100644 --- a/DataAccess/src/main/java/DataAccess/Services/Interfaces/IBankAccountService.java +++ b/DataAccess/src/main/java/DataAccess/Services/Interfaces/IBankAccountService.java @@ -1,13 +1,21 @@ package DataAccess.Services.Interfaces; import Application.Models.Entities.BankAccount; -import org.springframework.stereotype.Service; + +import java.util.List; public interface IBankAccountService { BankAccount GetAccount(int id); + void UpdateAccount(BankAccount account); + void DeleteAccount(BankAccount account); + boolean Deposit(int accountId, double amount); + boolean Withdraw(int accountId, double amount); + boolean Transfer(int accountFromId, int accountToId, double amount); + + List GetAllAccounts(); } diff --git a/DataAccess/src/main/java/DataAccess/Services/Interfaces/IOperationService.java b/DataAccess/src/main/java/DataAccess/Services/Interfaces/IOperationService.java index ec28f93..7b0131e 100644 --- a/DataAccess/src/main/java/DataAccess/Services/Interfaces/IOperationService.java +++ b/DataAccess/src/main/java/DataAccess/Services/Interfaces/IOperationService.java @@ -6,7 +6,12 @@ public interface IOperationService { Operation GetOperation(int id); + void SaveOperation(Operation operation); + void DeleteOperation(Operation operation); + List FindAllOperationsByAccountId(int id); + + List FindAllOperations(); } diff --git a/DataAccess/src/main/java/DataAccess/Services/Interfaces/IUserService.java b/DataAccess/src/main/java/DataAccess/Services/Interfaces/IUserService.java index aceb3ae..6e3ead8 100644 --- a/DataAccess/src/main/java/DataAccess/Services/Interfaces/IUserService.java +++ b/DataAccess/src/main/java/DataAccess/Services/Interfaces/IUserService.java @@ -1,13 +1,15 @@ package DataAccess.Services.Interfaces; import Application.Models.Entities.User; -import org.springframework.stereotype.Service; import java.util.List; public interface IUserService { User GetUser(int id); + void SaveUser(User user); + void DeleteUser(User user); - List getAllUsers(); + + List GetAllUsers(); } diff --git a/DataAccess/src/main/java/DataAccess/Services/OperationService.java b/DataAccess/src/main/java/DataAccess/Services/OperationService.java index 6f28ae1..daa4d7a 100644 --- a/DataAccess/src/main/java/DataAccess/Services/OperationService.java +++ b/DataAccess/src/main/java/DataAccess/Services/OperationService.java @@ -36,4 +36,9 @@ public void DeleteOperation(Operation operation) { public List FindAllOperationsByAccountId(int id) { return OperationRepository.findAllByBankAccount_Id(id); } + + @Override + public List FindAllOperations() { + return OperationRepository.findAll(); + } } diff --git a/DataAccess/src/main/java/DataAccess/Services/UserService.java b/DataAccess/src/main/java/DataAccess/Services/UserService.java index a465191..b49d22a 100644 --- a/DataAccess/src/main/java/DataAccess/Services/UserService.java +++ b/DataAccess/src/main/java/DataAccess/Services/UserService.java @@ -33,7 +33,7 @@ public void DeleteUser(User user) { } @Override - public List getAllUsers() { + public List GetAllUsers() { return UserRepository.findAll(); } } diff --git a/Presentation/pom.xml b/Presentation/pom.xml index 03ea269..28318e0 100644 --- a/Presentation/pom.xml +++ b/Presentation/pom.xml @@ -22,20 +22,15 @@ - - org.junit.jupiter - junit-jupiter-api - 5.9.2 - test - org.junit.jupiter - junit-jupiter-engine + junit-jupiter 5.9.2 test + org.projectlombok diff --git a/Presentation/src/main/java/Presentation/Configs/AppConfig.java b/Presentation/src/main/java/Presentation/Configs/AppConfig.java index 805e639..81394c5 100644 --- a/Presentation/src/main/java/Presentation/Configs/AppConfig.java +++ b/Presentation/src/main/java/Presentation/Configs/AppConfig.java @@ -1,11 +1,12 @@ package Presentation.Configs; -import Application.Managers.UserManager; +import Application.Managers.IUserManager; import Presentation.Console.Menu; -import Presentation.Controllers.UserController; +import Presentation.Controllers.*; import DataAccess.Services.Interfaces.IBankAccountService; import DataAccess.Services.Interfaces.IOperationService; import DataAccess.Services.Interfaces.IUserService; +import Presentation.Interfaces.IUserController; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; @@ -22,7 +23,7 @@ public Scanner scanner() { @Bean public UserController userController( - UserManager userManager, + IUserManager userManager, IUserService userService, IBankAccountService bankAccountService, IOperationService operationService) { @@ -30,7 +31,7 @@ public UserController userController( } @Bean - public Menu menu(UserController userController, Scanner scanner) { + public Menu menu(IUserController userController, Scanner scanner) { return new Menu(userController, scanner); } } \ No newline at end of file diff --git a/Presentation/src/main/java/Presentation/Console/Menu.java b/Presentation/src/main/java/Presentation/Console/Menu.java index 148fcfa..564e76d 100644 --- a/Presentation/src/main/java/Presentation/Console/Menu.java +++ b/Presentation/src/main/java/Presentation/Console/Menu.java @@ -7,7 +7,6 @@ import Application.Models.Entities.User; import Application.Models.Enums.HairColor; import Application.Models.Enums.Sex; -import Presentation.Controllers.UserController; import Presentation.Interfaces.IMenu; import Presentation.Interfaces.IUserController; import org.springframework.beans.factory.annotation.Autowired; @@ -24,7 +23,7 @@ public class Menu implements IMenu { private final Scanner scanner; @Autowired - public Menu(UserController controller, Scanner scanner) { + public Menu(IUserController controller, Scanner scanner) { this.controller = controller; this.scanner = scanner; } diff --git a/Presentation/src/main/java/Presentation/Controllers/UserController.java b/Presentation/src/main/java/Presentation/Controllers/UserController.java index 0db2aae..d2f2ead 100644 --- a/Presentation/src/main/java/Presentation/Controllers/UserController.java +++ b/Presentation/src/main/java/Presentation/Controllers/UserController.java @@ -1,10 +1,12 @@ package Presentation.Controllers; -import Application.Managers.UserManager; +import Application.Managers.IUserManager; import Application.Models.Entities.BankAccount; import Application.Models.Entities.Operation; import Application.Models.Entities.User; +import Application.Models.Enums.HairColor; import Application.Models.Enums.OperationType; +import Application.Models.Enums.Sex; import Application.ResultTypes.BankAccountResult; import Application.ResultTypes.OperationResult; import Application.ResultTypes.UserResult; @@ -20,13 +22,13 @@ @Component public class UserController implements IUserController { - private final UserManager userManager; + private final IUserManager userManager; private final IUserService userService; private final IBankAccountService bankAccountService; private final IOperationService operationService; @Autowired - public UserController(UserManager userManager, IUserService userService, IBankAccountService bankAccountService, IOperationService operationService) { + public UserController(IUserManager userManager, IUserService userService, IBankAccountService bankAccountService, IOperationService operationService) { this.userManager = userManager; this.userService = userService; this.bankAccountService = bankAccountService; @@ -61,6 +63,58 @@ public User GetUserById(int id) { } } + @Override + public List GetAllUsersFiltered(Sex sex, HairColor color) { + List users = userService.GetAllUsers(); + return users.stream() + .filter(u -> (sex == null || u.getSex() == sex)) + .filter(u -> (color == null || u.getHairType() == color)) + .toList(); + } + + @Override + public List GetFriends(int userId) { + User user = userService.GetUser(userId); + if (user != null) { + return user.getFriends(); + } + return List.of(); + } + + @Override + public List GetUserBankAccounts(int userId) { + User user = userService.GetUser(userId); + if (user != null) { + return user.getBankAccounts(); + } + return List.of(); + } + + @Override + public List GetAllAccounts() { + return bankAccountService.GetAllAccounts(); + } + + @Override + public List GetFilteredOperations(OperationType type, Integer accountId) { + List operations; + + if (accountId != null) { + operations = operationService.FindAllOperationsByAccountId(accountId); + } else { + operations = operationService.FindAllOperations(); + } + + if (type != null) { + operations = operations.stream() + .filter(o -> o.getType().equalsIgnoreCase(type.toString())) + .toList(); + } + + return operations; + } + + @Override public BankAccount GetBankAccountById(int id) { try { @@ -142,7 +196,10 @@ public OperationResult CheckBalance(int userId, int accountId) { @Override public OperationResult Deposit(BankAccount bankAccount, Double amount) { try { - bankAccountService.Deposit(bankAccount.getId(), amount); + boolean success = bankAccountService.Deposit(bankAccount.getId(), amount); + if (!success) { + return new OperationResult.OperationError("Deposit failed."); + } operationService.SaveOperation(new Operation(bankAccount, OperationType.Deposit, amount)); return new OperationResult.Success(); } catch (Exception e) { @@ -216,5 +273,4 @@ public UserResult DeleteUserById(int id) { return new UserResult.UserDeletionError("Ошибка при удалении пользователя: " + e.getMessage()); } } - } diff --git a/Presentation/src/main/java/Presentation/Controllers/UserDTOController.java b/Presentation/src/main/java/Presentation/Controllers/UserDTOController.java index 0d83b79..cc271bc 100644 --- a/Presentation/src/main/java/Presentation/Controllers/UserDTOController.java +++ b/Presentation/src/main/java/Presentation/Controllers/UserDTOController.java @@ -3,6 +3,7 @@ import Application.Models.Entities.User; import Application.ResultTypes.UserResult; import Presentation.DTO.UserDTO; +import Presentation.Interfaces.IUserController; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.media.Content; @@ -18,9 +19,10 @@ @RequestMapping("/users") public class UserDTOController { - private final UserController userController; + private final IUserController userController; - public UserDTOController(UserController userController) { + @Autowired + public UserDTOController(IUserController userController) { this.userController = userController; } diff --git a/Presentation/src/main/java/Presentation/Controllers/UserDataController.java b/Presentation/src/main/java/Presentation/Controllers/UserDataController.java new file mode 100644 index 0000000..6b70a63 --- /dev/null +++ b/Presentation/src/main/java/Presentation/Controllers/UserDataController.java @@ -0,0 +1,71 @@ +package Presentation.Controllers; + +import Application.Models.Entities.BankAccount; +import Application.Models.Entities.Operation; +import Application.Models.Entities.User; +import Application.Models.Enums.HairColor; +import Application.Models.Enums.OperationType; +import Application.Models.Enums.Sex; +import Presentation.DTO.BankAccountDTO; +import Presentation.DTO.OperationDTO; +import Presentation.DTO.UserDTO; +import Presentation.Interfaces.IUserController; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +@RestController +@RequestMapping("/data") +public class UserDataController { + + private final IUserController userController; + + @Autowired + public UserDataController(IUserController userController) { + this.userController = userController; + } + + @GetMapping("/users") + public ResponseEntity> getAllUsersFiltered( + @RequestParam(required = false) Sex sex, + @RequestParam(required = false) HairColor hairColor + ) { + List users = userController.GetAllUsersFiltered(sex, hairColor); + List dtos = users.stream().map(UserDTO::new).toList(); + return ResponseEntity.ok(dtos); + } + + @GetMapping("/users/{id}/friends") + public ResponseEntity> getFriends(@PathVariable int id) { + List friends = userController.GetFriends(id); + List dtos = friends.stream().map(UserDTO::new).toList(); + return ResponseEntity.ok(dtos); + } + + @GetMapping("/users/{id}/accounts") + public ResponseEntity> getAccountsByUser(@PathVariable int id) { + List accounts = userController.GetUserBankAccounts(id); + List dtos = accounts.stream().map(BankAccountDTO::new).toList(); + return ResponseEntity.ok(dtos); + } + + @GetMapping("/accounts") + public ResponseEntity> getAllAccounts() { + List accounts = userController.GetAllAccounts(); + List dtos = accounts.stream().map(BankAccountDTO::new).toList(); + return ResponseEntity.ok(dtos); + } + + @GetMapping("/operations") + public ResponseEntity> getTransactions( + @RequestParam(required = false) OperationType type, + @RequestParam(required = false) Integer accountId + ) { + List txs = userController.GetFilteredOperations(type, accountId); + List dtos = txs.stream().map(OperationDTO::new).toList(); + return ResponseEntity.ok(dtos); + } +} + diff --git a/Presentation/src/main/java/Presentation/DTO/BankAccountDTO.java b/Presentation/src/main/java/Presentation/DTO/BankAccountDTO.java new file mode 100644 index 0000000..6039bc6 --- /dev/null +++ b/Presentation/src/main/java/Presentation/DTO/BankAccountDTO.java @@ -0,0 +1,21 @@ +package Presentation.DTO; + +import Application.Models.Entities.BankAccount; +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +public class BankAccountDTO { + private final Integer id; + private final Double balance; + private final String userLogin; + private final Integer userId; + + public BankAccountDTO(BankAccount account) { + this.id = account.getId(); + this.balance = account.getBalance(); + this.userLogin = account.getUserLogin(); + this.userId = account.getUser() != null ? account.getUser().getId() : null; + } +} diff --git a/Presentation/src/main/java/Presentation/DTO/OperationDTO.java b/Presentation/src/main/java/Presentation/DTO/OperationDTO.java new file mode 100644 index 0000000..b1a3408 --- /dev/null +++ b/Presentation/src/main/java/Presentation/DTO/OperationDTO.java @@ -0,0 +1,22 @@ +package Presentation.DTO; + +import Application.Models.Entities.Operation; +import Application.Models.Enums.OperationType; +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +public class OperationDTO { + private final Integer id; + private final OperationType type; + private final Double amount; + private final Integer accountId; + + public OperationDTO(Operation operation) { + this.id = operation.getId(); + this.amount = operation.getAmount(); + this.type = OperationType.valueOf(operation.getType()); + this.accountId = operation.getBankAccount().getId(); + } +} diff --git a/Presentation/src/main/java/Presentation/DTO/UserDTO.java b/Presentation/src/main/java/Presentation/DTO/UserDTO.java index 0e8e74a..acbe7b5 100644 --- a/Presentation/src/main/java/Presentation/DTO/UserDTO.java +++ b/Presentation/src/main/java/Presentation/DTO/UserDTO.java @@ -1,19 +1,39 @@ package Presentation.DTO; +import Application.Models.Entities.BankAccount; import Application.Models.Entities.User; +import Application.Models.Enums.HairColor; +import Application.Models.Enums.Sex; import lombok.AllArgsConstructor; import lombok.Getter; -@AllArgsConstructor +import java.util.List; +import java.util.stream.Collectors; + @Getter +@AllArgsConstructor public class UserDTO { private final Integer id; private final String login; private final String name; + private final Integer age; + private final Sex sex; + private final HairColor hairType; + private final List friendIds; + private final List bankAccountIds; public UserDTO(User user) { this.id = user.getId(); this.login = user.getLogin(); this.name = user.getName(); + this.age = user.getAge(); + this.sex = user.getSex(); + this.hairType = user.getHairType(); + this.friendIds = user.getFriends().stream() + .map(User::getId) + .collect(Collectors.toList()); + this.bankAccountIds = user.getBankAccounts().stream() + .map(BankAccount::getId) + .collect(Collectors.toList()); } } diff --git a/Presentation/src/main/java/Presentation/Interfaces/IFlywayController.java b/Presentation/src/main/java/Presentation/Interfaces/IFlywayController.java index 0d847ed..4c7e55e 100644 --- a/Presentation/src/main/java/Presentation/Interfaces/IFlywayController.java +++ b/Presentation/src/main/java/Presentation/Interfaces/IFlywayController.java @@ -2,5 +2,6 @@ public interface IFlywayController { void FlywayInit(); + void FlywayMigrate(); } diff --git a/Presentation/src/main/java/Presentation/Interfaces/IUserController.java b/Presentation/src/main/java/Presentation/Interfaces/IUserController.java index 14ae532..526ea14 100644 --- a/Presentation/src/main/java/Presentation/Interfaces/IUserController.java +++ b/Presentation/src/main/java/Presentation/Interfaces/IUserController.java @@ -1,11 +1,17 @@ package Presentation.Interfaces; +import Application.Models.Entities.Operation; +import Application.Models.Enums.HairColor; +import Application.Models.Enums.OperationType; +import Application.Models.Enums.Sex; import Application.ResultTypes.BankAccountResult; import Application.ResultTypes.OperationResult; import Application.ResultTypes.UserResult; import Application.Models.Entities.BankAccount; import Application.Models.Entities.User; +import java.util.List; + public interface IUserController { UserResult CreateUser(User user); @@ -14,6 +20,16 @@ public interface IUserController { User GetUserById(int id); + List GetAllUsersFiltered(Sex sex, HairColor color); + + List GetFriends(int userId); + + List GetUserBankAccounts(int userId); + + List GetAllAccounts(); + + List GetFilteredOperations(OperationType type, Integer accountId); + BankAccount GetBankAccountById(int id); UserResult DeleteUser(User user); diff --git a/Presentation/src/test/java/BankTests.java b/Presentation/src/test/java/BankTests.java index 9752158..bb015bc 100644 --- a/Presentation/src/test/java/BankTests.java +++ b/Presentation/src/test/java/BankTests.java @@ -1,31 +1,26 @@ -import Application.Managers.UserManager; import Application.ResultTypes.OperationResult; import Application.Models.Entities.BankAccount; import Application.Models.Entities.User; import Application.Models.Enums.HairColor; import Application.Models.Enums.Sex; -import Presentation.Controllers.UserController; import DataAccess.Services.BankAccountService; import DataAccess.Services.OperationService; -import DataAccess.Services.UserService; +import Presentation.Controllers.*; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.mockito.junit.jupiter.MockitoExtension; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertInstanceOf; import static org.mockito.Mockito.*; +@ExtendWith(MockitoExtension.class) public class BankTests { - @Mock - private UserManager userManager; - - @Mock - private UserService UserService; - @Mock private BankAccountService bankAccountService; @@ -48,7 +43,7 @@ void setUp() { } @Test - void testWithdrawWithSufficientBalance() { + public void testWithdrawWithSufficientBalance() { double withdrawAmount = 50.0; when(bankAccountService.Withdraw(bankAccount.getId(), withdrawAmount)).thenReturn(true); doNothing().when(operationService).SaveOperation(any()); @@ -61,7 +56,7 @@ void testWithdrawWithSufficientBalance() { } @Test - void testWithdrawWithInsufficientBalance() { + public void testWithdrawWithInsufficientBalance() { double withdrawAmount = 150.0; when(bankAccountService.Withdraw(bankAccount.getId(), withdrawAmount)).thenReturn(false); @@ -70,11 +65,11 @@ void testWithdrawWithInsufficientBalance() { assertInstanceOf(OperationResult.OperationError.class, operationResult); assertEquals("Not enough balance.", ((OperationResult.OperationError) operationResult).getMessage()); verify(bankAccountService, times(1)).Withdraw(bankAccount.getId(), withdrawAmount); - verify(operationService, times(0)).SaveOperation(any()); // SaveOperation не должен вызываться + verify(operationService, times(0)).SaveOperation(any()); } @Test - void testDeposit() { + public void testDeposit() { double depositAmount = 100.0; when(bankAccountService.Deposit(bankAccount.getId(), depositAmount)).thenReturn(true); doNothing().when(operationService).SaveOperation(any()); From 2371ad08868066263c6dd13c938a0a2bf8752da8 Mon Sep 17 00:00:00 2001 From: Alexander Kim Date: Tue, 8 Apr 2025 21:42:58 +0300 Subject: [PATCH 4/6] fix: repair tests build; configure maven-surefire-plugin --- Presentation/pom.xml | 4 ++-- Presentation/src/test/java/BankTests.java | 20 ++++++++++++++------ 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/Presentation/pom.xml b/Presentation/pom.xml index 28318e0..310d0e3 100644 --- a/Presentation/pom.xml +++ b/Presentation/pom.xml @@ -26,7 +26,7 @@ org.junit.jupiter junit-jupiter - 5.9.2 + 5.10.0 test @@ -131,7 +131,7 @@ org.apache.maven.plugins maven-surefire-plugin - 2.21.0 + 3.0.0-M9 org.junit.jupiter diff --git a/Presentation/src/test/java/BankTests.java b/Presentation/src/test/java/BankTests.java index bb015bc..716fa40 100644 --- a/Presentation/src/test/java/BankTests.java +++ b/Presentation/src/test/java/BankTests.java @@ -1,17 +1,19 @@ +import Application.Managers.UserManager; import Application.ResultTypes.OperationResult; import Application.Models.Entities.BankAccount; import Application.Models.Entities.User; import Application.Models.Enums.HairColor; import Application.Models.Enums.Sex; import DataAccess.Services.BankAccountService; +import DataAccess.Services.Interfaces.IUserService; import DataAccess.Services.OperationService; import Presentation.Controllers.*; +import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; import org.mockito.Mock; -import org.mockito.MockitoAnnotations; import org.mockito.junit.jupiter.MockitoExtension; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -27,21 +29,27 @@ public class BankTests { @Mock private OperationService operationService; + @Mock + private UserManager userManager; + + @Mock + private IUserService userService; + @InjectMocks private UserController userController; - private BankAccount bankAccount; - private User user; + private static BankAccount bankAccount; + private static User user; - @BeforeEach - void setUp() { - MockitoAnnotations.initMocks(this); + @BeforeAll + static void init() { user = new User("lim0sha", "Sasha", 22, Sex.Male, HairColor.Brown); bankAccount = new BankAccount(user); bankAccount.setId(1); bankAccount.setBalance(100.0); } + @Test public void testWithdrawWithSufficientBalance() { double withdrawAmount = 50.0; From e4e847c35e0abdf70e06b71f3d4218cc6a976ed6 Mon Sep 17 00:00:00 2001 From: Alexander Kim Date: Tue, 8 Apr 2025 21:58:03 +0300 Subject: [PATCH 5/6] feat: add API responses for UserDataController --- .../Controllers/UserDataController.java | 49 +++++++++++++++---- 1 file changed, 40 insertions(+), 9 deletions(-) diff --git a/Presentation/src/main/java/Presentation/Controllers/UserDataController.java b/Presentation/src/main/java/Presentation/Controllers/UserDataController.java index 6b70a63..cc677e8 100644 --- a/Presentation/src/main/java/Presentation/Controllers/UserDataController.java +++ b/Presentation/src/main/java/Presentation/Controllers/UserDataController.java @@ -1,7 +1,6 @@ package Presentation.Controllers; import Application.Models.Entities.BankAccount; -import Application.Models.Entities.Operation; import Application.Models.Entities.User; import Application.Models.Enums.HairColor; import Application.Models.Enums.OperationType; @@ -10,6 +9,12 @@ import Presentation.DTO.OperationDTO; import Presentation.DTO.UserDTO; import Presentation.Interfaces.IUserController; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; @@ -27,30 +32,52 @@ public UserDataController(IUserController userController) { this.userController = userController; } + @Operation(summary = "Получить всех пользователей с фильтрами", description = "Возвращает список пользователей, отфильтрованных по полу и цвету волос") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Список пользователей", content = @Content(mediaType = "application/json", schema = @Schema(implementation = UserDTO.class))), + @ApiResponse(responseCode = "400", description = "Некорректные параметры запроса") + }) @GetMapping("/users") public ResponseEntity> getAllUsersFiltered( - @RequestParam(required = false) Sex sex, - @RequestParam(required = false) HairColor hairColor + @Parameter(description = "Пол пользователя") @RequestParam(required = false) Sex sex, + @Parameter(description = "Цвет волос пользователя") @RequestParam(required = false) HairColor hairColor ) { List users = userController.GetAllUsersFiltered(sex, hairColor); List dtos = users.stream().map(UserDTO::new).toList(); return ResponseEntity.ok(dtos); } + @Operation(summary = "Получить друзей пользователя", description = "Возвращает список друзей по ID пользователя") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Список друзей", content = @Content(mediaType = "application/json", schema = @Schema(implementation = UserDTO.class))), + @ApiResponse(responseCode = "404", description = "Пользователь не найден"), + @ApiResponse(responseCode = "400", description = "Некорректный ID пользователя") + }) @GetMapping("/users/{id}/friends") - public ResponseEntity> getFriends(@PathVariable int id) { + public ResponseEntity> getFriends(@Parameter(description = "ID пользователя") @PathVariable int id) { List friends = userController.GetFriends(id); List dtos = friends.stream().map(UserDTO::new).toList(); return ResponseEntity.ok(dtos); } + @Operation(summary = "Получить банковские счета пользователя", description = "Возвращает все банковские счета, принадлежащие пользователю по ID") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Список счетов", content = @Content(mediaType = "application/json", schema = @Schema(implementation = BankAccountDTO.class))), + @ApiResponse(responseCode = "404", description = "Пользователь не найден"), + @ApiResponse(responseCode = "400", description = "Некорректный ID пользователя") + }) @GetMapping("/users/{id}/accounts") - public ResponseEntity> getAccountsByUser(@PathVariable int id) { + public ResponseEntity> getAccountsByUser(@Parameter(description = "ID пользователя") @PathVariable int id) { List accounts = userController.GetUserBankAccounts(id); List dtos = accounts.stream().map(BankAccountDTO::new).toList(); return ResponseEntity.ok(dtos); } + @Operation(summary = "Получить все банковские счета", description = "Возвращает список всех банковских счетов в системе") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Список счетов", content = @Content(mediaType = "application/json", schema = @Schema(implementation = BankAccountDTO.class))), + @ApiResponse(responseCode = "400", description = "Ошибка при обработке запроса") + }) @GetMapping("/accounts") public ResponseEntity> getAllAccounts() { List accounts = userController.GetAllAccounts(); @@ -58,14 +85,18 @@ public ResponseEntity> getAllAccounts() { return ResponseEntity.ok(dtos); } + @Operation(summary = "Получить операции (транзакции)", description = "Возвращает список операций с фильтрацией по типу и ID счета") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Список операций", content = @Content(mediaType = "application/json", schema = @Schema(implementation = OperationDTO.class))), + @ApiResponse(responseCode = "400", description = "Некорректные параметры запроса") + }) @GetMapping("/operations") public ResponseEntity> getTransactions( - @RequestParam(required = false) OperationType type, - @RequestParam(required = false) Integer accountId + @Parameter(description = "Тип операции (Deposit, Withdraw, Transfer)") @RequestParam(required = false) OperationType type, + @Parameter(description = "ID банковского счета") @RequestParam(required = false) Integer accountId ) { - List txs = userController.GetFilteredOperations(type, accountId); + List txs = userController.GetFilteredOperations(type, accountId); List dtos = txs.stream().map(OperationDTO::new).toList(); return ResponseEntity.ok(dtos); } } - From 0335952f79479309b88792aa122483db06bae9f7 Mon Sep 17 00:00:00 2001 From: Alexander Kim Date: Tue, 15 Apr 2025 21:53:11 +0300 Subject: [PATCH 6/6] fix: remove prints in UserManager; remove FlywayController; feat: add BankAccountDTOController + minor fixes --- .../Application/Managers/IUserManager.java | 9 -- .../Application/Managers/UserManager.java | 56 +-------- .../Application/Models/Entities/User.java | 3 +- .../Services/BankAccountService.java | 5 +- .../java/Presentation/Configs/AppConfig.java | 12 +- .../Presentation/Configs/AppInitializer.java | 9 +- .../main/java/Presentation/Console/Menu.java | 63 ++++------ .../Controllers/BankAccountDTOController.java | 111 ++++++++++++++++++ ...serController.java => BaseController.java} | 45 ++++--- .../Controllers/FlywayController.java | 23 ---- .../Controllers/UserDTOController.java | 20 ++-- .../Controllers/UserDataController.java | 18 +-- ...erController.java => IBaseController.java} | 12 +- .../Interfaces/IFlywayController.java | 7 -- Presentation/src/test/java/BankTests.java | 9 +- 15 files changed, 198 insertions(+), 204 deletions(-) create mode 100644 Presentation/src/main/java/Presentation/Controllers/BankAccountDTOController.java rename Presentation/src/main/java/Presentation/Controllers/{UserController.java => BaseController.java} (91%) delete mode 100644 Presentation/src/main/java/Presentation/Controllers/FlywayController.java rename Presentation/src/main/java/Presentation/Interfaces/{IUserController.java => IBaseController.java} (86%) delete mode 100644 Presentation/src/main/java/Presentation/Interfaces/IFlywayController.java diff --git a/Application/src/main/java/Application/Managers/IUserManager.java b/Application/src/main/java/Application/Managers/IUserManager.java index 70c5ce3..12f95a3 100644 --- a/Application/src/main/java/Application/Managers/IUserManager.java +++ b/Application/src/main/java/Application/Managers/IUserManager.java @@ -1,14 +1,9 @@ package Application.Managers; import Application.Models.Entities.BankAccount; -import Application.Models.Entities.Operation; import Application.Models.Entities.User; -import Application.ResultTypes.OperationResult; - -import java.util.List; public interface IUserManager { - void GetUserInfo(User user); void AddFriend(User user, User other); @@ -17,8 +12,4 @@ public interface IUserManager { void AddBankAccount(User user, BankAccount bankAccount); void RemoveBankAccount(User user, BankAccount bankAccount); - - void CheckBalance(User user, BankAccount bankAccount); - - OperationResult PrintHistory(BankAccount account, List operations); } diff --git a/Application/src/main/java/Application/Managers/UserManager.java b/Application/src/main/java/Application/Managers/UserManager.java index d63b859..61318fd 100644 --- a/Application/src/main/java/Application/Managers/UserManager.java +++ b/Application/src/main/java/Application/Managers/UserManager.java @@ -1,49 +1,12 @@ package Application.Managers; -import Application.ResultTypes.OperationResult; import Application.Models.Entities.BankAccount; -import Application.Models.Entities.Operation; import Application.Models.Entities.User; import org.springframework.stereotype.Component; -import java.util.List; - @Component public class UserManager implements IUserManager { - public void GetUserInfo(User user) { - - if (user == null) { - System.out.println("Пользователь с ID: [null] не найден."); - return; - } - - System.out.println("ID: " + user.getId()); - System.out.println("Логин: " + user.getLogin()); - System.out.println("Имя: " + user.getName()); - System.out.println("Возраст: " + user.getAge()); - System.out.println("Пол: " + user.getSex()); - System.out.println("Цвет волос: " + user.getHairType()); - - System.out.println("\nБанковские счета:"); - if (user.getBankAccounts().isEmpty()) { - System.out.println("Нет привязанных счетов."); - } else { - for (BankAccount account : user.getBankAccounts()) { - System.out.println("ID счета: " + account.getId() + ", Баланс: " + account.getBalance()); - } - } - - System.out.println("\nДрузья:"); - if (user.getFriends().isEmpty()) { - System.out.println("Нет друзей."); - } else { - for (User friend : user.getFriends()) { - System.out.println("ID друга: " + friend.getId() + ", Имя: " + friend.getName()); - } - } - } - public void AddFriend(User user, User other) { user.getFriends().add(other); other.getFriends().add(user); @@ -56,27 +19,10 @@ public void RemoveFriend(User user, User other) { public void AddBankAccount(User user, BankAccount bankAccount) { user.getBankAccounts().add(bankAccount); + bankAccount.setUser(user); } public void RemoveBankAccount(User user, BankAccount bankAccount) { user.getBankAccounts().remove(bankAccount.getId()); } - - public void CheckBalance(User user, BankAccount bankAccount) { - System.out.println("User: " + user.getId()); - System.out.println("BankAccount: " + bankAccount.getId()); - System.out.println("Balance: " + bankAccount.getBalance()); - } - - public OperationResult PrintHistory(BankAccount account, List operations) { - if (operations == null) { - return new OperationResult.OperationError("Operations can not be null."); - } else { - System.out.println("Account Id: " + account.getId()); - for (Operation operation : operations) { - System.out.println("Operation: " + operation.getType() + "Amount: " + operation.getAmount()); - } - return new OperationResult.Success(); - } - } } diff --git a/Application/src/main/java/Application/Models/Entities/User.java b/Application/src/main/java/Application/Models/Entities/User.java index 356ffcb..7d23605 100644 --- a/Application/src/main/java/Application/Models/Entities/User.java +++ b/Application/src/main/java/Application/Models/Entities/User.java @@ -33,7 +33,8 @@ public class User { @Column(name = "haircolor") private HairColor hairType; - @OneToMany(mappedBy = "user", cascade = CascadeType.REMOVE, orphanRemoval = true, fetch = FetchType.EAGER) + @OneToMany(mappedBy = "user", cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REMOVE} + , orphanRemoval = true, fetch = FetchType.EAGER) private List bankAccounts = new ArrayList<>(); @ManyToMany(fetch = FetchType.EAGER) diff --git a/DataAccess/src/main/java/DataAccess/Services/BankAccountService.java b/DataAccess/src/main/java/DataAccess/Services/BankAccountService.java index 1bf8629..11619e1 100644 --- a/DataAccess/src/main/java/DataAccess/Services/BankAccountService.java +++ b/DataAccess/src/main/java/DataAccess/Services/BankAccountService.java @@ -25,8 +25,11 @@ public BankAccount GetAccount(int id) { } @Override + @Transactional public void UpdateAccount(BankAccount account) { - BankAccountRepository.save(account); + if (account != null) { + BankAccountRepository.save(account); + } } @Override diff --git a/Presentation/src/main/java/Presentation/Configs/AppConfig.java b/Presentation/src/main/java/Presentation/Configs/AppConfig.java index 81394c5..c9d1f91 100644 --- a/Presentation/src/main/java/Presentation/Configs/AppConfig.java +++ b/Presentation/src/main/java/Presentation/Configs/AppConfig.java @@ -2,11 +2,11 @@ import Application.Managers.IUserManager; import Presentation.Console.Menu; -import Presentation.Controllers.*; import DataAccess.Services.Interfaces.IBankAccountService; import DataAccess.Services.Interfaces.IOperationService; import DataAccess.Services.Interfaces.IUserService; -import Presentation.Interfaces.IUserController; +import Presentation.Interfaces.IBaseController; +import Presentation.Controllers.BaseController; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; @@ -22,16 +22,16 @@ public Scanner scanner() { } @Bean - public UserController userController( + public BaseController baseController( IUserManager userManager, IUserService userService, IBankAccountService bankAccountService, IOperationService operationService) { - return new UserController(userManager, userService, bankAccountService, operationService); + return new BaseController(userManager, userService, bankAccountService, operationService); } @Bean - public Menu menu(IUserController userController, Scanner scanner) { - return new Menu(userController, scanner); + public Menu menu(IBaseController baseController, Scanner scanner) { + return new Menu(baseController, scanner); } } \ No newline at end of file diff --git a/Presentation/src/main/java/Presentation/Configs/AppInitializer.java b/Presentation/src/main/java/Presentation/Configs/AppInitializer.java index 46ba630..622be4a 100644 --- a/Presentation/src/main/java/Presentation/Configs/AppInitializer.java +++ b/Presentation/src/main/java/Presentation/Configs/AppInitializer.java @@ -1,6 +1,5 @@ package Presentation.Configs; -import Presentation.Interfaces.IFlywayController; import Presentation.Interfaces.IMenu; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.CommandLineRunner; @@ -9,19 +8,15 @@ @Component public class AppInitializer implements CommandLineRunner { - private final IFlywayController flywayController; private final IMenu menu; @Autowired - public AppInitializer(IFlywayController flywayController, IMenu menu) { - this.flywayController = flywayController; + public AppInitializer(IMenu menu) { this.menu = menu; } @Override public void run(String... args) { - flywayController.FlywayInit(); - flywayController.FlywayMigrate(); - menu.Run(); + // menu.Run(); } } \ No newline at end of file diff --git a/Presentation/src/main/java/Presentation/Console/Menu.java b/Presentation/src/main/java/Presentation/Console/Menu.java index 564e76d..dc46e4c 100644 --- a/Presentation/src/main/java/Presentation/Console/Menu.java +++ b/Presentation/src/main/java/Presentation/Console/Menu.java @@ -8,7 +8,7 @@ import Application.Models.Enums.HairColor; import Application.Models.Enums.Sex; import Presentation.Interfaces.IMenu; -import Presentation.Interfaces.IUserController; +import Presentation.Interfaces.IBaseController; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.ComponentScan; import org.springframework.stereotype.Component; @@ -19,12 +19,12 @@ @ComponentScan(basePackages = "Presentation") public class Menu implements IMenu { - private final IUserController controller; + private final IBaseController baseController; private final Scanner scanner; @Autowired - public Menu(IUserController controller, Scanner scanner) { - this.controller = controller; + public Menu(IBaseController baseController, Scanner scanner) { + this.baseController = baseController; this.scanner = scanner; } @@ -48,13 +48,11 @@ public void Run() { switch (choice) { case 1 -> createUser(); - case 2 -> getUserInfo(); - case 3 -> manageFriends(); - case 4 -> createBankAccount(); - case 5 -> checkBalance(); - case 6 -> withdraw(); - case 7 -> deposit(); - case 8 -> transfer(); + case 2 -> manageFriends(); + case 3 -> createBankAccount(); + case 4 -> withdraw(); + case 5 -> deposit(); + case 6 -> transfer(); case 0 -> { System.out.println("Выход..."); return; @@ -144,7 +142,7 @@ private void createUser() { User user = new User(login, name, age, sex, hairColor); - UserResult result = controller.CreateUser(user); + UserResult result = baseController.CreateUser(user); if (result instanceof UserResult.Success) { System.out.println("Пользователь создан!"); } else { @@ -152,12 +150,6 @@ private void createUser() { } } - private void getUserInfo() { - System.out.print("Введите ID пользователя: "); - int userId = scanner.nextInt(); - controller.GetUserInfo(userId); - } - private void manageFriends() { System.out.print("Введите ID пользователя: "); int userId = scanner.nextInt(); @@ -168,10 +160,10 @@ private void manageFriends() { int action = scanner.nextInt(); if (action == 1) { - controller.AddFriend(userId, friendId); + baseController.AddFriend(userId, friendId); System.out.println("Друг добавлен."); } else if (action == 2) { - controller.RemoveFriend(userId, friendId); + baseController.RemoveFriend(userId, friendId); System.out.println("Друг удален."); } else { System.out.println("Неверная команда."); @@ -184,14 +176,14 @@ private void manageFriends() { private void createBankAccount() { System.out.print("Введите ID пользователя: "); int userId = scanner.nextInt(); - User user = controller.GetUserById(userId); + User user = baseController.GetUserById(userId); if (user == null) { System.out.println("Пользователь с ID " + userId + " не найден."); return; } BankAccount account = new BankAccount(user); - BankAccountResult result = controller.addBankAccount(userId, account); + BankAccountResult result = baseController.AddBankAccount(userId, account); if (result instanceof BankAccountResult.Success) { System.out.println("Счет создан!"); } else { @@ -199,28 +191,15 @@ private void createBankAccount() { } } - private void checkBalance() { - System.out.print("Введите ID счета: "); - int accountId = scanner.nextInt(); - BankAccount account = controller.GetBankAccountById(accountId); - - if (account == null) { - System.out.println("Счет не найден."); - return; - } - - controller.CheckBalance(account.getUser().getId(), accountId); - } - private void withdraw() { System.out.print("Введите ID счета: "); int accountId = scanner.nextInt(); System.out.print("Введите сумму снятия: "); double amount = scanner.nextDouble(); - BankAccount account = controller.GetBankAccountById(accountId); + BankAccount account = baseController.GetBankAccountById(accountId); if (account != null) { - OperationResult result = controller.Withdraw(account, amount); + OperationResult result = baseController.Withdraw(account, amount); if (result instanceof OperationResult.Success) { System.out.println("Деньги сняты."); @@ -238,9 +217,9 @@ private void deposit() { System.out.print("Введите сумму пополнения: "); double amount = scanner.nextDouble(); - BankAccount account = controller.GetBankAccountById(accountId); + BankAccount account = baseController.GetBankAccountById(accountId); if (account != null) { - OperationResult result = controller.Deposit(account, amount); + OperationResult result = baseController.Deposit(account, amount); if (result instanceof OperationResult.Success) { System.out.println("Счет пополнен."); } else if (result instanceof OperationResult.OperationError error) { @@ -262,11 +241,11 @@ private void transfer() { System.out.print("Введите сумму перевода: "); double amount = Double.parseDouble(scanner.nextLine().trim().replace(',', '.')); - BankAccount fromAccount = controller.GetBankAccountById(fromId); - BankAccount toAccount = controller.GetBankAccountById(toId); + BankAccount fromAccount = baseController.GetBankAccountById(fromId); + BankAccount toAccount = baseController.GetBankAccountById(toId); if (fromAccount != null && toAccount != null) { - OperationResult result = controller.Transfer(fromAccount, toAccount, amount); + OperationResult result = baseController.Transfer(fromAccount, toAccount, amount); if (result instanceof OperationResult.Success) { System.out.println("Перевод выполнен."); } else if (result instanceof OperationResult.OperationError error) { diff --git a/Presentation/src/main/java/Presentation/Controllers/BankAccountDTOController.java b/Presentation/src/main/java/Presentation/Controllers/BankAccountDTOController.java new file mode 100644 index 0000000..be441f4 --- /dev/null +++ b/Presentation/src/main/java/Presentation/Controllers/BankAccountDTOController.java @@ -0,0 +1,111 @@ +package Presentation.Controllers; + +import Application.Models.Entities.BankAccount; +import Application.ResultTypes.BankAccountResult; +import Presentation.DTO.BankAccountDTO; +import Presentation.Interfaces.IBaseController; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + + +@RestController +@RequestMapping("/bankaccounts") +public class BankAccountDTOController { + + private final IBaseController baseController; + + @Autowired + public BankAccountDTOController(IBaseController baseController) { + this.baseController = baseController; + } + + @Operation(summary = "Получить счет по ID", description = "Получает информацию о счете по ID") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Счет найден", content = @Content(mediaType = "application/json", schema = @Schema(implementation = BankAccountDTO.class))), + @ApiResponse(responseCode = "404", description = "Счет не найден") + }) + @GetMapping("/{id}") + public ResponseEntity getBankAccountById(@Parameter(description = "ID счета") @PathVariable int id) { + BankAccount account = baseController.GetBankAccountById(id); + if (account == null) { + return ResponseEntity.notFound().build(); + } + return ResponseEntity.ok(new BankAccountDTO(account)); + } + + @Operation(summary = "Создать новый счет", description = "Создает новый счет") + @ApiResponses(value = { + @ApiResponse(responseCode = "201", description = "Счет создан"), + @ApiResponse(responseCode = "400", description = "Некорректные данные") + }) + @PostMapping(consumes = "application/json", produces = "application/json") + public ResponseEntity createBankAccount(@RequestBody BankAccount account) { + try { + account.setId(null); + BankAccountResult result = baseController.AddBankAccount(account.getUser().getId(), account); + if (result instanceof BankAccountResult.Success) { + return ResponseEntity.status(HttpStatus.CREATED).body(result); + } else { + return ResponseEntity.badRequest().body(result); + } + } catch (Exception e) { + e.printStackTrace(); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(e.getMessage()); + } + } + + + + @Operation(summary = "Обновить данные счета", description = "Обновляет данные о счете по ID") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Счет обновлен", content = @Content(mediaType = "application/json", schema = @Schema(implementation = BankAccountDTO.class))), + @ApiResponse(responseCode = "404", description = "Счет не найден"), + @ApiResponse(responseCode = "400", description = "Некорректные данные") + }) + @PutMapping("/{id}") + public ResponseEntity updateBankAccount(@Parameter(description = "ID счета") @PathVariable int id, + @RequestBody BankAccount bankAccount) { + BankAccount existingAccount = baseController.GetBankAccountById(id); + if (existingAccount == null) { + return ResponseEntity.notFound().build(); + } + + existingAccount.setBalance(bankAccount.getBalance()); + existingAccount.setUser(bankAccount.getUser()); + + BankAccountResult result = baseController.UpdateBankAccount(existingAccount); + if (result instanceof BankAccountResult.Success) { + return ResponseEntity.ok(new BankAccountDTO(existingAccount)); + } else { + return ResponseEntity.badRequest().body(result); + } + } + + + @Operation(summary = "Удалить счет", description = "Удаляет счет по ID") + @ApiResponses(value = { + @ApiResponse(responseCode = "204", description = "Счет удален"), + @ApiResponse(responseCode = "404", description = "Счет не найден") + }) + @DeleteMapping("/{id}") + public ResponseEntity deleteBankAccount(@Parameter(description = "ID счета") @PathVariable int id) { + BankAccount account = baseController.GetBankAccountById(id); + if (account == null) { + return ResponseEntity.notFound().build(); + } + BankAccountResult result = baseController.RemoveBankAccount(account.getUser().getId(), account); + if (result instanceof BankAccountResult.Success) { + return ResponseEntity.noContent().build(); + } else { + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(result); + } + } +} diff --git a/Presentation/src/main/java/Presentation/Controllers/UserController.java b/Presentation/src/main/java/Presentation/Controllers/BaseController.java similarity index 91% rename from Presentation/src/main/java/Presentation/Controllers/UserController.java rename to Presentation/src/main/java/Presentation/Controllers/BaseController.java index d2f2ead..06cc749 100644 --- a/Presentation/src/main/java/Presentation/Controllers/UserController.java +++ b/Presentation/src/main/java/Presentation/Controllers/BaseController.java @@ -10,7 +10,7 @@ import Application.ResultTypes.BankAccountResult; import Application.ResultTypes.OperationResult; import Application.ResultTypes.UserResult; -import Presentation.Interfaces.IUserController; +import Presentation.Interfaces.IBaseController; import DataAccess.Services.Interfaces.IBankAccountService; import DataAccess.Services.Interfaces.IOperationService; import DataAccess.Services.Interfaces.IUserService; @@ -20,7 +20,7 @@ import java.util.List; @Component -public class UserController implements IUserController { +public class BaseController implements IBaseController { private final IUserManager userManager; private final IUserService userService; @@ -28,7 +28,7 @@ public class UserController implements IUserController { private final IOperationService operationService; @Autowired - public UserController(IUserManager userManager, IUserService userService, IBankAccountService bankAccountService, IOperationService operationService) { + public BaseController(IUserManager userManager, IUserService userService, IBankAccountService bankAccountService, IOperationService operationService) { this.userManager = userManager; this.userService = userService; this.bankAccountService = bankAccountService; @@ -134,11 +134,6 @@ public UserResult DeleteUser(User user) { } } - @Override - public void GetUserInfo(int id) { - userManager.GetUserInfo(userService.GetUser(id)); - } - @Override public void AddFriend(int userId, int otherId) { User user1 = userService.GetUser(userId); @@ -158,25 +153,41 @@ public void RemoveFriend(int userId, int otherId) { } @Override - public BankAccountResult addBankAccount(int userId, BankAccount bankAccount) { + public BankAccountResult AddBankAccount(int userId, BankAccount bankAccount) { try { User user = userService.GetUser(userId); + if (user == null) { + throw new IllegalStateException("User not found"); + } + bankAccount.setId(null); userManager.AddBankAccount(user, bankAccount); userService.SaveUser(user); - bankAccountService.UpdateAccount(bankAccount); return new BankAccountResult.Success(); } catch (Exception e) { return new BankAccountResult.BankAccountCreationError(e.getMessage()); } } + @Override + public BankAccountResult UpdateBankAccount(BankAccount bankAccount) { + try { + if (bankAccount == null || bankAccount.getId() == null) { + return new BankAccountResult.BankAccountUpdateError("Некорректные данные счета"); + } + bankAccountService.UpdateAccount(bankAccount); + return new BankAccountResult.Success(); + } catch (Exception e) { + return new BankAccountResult.BankAccountUpdateError(e.getMessage()); + } + } + @Override public BankAccountResult RemoveBankAccount(int userId, BankAccount bankAccount) { try { User user = userService.GetUser(userId); userManager.RemoveBankAccount(user, bankAccount); userService.SaveUser(user); - bankAccountService.UpdateAccount(bankAccount); + bankAccountService.DeleteAccount(bankAccount); return new BankAccountResult.Success(); } catch (Exception e) { return new BankAccountResult.BankAccountDeletionError(e.getMessage()); @@ -247,18 +258,6 @@ public OperationResult Transfer(BankAccount bankAccount1, BankAccount bankAccoun } } - @Override - public OperationResult GetOperationHistory(int bankAccountId) { - try { - BankAccount account = bankAccountService.GetAccount(bankAccountId); - List operations = operationService.FindAllOperationsByAccountId(account.getId()); - return userManager.PrintHistory(account, operations); - } catch (Exception e) { - e.printStackTrace(); - return new OperationResult.OperationError(e.getMessage()); - } - } - @Override public UserResult DeleteUserById(int id) { try { diff --git a/Presentation/src/main/java/Presentation/Controllers/FlywayController.java b/Presentation/src/main/java/Presentation/Controllers/FlywayController.java deleted file mode 100644 index 8b0c437..0000000 --- a/Presentation/src/main/java/Presentation/Controllers/FlywayController.java +++ /dev/null @@ -1,23 +0,0 @@ -package Presentation.Controllers; - -import Presentation.Interfaces.IFlywayController; -import org.flywaydb.core.Flyway; -import org.springframework.stereotype.Component; - -@Component -public class FlywayController implements IFlywayController { - Flyway flyway = null; - - @Override - public void FlywayInit() { - String url = System.getProperty("DB_URL"); - String username = System.getProperty("DB_USERNAME"); - String password = System.getProperty("DB_PASSWORD"); - flyway = Flyway.configure().dataSource(url, username, password).load(); - } - - @Override - public void FlywayMigrate() { - flyway.migrate(); - } -} diff --git a/Presentation/src/main/java/Presentation/Controllers/UserDTOController.java b/Presentation/src/main/java/Presentation/Controllers/UserDTOController.java index cc271bc..b008660 100644 --- a/Presentation/src/main/java/Presentation/Controllers/UserDTOController.java +++ b/Presentation/src/main/java/Presentation/Controllers/UserDTOController.java @@ -3,7 +3,7 @@ import Application.Models.Entities.User; import Application.ResultTypes.UserResult; import Presentation.DTO.UserDTO; -import Presentation.Interfaces.IUserController; +import Presentation.Interfaces.IBaseController; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.media.Content; @@ -19,11 +19,11 @@ @RequestMapping("/users") public class UserDTOController { - private final IUserController userController; + private final IBaseController baseController; @Autowired - public UserDTOController(IUserController userController) { - this.userController = userController; + public UserDTOController(IBaseController baseController) { + this.baseController = baseController; } @Operation(summary = "Получить пользователя по ID", description = "Получает информацию о пользователе по ID") @@ -33,7 +33,7 @@ public UserDTOController(IUserController userController) { }) @GetMapping("/{id}") public ResponseEntity getUserById(@Parameter(description = "ID пользователя") @PathVariable int id) { - User user = userController.GetUserById(id); + User user = baseController.GetUserById(id); if (user == null) { return ResponseEntity.notFound().build(); } @@ -47,7 +47,7 @@ public ResponseEntity getUserById(@Parameter(description = "ID поль }) @PostMapping public ResponseEntity createUser(@RequestBody User user) { - UserResult result = userController.CreateUser(user); + UserResult result = baseController.CreateUser(user); if (result instanceof UserResult.Success) { return ResponseEntity.status(HttpStatus.CREATED).body(result); } else { @@ -63,11 +63,11 @@ public ResponseEntity createUser(@RequestBody User user) { }) @PutMapping("/{id}") public ResponseEntity updateUser(@Parameter(description = "ID пользователя") @PathVariable int id, @RequestBody User user) { - User existingUser = userController.GetUserById(id); + User existingUser = baseController.GetUserById(id); if (existingUser == null) { return ResponseEntity.notFound().build(); } - UserResult result = userController.UpdateUser(user); + UserResult result = baseController.UpdateUser(user); if (result instanceof UserResult.Success) { return ResponseEntity.ok(new UserDTO(user)); } else { @@ -82,11 +82,11 @@ public ResponseEntity updateUser(@Parameter(description = "ID пользов }) @DeleteMapping("/{id}") public ResponseEntity deleteUser(@Parameter(description = "ID пользователя") @PathVariable int id) { - User user = userController.GetUserById(id); + User user = baseController.GetUserById(id); if (user == null) { return ResponseEntity.notFound().build(); } - UserResult result = userController.DeleteUser(user); + UserResult result = baseController.DeleteUser(user); if (result instanceof UserResult.Success) { return ResponseEntity.noContent().build(); } else { diff --git a/Presentation/src/main/java/Presentation/Controllers/UserDataController.java b/Presentation/src/main/java/Presentation/Controllers/UserDataController.java index cc677e8..d60c6f7 100644 --- a/Presentation/src/main/java/Presentation/Controllers/UserDataController.java +++ b/Presentation/src/main/java/Presentation/Controllers/UserDataController.java @@ -8,7 +8,7 @@ import Presentation.DTO.BankAccountDTO; import Presentation.DTO.OperationDTO; import Presentation.DTO.UserDTO; -import Presentation.Interfaces.IUserController; +import Presentation.Interfaces.IBaseController; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.media.Content; @@ -25,11 +25,11 @@ @RequestMapping("/data") public class UserDataController { - private final IUserController userController; + private final IBaseController baseController; @Autowired - public UserDataController(IUserController userController) { - this.userController = userController; + public UserDataController(IBaseController baseController) { + this.baseController = baseController; } @Operation(summary = "Получить всех пользователей с фильтрами", description = "Возвращает список пользователей, отфильтрованных по полу и цвету волос") @@ -42,7 +42,7 @@ public ResponseEntity> getAllUsersFiltered( @Parameter(description = "Пол пользователя") @RequestParam(required = false) Sex sex, @Parameter(description = "Цвет волос пользователя") @RequestParam(required = false) HairColor hairColor ) { - List users = userController.GetAllUsersFiltered(sex, hairColor); + List users = baseController.GetAllUsersFiltered(sex, hairColor); List dtos = users.stream().map(UserDTO::new).toList(); return ResponseEntity.ok(dtos); } @@ -55,7 +55,7 @@ public ResponseEntity> getAllUsersFiltered( }) @GetMapping("/users/{id}/friends") public ResponseEntity> getFriends(@Parameter(description = "ID пользователя") @PathVariable int id) { - List friends = userController.GetFriends(id); + List friends = baseController.GetFriends(id); List dtos = friends.stream().map(UserDTO::new).toList(); return ResponseEntity.ok(dtos); } @@ -68,7 +68,7 @@ public ResponseEntity> getFriends(@Parameter(description = "ID п }) @GetMapping("/users/{id}/accounts") public ResponseEntity> getAccountsByUser(@Parameter(description = "ID пользователя") @PathVariable int id) { - List accounts = userController.GetUserBankAccounts(id); + List accounts = baseController.GetUserBankAccounts(id); List dtos = accounts.stream().map(BankAccountDTO::new).toList(); return ResponseEntity.ok(dtos); } @@ -80,7 +80,7 @@ public ResponseEntity> getAccountsByUser(@Parameter(descrip }) @GetMapping("/accounts") public ResponseEntity> getAllAccounts() { - List accounts = userController.GetAllAccounts(); + List accounts = baseController.GetAllAccounts(); List dtos = accounts.stream().map(BankAccountDTO::new).toList(); return ResponseEntity.ok(dtos); } @@ -95,7 +95,7 @@ public ResponseEntity> getTransactions( @Parameter(description = "Тип операции (Deposit, Withdraw, Transfer)") @RequestParam(required = false) OperationType type, @Parameter(description = "ID банковского счета") @RequestParam(required = false) Integer accountId ) { - List txs = userController.GetFilteredOperations(type, accountId); + List txs = baseController.GetFilteredOperations(type, accountId); List dtos = txs.stream().map(OperationDTO::new).toList(); return ResponseEntity.ok(dtos); } diff --git a/Presentation/src/main/java/Presentation/Interfaces/IUserController.java b/Presentation/src/main/java/Presentation/Interfaces/IBaseController.java similarity index 86% rename from Presentation/src/main/java/Presentation/Interfaces/IUserController.java rename to Presentation/src/main/java/Presentation/Interfaces/IBaseController.java index 526ea14..7a50acc 100644 --- a/Presentation/src/main/java/Presentation/Interfaces/IUserController.java +++ b/Presentation/src/main/java/Presentation/Interfaces/IBaseController.java @@ -9,10 +9,12 @@ import Application.ResultTypes.UserResult; import Application.Models.Entities.BankAccount; import Application.Models.Entities.User; +import org.springframework.stereotype.Component; import java.util.List; -public interface IUserController { +@Component +public interface IBaseController { UserResult CreateUser(User user); @@ -34,13 +36,13 @@ public interface IUserController { UserResult DeleteUser(User user); - void GetUserInfo(int id); - void AddFriend(int userId, int otherId); void RemoveFriend(int userId, int otherId); - BankAccountResult addBankAccount(int userId, BankAccount bankAccount); + BankAccountResult AddBankAccount(int userId, BankAccount bankAccount); + + BankAccountResult UpdateBankAccount(BankAccount bankAccount); BankAccountResult RemoveBankAccount(int userId, BankAccount bankAccount); @@ -52,7 +54,5 @@ public interface IUserController { OperationResult Transfer(BankAccount bankAccount1, BankAccount bankAccount2, Double amount); - OperationResult GetOperationHistory(int bankAccountId); - UserResult DeleteUserById(int id); } diff --git a/Presentation/src/main/java/Presentation/Interfaces/IFlywayController.java b/Presentation/src/main/java/Presentation/Interfaces/IFlywayController.java deleted file mode 100644 index 4c7e55e..0000000 --- a/Presentation/src/main/java/Presentation/Interfaces/IFlywayController.java +++ /dev/null @@ -1,7 +0,0 @@ -package Presentation.Interfaces; - -public interface IFlywayController { - void FlywayInit(); - - void FlywayMigrate(); -} diff --git a/Presentation/src/test/java/BankTests.java b/Presentation/src/test/java/BankTests.java index 716fa40..9b3466f 100644 --- a/Presentation/src/test/java/BankTests.java +++ b/Presentation/src/test/java/BankTests.java @@ -9,7 +9,6 @@ import DataAccess.Services.OperationService; import Presentation.Controllers.*; import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; @@ -36,7 +35,7 @@ public class BankTests { private IUserService userService; @InjectMocks - private UserController userController; + private BaseController baseController; private static BankAccount bankAccount; private static User user; @@ -56,7 +55,7 @@ public void testWithdrawWithSufficientBalance() { when(bankAccountService.Withdraw(bankAccount.getId(), withdrawAmount)).thenReturn(true); doNothing().when(operationService).SaveOperation(any()); - OperationResult operationResult = userController.Withdraw(bankAccount, withdrawAmount); + OperationResult operationResult = baseController.Withdraw(bankAccount, withdrawAmount); assertInstanceOf(OperationResult.Success.class, operationResult); verify(bankAccountService, times(1)).Withdraw(bankAccount.getId(), withdrawAmount); @@ -68,7 +67,7 @@ public void testWithdrawWithInsufficientBalance() { double withdrawAmount = 150.0; when(bankAccountService.Withdraw(bankAccount.getId(), withdrawAmount)).thenReturn(false); - OperationResult operationResult = userController.Withdraw(bankAccount, withdrawAmount); + OperationResult operationResult = baseController.Withdraw(bankAccount, withdrawAmount); assertInstanceOf(OperationResult.OperationError.class, operationResult); assertEquals("Not enough balance.", ((OperationResult.OperationError) operationResult).getMessage()); @@ -82,7 +81,7 @@ public void testDeposit() { when(bankAccountService.Deposit(bankAccount.getId(), depositAmount)).thenReturn(true); doNothing().when(operationService).SaveOperation(any()); - OperationResult operationResult = userController.Deposit(bankAccount, depositAmount); + OperationResult operationResult = baseController.Deposit(bankAccount, depositAmount); assertInstanceOf(OperationResult.Success.class, operationResult); verify(bankAccountService, times(1)).Deposit(bankAccount.getId(), depositAmount);