From d1be8e7014abea2b0605a9c09e35ad80082fe2f4 Mon Sep 17 00:00:00 2001 From: RoyceDa Date: Mon, 2 Feb 2026 03:20:12 +0200 Subject: [PATCH] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=20Hybernate=20=D0=B8=20=D1=80=D0=B5=D0=B0=D0=BB=D0=B8?= =?UTF-8?q?=D0=B7=D0=BE=D0=B2=D0=B0=D0=BD=20=D0=BF=D1=80=D0=BE=D1=82=D0=BE?= =?UTF-8?q?=D1=82=D0=B8=D0=BF=20=D0=91=D0=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docker-compose.dev.yml | 22 +- pom.xml | 22 +- .../com/rosetta/im/database/BaseEntity.java | 29 +++ .../rosetta/im/database/DatabaseManager.java | 80 ++++++ .../rosetta/im/database/HibernateUtil.java | 33 +++ .../converters/StringListConverter.java | 27 +++ .../com/rosetta/im/database/entity/User.java | 229 ++++++++++++++++++ src/main/resources/hibernate.cfg.xml | 17 ++ 8 files changed, 452 insertions(+), 7 deletions(-) create mode 100644 src/main/java/com/rosetta/im/database/BaseEntity.java create mode 100644 src/main/java/com/rosetta/im/database/DatabaseManager.java create mode 100644 src/main/java/com/rosetta/im/database/HibernateUtil.java create mode 100644 src/main/java/com/rosetta/im/database/converters/StringListConverter.java create mode 100644 src/main/java/com/rosetta/im/database/entity/User.java create mode 100644 src/main/resources/hibernate.cfg.xml diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml index d40619c..21b1c22 100644 --- a/docker-compose.dev.yml +++ b/docker-compose.dev.yml @@ -2,15 +2,27 @@ version: '3.8' services: db: - image: postgres:latest + image: postgres:16-alpine environment: - POSTGRES_DB: your_database - POSTGRES_USER: your_user - POSTGRES_PASSWORD: your_password + POSTGRES_DB: rosetta_db + POSTGRES_USER: rosetta_user + POSTGRES_PASSWORD: rosetta_password ports: - "5432:5432" + volumes: + - postgres_data:/var/lib/postgresql/data + healthcheck: + test: ["CMD-SHELL", "pg_isready -U rosetta_user"] + interval: 10s + timeout: 5s + retries: 5 adminer: image: adminer ports: - - "8080:8080" \ No newline at end of file + - "8080:8080" + depends_on: + - db + +volumes: + postgres_data: \ No newline at end of file diff --git a/pom.xml b/pom.xml index 19b9e3e..c84b6a0 100644 --- a/pom.xml +++ b/pom.xml @@ -16,13 +16,31 @@ - - org.java-websocket Java-WebSocket 1.6.0 + + + org.hibernate.orm + hibernate-core + 6.4.0.Final + + + + + org.postgresql + postgresql + 42.7.1 + + + + + jakarta.persistence + jakarta.persistence-api + 3.1.0 + \ No newline at end of file diff --git a/src/main/java/com/rosetta/im/database/BaseEntity.java b/src/main/java/com/rosetta/im/database/BaseEntity.java new file mode 100644 index 0000000..bb11391 --- /dev/null +++ b/src/main/java/com/rosetta/im/database/BaseEntity.java @@ -0,0 +1,29 @@ +package com.rosetta.im.database; + +public class BaseEntity { + + /** + * Сохраняет сущность в базе данных. + * @param entity Сущность для сохранения. + */ + public void save(Object entity) { + DatabaseManager.save(entity); + } + + /** + * Обновляет сущность в базе данных. + * @param entity Сущность для обновления. + */ + public void update(Object entity) { + DatabaseManager.update(entity); + } + + /** + * Удаляет сущность из базы данных. + * @param entity Сущность для удаления. + */ + public void delete(Object entity) { + DatabaseManager.delete(entity); + } + +} diff --git a/src/main/java/com/rosetta/im/database/DatabaseManager.java b/src/main/java/com/rosetta/im/database/DatabaseManager.java new file mode 100644 index 0000000..62029b7 --- /dev/null +++ b/src/main/java/com/rosetta/im/database/DatabaseManager.java @@ -0,0 +1,80 @@ +package com.rosetta.im.database; + +import org.hibernate.Session; +import org.hibernate.Transaction; + +import java.util.List; + +public class DatabaseManager { + + public static T save(T entity) { + Session session = HibernateUtil.openSession(); + Transaction transaction = null; + try { + transaction = session.beginTransaction(); + session.persist(entity); + transaction.commit(); + return entity; + } catch (Exception e) { + if (transaction != null) { + transaction.rollback(); + } + throw new RuntimeException("Error saving entity: " + e.getMessage(), e); + } finally { + session.close(); + } + } + + public static T update(T entity) { + Session session = HibernateUtil.openSession(); + Transaction transaction = null; + try { + transaction = session.beginTransaction(); + session.merge(entity); + transaction.commit(); + return entity; + } catch (Exception e) { + if (transaction != null) { + transaction.rollback(); + } + throw new RuntimeException("Error updating entity: " + e.getMessage(), e); + } finally { + session.close(); + } + } + + public static T findById(Class entityClass, Long id) { + Session session = HibernateUtil.openSession(); + try { + return session.find(entityClass, id); + } finally { + session.close(); + } + } + + public static List findAll(Class entityClass) { + Session session = HibernateUtil.openSession(); + try { + return session.createQuery("FROM " + entityClass.getSimpleName(), entityClass).list(); + } finally { + session.close(); + } + } + + public static void delete(T entity) { + Session session = HibernateUtil.openSession(); + Transaction transaction = null; + try { + transaction = session.beginTransaction(); + session.remove(entity); + transaction.commit(); + } catch (Exception e) { + if (transaction != null) { + transaction.rollback(); + } + throw new RuntimeException("Error deleting entity: " + e.getMessage(), e); + } finally { + session.close(); + } + } +} diff --git a/src/main/java/com/rosetta/im/database/HibernateUtil.java b/src/main/java/com/rosetta/im/database/HibernateUtil.java new file mode 100644 index 0000000..a1596de --- /dev/null +++ b/src/main/java/com/rosetta/im/database/HibernateUtil.java @@ -0,0 +1,33 @@ +package com.rosetta.im.database; + +import org.hibernate.Session; +import org.hibernate.SessionFactory; +import org.hibernate.cfg.Configuration; + +public class HibernateUtil { + private static final SessionFactory sessionFactory; + + static { + try { + sessionFactory = new Configuration().configure().buildSessionFactory(); + } catch (Exception e) { + throw new ExceptionInInitializerError("Error initializing Hibernate: " + e.getMessage()); + } + } + + public static SessionFactory getSessionFactory() { + return sessionFactory; + } + + public static Session getCurrentSession() { + return sessionFactory.getCurrentSession(); + } + + public static Session openSession() { + return sessionFactory.openSession(); + } + + public static void shutdown() { + sessionFactory.close(); + } +} diff --git a/src/main/java/com/rosetta/im/database/converters/StringListConverter.java b/src/main/java/com/rosetta/im/database/converters/StringListConverter.java new file mode 100644 index 0000000..6bd4d5b --- /dev/null +++ b/src/main/java/com/rosetta/im/database/converters/StringListConverter.java @@ -0,0 +1,27 @@ +package com.rosetta.im.database.converters; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import jakarta.persistence.AttributeConverter; +import jakarta.persistence.Converter; + +@Converter +public class StringListConverter implements AttributeConverter, String> { + @Override + public String convertToDatabaseColumn(List attribute) { + if (attribute == null || attribute.isEmpty()) { + return ""; + } + return String.join(",", attribute); + } + + @Override + public List convertToEntityAttribute(String dbData) { + if (dbData == null || dbData.isBlank()) { + return new ArrayList<>(); + } + return new ArrayList<>(Arrays.asList(dbData.split(","))); + } +} \ No newline at end of file diff --git a/src/main/java/com/rosetta/im/database/entity/User.java b/src/main/java/com/rosetta/im/database/entity/User.java new file mode 100644 index 0000000..e6d7a40 --- /dev/null +++ b/src/main/java/com/rosetta/im/database/entity/User.java @@ -0,0 +1,229 @@ +package com.rosetta.im.database.entity; + +import com.rosetta.im.database.BaseEntity; +import com.rosetta.im.database.HibernateUtil; +import com.rosetta.im.database.converters.StringListConverter; + +import jakarta.persistence.Column; +import jakarta.persistence.Convert; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.Index; +import jakarta.persistence.PrePersist; +import jakarta.persistence.PreUpdate; +import jakarta.persistence.Table; +import org.hibernate.Session; +import org.hibernate.Transaction; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +@Entity +@Table(name = "users", indexes = { + @Index(name = "idx_users_publickey", columnList = "publicKey", unique = true) +}) +public class User extends BaseEntity { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(name = "privateKey", nullable = false) + private String privateKey; + + @Column(name = "username") + private String username; + + @Column(name = "title") + private String title; + + @Column(name = "publicKey", nullable = false, unique = true) + private String publicKey; + + @Column(name = "timestamp", nullable = false) + private long timestamp; + + @Column(name = "createdTime", nullable = false, updatable = false) + private Date createdTime; + + @Column(name = "verified", nullable = false) + private int verified; + + @Convert(converter = StringListConverter.class) + @Column(name = "notificationsTokens", nullable = false) + private List notificationsTokens = new ArrayList<>(); + + @PrePersist + protected void onCreate() { + createdTime = new Date(); + } + + @PreUpdate + protected void onUpdate() { + if (createdTime == null) { + createdTime = new Date(); + } + } + + public Long getId() { + return id; + } + + public String getPrivateKey() { + return privateKey; + } + + public void setPrivateKey(String privateKey) { + this.privateKey = privateKey; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getPublicKey() { + return publicKey; + } + + public void setPublicKey(String publicKey) { + this.publicKey = publicKey; + } + + public long getTimestamp() { + return timestamp; + } + + public void setTimestamp(long timestamp) { + this.timestamp = timestamp; + } + + public Date getCreatedTime() { + return createdTime; + } + + public int getVerified() { + return verified; + } + + public void setVerified(int verified) { + this.verified = verified; + } + + public List getNotificationsTokens() { + return notificationsTokens; + } + + public void setNotificationsTokens(List notificationsTokens) { + this.notificationsTokens = notificationsTokens; + } + + public static User getByPrivateKey(String privateKey) { + try (Session session = HibernateUtil.openSession()) { + return session.createQuery( + "from User where privateKey = :privateKey", User.class) + .setParameter("privateKey", privateKey) + .uniqueResult(); + } + } + + public static User getByUsername(String username) { + try (Session session = HibernateUtil.openSession()) { + return session.createQuery( + "from User where username = :username", User.class) + .setParameter("username", username) + .uniqueResult(); + } + } + + public static User getByPublicKey(String publicKey) { + try (Session session = HibernateUtil.openSession()) { + return session.createQuery( + "from User where publicKey = :publicKey", User.class) + .setParameter("publicKey", publicKey) + .uniqueResult(); + } + } + + public static void addNotificationToken(String privateKey, String token) { + Session session = HibernateUtil.openSession(); + Transaction transaction = null; + try { + transaction = session.beginTransaction(); + User user = session.createQuery( + "from User where privateKey = :privateKey", User.class) + .setParameter("privateKey", privateKey) + .uniqueResult(); + if (user != null) { + if (!user.notificationsTokens.contains(token)) { + user.notificationsTokens.add(token); + session.merge(user); + } + } + transaction.commit(); + } catch (Exception e) { + if (transaction != null) { + transaction.rollback(); + } + throw new RuntimeException("Error adding notification token: " + e.getMessage(), e); + } finally { + session.close(); + } + } + + public static void removeNotificationToken(String privateKey, String token) { + Session session = HibernateUtil.openSession(); + Transaction transaction = null; + try { + transaction = session.beginTransaction(); + User user = session.createQuery( + "from User where privateKey = :privateKey", User.class) + .setParameter("privateKey", privateKey) + .uniqueResult(); + if (user != null) { + user.notificationsTokens = new ArrayList<>(user.notificationsTokens.stream() + .filter(t -> !t.equals(token)) + .toList()); + session.merge(user); + } + transaction.commit(); + } catch (Exception e) { + if (transaction != null) { + transaction.rollback(); + } + throw new RuntimeException("Error removing notification token: " + e.getMessage(), e); + } finally { + session.close(); + } + } + + public static List getNotificationTokensByPrivateKey(String privateKey) { + User user = getByPrivateKey(privateKey); + if (user != null) { + return user.notificationsTokens; + } + return List.of(); + } + + public static List getNotificationsTokensByPublicKey(String publicKey) { + User user = getByPublicKey(publicKey); + if (user != null) { + return user.notificationsTokens; + } + return List.of(); + } +} diff --git a/src/main/resources/hibernate.cfg.xml b/src/main/resources/hibernate.cfg.xml new file mode 100644 index 0000000..80bb79d --- /dev/null +++ b/src/main/resources/hibernate.cfg.xml @@ -0,0 +1,17 @@ + + + + + org.postgresql.Driver + jdbc:postgresql://localhost:5432/rosetta_db + rosetta_user + rosetta_password + org.hibernate.dialect.PostgreSQLDialect + update + true + true + + + + +