diff --git a/L24-webServer/build.gradle.kts b/L24-webServer/build.gradle.kts index f149e5b..217ccaa 100644 --- a/L24-webServer/build.gradle.kts +++ b/L24-webServer/build.gradle.kts @@ -11,8 +11,17 @@ dependencies { implementation("org.eclipse.jetty:jetty-util") implementation("org.freemarker:freemarker") + implementation("org.postgresql:postgresql") + + implementation("com.h2database:h2") + implementation("org.hibernate.orm:hibernate-core") + + implementation ("org.projectlombok:lombok") + annotationProcessor ("org.projectlombok:lombok") + testImplementation("org.junit.jupiter:junit-jupiter-engine") testImplementation("org.junit.jupiter:junit-jupiter-params") testImplementation("org.assertj:assertj-core") testImplementation("org.mockito:mockito-junit-jupiter") + } \ No newline at end of file diff --git a/L24-webServer/docker/runDb.sh b/L24-webServer/docker/runDb.sh new file mode 100644 index 0000000..7ace52a --- /dev/null +++ b/L24-webServer/docker/runDb.sh @@ -0,0 +1,7 @@ +docker kill pg-docker +docker run --rm --name pg-docker \ +-e POSTGRES_PASSWORD=pwd \ +-e POSTGRES_USER=usr \ +-e POSTGRES_DB=demoDB \ +-p 5430:5432 \ +postgres:12 \ No newline at end of file diff --git a/L24-webServer/src/main/java/ru/otus/TransactionManagerFactory.java b/L24-webServer/src/main/java/ru/otus/TransactionManagerFactory.java new file mode 100644 index 0000000..621fa88 --- /dev/null +++ b/L24-webServer/src/main/java/ru/otus/TransactionManagerFactory.java @@ -0,0 +1,24 @@ +package ru.otus; + +import org.hibernate.cfg.Configuration; +import ru.otus.from_orm_hw.core.repository.HibernateUtils; +import ru.otus.from_orm_hw.core.sessionmanager.TransactionManager; +import ru.otus.from_orm_hw.core.sessionmanager.TransactionManagerHibernate; +import ru.otus.from_orm_hw.crm.model.Address; +import ru.otus.from_orm_hw.crm.model.Client; +import ru.otus.from_orm_hw.crm.model.Phone; +import ru.otus.model.User; + +public class TransactionManagerFactory { + + public static final String HIBERNATE_CFG_FILE = "hibernate.cfg.xml"; + + public static TransactionManager initTransactionManager() { + var configuration = new Configuration().configure(HIBERNATE_CFG_FILE); + + var sessionFactory = + HibernateUtils.buildSessionFactory(configuration, Client.class, Address.class, Phone.class, User.class); + + return new TransactionManagerHibernate(sessionFactory); + } +} diff --git a/L24-webServer/src/main/java/ru/otus/WebServerSimpleDemo.java b/L24-webServer/src/main/java/ru/otus/WebServerSimpleDemo.java index 6cf236d..1227c59 100644 --- a/L24-webServer/src/main/java/ru/otus/WebServerSimpleDemo.java +++ b/L24-webServer/src/main/java/ru/otus/WebServerSimpleDemo.java @@ -2,8 +2,14 @@ import com.google.gson.Gson; import com.google.gson.GsonBuilder; -import ru.otus.dao.InMemoryUserDao; +import ru.otus.dao.ClientDao; +import ru.otus.dao.DbClientDao; +import ru.otus.dao.DbUserDao; import ru.otus.dao.UserDao; +import ru.otus.from_orm_hw.core.repository.DataTemplateHibernate; +import ru.otus.from_orm_hw.core.sessionmanager.TransactionManager; +import ru.otus.from_orm_hw.crm.model.Client; +import ru.otus.model.User; import ru.otus.server.UsersWebServer; import ru.otus.server.UsersWebServerSimple; import ru.otus.services.TemplateProcessor; @@ -26,11 +32,15 @@ public class WebServerSimpleDemo { private static final String TEMPLATES_DIR = "/templates/"; public static void main(String[] args) throws Exception { - UserDao userDao = new InMemoryUserDao(); + TransactionManager tm = TransactionManagerFactory.initTransactionManager(); + + UserDao userDao = new DbUserDao(tm, new DataTemplateHibernate<>(User.class)); + ClientDao clientDao = new DbClientDao(tm, new DataTemplateHibernate<>(Client.class)); Gson gson = new GsonBuilder().serializeNulls().setPrettyPrinting().create(); TemplateProcessor templateProcessor = new TemplateProcessorImpl(TEMPLATES_DIR); - UsersWebServer usersWebServer = new UsersWebServerSimple(WEB_SERVER_PORT, userDao, gson, templateProcessor); + UsersWebServer usersWebServer = + new UsersWebServerSimple(WEB_SERVER_PORT, userDao, clientDao, gson, templateProcessor); usersWebServer.start(); usersWebServer.join(); diff --git a/L24-webServer/src/main/java/ru/otus/WebServerWithBasicSecurityDemo.java b/L24-webServer/src/main/java/ru/otus/WebServerWithBasicSecurityDemo.java index 1273047..4bb1257 100644 --- a/L24-webServer/src/main/java/ru/otus/WebServerWithBasicSecurityDemo.java +++ b/L24-webServer/src/main/java/ru/otus/WebServerWithBasicSecurityDemo.java @@ -7,9 +7,15 @@ import org.eclipse.jetty.security.LoginService; import org.eclipse.jetty.util.resource.PathResourceFactory; import org.eclipse.jetty.util.resource.Resource; -import ru.otus.dao.InMemoryUserDao; +import ru.otus.dao.ClientDao; +import ru.otus.dao.DbClientDao; +import ru.otus.dao.DbUserDao; import ru.otus.dao.UserDao; +import ru.otus.from_orm_hw.core.repository.DataTemplateHibernate; +import ru.otus.from_orm_hw.core.sessionmanager.TransactionManager; +import ru.otus.from_orm_hw.crm.model.Client; import ru.otus.helpers.FileSystemHelper; +import ru.otus.model.User; import ru.otus.server.UsersWebServer; import ru.otus.server.UsersWebServerWithBasicSecurity; import ru.otus.services.TemplateProcessor; @@ -34,7 +40,11 @@ public class WebServerWithBasicSecurityDemo { private static final String REALM_NAME = "AnyRealm"; public static void main(String[] args) throws Exception { - UserDao userDao = new InMemoryUserDao(); + TransactionManager tm = TransactionManagerFactory.initTransactionManager(); + + UserDao userDao = new DbUserDao(tm, new DataTemplateHibernate<>(User.class)); + ClientDao clientDao = new DbClientDao(tm, new DataTemplateHibernate<>(Client.class)); + Gson gson = new GsonBuilder().serializeNulls().setPrettyPrinting().create(); TemplateProcessor templateProcessor = new TemplateProcessorImpl(TEMPLATES_DIR); @@ -46,8 +56,8 @@ public static void main(String[] args) throws Exception { LoginService loginService = new HashLoginService(REALM_NAME, configResource); // LoginService loginService = new InMemoryLoginServiceImpl(userDao); // NOSONAR - UsersWebServer usersWebServer = - new UsersWebServerWithBasicSecurity(WEB_SERVER_PORT, loginService, userDao, gson, templateProcessor); + UsersWebServer usersWebServer = new UsersWebServerWithBasicSecurity( + WEB_SERVER_PORT, loginService, userDao, clientDao, gson, templateProcessor); usersWebServer.start(); usersWebServer.join(); diff --git a/L24-webServer/src/main/java/ru/otus/WebServerWithFilterBasedSecurityDemo.java b/L24-webServer/src/main/java/ru/otus/WebServerWithFilterBasedSecurityDemo.java index 9cb4c15..2d49a67 100644 --- a/L24-webServer/src/main/java/ru/otus/WebServerWithFilterBasedSecurityDemo.java +++ b/L24-webServer/src/main/java/ru/otus/WebServerWithFilterBasedSecurityDemo.java @@ -2,8 +2,14 @@ import com.google.gson.Gson; import com.google.gson.GsonBuilder; -import ru.otus.dao.InMemoryUserDao; +import ru.otus.dao.ClientDao; +import ru.otus.dao.DbClientDao; +import ru.otus.dao.DbUserDao; import ru.otus.dao.UserDao; +import ru.otus.from_orm_hw.core.repository.DataTemplateHibernate; +import ru.otus.from_orm_hw.core.sessionmanager.TransactionManager; +import ru.otus.from_orm_hw.crm.model.Client; +import ru.otus.model.User; import ru.otus.server.UsersWebServer; import ru.otus.server.UsersWebServerWithFilterBasedSecurity; import ru.otus.services.TemplateProcessor; @@ -28,13 +34,17 @@ public class WebServerWithFilterBasedSecurityDemo { private static final String TEMPLATES_DIR = "/templates/"; public static void main(String[] args) throws Exception { - UserDao userDao = new InMemoryUserDao(); + TransactionManager tm = TransactionManagerFactory.initTransactionManager(); + + UserDao userDao = new DbUserDao(tm, new DataTemplateHibernate<>(User.class)); + ClientDao clientDao = new DbClientDao(tm, new DataTemplateHibernate<>(Client.class)); + Gson gson = new GsonBuilder().serializeNulls().setPrettyPrinting().create(); TemplateProcessor templateProcessor = new TemplateProcessorImpl(TEMPLATES_DIR); UserAuthService authService = new UserAuthServiceImpl(userDao); UsersWebServer usersWebServer = new UsersWebServerWithFilterBasedSecurity( - WEB_SERVER_PORT, authService, userDao, gson, templateProcessor); + WEB_SERVER_PORT, authService, userDao, clientDao, gson, templateProcessor); usersWebServer.start(); usersWebServer.join(); diff --git a/L24-webServer/src/main/java/ru/otus/dao/ClientDao.java b/L24-webServer/src/main/java/ru/otus/dao/ClientDao.java new file mode 100644 index 0000000..33487a5 --- /dev/null +++ b/L24-webServer/src/main/java/ru/otus/dao/ClientDao.java @@ -0,0 +1,20 @@ +package ru.otus.dao; + +import java.util.List; +import java.util.Optional; +import ru.otus.from_orm_hw.crm.model.Client; + +public interface ClientDao { + + Optional findById(long id); + + List getAll(); + + Optional createClient(Client client); + + Optional addPhone(Long clientId, String number); + + Optional deletePhone(Long clientId, String number); + + Optional updateAddress(Long clientId, String address); +} diff --git a/L24-webServer/src/main/java/ru/otus/dao/DbClientDao.java b/L24-webServer/src/main/java/ru/otus/dao/DbClientDao.java new file mode 100644 index 0000000..8256afc --- /dev/null +++ b/L24-webServer/src/main/java/ru/otus/dao/DbClientDao.java @@ -0,0 +1,99 @@ +package ru.otus.dao; + +import java.util.List; +import java.util.Optional; +import java.util.function.Function; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import ru.otus.from_orm_hw.core.repository.DataTemplate; +import ru.otus.from_orm_hw.core.sessionmanager.TransactionManager; +import ru.otus.from_orm_hw.crm.model.Address; +import ru.otus.from_orm_hw.crm.model.Client; +import ru.otus.from_orm_hw.crm.model.Phone; + +public class DbClientDao implements ClientDao { + + private final Logger logger = LoggerFactory.getLogger(DbClientDao.class); + + private final TransactionManager tm; + private final DataTemplate dataTemplate; + + public DbClientDao(TransactionManager tm, DataTemplate dataTemplate) { + this.tm = tm; + this.dataTemplate = dataTemplate; + } + + @Override + public Optional findById(long id) { + return tm.doInReadOnlyTransaction(session -> { + var clientOptional = dataTemplate.findById(session, id); + logger.info("user: {}", clientOptional); + return clientOptional; + }); + } + + @Override + public List getAll() { + return tm.doInReadOnlyTransaction(session -> { + var clientsOptional = dataTemplate.findAll(session); + logger.info("user: {}", clientsOptional); + return clientsOptional; + }); + } + + @Override + public Optional createClient(final Client client) { + return tm.doInTransaction(session -> { + Client createdClient = dataTemplate.insert(session, client); + return Optional.ofNullable(createdClient); + }); + } + + @Override + public Optional addPhone(final Long clientId, final String number) { + + return updateClient(clientId, client -> { + Phone phone = new Phone(); + phone.setNumber(number); + + client.getPhones().add(phone); + return client; + }); + } + + @Override + public Optional deletePhone(final Long clientId, final String number) { + + return updateClient(clientId, client -> { + client.getPhones().removeIf(p -> p.getNumber().equals(number)); + + return client; + }); + } + + @Override + public Optional updateAddress(final Long clientId, final String address) { + + return updateClient(clientId, client -> { + Address newAddress = new Address(); + newAddress.setStreet(address); + + client.setAddress(newAddress); + + return client; + }); + } + + private Optional updateClient(Long clientId, Function operation) { + return tm.doInTransaction(session -> { + var clientOptional = dataTemplate.findById(session, clientId); + + if (clientOptional.isPresent()) { + Client client = clientOptional.get(); + + return Optional.ofNullable(session.merge(operation.apply(client))); + } + return Optional.empty(); + }); + } +} diff --git a/L24-webServer/src/main/java/ru/otus/dao/DbUserDao.java b/L24-webServer/src/main/java/ru/otus/dao/DbUserDao.java new file mode 100644 index 0000000..3d20cab --- /dev/null +++ b/L24-webServer/src/main/java/ru/otus/dao/DbUserDao.java @@ -0,0 +1,61 @@ +package ru.otus.dao; + +import java.util.Optional; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import ru.otus.from_orm_hw.core.repository.DataTemplate; +import ru.otus.from_orm_hw.core.sessionmanager.TransactionManager; +import ru.otus.model.User; + +public class DbUserDao implements UserDao { + + private final Logger logger = LoggerFactory.getLogger(DbUserDao.class); + + private final TransactionManager tm; + private final DataTemplate dataTemplate; + + public DbUserDao(TransactionManager tm, DataTemplate dataTemplate) { + this.tm = tm; + this.dataTemplate = dataTemplate; + } + + @Override + public Optional findById(long id) { + return tm.doInReadOnlyTransaction(session -> { + var userOptional = dataTemplate.findById(session, id); + logger.info("user: {}", userOptional); + return userOptional; + }); + } + + @Override + public Optional findRandomUser() { + + return tm.doInTransaction(session -> { + User userNullable = session.createQuery("FROM User ORDER BY random()", User.class) + .setMaxResults(1) + .uniqueResult(); + + return Optional.ofNullable(userNullable); + }); + } + + @Override + public Optional findByLogin(String login) { + return tm.doInReadOnlyTransaction(session -> { + User usr = session.createQuery("FROM User WHERE login = :login", User.class) + .setParameter("login", login) + .uniqueResult(); + + return Optional.ofNullable(usr); + }); + } + + @Override + public Optional createUser(final User user) { + return tm.doInTransaction(session -> { + User usr = dataTemplate.insert(session, user); + return Optional.ofNullable(usr); + }); + } +} diff --git a/L24-webServer/src/main/java/ru/otus/dao/InMemoryUserDao.java b/L24-webServer/src/main/java/ru/otus/dao/InMemoryUserDao.java index 5642f9f..c5f7298 100644 --- a/L24-webServer/src/main/java/ru/otus/dao/InMemoryUserDao.java +++ b/L24-webServer/src/main/java/ru/otus/dao/InMemoryUserDao.java @@ -38,4 +38,11 @@ public Optional findRandomUser() { public Optional findByLogin(String login) { return users.values().stream().filter(v -> v.getLogin().equals(login)).findFirst(); } + + @Override + public Optional createUser(final User user) { + long nextId = users.keySet().stream().max(Long::compare).get() + 1; + + return Optional.of(users.put(nextId, user)); + } } diff --git a/L24-webServer/src/main/java/ru/otus/dao/UserDao.java b/L24-webServer/src/main/java/ru/otus/dao/UserDao.java index d131bcf..acd6a3f 100644 --- a/L24-webServer/src/main/java/ru/otus/dao/UserDao.java +++ b/L24-webServer/src/main/java/ru/otus/dao/UserDao.java @@ -10,4 +10,6 @@ public interface UserDao { Optional findRandomUser(); Optional findByLogin(String login); + + Optional createUser(User user); } diff --git a/L24-webServer/src/main/java/ru/otus/from_orm_hw/core/repository/DataTemplate.java b/L24-webServer/src/main/java/ru/otus/from_orm_hw/core/repository/DataTemplate.java new file mode 100644 index 0000000..961260c --- /dev/null +++ b/L24-webServer/src/main/java/ru/otus/from_orm_hw/core/repository/DataTemplate.java @@ -0,0 +1,17 @@ +package ru.otus.from_orm_hw.core.repository; + +import java.util.List; +import java.util.Optional; +import org.hibernate.Session; + +public interface DataTemplate { + Optional findById(Session session, long id); + + List findByEntityField(Session session, String entityFieldName, Object entityFieldValue); + + List findAll(Session session); + + T insert(Session session, T object); + + T update(Session session, T object); +} diff --git a/L24-webServer/src/main/java/ru/otus/from_orm_hw/core/repository/DataTemplateException.java b/L24-webServer/src/main/java/ru/otus/from_orm_hw/core/repository/DataTemplateException.java new file mode 100644 index 0000000..c15eadc --- /dev/null +++ b/L24-webServer/src/main/java/ru/otus/from_orm_hw/core/repository/DataTemplateException.java @@ -0,0 +1,7 @@ +package ru.otus.from_orm_hw.core.repository; + +public class DataTemplateException extends RuntimeException { + public DataTemplateException(Exception ex) { + super(ex); + } +} diff --git a/L24-webServer/src/main/java/ru/otus/from_orm_hw/core/repository/DataTemplateHibernate.java b/L24-webServer/src/main/java/ru/otus/from_orm_hw/core/repository/DataTemplateHibernate.java new file mode 100644 index 0000000..3251097 --- /dev/null +++ b/L24-webServer/src/main/java/ru/otus/from_orm_hw/core/repository/DataTemplateHibernate.java @@ -0,0 +1,47 @@ +package ru.otus.from_orm_hw.core.repository; + +import java.util.List; +import java.util.Optional; +import org.hibernate.Session; + +public class DataTemplateHibernate implements DataTemplate { + + private final Class clazz; + + public DataTemplateHibernate(Class clazz) { + this.clazz = clazz; + } + + @Override + public Optional findById(Session session, long id) { + return Optional.ofNullable(session.find(clazz, id)); + } + + @Override + public List findByEntityField(Session session, String entityFieldName, Object entityFieldValue) { + var criteriaBuilder = session.getCriteriaBuilder(); + var criteriaQuery = criteriaBuilder.createQuery(clazz); + var root = criteriaQuery.from(clazz); + criteriaQuery.select(root).where(criteriaBuilder.equal(root.get(entityFieldName), entityFieldValue)); + + var query = session.createQuery(criteriaQuery); + return query.getResultList(); + } + + @Override + public List findAll(Session session) { + return session.createQuery(String.format("from %s", clazz.getSimpleName()), clazz) + .getResultList(); + } + + @Override + public T insert(Session session, T object) { + session.persist(object); + return object; + } + + @Override + public T update(Session session, T object) { + return session.merge(object); + } +} diff --git a/L24-webServer/src/main/java/ru/otus/from_orm_hw/core/repository/HibernateUtils.java b/L24-webServer/src/main/java/ru/otus/from_orm_hw/core/repository/HibernateUtils.java new file mode 100644 index 0000000..fb4eaa5 --- /dev/null +++ b/L24-webServer/src/main/java/ru/otus/from_orm_hw/core/repository/HibernateUtils.java @@ -0,0 +1,28 @@ +package ru.otus.from_orm_hw.core.repository; + +import java.util.Arrays; +import org.hibernate.SessionFactory; +import org.hibernate.boot.Metadata; +import org.hibernate.boot.MetadataSources; +import org.hibernate.boot.registry.StandardServiceRegistry; +import org.hibernate.boot.registry.StandardServiceRegistryBuilder; +import org.hibernate.cfg.Configuration; + +public final class HibernateUtils { + + private HibernateUtils() {} + + public static SessionFactory buildSessionFactory(Configuration configuration, Class... annotatedClasses) { + MetadataSources metadataSources = new MetadataSources(createServiceRegistry(configuration)); + Arrays.stream(annotatedClasses).forEach(metadataSources::addAnnotatedClass); + + Metadata metadata = metadataSources.getMetadataBuilder().build(); + return metadata.getSessionFactoryBuilder().build(); + } + + private static StandardServiceRegistry createServiceRegistry(Configuration configuration) { + return new StandardServiceRegistryBuilder() + .applySettings(configuration.getProperties()) + .build(); + } +} diff --git a/L24-webServer/src/main/java/ru/otus/from_orm_hw/core/sessionmanager/DataBaseOperationException.java b/L24-webServer/src/main/java/ru/otus/from_orm_hw/core/sessionmanager/DataBaseOperationException.java new file mode 100644 index 0000000..bf3d58e --- /dev/null +++ b/L24-webServer/src/main/java/ru/otus/from_orm_hw/core/sessionmanager/DataBaseOperationException.java @@ -0,0 +1,7 @@ +package ru.otus.from_orm_hw.core.sessionmanager; + +public class DataBaseOperationException extends RuntimeException { + public DataBaseOperationException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/L24-webServer/src/main/java/ru/otus/from_orm_hw/core/sessionmanager/TransactionAction.java b/L24-webServer/src/main/java/ru/otus/from_orm_hw/core/sessionmanager/TransactionAction.java new file mode 100644 index 0000000..a21b783 --- /dev/null +++ b/L24-webServer/src/main/java/ru/otus/from_orm_hw/core/sessionmanager/TransactionAction.java @@ -0,0 +1,6 @@ +package ru.otus.from_orm_hw.core.sessionmanager; + +import java.util.function.Function; +import org.hibernate.Session; + +public interface TransactionAction extends Function {} diff --git a/L24-webServer/src/main/java/ru/otus/from_orm_hw/core/sessionmanager/TransactionManager.java b/L24-webServer/src/main/java/ru/otus/from_orm_hw/core/sessionmanager/TransactionManager.java new file mode 100644 index 0000000..1a38458 --- /dev/null +++ b/L24-webServer/src/main/java/ru/otus/from_orm_hw/core/sessionmanager/TransactionManager.java @@ -0,0 +1,8 @@ +package ru.otus.from_orm_hw.core.sessionmanager; + +public interface TransactionManager { + + T doInTransaction(TransactionAction action); + + T doInReadOnlyTransaction(TransactionAction action); +} diff --git a/L24-webServer/src/main/java/ru/otus/from_orm_hw/core/sessionmanager/TransactionManagerHibernate.java b/L24-webServer/src/main/java/ru/otus/from_orm_hw/core/sessionmanager/TransactionManagerHibernate.java new file mode 100644 index 0000000..a7ee0bd --- /dev/null +++ b/L24-webServer/src/main/java/ru/otus/from_orm_hw/core/sessionmanager/TransactionManagerHibernate.java @@ -0,0 +1,49 @@ +package ru.otus.from_orm_hw.core.sessionmanager; + +import java.util.concurrent.Callable; +import org.hibernate.SessionFactory; + +public class TransactionManagerHibernate implements TransactionManager { + private final SessionFactory sessionFactory; + + public TransactionManagerHibernate(SessionFactory sessionFactory) { + this.sessionFactory = sessionFactory; + } + + @Override + public T doInTransaction(TransactionAction action) { + return doInTransaction(action, false); + } + + @Override + public T doInReadOnlyTransaction(TransactionAction action) { + return doInTransaction(action, true); + } + + private T doInTransaction(TransactionAction action, boolean readOnlyTran) { + return wrapException(() -> { + try (var session = sessionFactory.openSession()) { + if (readOnlyTran) { + session.setDefaultReadOnly(true); + } + var transaction = session.beginTransaction(); + try { + var result = action.apply(session); + transaction.commit(); + return result; + } catch (Exception ex) { + transaction.rollback(); + throw ex; + } + } + }); + } + + private T wrapException(Callable action) { + try { + return action.call(); + } catch (Exception ex) { + throw new DataBaseOperationException("Exception in transaction", ex); + } + } +} diff --git a/L24-webServer/src/main/java/ru/otus/from_orm_hw/crm/model/Address.java b/L24-webServer/src/main/java/ru/otus/from_orm_hw/crm/model/Address.java new file mode 100644 index 0000000..7308efb --- /dev/null +++ b/L24-webServer/src/main/java/ru/otus/from_orm_hw/crm/model/Address.java @@ -0,0 +1,41 @@ +package ru.otus.from_orm_hw.crm.model; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Entity +@Table(name = "addresses") +@NoArgsConstructor +@Getter +@Setter +public class Address implements Cloneable { + + @Id + @Column(name = "id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(name = "street") + private String street; + + public Address(Long id, String street) { + this.id = id; + this.street = street; + } + + public Address clone() { + return new Address(id, street); + } + + @Override + public String toString() { + return "Address{" + "id=" + id + ", street='" + street + '\'' + '}'; + } +} diff --git a/L24-webServer/src/main/java/ru/otus/from_orm_hw/crm/model/Client.java b/L24-webServer/src/main/java/ru/otus/from_orm_hw/crm/model/Client.java new file mode 100644 index 0000000..04d4fea --- /dev/null +++ b/L24-webServer/src/main/java/ru/otus/from_orm_hw/crm/model/Client.java @@ -0,0 +1,96 @@ +package ru.otus.from_orm_hw.crm.model; + +import jakarta.persistence.CascadeType; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.OneToMany; +import jakarta.persistence.OneToOne; +import jakarta.persistence.SequenceGenerator; +import jakarta.persistence.Table; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@Entity +@Table(name = "client") +public class Client implements Cloneable { + + @Id + @SequenceGenerator(name = "client_gen", sequenceName = "client_seq", initialValue = 1, allocationSize = 1) + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "client_gen") + @Column(name = "id") + private Long id; + + @Column(name = "name") + private String name; + + @OneToOne(cascade = CascadeType.ALL, orphanRemoval = true) + @JoinColumn(name = "client_id") + private Address address; + + @OneToMany(mappedBy = "client", cascade = CascadeType.ALL, orphanRemoval = true) + private List phones = new ArrayList<>(); + + public Client(String name) { + this.id = null; + this.name = name; + } + + public Client(Long id, String name) { + this.id = id; + this.name = name; + } + + public Client(Long id, String name, Address address, List phones) { + this.id = id; + this.name = name; + + if (address != null) { + this.address = address.clone(); + } + this.phones = phones; + + if (phones != null) { + List phonesCopy = new ArrayList<>(); + for (Phone p : phones) { + + Phone phoneCopy = p.clone(); + phoneCopy.setClient(this); + phonesCopy.add(phoneCopy); + } + this.phones = phonesCopy; + } + } + + @Override + @SuppressWarnings({"java:S2975", "java:S1182"}) + public Client clone() { + return new Client(this.id, this.name, this.address, this.phones); + } + + @Override + public String toString() { + return "Client{" + "id=" + id + ", name='" + name + '\'' + ", phones='" + phones + '\'' + ", address='" + + address + '\'' + '}'; + } + + public String addressText() { + if (getAddress() == null) return "null"; + else return getAddress().getStreet(); + } + + public String phonesText() { + if (getPhones() == null) return "null"; + else return getPhones().stream().map(Phone::getNumber).collect(Collectors.joining(", ")); + } +} diff --git a/L24-webServer/src/main/java/ru/otus/from_orm_hw/crm/model/Phone.java b/L24-webServer/src/main/java/ru/otus/from_orm_hw/crm/model/Phone.java new file mode 100644 index 0000000..84f962a --- /dev/null +++ b/L24-webServer/src/main/java/ru/otus/from_orm_hw/crm/model/Phone.java @@ -0,0 +1,49 @@ +package ru.otus.from_orm_hw.crm.model; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Entity +@Table(name = "phones") +@NoArgsConstructor +@Getter +@Setter +public class Phone implements Cloneable { + + @Id + @Column(name = "id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(name = "number") + private String number; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "client_id") + private Client client; + + public Phone(Long id, String number) { + this.id = id; + this.number = number; + } + + @Override + public Phone clone() { + return new Phone(id, number); + } + + @Override + public String toString() { + return "Phone{" + "id=" + id + ", number='" + number + '\'' + '}'; + } +} diff --git a/L24-webServer/src/main/java/ru/otus/from_orm_hw/crm/service/DBServiceClient.java b/L24-webServer/src/main/java/ru/otus/from_orm_hw/crm/service/DBServiceClient.java new file mode 100644 index 0000000..d9ebca4 --- /dev/null +++ b/L24-webServer/src/main/java/ru/otus/from_orm_hw/crm/service/DBServiceClient.java @@ -0,0 +1,14 @@ +package ru.otus.from_orm_hw.crm.service; + +import java.util.List; +import java.util.Optional; +import ru.otus.from_orm_hw.crm.model.Client; + +public interface DBServiceClient { + + Client saveClient(Client client); + + Optional getClient(long id); + + List findAll(); +} diff --git a/L24-webServer/src/main/java/ru/otus/from_orm_hw/crm/service/DbServiceClientImpl.java b/L24-webServer/src/main/java/ru/otus/from_orm_hw/crm/service/DbServiceClientImpl.java new file mode 100644 index 0000000..633df1a --- /dev/null +++ b/L24-webServer/src/main/java/ru/otus/from_orm_hw/crm/service/DbServiceClientImpl.java @@ -0,0 +1,54 @@ +package ru.otus.from_orm_hw.crm.service; + +import java.util.List; +import java.util.Optional; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import ru.otus.from_orm_hw.core.repository.DataTemplate; +import ru.otus.from_orm_hw.core.sessionmanager.TransactionManager; +import ru.otus.from_orm_hw.crm.model.Client; + +public class DbServiceClientImpl implements DBServiceClient { + private static final Logger log = LoggerFactory.getLogger(DbServiceClientImpl.class); + + private final DataTemplate clientDataTemplate; + private final TransactionManager transactionManager; + + public DbServiceClientImpl(TransactionManager transactionManager, DataTemplate clientDataTemplate) { + this.transactionManager = transactionManager; + this.clientDataTemplate = clientDataTemplate; + } + + @Override + public Client saveClient(Client client) { + return transactionManager.doInTransaction(session -> { + var clientCloned = client.clone(); + if (client.getId() == null) { + var savedClient = clientDataTemplate.insert(session, clientCloned); + log.info("created client: {}", clientCloned); + return savedClient; + } + var savedClient = clientDataTemplate.update(session, clientCloned); + log.info("updated client: {}", savedClient); + return savedClient; + }); + } + + @Override + public Optional getClient(long id) { + return transactionManager.doInReadOnlyTransaction(session -> { + var clientOptional = clientDataTemplate.findById(session, id); + log.info("client: {}", clientOptional); + return clientOptional; + }); + } + + @Override + public List findAll() { + return transactionManager.doInReadOnlyTransaction(session -> { + var clientList = clientDataTemplate.findAll(session); + log.info("clientList:{}", clientList); + return clientList; + }); + } +} diff --git a/L24-webServer/src/main/java/ru/otus/model/RequestCreateClientModel.java b/L24-webServer/src/main/java/ru/otus/model/RequestCreateClientModel.java new file mode 100644 index 0000000..6156d14 --- /dev/null +++ b/L24-webServer/src/main/java/ru/otus/model/RequestCreateClientModel.java @@ -0,0 +1,14 @@ +package ru.otus.model; + +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +public class RequestCreateClientModel { + private String name; + private String address; + private String number; +} diff --git a/L24-webServer/src/main/java/ru/otus/model/RequestPhoneModel.java b/L24-webServer/src/main/java/ru/otus/model/RequestPhoneModel.java new file mode 100644 index 0000000..eab2bea --- /dev/null +++ b/L24-webServer/src/main/java/ru/otus/model/RequestPhoneModel.java @@ -0,0 +1,13 @@ +package ru.otus.model; + +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +public class RequestPhoneModel { + private Long clientId; + private String number; +} diff --git a/L24-webServer/src/main/java/ru/otus/model/RequestUpdateAddressModel.java b/L24-webServer/src/main/java/ru/otus/model/RequestUpdateAddressModel.java new file mode 100644 index 0000000..8c070c4 --- /dev/null +++ b/L24-webServer/src/main/java/ru/otus/model/RequestUpdateAddressModel.java @@ -0,0 +1,13 @@ +package ru.otus.model; + +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +public class RequestUpdateAddressModel { + private Long clientId; + private String address; +} diff --git a/L24-webServer/src/main/java/ru/otus/model/User.java b/L24-webServer/src/main/java/ru/otus/model/User.java index c380873..719836d 100644 --- a/L24-webServer/src/main/java/ru/otus/model/User.java +++ b/L24-webServer/src/main/java/ru/otus/model/User.java @@ -1,11 +1,35 @@ package ru.otus.model; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@RequiredArgsConstructor +@Entity +@Table(name = "users") public class User { - private final long id; - private final String name; - private final String login; - private final String password; + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id") + private Long id; + + @Column(name = "name") + private String name; + + @Column(name = "login") + private String login; + + @Column(name = "password") + private String password; public User(long id, String name, String login, String password) { this.id = id; @@ -13,20 +37,4 @@ public User(long id, String name, String login, String password) { this.login = login; this.password = password; } - - public long getId() { - return id; - } - - public String getName() { - return name; - } - - public String getLogin() { - return login; - } - - public String getPassword() { - return password; - } } diff --git a/L24-webServer/src/main/java/ru/otus/server/UsersWebServerSimple.java b/L24-webServer/src/main/java/ru/otus/server/UsersWebServerSimple.java index 85525d1..a188543 100644 --- a/L24-webServer/src/main/java/ru/otus/server/UsersWebServerSimple.java +++ b/L24-webServer/src/main/java/ru/otus/server/UsersWebServerSimple.java @@ -6,9 +6,14 @@ import org.eclipse.jetty.server.Handler; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.handler.ResourceHandler; +import ru.otus.dao.ClientDao; import ru.otus.dao.UserDao; import ru.otus.helpers.FileSystemHelper; import ru.otus.services.TemplateProcessor; +import ru.otus.servlet.ClientsAddressApiServlet; +import ru.otus.servlet.ClientsApiServlet; +import ru.otus.servlet.ClientsPhoneApiServlet; +import ru.otus.servlet.ClientsServlet; import ru.otus.servlet.UsersApiServlet; import ru.otus.servlet.UsersServlet; @@ -17,12 +22,15 @@ public class UsersWebServerSimple implements UsersWebServer { private static final String COMMON_RESOURCES_DIR = "static"; private final UserDao userDao; + private final ClientDao clientDao; private final Gson gson; protected final TemplateProcessor templateProcessor; private final Server server; - public UsersWebServerSimple(int port, UserDao userDao, Gson gson, TemplateProcessor templateProcessor) { + public UsersWebServerSimple( + int port, UserDao userDao, ClientDao clientDao, Gson gson, TemplateProcessor templateProcessor) { this.userDao = userDao; + this.clientDao = clientDao; this.gson = gson; this.templateProcessor = templateProcessor; server = new Server(port); @@ -53,7 +61,7 @@ private void initContext() { Handler.Sequence sequence = new Handler.Sequence(); sequence.addHandler(resourceHandler); - sequence.addHandler(applySecurity(servletContextHandler, "/users", "/api/user/*")); + sequence.addHandler(applySecurity(servletContextHandler, "/users", "/api/user/*", "/clients")); server.setHandler(sequence); } @@ -75,7 +83,15 @@ private ResourceHandler createResourceHandler() { private ServletContextHandler createServletContextHandler() { ServletContextHandler servletContextHandler = new ServletContextHandler(ServletContextHandler.SESSIONS); servletContextHandler.addServlet(new ServletHolder(new UsersServlet(templateProcessor, userDao)), "/users"); + servletContextHandler.addServlet( + new ServletHolder(new ClientsServlet(templateProcessor, clientDao)), "/clients"); + servletContextHandler.addServlet(new ServletHolder(new UsersApiServlet(userDao, gson)), "/api/user/*"); + servletContextHandler.addServlet(new ServletHolder(new ClientsApiServlet(clientDao, gson)), "/api/client"); + servletContextHandler.addServlet( + new ServletHolder(new ClientsPhoneApiServlet(clientDao, gson)), "/api/client/phone"); + servletContextHandler.addServlet( + new ServletHolder(new ClientsAddressApiServlet(clientDao, gson)), "/api/client/address"); return servletContextHandler; } } diff --git a/L24-webServer/src/main/java/ru/otus/server/UsersWebServerWithBasicSecurity.java b/L24-webServer/src/main/java/ru/otus/server/UsersWebServerWithBasicSecurity.java index 6303424..f7b05e6 100644 --- a/L24-webServer/src/main/java/ru/otus/server/UsersWebServerWithBasicSecurity.java +++ b/L24-webServer/src/main/java/ru/otus/server/UsersWebServerWithBasicSecurity.java @@ -11,6 +11,7 @@ import org.eclipse.jetty.security.LoginService; import org.eclipse.jetty.security.authentication.BasicAuthenticator; import org.eclipse.jetty.server.Handler; +import ru.otus.dao.ClientDao; import ru.otus.dao.UserDao; import ru.otus.services.TemplateProcessor; @@ -21,8 +22,13 @@ public class UsersWebServerWithBasicSecurity extends UsersWebServerSimple { private final LoginService loginService; public UsersWebServerWithBasicSecurity( - int port, LoginService loginService, UserDao userDao, Gson gson, TemplateProcessor templateProcessor) { - super(port, userDao, gson, templateProcessor); + int port, + LoginService loginService, + UserDao userDao, + ClientDao clientDao, + Gson gson, + TemplateProcessor templateProcessor) { + super(port, userDao, clientDao, gson, templateProcessor); this.loginService = loginService; } diff --git a/L24-webServer/src/main/java/ru/otus/server/UsersWebServerWithFilterBasedSecurity.java b/L24-webServer/src/main/java/ru/otus/server/UsersWebServerWithFilterBasedSecurity.java index 5971891..894928e 100644 --- a/L24-webServer/src/main/java/ru/otus/server/UsersWebServerWithFilterBasedSecurity.java +++ b/L24-webServer/src/main/java/ru/otus/server/UsersWebServerWithFilterBasedSecurity.java @@ -6,6 +6,7 @@ import org.eclipse.jetty.ee10.servlet.ServletContextHandler; import org.eclipse.jetty.ee10.servlet.ServletHolder; import org.eclipse.jetty.server.Handler; +import ru.otus.dao.ClientDao; import ru.otus.dao.UserDao; import ru.otus.services.TemplateProcessor; import ru.otus.services.UserAuthService; @@ -16,8 +17,13 @@ public class UsersWebServerWithFilterBasedSecurity extends UsersWebServerSimple private final UserAuthService authService; public UsersWebServerWithFilterBasedSecurity( - int port, UserAuthService authService, UserDao userDao, Gson gson, TemplateProcessor templateProcessor) { - super(port, userDao, gson, templateProcessor); + int port, + UserAuthService authService, + UserDao userDao, + ClientDao clientDao, + Gson gson, + TemplateProcessor templateProcessor) { + super(port, userDao, clientDao, gson, templateProcessor); this.authService = authService; } diff --git a/L24-webServer/src/main/java/ru/otus/servlet/ClientsAddressApiServlet.java b/L24-webServer/src/main/java/ru/otus/servlet/ClientsAddressApiServlet.java new file mode 100644 index 0000000..965c3cc --- /dev/null +++ b/L24-webServer/src/main/java/ru/otus/servlet/ClientsAddressApiServlet.java @@ -0,0 +1,56 @@ +package ru.otus.servlet; + +import com.google.gson.Gson; +import jakarta.servlet.ServletOutputStream; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import java.io.BufferedReader; +import java.io.IOException; +import ru.otus.dao.ClientDao; +import ru.otus.model.RequestUpdateAddressModel; + +@SuppressWarnings({"java:S1989"}) +public class ClientsAddressApiServlet extends HttpServlet { + + private static final int ID_PATH_PARAM_POSITION = 1; + + private final transient ClientDao clientsDao; + private final transient Gson gson; + + public ClientsAddressApiServlet(ClientDao clientsDao, Gson gson) { + this.clientsDao = clientsDao; + this.gson = gson; + } + + protected void doPut(HttpServletRequest request, HttpServletResponse response) throws IOException { + response.setContentType("application/json;charset=UTF-8"); + + StringBuilder sb = new StringBuilder(); + try (BufferedReader reader = request.getReader()) { + String line; + while ((line = reader.readLine()) != null) { + sb.append(line); + } + } + + var requestModel = gson.fromJson(sb.toString(), RequestUpdateAddressModel.class); + + var clientOptional = clientsDao.updateAddress(requestModel.getClientId(), requestModel.getAddress()); + + if (clientOptional.isPresent()) { + response.setStatus(HttpServletResponse.SC_CREATED); + } else { + response.setStatus(HttpServletResponse.SC_BAD_REQUEST); + } + + ServletOutputStream out = response.getOutputStream(); + // out.print(gson.toJson(clientOptional)); + } + + private long extractIdFromRequest(HttpServletRequest request) { + String[] path = request.getPathInfo().split("/"); + String id = (path.length > 1) ? path[ID_PATH_PARAM_POSITION] : String.valueOf(-1); + return Long.parseLong(id); + } +} diff --git a/L24-webServer/src/main/java/ru/otus/servlet/ClientsApiServlet.java b/L24-webServer/src/main/java/ru/otus/servlet/ClientsApiServlet.java new file mode 100644 index 0000000..f572f3f --- /dev/null +++ b/L24-webServer/src/main/java/ru/otus/servlet/ClientsApiServlet.java @@ -0,0 +1,60 @@ +package ru.otus.servlet; + +import com.google.gson.Gson; +import jakarta.servlet.ServletException; +import jakarta.servlet.ServletOutputStream; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import java.io.BufferedReader; +import java.io.IOException; +import java.util.List; +import ru.otus.dao.ClientDao; +import ru.otus.from_orm_hw.crm.model.Address; +import ru.otus.from_orm_hw.crm.model.Client; +import ru.otus.from_orm_hw.crm.model.Phone; +import ru.otus.model.*; + +@SuppressWarnings({"java:S1989"}) +public class ClientsApiServlet extends HttpServlet { + + private final transient ClientDao clientsDao; + private final transient Gson gson; + + public ClientsApiServlet(ClientDao clientsDao, Gson gson) { + this.clientsDao = clientsDao; + this.gson = gson; + } + + protected void doPost(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + response.setContentType("application/json;charset=UTF-8"); + + StringBuilder sb = new StringBuilder(); + try (BufferedReader reader = request.getReader()) { + String line; + while ((line = reader.readLine()) != null) { + sb.append(line); + } + } + + Gson gson = new Gson(); + var requestModel = gson.fromJson(sb.toString(), RequestCreateClientModel.class); + + var client = new Client( + null, + requestModel.getName(), + new Address(null, requestModel.getAddress()), + List.of(new Phone(null, requestModel.getNumber()))); + + var clientOptional = clientsDao.createClient(client); + + if (clientOptional.isPresent()) { + response.setStatus(HttpServletResponse.SC_CREATED); + } else { + response.setStatus(HttpServletResponse.SC_BAD_REQUEST); + } + + ServletOutputStream out = response.getOutputStream(); + } +} diff --git a/L24-webServer/src/main/java/ru/otus/servlet/ClientsPhoneApiServlet.java b/L24-webServer/src/main/java/ru/otus/servlet/ClientsPhoneApiServlet.java new file mode 100644 index 0000000..1c0358c --- /dev/null +++ b/L24-webServer/src/main/java/ru/otus/servlet/ClientsPhoneApiServlet.java @@ -0,0 +1,78 @@ +package ru.otus.servlet; + +import com.google.gson.Gson; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import java.io.BufferedReader; +import java.io.IOException; +import ru.otus.dao.ClientDao; +import ru.otus.model.RequestPhoneModel; + +@SuppressWarnings({"java:S1989"}) +public class ClientsPhoneApiServlet extends HttpServlet { + + private static final int ID_PATH_PARAM_POSITION = 1; + + private final transient ClientDao clientsDao; + private final transient Gson gson; + + public ClientsPhoneApiServlet(ClientDao clientsDao, Gson gson) { + this.clientsDao = clientsDao; + this.gson = gson; + } + + protected void doDelete(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + response.setContentType("application/json;charset=UTF-8"); + + StringBuilder sb = new StringBuilder(); + try (BufferedReader reader = request.getReader()) { + String line; + while ((line = reader.readLine()) != null) { + sb.append(line); + } + } + + Gson gson = new Gson(); + var requestModel = gson.fromJson(sb.toString(), RequestPhoneModel.class); + + var clientOptional = clientsDao.deletePhone(requestModel.getClientId(), requestModel.getNumber()); + + if (clientOptional.isPresent()) { + response.setStatus(HttpServletResponse.SC_CREATED); + } else { + response.setStatus(HttpServletResponse.SC_BAD_REQUEST); + } + } + + protected void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException { + response.setContentType("application/json;charset=UTF-8"); + + StringBuilder sb = new StringBuilder(); + try (BufferedReader reader = request.getReader()) { + String line; + while ((line = reader.readLine()) != null) { + sb.append(line); + } + } + + Gson gson = new Gson(); + var requestModel = gson.fromJson(sb.toString(), RequestPhoneModel.class); + + var clientOptional = clientsDao.addPhone(requestModel.getClientId(), requestModel.getNumber()); + + if (clientOptional.isPresent()) { + response.setStatus(HttpServletResponse.SC_CREATED); + } else { + response.setStatus(HttpServletResponse.SC_BAD_REQUEST); + } + } + + private long extractIdFromRequest(HttpServletRequest request) { + String[] path = request.getPathInfo().split("/"); + String id = (path.length > 1) ? path[ID_PATH_PARAM_POSITION] : String.valueOf(-1); + return Long.parseLong(id); + } +} diff --git a/L24-webServer/src/main/java/ru/otus/servlet/ClientsServlet.java b/L24-webServer/src/main/java/ru/otus/servlet/ClientsServlet.java new file mode 100644 index 0000000..4feda41 --- /dev/null +++ b/L24-webServer/src/main/java/ru/otus/servlet/ClientsServlet.java @@ -0,0 +1,35 @@ +package ru.otus.servlet; + +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import ru.otus.dao.ClientDao; +import ru.otus.services.TemplateProcessor; + +@SuppressWarnings({"java:S1989"}) +public class ClientsServlet extends HttpServlet { + + private static final String CLIENTS_PAGE_TEMPLATE = "clients.html"; + private static final String TEMPLATE_ATTR_CLIENTS = "clients"; + + private final transient ClientDao clientDao; + private final transient TemplateProcessor templateProcessor; + + public ClientsServlet(TemplateProcessor templateProcessor, ClientDao clientDao) { + this.templateProcessor = templateProcessor; + this.clientDao = clientDao; + } + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse response) throws IOException { + Map paramsMap = new HashMap<>(); + var listClients = clientDao.getAll(); + paramsMap.put(TEMPLATE_ATTR_CLIENTS, listClients); + + response.setContentType("text/html"); + response.getWriter().println(templateProcessor.getPage(CLIENTS_PAGE_TEMPLATE, paramsMap)); + } +} diff --git a/L24-webServer/src/main/java/ru/otus/servlet/UsersApiServlet.java b/L24-webServer/src/main/java/ru/otus/servlet/UsersApiServlet.java index d097440..23f1962 100644 --- a/L24-webServer/src/main/java/ru/otus/servlet/UsersApiServlet.java +++ b/L24-webServer/src/main/java/ru/otus/servlet/UsersApiServlet.java @@ -5,6 +5,7 @@ import jakarta.servlet.http.HttpServlet; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; +import java.io.BufferedReader; import java.io.IOException; import ru.otus.dao.UserDao; import ru.otus.model.User; @@ -31,6 +32,26 @@ protected void doGet(HttpServletRequest request, HttpServletResponse response) t out.print(gson.toJson(user)); } + @Override + protected void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException { + response.setContentType("application/json;charset=UTF-8"); + + StringBuilder sb = new StringBuilder(); + try (BufferedReader reader = request.getReader()) { + String line; + while ((line = reader.readLine()) != null) { + sb.append(line); + } + } + + User user = gson.fromJson(sb.toString(), User.class); + + var createdUsr = userDao.createUser(user); + + ServletOutputStream out = response.getOutputStream(); + out.print(gson.toJson(createdUsr.get())); + } + private long extractIdFromRequest(HttpServletRequest request) { String[] path = request.getPathInfo().split("/"); String id = (path.length > 1) ? path[ID_PATH_PARAM_POSITION] : String.valueOf(-1); diff --git a/L24-webServer/src/main/java/ru/otus/servlet/UsersServlet.java b/L24-webServer/src/main/java/ru/otus/servlet/UsersServlet.java index c7054e6..908d97c 100644 --- a/L24-webServer/src/main/java/ru/otus/servlet/UsersServlet.java +++ b/L24-webServer/src/main/java/ru/otus/servlet/UsersServlet.java @@ -15,6 +15,8 @@ public class UsersServlet extends HttpServlet { private static final String USERS_PAGE_TEMPLATE = "users.html"; private static final String TEMPLATE_ATTR_RANDOM_USER = "randomUser"; + private static final String DEFAULT_PASSWORD = "111"; + private final transient UserDao userDao; private final transient TemplateProcessor templateProcessor; @@ -26,7 +28,12 @@ public UsersServlet(TemplateProcessor templateProcessor, UserDao userDao) { @Override protected void doGet(HttpServletRequest req, HttpServletResponse response) throws IOException { Map paramsMap = new HashMap<>(); - userDao.findRandomUser().ifPresent(randomUser -> paramsMap.put(TEMPLATE_ATTR_RANDOM_USER, randomUser)); + + var randomUserOpt = userDao.findRandomUser(); + + if (randomUserOpt.isPresent()) { + paramsMap.put(TEMPLATE_ATTR_RANDOM_USER, randomUserOpt.get()); + } response.setContentType("text/html"); response.getWriter().println(templateProcessor.getPage(USERS_PAGE_TEMPLATE, paramsMap)); diff --git a/L24-webServer/src/main/resources/hibernate.cfg.xml b/L24-webServer/src/main/resources/hibernate.cfg.xml new file mode 100644 index 0000000..daa3957 --- /dev/null +++ b/L24-webServer/src/main/resources/hibernate.cfg.xml @@ -0,0 +1,22 @@ + + + + + + org.hibernate.dialect.PostgreSQLDialect + + + jdbc:postgresql://localhost:5430/demoDB + + usr + pwd + + true + true + + create-drop + false + + + diff --git a/L24-webServer/src/main/resources/logback.xml b/L24-webServer/src/main/resources/logback.xml new file mode 100644 index 0000000..5ff97c1 --- /dev/null +++ b/L24-webServer/src/main/resources/logback.xml @@ -0,0 +1,18 @@ + + + + + + %d{yyyy-MM-dd_HH:mm:ss.SSS} %-5level %logger{36} - %msg%n + + + + + + + + + + + + diff --git a/L24-webServer/src/main/resources/static/index.html b/L24-webServer/src/main/resources/static/index.html index 63fda19..49a88e5 100644 --- a/L24-webServer/src/main/resources/static/index.html +++ b/L24-webServer/src/main/resources/static/index.html @@ -7,7 +7,8 @@

Добро пожаловать на стартовую страницу примера

- Перейти на странцу информации о пользователях (возможно защищено паролем) + Перейти на странцу информации о пользователях (возможно защищено паролем)
+ Перейти на страницу информации о клиентах (возможно защищено паролем) \ No newline at end of file diff --git a/L24-webServer/src/main/resources/templates/clients.html b/L24-webServer/src/main/resources/templates/clients.html new file mode 100644 index 0000000..fc58e21 --- /dev/null +++ b/L24-webServer/src/main/resources/templates/clients.html @@ -0,0 +1,152 @@ + + + Клиенты + + + + + +

+
+

Создать клиента

+ + + + +

+
+
+

Список клиентов

+ + + + + + + + + + + <#list clients as client> + + + + + + + <#else> + + + + + +
IdИмяАдресТелефоны
${client.id}${client.name}${client.addressText()} изменить<#list client.phones as phone> ${phone.number} удалить
добавить
пусто
+ + \ No newline at end of file diff --git a/L24-webServer/src/main/resources/templates/users.html b/L24-webServer/src/main/resources/templates/users.html index e545c76..460c944 100644 --- a/L24-webServer/src/main/resources/templates/users.html +++ b/L24-webServer/src/main/resources/templates/users.html @@ -11,6 +11,35 @@ .then(response => response.json()) .then(user => userDataContainer.innerHTML = JSON.stringify(user)); } + + function createUser() { + const userNameTextBox = document.getElementById('userNameTextBox'); + const userLoginTextBox = document.getElementById('userLoginTextBox'); + const userPasswordTextBox = document.getElementById('userPasswordTextBox'); + const userCreatedContainer = document.getElementById('userCreatedContainer'); + + const userData = { + name: userNameTextBox.value, + login: userLoginTextBox.value, + password: userPasswordTextBox.value + }; + + fetch('api/user', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(userData) + }) + .then(response => response.json()) + .then(user => { + userCreatedContainer.innerHTML = JSON.stringify(user); + }) + .catch(error => { + console.error('Error:', error); + userCreatedContainer.innerHTML = 'Error creating user'; + }); + } @@ -20,6 +49,13 @@

Получить пользователя по id


 
+

Создать пользователя

+ + + + +

+
 

Случайный пользователь

@@ -31,12 +67,14 @@

Случайный пользователь

- - - - - - + <#if randomUser??> + + + + + + +
${randomUser.id}${randomUser.name}${randomUser.login}${randomUser.password}
${randomUser.id}${randomUser.name}${randomUser.login}${randomUser.password}