From b124fde528724d74f50507893cd4e18424b3db58 Mon Sep 17 00:00:00 2001 From: Kvitto Date: Sat, 14 Sep 2024 21:21:35 +0300 Subject: [PATCH 01/18] HW13 SqlStorageTest done --- src/com/urise/webapp/Config.java | 36 ++++++ src/com/urise/webapp/ResumeTestData.java | 11 +- .../urise/webapp/sql/ConnectionFactory.java | 8 ++ src/com/urise/webapp/storage/SqlStorage.java | 114 ++++++++++++++++++ .../webapp/storage/AbstractStorageTest.java | 3 +- .../urise/webapp/storage/AllStorageTest.java | 3 +- .../urise/webapp/storage/SqlStorageTest.java | 9 ++ 7 files changed, 174 insertions(+), 10 deletions(-) create mode 100644 src/com/urise/webapp/Config.java create mode 100644 src/com/urise/webapp/sql/ConnectionFactory.java create mode 100644 src/com/urise/webapp/storage/SqlStorage.java create mode 100644 test/com/urise/webapp/storage/SqlStorageTest.java diff --git a/src/com/urise/webapp/Config.java b/src/com/urise/webapp/Config.java new file mode 100644 index 0000000..b67e359 --- /dev/null +++ b/src/com/urise/webapp/Config.java @@ -0,0 +1,36 @@ +package com.urise.webapp; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.Properties; + +public class Config { + private static final File PROPS = new File("C:/Java/BaseJava/config/resumes.properties"); + private static final Config INSTANCE = new Config(); + private final Properties props = new Properties(); + private final File storageDir; + private final String url; + private final String user; + private final String password; + + public static Config get() {return INSTANCE;} + + private Config() { + try(InputStream is = new FileInputStream(PROPS)) { + props.load(is); + storageDir = new File(props.getProperty("storage.dir")); + url = props.getProperty("db.url"); + user = props.getProperty("db.user"); + password = props.getProperty("db.password"); + } catch (IOException e) { + throw new IllegalStateException("Invalid config file" + PROPS.getAbsolutePath(), e); + } + } + + public File getStorageDir() {return storageDir;} + public String getUrl() {return url;} + public String getUser() {return user;} + public String getPassword() {return password;} +} diff --git a/src/com/urise/webapp/ResumeTestData.java b/src/com/urise/webapp/ResumeTestData.java index a4ff47d..5a1cdf7 100644 --- a/src/com/urise/webapp/ResumeTestData.java +++ b/src/com/urise/webapp/ResumeTestData.java @@ -1,17 +1,12 @@ package com.urise.webapp; -import com.urise.webapp.model.*; - -import java.time.LocalDate; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; +import com.urise.webapp.model.Resume; public class ResumeTestData { public static Resume createResume(String uuid, String fullName) { Resume myResume = new Resume(uuid, fullName); - Map myContacts = myResume.getContacts(); +/* Map myContacts = myResume.getContacts(); myContacts.put(ContactType.PHONE, "+7(921) 855-0482"); myContacts.put(ContactType.SKYPE, "skype:grigory.kislin"); myContacts.put(ContactType.MAIL, "gkislin@yandex.ru"); @@ -149,7 +144,7 @@ public static Resume createResume(String uuid, String fullName) { for (SectionType section : SectionType.values()) { System.out.println(section.getTitle() + "\n" + myResume.getSections().get(section)); } - +*/ return myResume; } } diff --git a/src/com/urise/webapp/sql/ConnectionFactory.java b/src/com/urise/webapp/sql/ConnectionFactory.java new file mode 100644 index 0000000..08dff92 --- /dev/null +++ b/src/com/urise/webapp/sql/ConnectionFactory.java @@ -0,0 +1,8 @@ +package com.urise.webapp.sql; + +import java.sql.Connection; +import java.sql.SQLException; + +public interface ConnectionFactory { + Connection getConnection() throws SQLException; +} diff --git a/src/com/urise/webapp/storage/SqlStorage.java b/src/com/urise/webapp/storage/SqlStorage.java new file mode 100644 index 0000000..04a0a9f --- /dev/null +++ b/src/com/urise/webapp/storage/SqlStorage.java @@ -0,0 +1,114 @@ +package com.urise.webapp.storage; + +import com.urise.webapp.exception.ExistStorageException; +import com.urise.webapp.exception.NotExistStorageException; +import com.urise.webapp.exception.StorageException; +import com.urise.webapp.model.Resume; +import com.urise.webapp.sql.ConnectionFactory; + +import java.sql.*; +import java.util.ArrayList; +import java.util.List; + +public class SqlStorage implements Storage { + public final ConnectionFactory connectionFactory; + + public SqlStorage(String dbUrl, String dbUser, String dbPass) { + this.connectionFactory = () -> DriverManager.getConnection(dbUrl, dbUser, dbPass); + } + + @Override + public void clear() { + try (Connection connection = connectionFactory.getConnection(); + PreparedStatement ps = connection.prepareStatement("DELETE FROM resume")) { + ps.execute(); + } catch (SQLException e) { + throw new StorageException(e.getMessage()); + } + } + + @Override + public void update(Resume r) { + try (Connection connection = connectionFactory.getConnection(); + PreparedStatement ps = connection.prepareStatement("UPDATE resume r SET full_name=? WHERE r.uuid=?")) { + ps.setString(1, r.getFullName()); + ps.setString(2, r.getUuid()); + if (ps.executeUpdate() == 0) { + throw new NotExistStorageException(r.getUuid()); + } + } catch (SQLException e) { + throw new StorageException(e.getMessage()); + } + } + + @Override + public void save(Resume r) { + try (Connection connection = connectionFactory.getConnection(); + PreparedStatement ps = connection.prepareStatement("INSERT INTO resume (uuid, full_name) VALUES (?, ?)")) { + ps.setString(1, r.getUuid()); + ps.setString(2, r.getFullName()); + ps.execute(); + } catch (SQLException e) { + throw new ExistStorageException(e.getMessage()); + } + } + + @Override + public Resume get(String uuid) { + try (Connection connection = connectionFactory.getConnection(); + PreparedStatement ps = connection.prepareStatement("SELECT * FROM resume r WHERE r.uuid = ?")) { + ps.setString(1, uuid); + ResultSet rs = ps.executeQuery(); + if (!rs.next()) { + throw new NotExistStorageException(uuid); + } + return new Resume(uuid, rs.getString("full_name")); + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + + @Override + public void delete(String uuid) { + try (Connection connection = connectionFactory.getConnection(); + PreparedStatement ps = connection.prepareStatement("DELETE FROM resume WHERE uuid = ?")) { + ps.setString(1, uuid); + if (ps.executeUpdate() == 0) { + throw new NotExistStorageException(uuid); + } + } catch (SQLException e) { + throw new StorageException(e.getMessage()); + } + } + + @Override + public List getAllSorted() { + List resumes = new ArrayList<>(); + try (Connection connection = connectionFactory.getConnection(); + PreparedStatement ps = connection.prepareStatement("SELECT * FROM resume")) { + ResultSet rs = ps.executeQuery(); + while (rs.next()) { + resumes.add(new Resume(rs.getString("uuid").trim(), rs.getString("full_name"))); + } + } catch (SQLException e) { + throw new StorageException(e.getMessage()); + } + return resumes; + } + + @Override + public int size() { + int size; + try (Connection connection = connectionFactory.getConnection(); + PreparedStatement ps = connection.prepareStatement("SELECT count(*) AS count_rows FROM resume")) { + ResultSet rs = ps.executeQuery(); + if (!rs.next()) { + throw new NotExistStorageException("db error"); + } + size = rs.getInt("count_rows"); + } catch (SQLException e) { + throw new StorageException(e.getMessage()); + } + return size; + } +} diff --git a/test/com/urise/webapp/storage/AbstractStorageTest.java b/test/com/urise/webapp/storage/AbstractStorageTest.java index 90adaf5..c2d2c85 100644 --- a/test/com/urise/webapp/storage/AbstractStorageTest.java +++ b/test/com/urise/webapp/storage/AbstractStorageTest.java @@ -1,5 +1,6 @@ package com.urise.webapp.storage; +import com.urise.webapp.Config; import com.urise.webapp.exception.ExistStorageException; import com.urise.webapp.exception.NotExistStorageException; import com.urise.webapp.model.Resume; @@ -14,7 +15,7 @@ import static org.junit.Assert.*; public abstract class AbstractStorageTest { - protected static final File STORAGE_DIR = new File("basejava/storage"); + protected static final File STORAGE_DIR = Config.get().getStorageDir(); protected final Storage storage; diff --git a/test/com/urise/webapp/storage/AllStorageTest.java b/test/com/urise/webapp/storage/AllStorageTest.java index 31f6a43..c88d10b 100644 --- a/test/com/urise/webapp/storage/AllStorageTest.java +++ b/test/com/urise/webapp/storage/AllStorageTest.java @@ -14,7 +14,8 @@ PathStorageTest.class, XmlPathStorageTest.class, JsonPathStorageTest.class, - DataPathStorageTest.class + DataPathStorageTest.class, + SqlStorageTest.class }) public class AllStorageTest { } diff --git a/test/com/urise/webapp/storage/SqlStorageTest.java b/test/com/urise/webapp/storage/SqlStorageTest.java new file mode 100644 index 0000000..cd733d3 --- /dev/null +++ b/test/com/urise/webapp/storage/SqlStorageTest.java @@ -0,0 +1,9 @@ +package com.urise.webapp.storage; + +import com.urise.webapp.Config; + +public class SqlStorageTest extends AbstractStorageTest { + public SqlStorageTest() { + super(new SqlStorage(Config.get().getUrl(), Config.get().getUser(), Config.get().getPassword())); + } +} \ No newline at end of file From 12b703e9cfad0929eb2203b8074802a255923e08 Mon Sep 17 00:00:00 2001 From: Kvitto Date: Sat, 14 Sep 2024 21:24:59 +0300 Subject: [PATCH 02/18] HW13 refactoring with functional interface --- src/com/urise/webapp/storage/SqlHelper.java | 42 +++++++++ src/com/urise/webapp/storage/SqlStorage.java | 90 +++++++------------- 2 files changed, 71 insertions(+), 61 deletions(-) create mode 100644 src/com/urise/webapp/storage/SqlHelper.java diff --git a/src/com/urise/webapp/storage/SqlHelper.java b/src/com/urise/webapp/storage/SqlHelper.java new file mode 100644 index 0000000..bb490d3 --- /dev/null +++ b/src/com/urise/webapp/storage/SqlHelper.java @@ -0,0 +1,42 @@ +package com.urise.webapp.storage; + +import com.urise.webapp.exception.ExistStorageException; +import com.urise.webapp.exception.StorageException; +import com.urise.webapp.sql.ConnectionFactory; + +import java.io.IOException; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.PreparedStatement; +import java.sql.SQLException; + +public class SqlHelper { + public final ConnectionFactory connectionFactory; + + public SqlHelper(String dbUrl, String dbUser, String dbPass) { + this.connectionFactory = () -> DriverManager.getConnection(dbUrl, dbUser, dbPass); + } + + public T query(String sql, String[] values, SqlHelperQuery query) { + try (Connection connection = connectionFactory.getConnection(); + PreparedStatement ps = connection.prepareStatement(sql)) { + if (values != null) { + for (int i = 0; i < values.length; i++) { + ps.setString(i + 1, values[i]); + } + } + return query.execute(ps); + } catch (SQLException e) { + if (e.getSQLState().equals("23505")) { + throw new ExistStorageException(e.getMessage()); + } + throw new StorageException(e.getMessage()); + } catch (IOException e) { + throw new StorageException(e.getMessage()); + } + } + + public interface SqlHelperQuery { + T execute(PreparedStatement ps) throws IOException, SQLException; + } +} diff --git a/src/com/urise/webapp/storage/SqlStorage.java b/src/com/urise/webapp/storage/SqlStorage.java index 04a0a9f..e534362 100644 --- a/src/com/urise/webapp/storage/SqlStorage.java +++ b/src/com/urise/webapp/storage/SqlStorage.java @@ -1,114 +1,82 @@ package com.urise.webapp.storage; -import com.urise.webapp.exception.ExistStorageException; import com.urise.webapp.exception.NotExistStorageException; -import com.urise.webapp.exception.StorageException; import com.urise.webapp.model.Resume; -import com.urise.webapp.sql.ConnectionFactory; -import java.sql.*; +import java.sql.PreparedStatement; +import java.sql.ResultSet; import java.util.ArrayList; import java.util.List; public class SqlStorage implements Storage { - public final ConnectionFactory connectionFactory; + private final SqlHelper sqlHelper; public SqlStorage(String dbUrl, String dbUser, String dbPass) { - this.connectionFactory = () -> DriverManager.getConnection(dbUrl, dbUser, dbPass); + sqlHelper = new SqlHelper(dbUrl, dbUser, dbPass); } @Override public void clear() { - try (Connection connection = connectionFactory.getConnection(); - PreparedStatement ps = connection.prepareStatement("DELETE FROM resume")) { - ps.execute(); - } catch (SQLException e) { - throw new StorageException(e.getMessage()); - } + sqlHelper.query("DELETE FROM resume", null, PreparedStatement::execute); } @Override public void update(Resume r) { - try (Connection connection = connectionFactory.getConnection(); - PreparedStatement ps = connection.prepareStatement("UPDATE resume r SET full_name=? WHERE r.uuid=?")) { - ps.setString(1, r.getFullName()); - ps.setString(2, r.getUuid()); - if (ps.executeUpdate() == 0) { - throw new NotExistStorageException(r.getUuid()); - } - } catch (SQLException e) { - throw new StorageException(e.getMessage()); + if (sqlHelper.query("UPDATE resume r SET full_name=? WHERE r.uuid=?", + new String[]{r.getFullName(), r.getUuid()}, PreparedStatement::executeUpdate) == 0) { + throw new NotExistStorageException(r.getUuid()); } } @Override public void save(Resume r) { - try (Connection connection = connectionFactory.getConnection(); - PreparedStatement ps = connection.prepareStatement("INSERT INTO resume (uuid, full_name) VALUES (?, ?)")) { - ps.setString(1, r.getUuid()); - ps.setString(2, r.getFullName()); - ps.execute(); - } catch (SQLException e) { - throw new ExistStorageException(e.getMessage()); - } + sqlHelper.query("INSERT INTO resume (uuid, full_name) VALUES (?, ?)", + new String[]{r.getUuid(), r.getFullName()}, PreparedStatement::execute); } @Override public Resume get(String uuid) { - try (Connection connection = connectionFactory.getConnection(); - PreparedStatement ps = connection.prepareStatement("SELECT * FROM resume r WHERE r.uuid = ?")) { - ps.setString(1, uuid); - ResultSet rs = ps.executeQuery(); - if (!rs.next()) { - throw new NotExistStorageException(uuid); - } - return new Resume(uuid, rs.getString("full_name")); - } catch (SQLException e) { - throw new RuntimeException(e); - } + String name = sqlHelper.query("SELECT * FROM resume r WHERE r.uuid = ?", + new String[]{uuid}, ps -> { + ps.setString(1, uuid); + ResultSet rs = ps.executeQuery(); + if (!rs.next()) { + throw new NotExistStorageException(uuid); + } + return rs.getString("full_name"); + }); + return new Resume(uuid, name); } @Override public void delete(String uuid) { - try (Connection connection = connectionFactory.getConnection(); - PreparedStatement ps = connection.prepareStatement("DELETE FROM resume WHERE uuid = ?")) { - ps.setString(1, uuid); - if (ps.executeUpdate() == 0) { - throw new NotExistStorageException(uuid); - } - } catch (SQLException e) { - throw new StorageException(e.getMessage()); + if (sqlHelper.query("DELETE FROM resume WHERE uuid = ?", + new String[]{uuid}, PreparedStatement::executeUpdate) == 0) { + throw new NotExistStorageException(uuid); } } @Override public List getAllSorted() { List resumes = new ArrayList<>(); - try (Connection connection = connectionFactory.getConnection(); - PreparedStatement ps = connection.prepareStatement("SELECT * FROM resume")) { + sqlHelper.query("SELECT * FROM resume",null, ps -> { ResultSet rs = ps.executeQuery(); while (rs.next()) { resumes.add(new Resume(rs.getString("uuid").trim(), rs.getString("full_name"))); } - } catch (SQLException e) { - throw new StorageException(e.getMessage()); - } + return null; + }); return resumes; } @Override public int size() { - int size; - try (Connection connection = connectionFactory.getConnection(); - PreparedStatement ps = connection.prepareStatement("SELECT count(*) AS count_rows FROM resume")) { + return sqlHelper.query("SELECT count(*) AS count_rows FROM resume",null, ps -> { ResultSet rs = ps.executeQuery(); if (!rs.next()) { throw new NotExistStorageException("db error"); } - size = rs.getInt("count_rows"); - } catch (SQLException e) { - throw new StorageException(e.getMessage()); - } - return size; + return rs.getInt("count_rows"); + }); } } From b3e1c0b79b67e79f04e6472ded2cbd6fc453dcc4 Mon Sep 17 00:00:00 2001 From: Kvitto Date: Sun, 15 Sep 2024 22:34:42 +0300 Subject: [PATCH 03/18] HW13 after review --- src/com/urise/webapp/Config.java | 18 +++---- src/com/urise/webapp/storage/SqlHelper.java | 12 ++--- src/com/urise/webapp/storage/SqlStorage.java | 52 +++++++++++++------ .../webapp/storage/AbstractStorageTest.java | 11 ++-- .../urise/webapp/storage/SqlStorageTest.java | 2 +- 5 files changed, 55 insertions(+), 40 deletions(-) diff --git a/src/com/urise/webapp/Config.java b/src/com/urise/webapp/Config.java index b67e359..073f3e1 100644 --- a/src/com/urise/webapp/Config.java +++ b/src/com/urise/webapp/Config.java @@ -1,5 +1,8 @@ package com.urise.webapp; +import com.urise.webapp.storage.SqlStorage; +import com.urise.webapp.storage.Storage; + import java.io.File; import java.io.FileInputStream; import java.io.IOException; @@ -11,9 +14,8 @@ public class Config { private static final Config INSTANCE = new Config(); private final Properties props = new Properties(); private final File storageDir; - private final String url; - private final String user; - private final String password; + + private final Storage storage; public static Config get() {return INSTANCE;} @@ -21,16 +23,14 @@ private Config() { try(InputStream is = new FileInputStream(PROPS)) { props.load(is); storageDir = new File(props.getProperty("storage.dir")); - url = props.getProperty("db.url"); - user = props.getProperty("db.user"); - password = props.getProperty("db.password"); + storage = new SqlStorage(props); } catch (IOException e) { throw new IllegalStateException("Invalid config file" + PROPS.getAbsolutePath(), e); } } public File getStorageDir() {return storageDir;} - public String getUrl() {return url;} - public String getUser() {return user;} - public String getPassword() {return password;} + + public Storage getStorage() {return storage;} + } diff --git a/src/com/urise/webapp/storage/SqlHelper.java b/src/com/urise/webapp/storage/SqlHelper.java index bb490d3..38010ab 100644 --- a/src/com/urise/webapp/storage/SqlHelper.java +++ b/src/com/urise/webapp/storage/SqlHelper.java @@ -6,25 +6,19 @@ import java.io.IOException; import java.sql.Connection; -import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.SQLException; public class SqlHelper { public final ConnectionFactory connectionFactory; - public SqlHelper(String dbUrl, String dbUser, String dbPass) { - this.connectionFactory = () -> DriverManager.getConnection(dbUrl, dbUser, dbPass); + public SqlHelper(ConnectionFactory connectionFactory) { + this.connectionFactory = connectionFactory; } - public T query(String sql, String[] values, SqlHelperQuery query) { + public T query(String sql, SqlHelperQuery query) { try (Connection connection = connectionFactory.getConnection(); PreparedStatement ps = connection.prepareStatement(sql)) { - if (values != null) { - for (int i = 0; i < values.length; i++) { - ps.setString(i + 1, values[i]); - } - } return query.execute(ps); } catch (SQLException e) { if (e.getSQLState().equals("23505")) { diff --git a/src/com/urise/webapp/storage/SqlStorage.java b/src/com/urise/webapp/storage/SqlStorage.java index e534362..cc95bad 100644 --- a/src/com/urise/webapp/storage/SqlStorage.java +++ b/src/com/urise/webapp/storage/SqlStorage.java @@ -2,42 +2,58 @@ import com.urise.webapp.exception.NotExistStorageException; import com.urise.webapp.model.Resume; +import com.urise.webapp.sql.ConnectionFactory; +import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.util.ArrayList; import java.util.List; +import java.util.Properties; public class SqlStorage implements Storage { + public final ConnectionFactory connectionFactory; private final SqlHelper sqlHelper; - public SqlStorage(String dbUrl, String dbUser, String dbPass) { - sqlHelper = new SqlHelper(dbUrl, dbUser, dbPass); + public SqlStorage(Properties properties) { + this.connectionFactory = () -> DriverManager.getConnection(properties.getProperty("db.url"), + properties.getProperty("db.user"), properties.getProperty("db.password")); + sqlHelper = new SqlHelper(connectionFactory); } @Override public void clear() { - sqlHelper.query("DELETE FROM resume", null, PreparedStatement::execute); + sqlHelper.query("DELETE FROM resume", PreparedStatement::execute); } @Override public void update(Resume r) { - if (sqlHelper.query("UPDATE resume r SET full_name=? WHERE r.uuid=?", - new String[]{r.getFullName(), r.getUuid()}, PreparedStatement::executeUpdate) == 0) { - throw new NotExistStorageException(r.getUuid()); - } + sqlHelper.query("UPDATE resume r SET full_name=? WHERE r.uuid=?", + ps -> { + ps.setString(1, r.getFullName()); + ps.setString(2, r.getUuid()); + if (ps.executeUpdate() == 0) { + throw new NotExistStorageException(r.getUuid()); + } + return null; + }); } @Override public void save(Resume r) { sqlHelper.query("INSERT INTO resume (uuid, full_name) VALUES (?, ?)", - new String[]{r.getUuid(), r.getFullName()}, PreparedStatement::execute); + ps -> { + ps.setString(1, r.getUuid()); + ps.setString(2, r.getFullName()); + ps.execute(); + return null; + }); } @Override public Resume get(String uuid) { String name = sqlHelper.query("SELECT * FROM resume r WHERE r.uuid = ?", - new String[]{uuid}, ps -> { + ps -> { ps.setString(1, uuid); ResultSet rs = ps.executeQuery(); if (!rs.next()) { @@ -50,19 +66,23 @@ public Resume get(String uuid) { @Override public void delete(String uuid) { - if (sqlHelper.query("DELETE FROM resume WHERE uuid = ?", - new String[]{uuid}, PreparedStatement::executeUpdate) == 0) { - throw new NotExistStorageException(uuid); - } + sqlHelper.query("DELETE FROM resume WHERE uuid = ?", + ps -> { + ps.setString(1, uuid); + if (ps.executeUpdate() == 0) { + throw new NotExistStorageException(uuid); + } + return null; + }); } @Override public List getAllSorted() { List resumes = new ArrayList<>(); - sqlHelper.query("SELECT * FROM resume",null, ps -> { + sqlHelper.query("SELECT * FROM resume ORDER BY full_name", ps -> { ResultSet rs = ps.executeQuery(); while (rs.next()) { - resumes.add(new Resume(rs.getString("uuid").trim(), rs.getString("full_name"))); + resumes.add(new Resume(rs.getString("uuid"), rs.getString("full_name"))); } return null; }); @@ -71,7 +91,7 @@ public List getAllSorted() { @Override public int size() { - return sqlHelper.query("SELECT count(*) AS count_rows FROM resume",null, ps -> { + return sqlHelper.query("SELECT count(*) AS count_rows FROM resume", ps -> { ResultSet rs = ps.executeQuery(); if (!rs.next()) { throw new NotExistStorageException("db error"); diff --git a/test/com/urise/webapp/storage/AbstractStorageTest.java b/test/com/urise/webapp/storage/AbstractStorageTest.java index c2d2c85..5902202 100644 --- a/test/com/urise/webapp/storage/AbstractStorageTest.java +++ b/test/com/urise/webapp/storage/AbstractStorageTest.java @@ -10,19 +10,20 @@ import java.io.File; import java.util.Arrays; import java.util.List; +import java.util.UUID; import static com.urise.webapp.ResumeTestData.createResume; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; public abstract class AbstractStorageTest { protected static final File STORAGE_DIR = Config.get().getStorageDir(); protected final Storage storage; - private static final String UUID_1 = "uuid1"; - private static final String UUID_2 = "uuid2"; - private static final String UUID_3 = "uuid3"; - private static final String UUID_4 = "uuid4"; + private static final String UUID_1 = String.valueOf(UUID.randomUUID()); + private static final String UUID_2 = String.valueOf(UUID.randomUUID()); + private static final String UUID_3 = String.valueOf(UUID.randomUUID()); + private static final String UUID_4 = String.valueOf(UUID.randomUUID()); private static final Resume RESUME_1; private static final Resume RESUME_2; diff --git a/test/com/urise/webapp/storage/SqlStorageTest.java b/test/com/urise/webapp/storage/SqlStorageTest.java index cd733d3..afc9da9 100644 --- a/test/com/urise/webapp/storage/SqlStorageTest.java +++ b/test/com/urise/webapp/storage/SqlStorageTest.java @@ -4,6 +4,6 @@ public class SqlStorageTest extends AbstractStorageTest { public SqlStorageTest() { - super(new SqlStorage(Config.get().getUrl(), Config.get().getUser(), Config.get().getPassword())); + super(Config.get().getStorage()); } } \ No newline at end of file From d5ecb6ebb1f4c57bb4caa410e38fe23896616d32 Mon Sep 17 00:00:00 2001 From: Kvitto Date: Mon, 16 Sep 2024 19:55:24 +0300 Subject: [PATCH 04/18] HW13 encapsulate connection to SqlStorage in Config. --- src/com/urise/webapp/Config.java | 3 ++- src/com/urise/webapp/storage/SqlStorage.java | 6 ++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/com/urise/webapp/Config.java b/src/com/urise/webapp/Config.java index 073f3e1..0759527 100644 --- a/src/com/urise/webapp/Config.java +++ b/src/com/urise/webapp/Config.java @@ -23,7 +23,8 @@ private Config() { try(InputStream is = new FileInputStream(PROPS)) { props.load(is); storageDir = new File(props.getProperty("storage.dir")); - storage = new SqlStorage(props); + storage = new SqlStorage(props.getProperty("db.url"), + props.getProperty("db.user"), props.getProperty("db.password")); } catch (IOException e) { throw new IllegalStateException("Invalid config file" + PROPS.getAbsolutePath(), e); } diff --git a/src/com/urise/webapp/storage/SqlStorage.java b/src/com/urise/webapp/storage/SqlStorage.java index cc95bad..1eea0b1 100644 --- a/src/com/urise/webapp/storage/SqlStorage.java +++ b/src/com/urise/webapp/storage/SqlStorage.java @@ -9,15 +9,13 @@ import java.sql.ResultSet; import java.util.ArrayList; import java.util.List; -import java.util.Properties; public class SqlStorage implements Storage { public final ConnectionFactory connectionFactory; private final SqlHelper sqlHelper; - public SqlStorage(Properties properties) { - this.connectionFactory = () -> DriverManager.getConnection(properties.getProperty("db.url"), - properties.getProperty("db.user"), properties.getProperty("db.password")); + public SqlStorage(String dbUrl, String dbUser, String dbPass) { + this.connectionFactory = () -> DriverManager.getConnection(dbUrl, dbUser, dbPass); sqlHelper = new SqlHelper(connectionFactory); } From 84726a002a100c73b20135599f810ce9b95a6529 Mon Sep 17 00:00:00 2001 From: Kvitto Date: Wed, 18 Sep 2024 19:01:49 +0300 Subject: [PATCH 05/18] Prepare to HW14 --- src/com/urise/webapp/Config.java | 2 +- src/com/urise/webapp/ResumeTestData.java | 9 +- src/com/urise/webapp/sql/ExceptionUtil.java | 23 ++++ src/com/urise/webapp/sql/SqlExecutor.java | 8 ++ src/com/urise/webapp/sql/SqlHelper.java | 45 +++++++ src/com/urise/webapp/sql/SqlTransaction.java | 9 ++ src/com/urise/webapp/storage/SqlHelper.java | 36 ------ src/com/urise/webapp/storage/SqlStorage.java | 117 ++++++++++-------- .../webapp/storage/AbstractStorageTest.java | 8 +- 9 files changed, 163 insertions(+), 94 deletions(-) create mode 100644 src/com/urise/webapp/sql/ExceptionUtil.java create mode 100644 src/com/urise/webapp/sql/SqlExecutor.java create mode 100644 src/com/urise/webapp/sql/SqlHelper.java create mode 100644 src/com/urise/webapp/sql/SqlTransaction.java delete mode 100644 src/com/urise/webapp/storage/SqlHelper.java diff --git a/src/com/urise/webapp/Config.java b/src/com/urise/webapp/Config.java index 0759527..5e9465f 100644 --- a/src/com/urise/webapp/Config.java +++ b/src/com/urise/webapp/Config.java @@ -12,7 +12,6 @@ public class Config { private static final File PROPS = new File("C:/Java/BaseJava/config/resumes.properties"); private static final Config INSTANCE = new Config(); - private final Properties props = new Properties(); private final File storageDir; private final Storage storage; @@ -21,6 +20,7 @@ public class Config { private Config() { try(InputStream is = new FileInputStream(PROPS)) { + Properties props = new Properties(); props.load(is); storageDir = new File(props.getProperty("storage.dir")); storage = new SqlStorage(props.getProperty("db.url"), diff --git a/src/com/urise/webapp/ResumeTestData.java b/src/com/urise/webapp/ResumeTestData.java index 5a1cdf7..73e3e4f 100644 --- a/src/com/urise/webapp/ResumeTestData.java +++ b/src/com/urise/webapp/ResumeTestData.java @@ -1,12 +1,17 @@ package com.urise.webapp; +import com.urise.webapp.model.ContactType; import com.urise.webapp.model.Resume; +import com.urise.webapp.model.Section; +import com.urise.webapp.model.SectionType; + +import java.util.Map; public class ResumeTestData { public static Resume createResume(String uuid, String fullName) { Resume myResume = new Resume(uuid, fullName); -/* Map myContacts = myResume.getContacts(); + Map myContacts = myResume.getContacts(); myContacts.put(ContactType.PHONE, "+7(921) 855-0482"); myContacts.put(ContactType.SKYPE, "skype:grigory.kislin"); myContacts.put(ContactType.MAIL, "gkislin@yandex.ru"); @@ -16,7 +21,7 @@ public static Resume createResume(String uuid, String fullName) { myContacts.put(ContactType.HOME_PAGE, "http://gkislin.ru/"); Map mySections = myResume.getSections(); - +/* // OBJECTIVE section String myObjective = "Ведущий стажировок и корпоративного обучения по Java Web и Enterprise технологиям"; mySections.put(SectionType.OBJECTIVE, new TextSection(myObjective)); diff --git a/src/com/urise/webapp/sql/ExceptionUtil.java b/src/com/urise/webapp/sql/ExceptionUtil.java new file mode 100644 index 0000000..e0e9651 --- /dev/null +++ b/src/com/urise/webapp/sql/ExceptionUtil.java @@ -0,0 +1,23 @@ +package com.urise.webapp.sql; + +import com.urise.webapp.exception.ExistStorageException; +import com.urise.webapp.exception.StorageException; +import org.postgresql.util.PSQLException; + +import java.sql.SQLException; + +public class ExceptionUtil { + private ExceptionUtil() { + } + + public static StorageException convertException(SQLException e) { + if (e instanceof PSQLException) { + +// http://www.postgresql.org/docs/9.3/static/errcodes-appendix.html + if (e.getSQLState().equals("23505")) { + return new ExistStorageException(null); + } + } + return new StorageException(e.getMessage()); + } +} diff --git a/src/com/urise/webapp/sql/SqlExecutor.java b/src/com/urise/webapp/sql/SqlExecutor.java new file mode 100644 index 0000000..9543bfc --- /dev/null +++ b/src/com/urise/webapp/sql/SqlExecutor.java @@ -0,0 +1,8 @@ +package com.urise.webapp.sql; + +import java.sql.PreparedStatement; +import java.sql.SQLException; + +public interface SqlExecutor { + T execute(PreparedStatement st) throws SQLException; +} diff --git a/src/com/urise/webapp/sql/SqlHelper.java b/src/com/urise/webapp/sql/SqlHelper.java new file mode 100644 index 0000000..fd630ce --- /dev/null +++ b/src/com/urise/webapp/sql/SqlHelper.java @@ -0,0 +1,45 @@ +package com.urise.webapp.sql; + +import com.urise.webapp.exception.StorageException; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.SQLException; + +public class SqlHelper { + private final ConnectionFactory connectionFactory; + + public SqlHelper(ConnectionFactory connectionFactory) { + this.connectionFactory = connectionFactory; + } + + public void execute(String sql) { + execute(sql, PreparedStatement::execute); + } + + public T execute(String sql, SqlExecutor executor) { + try (Connection conn = connectionFactory.getConnection(); + PreparedStatement ps = conn.prepareStatement(sql)) { + return executor.execute(ps); + } catch (SQLException e) { + throw ExceptionUtil.convertException(e); + } + } + + public T transactionalExecute(SqlTransaction executor) { + try (Connection conn = connectionFactory.getConnection()) { + try { + conn.setAutoCommit(false); + T res = executor.execute(conn); + conn.commit(); + return res; + } catch (SQLException e) { + conn.rollback(); + throw ExceptionUtil.convertException(e); + } + } catch (SQLException e) { + throw new StorageException(e.getMessage()); + } + } + +} diff --git a/src/com/urise/webapp/sql/SqlTransaction.java b/src/com/urise/webapp/sql/SqlTransaction.java new file mode 100644 index 0000000..c4b2485 --- /dev/null +++ b/src/com/urise/webapp/sql/SqlTransaction.java @@ -0,0 +1,9 @@ +package com.urise.webapp.sql; + +import java.sql.Connection; + +import java.sql.SQLException; + +public interface SqlTransaction { + T execute(Connection conn) throws SQLException; +} diff --git a/src/com/urise/webapp/storage/SqlHelper.java b/src/com/urise/webapp/storage/SqlHelper.java deleted file mode 100644 index 38010ab..0000000 --- a/src/com/urise/webapp/storage/SqlHelper.java +++ /dev/null @@ -1,36 +0,0 @@ -package com.urise.webapp.storage; - -import com.urise.webapp.exception.ExistStorageException; -import com.urise.webapp.exception.StorageException; -import com.urise.webapp.sql.ConnectionFactory; - -import java.io.IOException; -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.SQLException; - -public class SqlHelper { - public final ConnectionFactory connectionFactory; - - public SqlHelper(ConnectionFactory connectionFactory) { - this.connectionFactory = connectionFactory; - } - - public T query(String sql, SqlHelperQuery query) { - try (Connection connection = connectionFactory.getConnection(); - PreparedStatement ps = connection.prepareStatement(sql)) { - return query.execute(ps); - } catch (SQLException e) { - if (e.getSQLState().equals("23505")) { - throw new ExistStorageException(e.getMessage()); - } - throw new StorageException(e.getMessage()); - } catch (IOException e) { - throw new StorageException(e.getMessage()); - } - } - - public interface SqlHelperQuery { - T execute(PreparedStatement ps) throws IOException, SQLException; - } -} diff --git a/src/com/urise/webapp/storage/SqlStorage.java b/src/com/urise/webapp/storage/SqlStorage.java index 1eea0b1..3c0e69f 100644 --- a/src/com/urise/webapp/storage/SqlStorage.java +++ b/src/com/urise/webapp/storage/SqlStorage.java @@ -1,100 +1,115 @@ package com.urise.webapp.storage; import com.urise.webapp.exception.NotExistStorageException; +import com.urise.webapp.model.ContactType; import com.urise.webapp.model.Resume; -import com.urise.webapp.sql.ConnectionFactory; +import com.urise.webapp.sql.SqlHelper; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.util.ArrayList; import java.util.List; +import java.util.Map; public class SqlStorage implements Storage { - public final ConnectionFactory connectionFactory; - private final SqlHelper sqlHelper; + public final SqlHelper sqlHelper; - public SqlStorage(String dbUrl, String dbUser, String dbPass) { - this.connectionFactory = () -> DriverManager.getConnection(dbUrl, dbUser, dbPass); - sqlHelper = new SqlHelper(connectionFactory); + public SqlStorage(String dbUrl, String dbUser, String dbPassword) { + sqlHelper = new SqlHelper(() -> DriverManager.getConnection(dbUrl, dbUser, dbPassword)); } @Override public void clear() { - sqlHelper.query("DELETE FROM resume", PreparedStatement::execute); + sqlHelper.execute("DELETE FROM resume"); } @Override - public void update(Resume r) { - sqlHelper.query("UPDATE resume r SET full_name=? WHERE r.uuid=?", + public Resume get(String uuid) { + return sqlHelper.execute("" + + " SELECT * FROM resume r " + + " LEFT JOIN contact c " + + " ON r.uuid = c.resume_uuid " + + " WHERE r.uuid =? ", ps -> { - ps.setString(1, r.getFullName()); - ps.setString(2, r.getUuid()); - if (ps.executeUpdate() == 0) { - throw new NotExistStorageException(r.getUuid()); + ps.setString(1, uuid); + ResultSet rs = ps.executeQuery(); + if (!rs.next()) { + throw new NotExistStorageException(uuid); } - return null; + Resume r = new Resume(uuid, rs.getString("full_name")); + do { + String value = rs.getString("value"); + ContactType type = ContactType.valueOf(rs.getString("type")); + r.addContact(type, value); + } while (rs.next()); + + return r; }); } @Override - public void save(Resume r) { - sqlHelper.query("INSERT INTO resume (uuid, full_name) VALUES (?, ?)", - ps -> { - ps.setString(1, r.getUuid()); - ps.setString(2, r.getFullName()); - ps.execute(); - return null; - }); + public void update(Resume r) { + sqlHelper.execute("UPDATE resume SET full_name = ? WHERE uuid = ?", ps -> { + ps.setString(1, r.getFullName()); + ps.setString(2, r.getUuid()); + if (ps.executeUpdate() == 0) { + throw new NotExistStorageException(r.getUuid()); + } + return null; + }); } @Override - public Resume get(String uuid) { - String name = sqlHelper.query("SELECT * FROM resume r WHERE r.uuid = ?", - ps -> { - ps.setString(1, uuid); - ResultSet rs = ps.executeQuery(); - if (!rs.next()) { - throw new NotExistStorageException(uuid); + public void save(Resume r) { + sqlHelper.transactionalExecute(conn -> { + try (PreparedStatement ps = conn.prepareStatement("INSERT INTO resume (uuid, full_name) VALUES (?,?)")) { + ps.setString(1, r.getUuid()); + ps.setString(2, r.getFullName()); + ps.execute(); } - return rs.getString("full_name"); - }); - return new Resume(uuid, name); + try (PreparedStatement ps = conn.prepareStatement("INSERT INTO contact (resume_uuid, type, value) VALUES (?,?,?)")) { + for (Map.Entry e : r.getContacts().entrySet()) { + ps.setString(1, r.getUuid()); + ps.setString(2, e.getKey().name()); + ps.setString(3, e.getValue()); + ps.addBatch(); + } + ps.executeBatch(); + } + return null; + } + ); } @Override public void delete(String uuid) { - sqlHelper.query("DELETE FROM resume WHERE uuid = ?", - ps -> { - ps.setString(1, uuid); - if (ps.executeUpdate() == 0) { - throw new NotExistStorageException(uuid); - } - return null; - }); + sqlHelper.execute("DELETE FROM resume WHERE uuid=?", ps -> { + ps.setString(1, uuid); + if (ps.executeUpdate() == 0) { + throw new NotExistStorageException(uuid); + } + return null; + }); } @Override public List getAllSorted() { - List resumes = new ArrayList<>(); - sqlHelper.query("SELECT * FROM resume ORDER BY full_name", ps -> { + return sqlHelper.execute("SELECT * FROM resume r ORDER BY full_name,uuid", ps -> { ResultSet rs = ps.executeQuery(); + List resumes = new ArrayList<>(); while (rs.next()) { resumes.add(new Resume(rs.getString("uuid"), rs.getString("full_name"))); } - return null; + return resumes; }); - return resumes; } @Override public int size() { - return sqlHelper.query("SELECT count(*) AS count_rows FROM resume", ps -> { - ResultSet rs = ps.executeQuery(); - if (!rs.next()) { - throw new NotExistStorageException("db error"); - } - return rs.getInt("count_rows"); + return sqlHelper.execute("SELECT count(*) FROM resume", st -> { + ResultSet rs = st.executeQuery(); + return rs.next() ? rs.getInt(1) : 0; }); } -} +} \ No newline at end of file diff --git a/test/com/urise/webapp/storage/AbstractStorageTest.java b/test/com/urise/webapp/storage/AbstractStorageTest.java index 5902202..c251622 100644 --- a/test/com/urise/webapp/storage/AbstractStorageTest.java +++ b/test/com/urise/webapp/storage/AbstractStorageTest.java @@ -20,10 +20,10 @@ public abstract class AbstractStorageTest { protected final Storage storage; - private static final String UUID_1 = String.valueOf(UUID.randomUUID()); - private static final String UUID_2 = String.valueOf(UUID.randomUUID()); - private static final String UUID_3 = String.valueOf(UUID.randomUUID()); - private static final String UUID_4 = String.valueOf(UUID.randomUUID()); + private static final String UUID_1 = UUID.randomUUID().toString(); + private static final String UUID_2 = UUID.randomUUID().toString(); + private static final String UUID_3 = UUID.randomUUID().toString(); + private static final String UUID_4 = UUID.randomUUID().toString(); private static final Resume RESUME_1; private static final Resume RESUME_2; From aae131e46a1395a88a5a071491534430a2bd9477 Mon Sep 17 00:00:00 2001 From: Kvitto Date: Wed, 18 Sep 2024 21:25:05 +0300 Subject: [PATCH 06/18] HW14 complete SqlStorage with transactions. --- src/com/urise/webapp/storage/SqlStorage.java | 103 +++++++++++-------- 1 file changed, 61 insertions(+), 42 deletions(-) diff --git a/src/com/urise/webapp/storage/SqlStorage.java b/src/com/urise/webapp/storage/SqlStorage.java index 3c0e69f..363b459 100644 --- a/src/com/urise/webapp/storage/SqlStorage.java +++ b/src/com/urise/webapp/storage/SqlStorage.java @@ -8,9 +8,11 @@ import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; +import java.sql.SQLException; import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.UUID; public class SqlStorage implements Storage { public final SqlHelper sqlHelper; @@ -27,59 +29,56 @@ public void clear() { @Override public Resume get(String uuid) { return sqlHelper.execute("" + - " SELECT * FROM resume r " + - " LEFT JOIN contact c " + - " ON r.uuid = c.resume_uuid " + - " WHERE r.uuid =? ", - ps -> { - ps.setString(1, uuid); - ResultSet rs = ps.executeQuery(); - if (!rs.next()) { - throw new NotExistStorageException(uuid); - } - Resume r = new Resume(uuid, rs.getString("full_name")); - do { - String value = rs.getString("value"); - ContactType type = ContactType.valueOf(rs.getString("type")); - r.addContact(type, value); - } while (rs.next()); + " SELECT * FROM resume r " + + " LEFT JOIN contact c " + + " ON r.uuid = c.resume_uuid " + + " WHERE r.uuid =? ", ps -> { + ps.setString(1, uuid); + ResultSet rs = ps.executeQuery(); + if (!rs.next()) { + throw new NotExistStorageException(uuid); + } + Resume r = new Resume(uuid, rs.getString("full_name")); + do { + r.addContact(ContactType.valueOf(rs.getString("type")), rs.getString("value")); + } while (rs.next()); - return r; - }); + return r; + }); } @Override public void update(Resume r) { - sqlHelper.execute("UPDATE resume SET full_name = ? WHERE uuid = ?", ps -> { - ps.setString(1, r.getFullName()); - ps.setString(2, r.getUuid()); - if (ps.executeUpdate() == 0) { - throw new NotExistStorageException(r.getUuid()); + sqlHelper.transactionalExecute(conn -> { + try (PreparedStatement ps = conn.prepareStatement( + "UPDATE resume SET full_name = ? WHERE uuid = ?")) { + psNameUuid(r, ps); + if (ps.executeUpdate() == 0) { + throw new NotExistStorageException(r.getUuid()); + } + return null; } - return null; }); } @Override public void save(Resume r) { sqlHelper.transactionalExecute(conn -> { - try (PreparedStatement ps = conn.prepareStatement("INSERT INTO resume (uuid, full_name) VALUES (?,?)")) { - ps.setString(1, r.getUuid()); - ps.setString(2, r.getFullName()); - ps.execute(); - } - try (PreparedStatement ps = conn.prepareStatement("INSERT INTO contact (resume_uuid, type, value) VALUES (?,?,?)")) { - for (Map.Entry e : r.getContacts().entrySet()) { - ps.setString(1, r.getUuid()); - ps.setString(2, e.getKey().name()); - ps.setString(3, e.getValue()); - ps.addBatch(); - } - ps.executeBatch(); - } - return null; + try (PreparedStatement ps = conn.prepareStatement( + "INSERT INTO resume (full_name, uuid) VALUES (?,?)")) { + psNameUuid(r, ps); + ps.execute(); + } + try (PreparedStatement ps = conn.prepareStatement( + "INSERT INTO contact (resume_uuid, type, value) VALUES (?,?,?)")) { + for (Map.Entry e : r.getContacts().entrySet()) { + psUuidNameValue(r, e, ps); + ps.addBatch(); } - ); + ps.executeBatch(); + } + return null; + }); } @Override @@ -95,11 +94,20 @@ public void delete(String uuid) { @Override public List getAllSorted() { - return sqlHelper.execute("SELECT * FROM resume r ORDER BY full_name,uuid", ps -> { + return sqlHelper.execute("" + + " SELECT * FROM resume r " + + " LEFT JOIN contact c " + + " ON r.uuid = c.resume_uuid " + + " ORDER BY full_name,uuid", ps -> { ResultSet rs = ps.executeQuery(); List resumes = new ArrayList<>(); + Resume r = new Resume(UUID.randomUUID().toString(),""); while (rs.next()) { - resumes.add(new Resume(rs.getString("uuid"), rs.getString("full_name"))); + if (!r.getUuid().equals(rs.getString("uuid"))) { + r = new Resume(rs.getString("uuid"), rs.getString("full_name")); + resumes.add(r); + } + r.addContact(ContactType.valueOf(rs.getString("type")), rs.getString("value")); } return resumes; }); @@ -112,4 +120,15 @@ public int size() { return rs.next() ? rs.getInt(1) : 0; }); } + + private static void psNameUuid(Resume r, PreparedStatement ps) throws SQLException { + ps.setString(1, r.getFullName()); + ps.setString(2, r.getUuid()); + } + + private static void psUuidNameValue(Resume r, Map.Entry e, PreparedStatement ps) throws SQLException { + ps.setString(1, r.getUuid()); + ps.setString(2, e.getKey().name()); + ps.setString(3, e.getValue()); + } } \ No newline at end of file From b9ca8a691fd4fd0bf6d602eebcaf4646d5de3be8 Mon Sep 17 00:00:00 2001 From: Kvitto Date: Fri, 20 Sep 2024 16:21:07 +0300 Subject: [PATCH 07/18] HW14 after review --- src/com/urise/webapp/storage/SqlStorage.java | 76 +++++++++++--------- 1 file changed, 44 insertions(+), 32 deletions(-) diff --git a/src/com/urise/webapp/storage/SqlStorage.java b/src/com/urise/webapp/storage/SqlStorage.java index 363b459..a8220ef 100644 --- a/src/com/urise/webapp/storage/SqlStorage.java +++ b/src/com/urise/webapp/storage/SqlStorage.java @@ -9,10 +9,7 @@ import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.UUID; +import java.util.*; public class SqlStorage implements Storage { public final SqlHelper sqlHelper; @@ -40,24 +37,40 @@ public Resume get(String uuid) { } Resume r = new Resume(uuid, rs.getString("full_name")); do { - r.addContact(ContactType.valueOf(rs.getString("type")), rs.getString("value")); + addContact(rs, r); } while (rs.next()); - return r; }); } + private static void addContact(ResultSet rs, Resume r) throws SQLException { + if (rs.getString("type") != null) { + r.addContact(ContactType.valueOf(rs.getString("type")), rs.getString("value")); + } + } + @Override public void update(Resume r) { sqlHelper.transactionalExecute(conn -> { try (PreparedStatement ps = conn.prepareStatement( "UPDATE resume SET full_name = ? WHERE uuid = ?")) { - psNameUuid(r, ps); + ps.setString(1, r.getFullName()); + ps.setString(2, r.getUuid()); if (ps.executeUpdate() == 0) { throw new NotExistStorageException(r.getUuid()); } - return null; } + try (PreparedStatement ps = conn.prepareStatement( + "UPDATE contact SET value = ? WHERE resume_uuid = ? AND type = ?")) { + for (Map.Entry e : r.getContacts().entrySet()) { + ps.setString(1, e.getKey().name()); + ps.setString(2, e.getValue()); + ps.setString(3, r.getUuid()); + ps.addBatch(); + } + ps.executeBatch(); + } + return null; }); } @@ -66,13 +79,16 @@ public void save(Resume r) { sqlHelper.transactionalExecute(conn -> { try (PreparedStatement ps = conn.prepareStatement( "INSERT INTO resume (full_name, uuid) VALUES (?,?)")) { - psNameUuid(r, ps); + ps.setString(1, r.getFullName()); + ps.setString(2, r.getUuid()); ps.execute(); } try (PreparedStatement ps = conn.prepareStatement( "INSERT INTO contact (resume_uuid, type, value) VALUES (?,?,?)")) { for (Map.Entry e : r.getContacts().entrySet()) { - psUuidNameValue(r, e, ps); + ps.setString(1, r.getUuid()); + ps.setString(2, e.getKey().name()); + ps.setString(3, e.getValue()); ps.addBatch(); } ps.executeBatch(); @@ -95,20 +111,26 @@ public void delete(String uuid) { @Override public List getAllSorted() { return sqlHelper.execute("" + - " SELECT * FROM resume r " + - " LEFT JOIN contact c " + - " ON r.uuid = c.resume_uuid " + - " ORDER BY full_name,uuid", ps -> { + " SELECT * FROM resume r " + + " LEFT JOIN contact c " + + " ON r.uuid = c.resume_uuid " + + " ORDER BY full_name, uuid", ps -> { ResultSet rs = ps.executeQuery(); - List resumes = new ArrayList<>(); - Resume r = new Resume(UUID.randomUUID().toString(),""); - while (rs.next()) { - if (!r.getUuid().equals(rs.getString("uuid"))) { - r = new Resume(rs.getString("uuid"), rs.getString("full_name")); - resumes.add(r); - } - r.addContact(ContactType.valueOf(rs.getString("type")), rs.getString("value")); + Map resumeMap = new HashMap<>(); + if (!rs.next()) { + throw new NotExistStorageException("database has not resumes"); } + do { + String uuid = rs.getString("uuid"); + Resume r = resumeMap.get(uuid); + if (r == null) { + r = new Resume(uuid, rs.getString("full_name")); + resumeMap.put(uuid, r); + } + addContact(rs, r); + } while (rs.next()); + List resumes = new ArrayList<>(resumeMap.values()); + Collections.sort(resumes); return resumes; }); } @@ -121,14 +143,4 @@ public int size() { }); } - private static void psNameUuid(Resume r, PreparedStatement ps) throws SQLException { - ps.setString(1, r.getFullName()); - ps.setString(2, r.getUuid()); - } - - private static void psUuidNameValue(Resume r, Map.Entry e, PreparedStatement ps) throws SQLException { - ps.setString(1, r.getUuid()); - ps.setString(2, e.getKey().name()); - ps.setString(3, e.getValue()); - } } \ No newline at end of file From 7bb3c5f62d444a870f45270e278bff143ed9bb85 Mon Sep 17 00:00:00 2001 From: Kvitto Date: Sun, 22 Sep 2024 23:38:58 +0300 Subject: [PATCH 08/18] HW14 add methods addContacts & delContacts + fix after review --- src/com/urise/webapp/storage/SqlStorage.java | 83 ++++++++++---------- 1 file changed, 42 insertions(+), 41 deletions(-) diff --git a/src/com/urise/webapp/storage/SqlStorage.java b/src/com/urise/webapp/storage/SqlStorage.java index a8220ef..70141a9 100644 --- a/src/com/urise/webapp/storage/SqlStorage.java +++ b/src/com/urise/webapp/storage/SqlStorage.java @@ -5,10 +5,7 @@ import com.urise.webapp.model.Resume; import com.urise.webapp.sql.SqlHelper; -import java.sql.DriverManager; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; +import java.sql.*; import java.util.*; public class SqlStorage implements Storage { @@ -43,12 +40,6 @@ public Resume get(String uuid) { }); } - private static void addContact(ResultSet rs, Resume r) throws SQLException { - if (rs.getString("type") != null) { - r.addContact(ContactType.valueOf(rs.getString("type")), rs.getString("value")); - } - } - @Override public void update(Resume r) { sqlHelper.transactionalExecute(conn -> { @@ -60,16 +51,8 @@ public void update(Resume r) { throw new NotExistStorageException(r.getUuid()); } } - try (PreparedStatement ps = conn.prepareStatement( - "UPDATE contact SET value = ? WHERE resume_uuid = ? AND type = ?")) { - for (Map.Entry e : r.getContacts().entrySet()) { - ps.setString(1, e.getKey().name()); - ps.setString(2, e.getValue()); - ps.setString(3, r.getUuid()); - ps.addBatch(); - } - ps.executeBatch(); - } + delContacts(r, conn); + addContacts(r, conn); return null; }); } @@ -83,16 +66,7 @@ public void save(Resume r) { ps.setString(2, r.getUuid()); ps.execute(); } - try (PreparedStatement ps = conn.prepareStatement( - "INSERT INTO contact (resume_uuid, type, value) VALUES (?,?,?)")) { - for (Map.Entry e : r.getContacts().entrySet()) { - ps.setString(1, r.getUuid()); - ps.setString(2, e.getKey().name()); - ps.setString(3, e.getValue()); - ps.addBatch(); - } - ps.executeBatch(); - } + addContacts(r, conn); return null; }); } @@ -117,18 +91,17 @@ public List getAllSorted() { " ORDER BY full_name, uuid", ps -> { ResultSet rs = ps.executeQuery(); Map resumeMap = new HashMap<>(); - if (!rs.next()) { - throw new NotExistStorageException("database has not resumes"); + if (rs.next()) { + do { + String uuid = rs.getString("uuid"); + Resume r = resumeMap.get(uuid); + if (r == null) { + r = new Resume(uuid, rs.getString("full_name")); + resumeMap.put(uuid, r); + } + addContact(rs, r); + } while (rs.next()); } - do { - String uuid = rs.getString("uuid"); - Resume r = resumeMap.get(uuid); - if (r == null) { - r = new Resume(uuid, rs.getString("full_name")); - resumeMap.put(uuid, r); - } - addContact(rs, r); - } while (rs.next()); List resumes = new ArrayList<>(resumeMap.values()); Collections.sort(resumes); return resumes; @@ -143,4 +116,32 @@ public int size() { }); } + private static void addContact(ResultSet rs, Resume r) throws SQLException { + String type = rs.getString("type"); + if (type != null) { + r.addContact(ContactType.valueOf(type), rs.getString("value")); + } + } + + private static void addContacts(Resume r, Connection conn) throws SQLException { + try (PreparedStatement ps = conn.prepareStatement( + "INSERT INTO contact (resume_uuid, type, value) VALUES (?,?,?)")) { + for (Map.Entry e : r.getContacts().entrySet()) { + ps.setString(1, r.getUuid()); + ps.setString(2, e.getKey().name()); + ps.setString(3, e.getValue()); + ps.addBatch(); + } + ps.executeBatch(); + } + } + + private void delContacts(Resume r, Connection conn) throws SQLException { + try (PreparedStatement ps = conn.prepareStatement( + "DELETE FROM contact WHERE resume_uuid=?")) { + ps.setString(1, r.getUuid()); + ps.executeUpdate(); + } + } + } \ No newline at end of file From 00dcdcee44474576f7f7501f50844b3f2e72cc7b Mon Sep 17 00:00:00 2001 From: Kvitto Date: Mon, 23 Sep 2024 21:22:33 +0300 Subject: [PATCH 09/18] HW14 getAllSorted changed resumeMap from HashMap to LinkedHashMap --- src/com/urise/webapp/storage/SqlStorage.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/com/urise/webapp/storage/SqlStorage.java b/src/com/urise/webapp/storage/SqlStorage.java index 70141a9..a708f1f 100644 --- a/src/com/urise/webapp/storage/SqlStorage.java +++ b/src/com/urise/webapp/storage/SqlStorage.java @@ -90,7 +90,7 @@ public List getAllSorted() { " ON r.uuid = c.resume_uuid " + " ORDER BY full_name, uuid", ps -> { ResultSet rs = ps.executeQuery(); - Map resumeMap = new HashMap<>(); + Map resumeMap = new LinkedHashMap<>(); if (rs.next()) { do { String uuid = rs.getString("uuid"); @@ -102,9 +102,7 @@ public List getAllSorted() { addContact(rs, r); } while (rs.next()); } - List resumes = new ArrayList<>(resumeMap.values()); - Collections.sort(resumes); - return resumes; + return resumeMap.values().stream().toList(); }); } From 7f1d86e929a18674c6a27a23f78d92b30847280b Mon Sep 17 00:00:00 2001 From: Kvitto Date: Tue, 24 Sep 2024 00:33:46 +0300 Subject: [PATCH 10/18] Prepare to Lesson 15 --- src/com/urise/webapp/ResumeTestData.java | 2 +- src/com/urise/webapp/storage/SqlStorage.java | 24 +++++++++---------- .../webapp/storage/AbstractStorageTest.java | 5 +++- 3 files changed, 16 insertions(+), 15 deletions(-) diff --git a/src/com/urise/webapp/ResumeTestData.java b/src/com/urise/webapp/ResumeTestData.java index 73e3e4f..11ce90c 100644 --- a/src/com/urise/webapp/ResumeTestData.java +++ b/src/com/urise/webapp/ResumeTestData.java @@ -18,7 +18,7 @@ public static Resume createResume(String uuid, String fullName) { myContacts.put(ContactType.LINKEDIN, "https://www.linkedin.com/in/gkislin"); myContacts.put(ContactType.GITHUB, "https://github.com/gkislin"); myContacts.put(ContactType.STACKOVERFLOW, "https://stackoverflow.com/users/548473"); - myContacts.put(ContactType.HOME_PAGE, "http://gkislin.ru/"); +// myContacts.put(ContactType.HOME_PAGE, "http://gkislin.ru/"); Map mySections = myResume.getSections(); /* diff --git a/src/com/urise/webapp/storage/SqlStorage.java b/src/com/urise/webapp/storage/SqlStorage.java index a708f1f..7588c94 100644 --- a/src/com/urise/webapp/storage/SqlStorage.java +++ b/src/com/urise/webapp/storage/SqlStorage.java @@ -22,7 +22,7 @@ public void clear() { @Override public Resume get(String uuid) { - return sqlHelper.execute("" + + return sqlHelper.execute( " SELECT * FROM resume r " + " LEFT JOIN contact c " + " ON r.uuid = c.resume_uuid " + @@ -84,25 +84,23 @@ public void delete(String uuid) { @Override public List getAllSorted() { - return sqlHelper.execute("" + + return sqlHelper.execute( " SELECT * FROM resume r " + " LEFT JOIN contact c " + " ON r.uuid = c.resume_uuid " + " ORDER BY full_name, uuid", ps -> { ResultSet rs = ps.executeQuery(); Map resumeMap = new LinkedHashMap<>(); - if (rs.next()) { - do { - String uuid = rs.getString("uuid"); - Resume r = resumeMap.get(uuid); - if (r == null) { - r = new Resume(uuid, rs.getString("full_name")); - resumeMap.put(uuid, r); - } - addContact(rs, r); - } while (rs.next()); + while (rs.next()) { + String uuid = rs.getString("uuid"); + Resume r = resumeMap.get(uuid); + if (r == null) { + r = new Resume(uuid, rs.getString("full_name")); + resumeMap.put(uuid, r); + } + addContact(rs, r); } - return resumeMap.values().stream().toList(); + return new ArrayList<>(resumeMap.values()); }); } diff --git a/test/com/urise/webapp/storage/AbstractStorageTest.java b/test/com/urise/webapp/storage/AbstractStorageTest.java index c251622..23da38e 100644 --- a/test/com/urise/webapp/storage/AbstractStorageTest.java +++ b/test/com/urise/webapp/storage/AbstractStorageTest.java @@ -3,6 +3,7 @@ import com.urise.webapp.Config; import com.urise.webapp.exception.ExistStorageException; import com.urise.webapp.exception.NotExistStorageException; +import com.urise.webapp.model.ContactType; import com.urise.webapp.model.Resume; import org.junit.Before; import org.junit.Test; @@ -63,6 +64,8 @@ public void clear() throws Exception { @Test public void update() throws Exception { Resume newResume = createResume(UUID_1, "newFirstResume"); + newResume.addContact(ContactType.HOME_PAGE, "http://gkislin.ru/"); + newResume.getContacts().put(ContactType.MAIL, "edarg@wsfws.ru"); storage.update(newResume); Resume oldRes = storage.get(UUID_1); assertEquals(newResume, oldRes); @@ -77,7 +80,7 @@ public void updateNotExist() throws Exception { public void getAllSorted() throws Exception { List list = storage.getAllSorted(); assertEquals(3, list.size()); - assertEquals(list, Arrays.asList(RESUME_1, RESUME_2, RESUME_3)); + assertEquals(Arrays.asList(RESUME_1, RESUME_2, RESUME_3), list); } @Test From d867afcfc45acb1c7a9ea3f94e86f96db0e35f0b Mon Sep 17 00:00:00 2001 From: Kvitto Date: Fri, 27 Sep 2024 15:20:21 +0300 Subject: [PATCH 11/18] Lesson 15 --- src/com/urise/webapp/web/ResumeServlet.java | 24 +++++++++++++++++++ .../webapp/storage/AbstractStorageTest.java | 5 +++- 2 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 src/com/urise/webapp/web/ResumeServlet.java diff --git a/src/com/urise/webapp/web/ResumeServlet.java b/src/com/urise/webapp/web/ResumeServlet.java new file mode 100644 index 0000000..0363301 --- /dev/null +++ b/src/com/urise/webapp/web/ResumeServlet.java @@ -0,0 +1,24 @@ +package com.urise.webapp.web; + +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +import java.io.IOException; + +public class ResumeServlet extends HttpServlet { + @Override + protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + request.setCharacterEncoding("UTF-8"); + response.setCharacterEncoding("UTF-8"); + response.setContentType("text/html;charset=UTF-8"); + String name = request.getParameter("name"); + response.getWriter().write(name == null ? "Hello Senior Java Developer" : "Hello " + name + " - new Senior Java Developer"); + } + + @Override + protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + + } +} diff --git a/test/com/urise/webapp/storage/AbstractStorageTest.java b/test/com/urise/webapp/storage/AbstractStorageTest.java index 23da38e..0bda946 100644 --- a/test/com/urise/webapp/storage/AbstractStorageTest.java +++ b/test/com/urise/webapp/storage/AbstractStorageTest.java @@ -10,6 +10,7 @@ import java.io.File; import java.util.Arrays; +import java.util.Collections; import java.util.List; import java.util.UUID; @@ -80,7 +81,9 @@ public void updateNotExist() throws Exception { public void getAllSorted() throws Exception { List list = storage.getAllSorted(); assertEquals(3, list.size()); - assertEquals(Arrays.asList(RESUME_1, RESUME_2, RESUME_3), list); + List sortedList = Arrays.asList(RESUME_1, RESUME_2, RESUME_3); + Collections.sort(sortedList); + assertEquals(sortedList, list); } @Test From 24349e35b20dc6214371900cdcee74786d677cca Mon Sep 17 00:00:00 2001 From: Kvitto Date: Fri, 27 Sep 2024 15:25:09 +0300 Subject: [PATCH 12/18] HW15 SqlStorage.getAllSorted - getAllSorted() - through two separate query. --- src/com/urise/webapp/ResumeTestData.java | 2 +- src/com/urise/webapp/storage/SqlStorage.java | 110 +++++++++---------- 2 files changed, 55 insertions(+), 57 deletions(-) diff --git a/src/com/urise/webapp/ResumeTestData.java b/src/com/urise/webapp/ResumeTestData.java index 11ce90c..90bb164 100644 --- a/src/com/urise/webapp/ResumeTestData.java +++ b/src/com/urise/webapp/ResumeTestData.java @@ -82,7 +82,7 @@ public static Resume createResume(String uuid, String fullName) { "архитектурных шаблонов, UML, функционального программирования"); myQualifications.add("Родной русский, английский \"upper intermediate\""); mySections.put(SectionType.QUALIFICATION, new ListSection(myQualifications)); - +/* // EXPERIENCE section List myCompanies = new ArrayList<>(); myCompanies.add(new Company("Java Online Projects", "http://javaops.ru/", diff --git a/src/com/urise/webapp/storage/SqlStorage.java b/src/com/urise/webapp/storage/SqlStorage.java index 7588c94..65237dd 100644 --- a/src/com/urise/webapp/storage/SqlStorage.java +++ b/src/com/urise/webapp/storage/SqlStorage.java @@ -24,35 +24,36 @@ public void clear() { public Resume get(String uuid) { return sqlHelper.execute( " SELECT * FROM resume r " + - " LEFT JOIN contact c " + - " ON r.uuid = c.resume_uuid " + - " WHERE r.uuid =? ", ps -> { - ps.setString(1, uuid); - ResultSet rs = ps.executeQuery(); - if (!rs.next()) { - throw new NotExistStorageException(uuid); - } - Resume r = new Resume(uuid, rs.getString("full_name")); - do { - addContact(rs, r); - } while (rs.next()); - return r; - }); + " LEFT JOIN contact c " + + " ON r.uuid = c.resume_uuid " + + " WHERE r.uuid =? ", + ps -> { + ps.setString(1, uuid); + ResultSet rs = ps.executeQuery(); + if (!rs.next()) { + throw new NotExistStorageException(uuid); + } + Resume r = new Resume(uuid, rs.getString("full_name")); + do { + addContact(rs, r); + } while (rs.next()); + + return r; + }); } @Override public void update(Resume r) { sqlHelper.transactionalExecute(conn -> { - try (PreparedStatement ps = conn.prepareStatement( - "UPDATE resume SET full_name = ? WHERE uuid = ?")) { + try (PreparedStatement ps = conn.prepareStatement("UPDATE resume SET full_name = ? WHERE uuid = ?")) { ps.setString(1, r.getFullName()); ps.setString(2, r.getUuid()); - if (ps.executeUpdate() == 0) { + if (ps.executeUpdate() != 1) { throw new NotExistStorageException(r.getUuid()); } } - delContacts(r, conn); - addContacts(r, conn); + deleteContacts(conn, r); + insertContact(conn, r); return null; }); } @@ -60,13 +61,12 @@ public void update(Resume r) { @Override public void save(Resume r) { sqlHelper.transactionalExecute(conn -> { - try (PreparedStatement ps = conn.prepareStatement( - "INSERT INTO resume (full_name, uuid) VALUES (?,?)")) { - ps.setString(1, r.getFullName()); - ps.setString(2, r.getUuid()); + try (PreparedStatement ps = conn.prepareStatement("INSERT INTO resume (uuid, full_name) VALUES (?,?)")) { + ps.setString(1, r.getUuid()); + ps.setString(2, r.getFullName()); ps.execute(); } - addContacts(r, conn); + insertContact(conn, r); return null; }); } @@ -84,24 +84,24 @@ public void delete(String uuid) { @Override public List getAllSorted() { + Map map = new LinkedHashMap<>(); + sqlHelper.execute( + "SELECT * FROM resume r ORDER BY full_name, uuid", ps -> { + ResultSet rs = ps.executeQuery(); + while (rs.next()) { + map.put(rs.getString("uuid"), new Resume(rs.getString("uuid"), rs.getString("full_name"))); + } + return null; + }); return sqlHelper.execute( - " SELECT * FROM resume r " + - " LEFT JOIN contact c " + - " ON r.uuid = c.resume_uuid " + - " ORDER BY full_name, uuid", ps -> { - ResultSet rs = ps.executeQuery(); - Map resumeMap = new LinkedHashMap<>(); - while (rs.next()) { - String uuid = rs.getString("uuid"); - Resume r = resumeMap.get(uuid); - if (r == null) { - r = new Resume(uuid, rs.getString("full_name")); - resumeMap.put(uuid, r); - } - addContact(rs, r); - } - return new ArrayList<>(resumeMap.values()); - }); + "SELECT * FROM contact", ps -> { + ResultSet rs = ps.executeQuery(); + while (rs.next()) { + map.get(rs.getString("resume_uuid")) + .addContact(ContactType.valueOf(rs.getString("type")), rs.getString("value")); + } + return new ArrayList<>(map.values()); + }); } @Override @@ -112,16 +112,8 @@ public int size() { }); } - private static void addContact(ResultSet rs, Resume r) throws SQLException { - String type = rs.getString("type"); - if (type != null) { - r.addContact(ContactType.valueOf(type), rs.getString("value")); - } - } - - private static void addContacts(Resume r, Connection conn) throws SQLException { - try (PreparedStatement ps = conn.prepareStatement( - "INSERT INTO contact (resume_uuid, type, value) VALUES (?,?,?)")) { + private void insertContact(Connection conn, Resume r) throws SQLException { + try (PreparedStatement ps = conn.prepareStatement("INSERT INTO contact (resume_uuid, type, value) VALUES (?,?,?)")) { for (Map.Entry e : r.getContacts().entrySet()) { ps.setString(1, r.getUuid()); ps.setString(2, e.getKey().name()); @@ -132,12 +124,18 @@ private static void addContacts(Resume r, Connection conn) throws SQLException { } } - private void delContacts(Resume r, Connection conn) throws SQLException { - try (PreparedStatement ps = conn.prepareStatement( - "DELETE FROM contact WHERE resume_uuid=?")) { + private void deleteContacts(Connection conn, Resume r) { + sqlHelper.execute("DELETE FROM contact WHERE resume_uuid=?", ps -> { ps.setString(1, r.getUuid()); - ps.executeUpdate(); - } + ps.execute(); + return null; + }); } + private void addContact(ResultSet rs, Resume r) throws SQLException { + String value = rs.getString("value"); + if (value != null) { + r.addContact(ContactType.valueOf(rs.getString("type")), value); + } + } } \ No newline at end of file From 4ab40d135c1a81953067cd03e4195a2ae2f8e65a Mon Sep 17 00:00:00 2001 From: Kvitto Date: Sat, 28 Sep 2024 19:01:04 +0300 Subject: [PATCH 13/18] HW15 SqlStorage - getAllSorted() - functionality for storing resume sections has been added. --- src/com/urise/webapp/ResumeTestData.java | 13 +++-- src/com/urise/webapp/storage/SqlStorage.java | 58 +++++++++++++++++--- 2 files changed, 57 insertions(+), 14 deletions(-) diff --git a/src/com/urise/webapp/ResumeTestData.java b/src/com/urise/webapp/ResumeTestData.java index 90bb164..a3092a5 100644 --- a/src/com/urise/webapp/ResumeTestData.java +++ b/src/com/urise/webapp/ResumeTestData.java @@ -1,13 +1,14 @@ package com.urise.webapp; -import com.urise.webapp.model.ContactType; -import com.urise.webapp.model.Resume; -import com.urise.webapp.model.Section; -import com.urise.webapp.model.SectionType; +import com.urise.webapp.model.*; +import java.util.ArrayList; +import java.util.List; import java.util.Map; public class ResumeTestData { + private ResumeTestData() {} + public static Resume createResume(String uuid, String fullName) { Resume myResume = new Resume(uuid, fullName); @@ -18,10 +19,10 @@ public static Resume createResume(String uuid, String fullName) { myContacts.put(ContactType.LINKEDIN, "https://www.linkedin.com/in/gkislin"); myContacts.put(ContactType.GITHUB, "https://github.com/gkislin"); myContacts.put(ContactType.STACKOVERFLOW, "https://stackoverflow.com/users/548473"); -// myContacts.put(ContactType.HOME_PAGE, "http://gkislin.ru/"); + myContacts.put(ContactType.HOME_PAGE, "http://gkislin.ru/"); Map mySections = myResume.getSections(); -/* + // OBJECTIVE section String myObjective = "Ведущий стажировок и корпоративного обучения по Java Web и Enterprise технологиям"; mySections.put(SectionType.OBJECTIVE, new TextSection(myObjective)); diff --git a/src/com/urise/webapp/storage/SqlStorage.java b/src/com/urise/webapp/storage/SqlStorage.java index 65237dd..691f871 100644 --- a/src/com/urise/webapp/storage/SqlStorage.java +++ b/src/com/urise/webapp/storage/SqlStorage.java @@ -1,8 +1,7 @@ package com.urise.webapp.storage; import com.urise.webapp.exception.NotExistStorageException; -import com.urise.webapp.model.ContactType; -import com.urise.webapp.model.Resume; +import com.urise.webapp.model.*; import com.urise.webapp.sql.SqlHelper; import java.sql.*; @@ -37,7 +36,7 @@ public Resume get(String uuid) { do { addContact(rs, r); } while (rs.next()); - + getSections(r); return r; }); } @@ -52,8 +51,10 @@ public void update(Resume r) { throw new NotExistStorageException(r.getUuid()); } } - deleteContacts(conn, r); + deleteContact(conn, r); + deleteSection(conn, r); insertContact(conn, r); + insertSection(conn, r); return null; }); } @@ -67,6 +68,7 @@ public void save(Resume r) { ps.execute(); } insertContact(conn, r); + insertSection(conn, r); return null; }); } @@ -93,15 +95,17 @@ public List getAllSorted() { } return null; }); - return sqlHelper.execute( + sqlHelper.execute( "SELECT * FROM contact", ps -> { ResultSet rs = ps.executeQuery(); while (rs.next()) { map.get(rs.getString("resume_uuid")) .addContact(ContactType.valueOf(rs.getString("type")), rs.getString("value")); } - return new ArrayList<>(map.values()); + return null; }); + map.values().forEach(this::getSections); + return new ArrayList<>(map.values()); } @Override @@ -124,8 +128,28 @@ private void insertContact(Connection conn, Resume r) throws SQLException { } } - private void deleteContacts(Connection conn, Resume r) { - sqlHelper.execute("DELETE FROM contact WHERE resume_uuid=?", ps -> { + private void insertSection(Connection conn, Resume r) throws SQLException { + try (PreparedStatement ps = conn.prepareStatement("INSERT INTO section (resume_uuid, type, value) VALUES (?,?,?)")) { + for (Map.Entry e : r.getSections().entrySet()) { + ps.setString(1, r.getUuid()); + ps.setString(2, e.getKey().name()); + ps.setString(3, e.getValue().toString()); + ps.addBatch(); + } + ps.executeBatch(); + } + } + + private void deleteContact(Connection conn, Resume r) { + sqlHelper.execute("DELETE FROM contact WHERE resume_uuid=?", ps -> { + ps.setString(1, r.getUuid()); + ps.execute(); + return null; + }); + } + + private void deleteSection(Connection conn, Resume r) { + sqlHelper.execute("DELETE FROM section WHERE resume_uuid=?", ps -> { ps.setString(1, r.getUuid()); ps.execute(); return null; @@ -138,4 +162,22 @@ private void addContact(ResultSet rs, Resume r) throws SQLException { r.addContact(ContactType.valueOf(rs.getString("type")), value); } } + + private void getSections(Resume resume) { + sqlHelper.execute( + "SELECT * FROM section WHERE resume_uuid =?", + ps -> { + ps.setString(1, resume.getUuid()); + ResultSet rs = ps.executeQuery(); + while (rs.next()) { + SectionType type = SectionType.valueOf(rs.getString("type")); + resume.getSections().put(type, (type == SectionType.OBJECTIVE || type == SectionType.PERSONAL) ? + new TextSection(rs.getString("value")) : + new ListSection(List.of(rs.getString("value").split("\n")))); + } + return null; + }); + } + + } \ No newline at end of file From 58bfc710e1dc3aee3cba578c2b2c2b22476f5196 Mon Sep 17 00:00:00 2001 From: Kvitto Date: Sat, 28 Sep 2024 20:20:57 +0300 Subject: [PATCH 14/18] HW15 ResumeServlet - added connection to db.resumes - response all resumes to web table --- src/com/urise/webapp/web/ResumeServlet.java | 28 +++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/src/com/urise/webapp/web/ResumeServlet.java b/src/com/urise/webapp/web/ResumeServlet.java index 0363301..2f979c8 100644 --- a/src/com/urise/webapp/web/ResumeServlet.java +++ b/src/com/urise/webapp/web/ResumeServlet.java @@ -1,11 +1,16 @@ package com.urise.webapp.web; +import com.urise.webapp.Config; +import com.urise.webapp.model.Resume; +import com.urise.webapp.storage.Storage; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServlet; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import java.io.IOException; +import java.io.PrintWriter; +import java.util.List; public class ResumeServlet extends HttpServlet { @Override @@ -13,8 +18,27 @@ protected void doGet(HttpServletRequest request, HttpServletResponse response) t request.setCharacterEncoding("UTF-8"); response.setCharacterEncoding("UTF-8"); response.setContentType("text/html;charset=UTF-8"); - String name = request.getParameter("name"); - response.getWriter().write(name == null ? "Hello Senior Java Developer" : "Hello " + name + " - new Senior Java Developer"); + + Storage db = Config.get().getStorage(); + List resumes = db.getAllSorted(); + + PrintWriter writer = response.getWriter(); + StringBuilder sb = new StringBuilder(); + + sb.append("Resume Servlet"); + sb.append(""); + sb.append("

Resume Servlet

"); + sb.append(""); + resumes.forEach(resume -> { + sb.append("") + .append("") + .append("") + .append(""); + }); + sb.append("
").append(resume.getUuid()).append("").append(resume.getFullName()).append("
"); + sb.append(""); + + writer.append(sb.toString()); } @Override From 9fc8bbfb01cd593e0ac31ee543351c8cf5db1aea Mon Sep 17 00:00:00 2001 From: Kvitto Date: Mon, 30 Sep 2024 09:03:10 +0300 Subject: [PATCH 15/18] HW15 ResumeServlet - fix after review --- src/com/urise/webapp/storage/SqlStorage.java | 67 ++++++++++++++------ src/com/urise/webapp/web/ResumeServlet.java | 10 ++- 2 files changed, 56 insertions(+), 21 deletions(-) diff --git a/src/com/urise/webapp/storage/SqlStorage.java b/src/com/urise/webapp/storage/SqlStorage.java index 691f871..67cebec 100644 --- a/src/com/urise/webapp/storage/SqlStorage.java +++ b/src/com/urise/webapp/storage/SqlStorage.java @@ -5,7 +5,10 @@ import com.urise.webapp.sql.SqlHelper; import java.sql.*; -import java.util.*; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; public class SqlStorage implements Storage { public final SqlHelper sqlHelper; @@ -21,24 +24,19 @@ public void clear() { @Override public Resume get(String uuid) { - return sqlHelper.execute( - " SELECT * FROM resume r " + - " LEFT JOIN contact c " + - " ON r.uuid = c.resume_uuid " + - " WHERE r.uuid =? ", + Resume resume = sqlHelper.execute( + "SELECT * FROM resume r WHERE r.uuid =?", ps -> { ps.setString(1, uuid); ResultSet rs = ps.executeQuery(); if (!rs.next()) { throw new NotExistStorageException(uuid); } - Resume r = new Resume(uuid, rs.getString("full_name")); - do { - addContact(rs, r); - } while (rs.next()); - getSections(r); - return r; + return new Resume(uuid, rs.getString("full_name")); }); + addContacts(resume); + addSections(resume); + return resume; } @Override @@ -104,7 +102,7 @@ public List getAllSorted() { } return null; }); - map.values().forEach(this::getSections); + map.values().forEach(this::addSections); return new ArrayList<>(map.values()); } @@ -133,13 +131,24 @@ private void insertSection(Connection conn, Resume r) throws SQLException { for (Map.Entry e : r.getSections().entrySet()) { ps.setString(1, r.getUuid()); ps.setString(2, e.getKey().name()); - ps.setString(3, e.getValue().toString()); + switch (e.getKey().ordinal()) { + case 0, 1 -> ps.setString(3, ((TextSection) e.getValue()).getContent()); + case 2, 3 -> ps.setString(3, listToString(((ListSection) e.getValue()).getItems())); + } ps.addBatch(); } ps.executeBatch(); } } + private String listToString(List list) { + StringBuilder sb = new StringBuilder(); + for (String s : list) { + sb.append(s).append("\n"); + } + return sb.toString(); + } + private void deleteContact(Connection conn, Resume r) { sqlHelper.execute("DELETE FROM contact WHERE resume_uuid=?", ps -> { ps.setString(1, r.getUuid()); @@ -156,6 +165,23 @@ private void deleteSection(Connection conn, Resume r) { }); } + private void addContacts(Resume r) { + sqlHelper.execute( + "SELECT * FROM contact c WHERE c.resume_uuid =?", + ps -> { + String uuid = r.getUuid(); + ps.setString(1, uuid); + ResultSet rs = ps.executeQuery(); + if (!rs.next()) { + throw new NotExistStorageException(uuid); + } + do { + addContact(rs, r); + } while (rs.next()); + return null; + }); + } + private void addContact(ResultSet rs, Resume r) throws SQLException { String value = rs.getString("value"); if (value != null) { @@ -163,7 +189,7 @@ private void addContact(ResultSet rs, Resume r) throws SQLException { } } - private void getSections(Resume resume) { + private void addSections(Resume resume) { sqlHelper.execute( "SELECT * FROM section WHERE resume_uuid =?", ps -> { @@ -171,13 +197,16 @@ private void getSections(Resume resume) { ResultSet rs = ps.executeQuery(); while (rs.next()) { SectionType type = SectionType.valueOf(rs.getString("type")); - resume.getSections().put(type, (type == SectionType.OBJECTIVE || type == SectionType.PERSONAL) ? - new TextSection(rs.getString("value")) : - new ListSection(List.of(rs.getString("value").split("\n")))); + Section section = switch (type) { + case PERSONAL, OBJECTIVE -> new TextSection(rs.getString("value")); + case ACHIEVEMENT, QUALIFICATION -> + new ListSection(List.of(rs.getString("value").split("\n"))); + case EXPERIENCE, EDUCATION -> new CompanySection(new ArrayList<>()); + }; + resume.getSections().put(type, section); } return null; }); } - } \ No newline at end of file diff --git a/src/com/urise/webapp/web/ResumeServlet.java b/src/com/urise/webapp/web/ResumeServlet.java index 2f979c8..3268ad6 100644 --- a/src/com/urise/webapp/web/ResumeServlet.java +++ b/src/com/urise/webapp/web/ResumeServlet.java @@ -13,14 +13,20 @@ import java.util.List; public class ResumeServlet extends HttpServlet { + private Storage storage; + + @Override + public void init() throws ServletException { + storage = Config.get().getStorage(); + } + @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding("UTF-8"); response.setCharacterEncoding("UTF-8"); response.setContentType("text/html;charset=UTF-8"); - Storage db = Config.get().getStorage(); - List resumes = db.getAllSorted(); + List resumes = storage.getAllSorted(); PrintWriter writer = response.getWriter(); StringBuilder sb = new StringBuilder(); From 6f45a18fb0fc0dbfc7784e29f6dce43471fee765 Mon Sep 17 00:00:00 2001 From: Kvitto Date: Mon, 30 Sep 2024 09:41:06 +0300 Subject: [PATCH 16/18] HW15 ResumeServlet - refactored getAllSorted() --- src/com/urise/webapp/storage/SqlStorage.java | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/src/com/urise/webapp/storage/SqlStorage.java b/src/com/urise/webapp/storage/SqlStorage.java index 67cebec..72e5286 100644 --- a/src/com/urise/webapp/storage/SqlStorage.java +++ b/src/com/urise/webapp/storage/SqlStorage.java @@ -93,16 +93,10 @@ public List getAllSorted() { } return null; }); - sqlHelper.execute( - "SELECT * FROM contact", ps -> { - ResultSet rs = ps.executeQuery(); - while (rs.next()) { - map.get(rs.getString("resume_uuid")) - .addContact(ContactType.valueOf(rs.getString("type")), rs.getString("value")); - } - return null; - }); - map.values().forEach(this::addSections); + map.values().forEach(r -> { + addContacts(r); + addSections(r); + }); return new ArrayList<>(map.values()); } @@ -189,11 +183,11 @@ private void addContact(ResultSet rs, Resume r) throws SQLException { } } - private void addSections(Resume resume) { + private void addSections(Resume r) { sqlHelper.execute( "SELECT * FROM section WHERE resume_uuid =?", ps -> { - ps.setString(1, resume.getUuid()); + ps.setString(1, r.getUuid()); ResultSet rs = ps.executeQuery(); while (rs.next()) { SectionType type = SectionType.valueOf(rs.getString("type")); @@ -203,7 +197,7 @@ private void addSections(Resume resume) { new ListSection(List.of(rs.getString("value").split("\n"))); case EXPERIENCE, EDUCATION -> new CompanySection(new ArrayList<>()); }; - resume.getSections().put(type, section); + r.getSections().put(type, section); } return null; }); From 8ec01fee220b4a63d36b9ec7a1fb059bf681f920 Mon Sep 17 00:00:00 2001 From: Kvitto Date: Mon, 30 Sep 2024 13:25:22 +0300 Subject: [PATCH 17/18] HW15 ResumeServlet - added two methods: addAllContacts() & addAllSections() --- src/com/urise/webapp/storage/SqlStorage.java | 87 +++++++++++++------- 1 file changed, 55 insertions(+), 32 deletions(-) diff --git a/src/com/urise/webapp/storage/SqlStorage.java b/src/com/urise/webapp/storage/SqlStorage.java index 72e5286..2ab096e 100644 --- a/src/com/urise/webapp/storage/SqlStorage.java +++ b/src/com/urise/webapp/storage/SqlStorage.java @@ -93,10 +93,8 @@ public List getAllSorted() { } return null; }); - map.values().forEach(r -> { - addContacts(r); - addSections(r); - }); + addAllContacts(map); + addAllSections(map); return new ArrayList<>(map.values()); } @@ -125,9 +123,12 @@ private void insertSection(Connection conn, Resume r) throws SQLException { for (Map.Entry e : r.getSections().entrySet()) { ps.setString(1, r.getUuid()); ps.setString(2, e.getKey().name()); - switch (e.getKey().ordinal()) { - case 0, 1 -> ps.setString(3, ((TextSection) e.getValue()).getContent()); - case 2, 3 -> ps.setString(3, listToString(((ListSection) e.getValue()).getItems())); + switch (e.getKey()) { + case PERSONAL, OBJECTIVE -> ps.setString(3, ((TextSection) e.getValue()).getContent()); + case ACHIEVEMENT, QUALIFICATION -> + ps.setString(3, listToString(((ListSection) e.getValue()).getItems())); + case EXPERIENCE, EDUCATION -> { + } } ps.addBatch(); } @@ -143,35 +144,40 @@ private String listToString(List list) { return sb.toString(); } - private void deleteContact(Connection conn, Resume r) { - sqlHelper.execute("DELETE FROM contact WHERE resume_uuid=?", ps -> { + private void deleteContact(Connection conn, Resume r) throws SQLException { + try (PreparedStatement ps = conn.prepareStatement("DELETE FROM contact WHERE resume_uuid=?")) { ps.setString(1, r.getUuid()); ps.execute(); - return null; - }); + } } - private void deleteSection(Connection conn, Resume r) { - sqlHelper.execute("DELETE FROM section WHERE resume_uuid=?", ps -> { + private void deleteSection(Connection conn, Resume r) throws SQLException { + try (PreparedStatement ps = conn.prepareStatement("DELETE FROM section WHERE resume_uuid=?")) { ps.setString(1, r.getUuid()); ps.execute(); - return null; - }); + } + } + + private void addAllContacts(Map map) { + sqlHelper.execute("SELECT * FROM contact", + ps -> { + ResultSet rs = ps.executeQuery(); + while (rs.next()) { + addContact(rs, map.get(rs.getString("resume_uuid"))); + } + return null; + }); } private void addContacts(Resume r) { sqlHelper.execute( "SELECT * FROM contact c WHERE c.resume_uuid =?", ps -> { - String uuid = r.getUuid(); - ps.setString(1, uuid); + ps.setString(1, r.getUuid()); ResultSet rs = ps.executeQuery(); - if (!rs.next()) { - throw new NotExistStorageException(uuid); - } - do { + while (rs.next()) { addContact(rs, r); - } while (rs.next()); + } return null; }); } @@ -179,10 +185,23 @@ private void addContacts(Resume r) { private void addContact(ResultSet rs, Resume r) throws SQLException { String value = rs.getString("value"); if (value != null) { - r.addContact(ContactType.valueOf(rs.getString("type")), value); + r.addContact(ContactType.valueOf(rs.getString("type")), rs.getString("value")); } } + private void addAllSections(Map map) { + sqlHelper.execute( + "SELECT * FROM section", + ps -> { + ResultSet rs = ps.executeQuery(); + while (rs.next()) { + addSection(rs, map.get(rs.getString("resume_uuid"))); + } + return null; + } + ); + } + private void addSections(Resume r) { sqlHelper.execute( "SELECT * FROM section WHERE resume_uuid =?", @@ -190,17 +209,21 @@ private void addSections(Resume r) { ps.setString(1, r.getUuid()); ResultSet rs = ps.executeQuery(); while (rs.next()) { - SectionType type = SectionType.valueOf(rs.getString("type")); - Section section = switch (type) { - case PERSONAL, OBJECTIVE -> new TextSection(rs.getString("value")); - case ACHIEVEMENT, QUALIFICATION -> - new ListSection(List.of(rs.getString("value").split("\n"))); - case EXPERIENCE, EDUCATION -> new CompanySection(new ArrayList<>()); - }; - r.getSections().put(type, section); + addSection(rs, r); } return null; - }); + } + ); + } + + private static void addSection(ResultSet rs, Resume r) throws SQLException { + SectionType type = SectionType.valueOf(rs.getString("type")); + Section section = switch (type) { + case PERSONAL, OBJECTIVE -> new TextSection(rs.getString("value")); + case ACHIEVEMENT, QUALIFICATION -> new ListSection(List.of(rs.getString("value").split("\n"))); + case EXPERIENCE, EDUCATION -> new CompanySection(new ArrayList<>()); + }; + r.getSections().put(type, section); } } \ No newline at end of file From 65858274ae5737e829ba7f3cd70bca41f6d55ba6 Mon Sep 17 00:00:00 2001 From: Kvitto Date: Sun, 6 Oct 2024 15:27:04 +0300 Subject: [PATCH 18/18] Lesson 16 --- src/com/urise/webapp/model/ContactType.java | 63 +++++- src/com/urise/webapp/model/Resume.java | 8 + src/com/urise/webapp/storage/SqlStorage.java | 186 +++++++++--------- src/com/urise/webapp/util/JsonParser.java | 20 +- .../urise/webapp/util/JsonSectionAdapter.java | 1 + src/com/urise/webapp/web/ResumeServlet.java | 79 +++++--- 6 files changed, 214 insertions(+), 143 deletions(-) diff --git a/src/com/urise/webapp/model/ContactType.java b/src/com/urise/webapp/model/ContactType.java index 3a04374..a503c3b 100644 --- a/src/com/urise/webapp/model/ContactType.java +++ b/src/com/urise/webapp/model/ContactType.java @@ -8,17 +8,44 @@ public enum ContactType { PHONE("Тел."), MOBILE("Мобильный"), HOME_PHONE("Домашний тел."), - SKYPE("Skype"), - MAIL("Почта"), - LINKEDIN("Профиль LinkedIn"), - GITHUB("Профиль GitHub"), - STACKOVERFLOW("Профиль Stackoverflow"), - HOME_PAGE("Домашняя страница"); + SKYPE("Skype") { + @Override + public String toHtml0(String value) { + return getTitle() + ": " + toLink("skype:" + value, value); + } + }, + MAIL("Почта") { + @Override + public String toHtml0(String value) { + return getTitle() + ": " + toLink("mailto:" + value, value); + } + }, + LINKEDIN("Профиль LinkedIn") { + @Override + public String toHtml0(String value) { + return toLink(value); + } + }, + GITHUB("Профиль GitHub") { + @Override + public String toHtml0(String value) { + return toLink(value); + } + }, + STACKOVERFLOW("Профиль Stackoverflow") { + @Override + public String toHtml0(String value) { + return toLink(value); + } + }, + HOME_PAGE("Домашняя страница") { + @Override + public String toHtml0(String value) { + return toLink(value); + } + }; - private String title; - - ContactType() { - } + private final String title; ContactType(String title) { this.title = title; @@ -27,4 +54,20 @@ public enum ContactType { public String getTitle() { return title; } + + protected String toHtml0(String value) { + return title + ": " + value; + } + + public String toHtml(String value) { + return (value == null) ? "" : toHtml0(value); + } + + public String toLink(String href) { + return toLink(href, title); + } + + public static String toLink(String href, String title) { + return "" + title + ""; + } } diff --git a/src/com/urise/webapp/model/Resume.java b/src/com/urise/webapp/model/Resume.java index 6f6d9de..3e04a87 100644 --- a/src/com/urise/webapp/model/Resume.java +++ b/src/com/urise/webapp/model/Resume.java @@ -94,4 +94,12 @@ public void addContact(ContactType contactType, String value) { public void addSections(SectionType type, Section section) { sections.put(type, section); } + + public void setFullName(String fullName) { + this.fullName = fullName; + } + + public String getContact(ContactType contactType) { + return contacts.get(contactType); + } } diff --git a/src/com/urise/webapp/storage/SqlStorage.java b/src/com/urise/webapp/storage/SqlStorage.java index 2ab096e..f014c92 100644 --- a/src/com/urise/webapp/storage/SqlStorage.java +++ b/src/com/urise/webapp/storage/SqlStorage.java @@ -3,6 +3,7 @@ import com.urise.webapp.exception.NotExistStorageException; import com.urise.webapp.model.*; import com.urise.webapp.sql.SqlHelper; +import com.urise.webapp.util.JsonParser; import java.sql.*; import java.util.ArrayList; @@ -24,19 +25,35 @@ public void clear() { @Override public Resume get(String uuid) { - Resume resume = sqlHelper.execute( - "SELECT * FROM resume r WHERE r.uuid =?", - ps -> { - ps.setString(1, uuid); - ResultSet rs = ps.executeQuery(); - if (!rs.next()) { - throw new NotExistStorageException(uuid); - } - return new Resume(uuid, rs.getString("full_name")); - }); - addContacts(resume); - addSections(resume); - return resume; + return sqlHelper.transactionalExecute(conn -> { + Resume r; + try (PreparedStatement ps = conn.prepareStatement("SELECT * FROM resume WHERE uuid =?")) { + ps.setString(1, uuid); + ResultSet rs = ps.executeQuery(); + if (!rs.next()) { + throw new NotExistStorageException(uuid); + } + r = new Resume(uuid, rs.getString("full_name")); + } + + try (PreparedStatement ps = conn.prepareStatement("SELECT * FROM contact WHERE resume_uuid =?")) { + ps.setString(1, uuid); + ResultSet rs = ps.executeQuery(); + while (rs.next()) { + addContact(rs, r); + } + } + + try (PreparedStatement ps = conn.prepareStatement("SELECT * FROM section WHERE resume_uuid =?")) { + ps.setString(1, uuid); + ResultSet rs = ps.executeQuery(); + while (rs.next()) { + addSection(rs, r); + } + } + + return r; + }); } @Override @@ -49,10 +66,10 @@ public void update(Resume r) { throw new NotExistStorageException(r.getUuid()); } } - deleteContact(conn, r); - deleteSection(conn, r); - insertContact(conn, r); - insertSection(conn, r); + deleteContacts(conn, r); + deleteSections(conn, r); + insertContacts(conn, r); + insertSections(conn, r); return null; }); } @@ -60,15 +77,16 @@ public void update(Resume r) { @Override public void save(Resume r) { sqlHelper.transactionalExecute(conn -> { - try (PreparedStatement ps = conn.prepareStatement("INSERT INTO resume (uuid, full_name) VALUES (?,?)")) { - ps.setString(1, r.getUuid()); - ps.setString(2, r.getFullName()); - ps.execute(); - } - insertContact(conn, r); - insertSection(conn, r); - return null; - }); + try (PreparedStatement ps = conn.prepareStatement("INSERT INTO resume (uuid, full_name) VALUES (?,?)")) { + ps.setString(1, r.getUuid()); + ps.setString(2, r.getFullName()); + ps.execute(); + } + insertContacts(conn, r); + insertSections(conn, r); + return null; + } + ); } @Override @@ -84,18 +102,35 @@ public void delete(String uuid) { @Override public List getAllSorted() { - Map map = new LinkedHashMap<>(); - sqlHelper.execute( - "SELECT * FROM resume r ORDER BY full_name, uuid", ps -> { - ResultSet rs = ps.executeQuery(); - while (rs.next()) { - map.put(rs.getString("uuid"), new Resume(rs.getString("uuid"), rs.getString("full_name"))); - } - return null; - }); - addAllContacts(map); - addAllSections(map); - return new ArrayList<>(map.values()); + return sqlHelper.transactionalExecute(conn -> { + Map resumes = new LinkedHashMap<>(); + + try (PreparedStatement ps = conn.prepareStatement("SELECT * FROM resume ORDER BY full_name, uuid")) { + ResultSet rs = ps.executeQuery(); + while (rs.next()) { + String uuid = rs.getString("uuid"); + resumes.put(uuid, new Resume(uuid, rs.getString("full_name"))); + } + } + + try (PreparedStatement ps = conn.prepareStatement("SELECT * FROM contact")) { + ResultSet rs = ps.executeQuery(); + while (rs.next()) { + Resume r = resumes.get(rs.getString("resume_uuid")); + addContact(rs, r); + } + } + + try (PreparedStatement ps = conn.prepareStatement("SELECT * FROM section")) { + ResultSet rs = ps.executeQuery(); + while (rs.next()) { + Resume r = resumes.get(rs.getString("resume_uuid")); + addSection(rs, r); + } + } + + return new ArrayList<>(resumes.values()); + }); } @Override @@ -106,7 +141,7 @@ public int size() { }); } - private void insertContact(Connection conn, Resume r) throws SQLException { + private void insertContacts(Connection conn, Resume r) throws SQLException { try (PreparedStatement ps = conn.prepareStatement("INSERT INTO contact (resume_uuid, type, value) VALUES (?,?,?)")) { for (Map.Entry e : r.getContacts().entrySet()) { ps.setString(1, r.getUuid()); @@ -118,41 +153,29 @@ private void insertContact(Connection conn, Resume r) throws SQLException { } } - private void insertSection(Connection conn, Resume r) throws SQLException { + private void insertSections(Connection conn, Resume r) throws SQLException { try (PreparedStatement ps = conn.prepareStatement("INSERT INTO section (resume_uuid, type, value) VALUES (?,?,?)")) { for (Map.Entry e : r.getSections().entrySet()) { ps.setString(1, r.getUuid()); ps.setString(2, e.getKey().name()); - switch (e.getKey()) { - case PERSONAL, OBJECTIVE -> ps.setString(3, ((TextSection) e.getValue()).getContent()); - case ACHIEVEMENT, QUALIFICATION -> - ps.setString(3, listToString(((ListSection) e.getValue()).getItems())); - case EXPERIENCE, EDUCATION -> { - } - } + Section section = e.getValue(); + ps.setString(3, JsonParser.write(section, Section.class)); ps.addBatch(); } ps.executeBatch(); } } - private String listToString(List list) { - StringBuilder sb = new StringBuilder(); - for (String s : list) { - sb.append(s).append("\n"); - } - return sb.toString(); + private void deleteContacts(Connection conn, Resume r) throws SQLException { + deleteAttributes(conn, r, "DELETE FROM contact WHERE resume_uuid=?"); } - private void deleteContact(Connection conn, Resume r) throws SQLException { - try (PreparedStatement ps = conn.prepareStatement("DELETE FROM contact WHERE resume_uuid=?")) { - ps.setString(1, r.getUuid()); - ps.execute(); - } + private void deleteSections(Connection conn, Resume r) throws SQLException { + deleteAttributes(conn, r, "DELETE FROM section WHERE resume_uuid=?"); } - private void deleteSection(Connection conn, Resume r) throws SQLException { - try (PreparedStatement ps = conn.prepareStatement("DELETE FROM section WHERE resume_uuid=?")) { + private void deleteAttributes(Connection conn, Resume r, String sql) throws SQLException { + try (PreparedStatement ps = conn.prepareStatement(sql)) { ps.setString(1, r.getUuid()); ps.execute(); } @@ -185,45 +208,16 @@ private void addContacts(Resume r) { private void addContact(ResultSet rs, Resume r) throws SQLException { String value = rs.getString("value"); if (value != null) { - r.addContact(ContactType.valueOf(rs.getString("type")), rs.getString("value")); + r.addContact(ContactType.valueOf(rs.getString("type")), value); } } - private void addAllSections(Map map) { - sqlHelper.execute( - "SELECT * FROM section", - ps -> { - ResultSet rs = ps.executeQuery(); - while (rs.next()) { - addSection(rs, map.get(rs.getString("resume_uuid"))); - } - return null; - } - ); - } - - private void addSections(Resume r) { - sqlHelper.execute( - "SELECT * FROM section WHERE resume_uuid =?", - ps -> { - ps.setString(1, r.getUuid()); - ResultSet rs = ps.executeQuery(); - while (rs.next()) { - addSection(rs, r); - } - return null; - } - ); - } - - private static void addSection(ResultSet rs, Resume r) throws SQLException { - SectionType type = SectionType.valueOf(rs.getString("type")); - Section section = switch (type) { - case PERSONAL, OBJECTIVE -> new TextSection(rs.getString("value")); - case ACHIEVEMENT, QUALIFICATION -> new ListSection(List.of(rs.getString("value").split("\n"))); - case EXPERIENCE, EDUCATION -> new CompanySection(new ArrayList<>()); - }; - r.getSections().put(type, section); + private void addSection(ResultSet rs, Resume r) throws SQLException { + String content = rs.getString("value"); + if (content != null) { + SectionType type = SectionType.valueOf(rs.getString("type")); + r.addSections(type, JsonParser.read(content, Section.class)); + } } } \ No newline at end of file diff --git a/src/com/urise/webapp/util/JsonParser.java b/src/com/urise/webapp/util/JsonParser.java index d6dd5a1..f908261 100644 --- a/src/com/urise/webapp/util/JsonParser.java +++ b/src/com/urise/webapp/util/JsonParser.java @@ -6,12 +6,10 @@ import java.io.Reader; import java.io.Writer; -import java.time.LocalDate; public class JsonParser { - private static final Gson GSON = new GsonBuilder() - .registerTypeAdapter(Section.class, new JsonSectionAdapter<>()) - .registerTypeAdapter(LocalDate.class, new LocalDateTypeAdapter()) + private static Gson GSON = new GsonBuilder() + .registerTypeAdapter(Section.class, new JsonSectionAdapter()) .create(); public static T read(Reader reader, Class clazz) { @@ -21,4 +19,16 @@ public static T read(Reader reader, Class clazz) { public static void write(T object, Writer writer) { GSON.toJson(object, writer); } -} + + public static T read(String content, Class clazz) { + return GSON.fromJson(content, clazz); + } + + public static String write(T object) { + return GSON.toJson(object); + } + + public static String write(T object, Class clazz) { + return GSON.toJson(object, clazz); + } +} \ No newline at end of file diff --git a/src/com/urise/webapp/util/JsonSectionAdapter.java b/src/com/urise/webapp/util/JsonSectionAdapter.java index 13ddbd7..2113163 100644 --- a/src/com/urise/webapp/util/JsonSectionAdapter.java +++ b/src/com/urise/webapp/util/JsonSectionAdapter.java @@ -22,6 +22,7 @@ public T deserialize(JsonElement json, Type type, JsonDeserializationContext con } } + @Override public JsonElement serialize(T section, Type type, JsonSerializationContext context) { JsonObject retValue = new JsonObject(); diff --git a/src/com/urise/webapp/web/ResumeServlet.java b/src/com/urise/webapp/web/ResumeServlet.java index 3268ad6..ad6e6c6 100644 --- a/src/com/urise/webapp/web/ResumeServlet.java +++ b/src/com/urise/webapp/web/ResumeServlet.java @@ -1,54 +1,69 @@ package com.urise.webapp.web; import com.urise.webapp.Config; +import com.urise.webapp.model.ContactType; import com.urise.webapp.model.Resume; import com.urise.webapp.storage.Storage; +import jakarta.servlet.ServletConfig; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServlet; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import java.io.IOException; -import java.io.PrintWriter; -import java.util.List; public class ResumeServlet extends HttpServlet { - private Storage storage; + + private Storage storage; // = Config.get().getStorage(); @Override - public void init() throws ServletException { + public void init(ServletConfig config) throws ServletException { + super.init(config); storage = Config.get().getStorage(); } - @Override - protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding("UTF-8"); - response.setCharacterEncoding("UTF-8"); - response.setContentType("text/html;charset=UTF-8"); - - List resumes = storage.getAllSorted(); - - PrintWriter writer = response.getWriter(); - StringBuilder sb = new StringBuilder(); - - sb.append("Resume Servlet"); - sb.append(""); - sb.append("

Resume Servlet

"); - sb.append(""); - resumes.forEach(resume -> { - sb.append("") - .append("") - .append("") - .append(""); - }); - sb.append("
").append(resume.getUuid()).append("").append(resume.getFullName()).append("
"); - sb.append(""); - - writer.append(sb.toString()); + String uuid = request.getParameter("uuid"); + String fullName = request.getParameter("fullName"); + Resume r = storage.get(uuid); + r.setFullName(fullName); + for (ContactType type : ContactType.values()) { + String value = request.getParameter(type.name()); + if (value != null && value.trim().length() != 0) { + r.addContact(type, value); + } else { + r.getContacts().remove(type); + } + } + storage.update(r); + response.sendRedirect("resume"); } - @Override - protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { - + protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + String uuid = request.getParameter("uuid"); + String action = request.getParameter("action"); + if (action == null) { + request.setAttribute("resumes", storage.getAllSorted()); + request.getRequestDispatcher("/WEB-INF/jsp/list.jsp").forward(request, response); + return; + } + Resume r; + switch (action) { + case "delete": + storage.delete(uuid); + response.sendRedirect("resume"); + return; + case "view": + case "edit": + r = storage.get(uuid); + break; + default: + throw new IllegalArgumentException("Action " + action + " is illegal"); + } + request.setAttribute("resume", r); + request.getRequestDispatcher( + ("view".equals(action) ? "/WEB-INF/jsp/view.jsp" : "/WEB-INF/jsp/edit.jsp") + ).forward(request, response); } -} +} \ No newline at end of file