From e868169f3db29e4640d5eb925b06023160693f18 Mon Sep 17 00:00:00 2001 From: Sergey Krylov Date: Thu, 5 Mar 2026 05:29:10 +0300 Subject: [PATCH] feat: add fetch size, max-rows, timeout settings --- resources/application.properties | 5 +- .../back/controller/ProfileController.java | 7 +- .../controller/rest/ProfileController.java | 7 +- src/ru/charm/back/dao/ProfileDao.java | 154 +++++++----------- src/ru/charm/back/dto/ProfileFilter.java | 17 ++ .../back/dto/ProfileSelectQueryBuilder.java | 115 +++++++++++++ .../back/dto/ProfileUpdateQueryBuilder.java | 109 +++++++++++++ src/ru/charm/back/dto/Query.java | 6 + .../mapper/RequestToProfileFilterMapper.java | 54 ++++++ src/ru/charm/back/service/ProfileService.java | 9 +- .../{ConfigFile.java => ConfigFileUtils.java} | 8 +- .../charm/back/utils/ConnectionManager.java | 48 ++++++ src/ru/charm/back/utils/DateTimeUtils.java | 25 +++ 13 files changed, 457 insertions(+), 107 deletions(-) create mode 100644 src/ru/charm/back/dto/ProfileFilter.java create mode 100644 src/ru/charm/back/dto/ProfileSelectQueryBuilder.java create mode 100644 src/ru/charm/back/dto/ProfileUpdateQueryBuilder.java create mode 100644 src/ru/charm/back/dto/Query.java create mode 100644 src/ru/charm/back/mapper/RequestToProfileFilterMapper.java rename src/ru/charm/back/utils/{ConfigFile.java => ConfigFileUtils.java} (71%) create mode 100644 src/ru/charm/back/utils/ConnectionManager.java create mode 100644 src/ru/charm/back/utils/DateTimeUtils.java diff --git a/resources/application.properties b/resources/application.properties index 8762ad0..9abd4cc 100644 --- a/resources/application.properties +++ b/resources/application.properties @@ -1,4 +1,7 @@ app.datasource.url=jdbc:postgresql://localhost:5434/charm_repository app.datasource.username=postgres app.datasource.password=123456 -app.datasource.driver=org.postgresql.Driver \ No newline at end of file +app.datasource.driver=org.postgresql.Driver +app.datasource.fetch-size=50 +app.datasource.max-rows=100 +app.datasource.query-timeout=5 \ No newline at end of file diff --git a/src/ru/charm/back/controller/ProfileController.java b/src/ru/charm/back/controller/ProfileController.java index f6f2bed..d3ce703 100644 --- a/src/ru/charm/back/controller/ProfileController.java +++ b/src/ru/charm/back/controller/ProfileController.java @@ -10,8 +10,10 @@ import jakarta.servlet.annotation.WebServlet; import jakarta.servlet.http.HttpServlet; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; +import ru.charm.back.dto.ProfileFilter; import ru.charm.back.dto.ProfileGetDto; import ru.charm.back.dto.ProfileUpdateDto; +import ru.charm.back.mapper.RequestToProfileFilterMapper; import ru.charm.back.mapper.RequestToProfileUpdateDtoMapper; import ru.charm.back.service.ProfileService; @@ -27,6 +29,8 @@ public class ProfileController extends HttpServlet { private final ProfileService service = ProfileService.getInstance(); private final RequestToProfileUpdateDtoMapper requestToProfileUpdateDtoMapper = RequestToProfileUpdateDtoMapper.getInstance(); + private final RequestToProfileFilterMapper requestToProfileFilterMapper = RequestToProfileFilterMapper.getInstance(); + @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { @@ -66,7 +70,8 @@ public class ProfileController extends HttpServlet { resp.sendError(SC_NOT_FOUND); } } else { - req.setAttribute("profiles", service.findAll()); + ProfileFilter filter = requestToProfileFilterMapper.map(req); + req.setAttribute("profiles", service.findAll(filter)); req.getRequestDispatcher("/WEB-INF/jsp/profiles.jsp").forward(req, resp); } } diff --git a/src/ru/charm/back/controller/rest/ProfileController.java b/src/ru/charm/back/controller/rest/ProfileController.java index 71fde65..71a655d 100644 --- a/src/ru/charm/back/controller/rest/ProfileController.java +++ b/src/ru/charm/back/controller/rest/ProfileController.java @@ -9,7 +9,9 @@ import jakarta.servlet.annotation.WebServlet; import jakarta.servlet.http.HttpServlet; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; +import ru.charm.back.dto.ProfileFilter; import ru.charm.back.dto.ProfileGetDto; +import ru.charm.back.mapper.RequestToProfileFilterMapper; import ru.charm.back.service.ProfileService; import java.io.IOException; @@ -23,6 +25,8 @@ import static ru.charm.back.utils.UrlUtils.REST_URL; @MultipartConfig public class ProfileController extends HttpServlet { private final ProfileService service = ProfileService.getInstance(); + private final RequestToProfileFilterMapper requestToProfileFilterMapper = RequestToProfileFilterMapper.getInstance(); + private final ObjectMapper objectMapper = JsonMapper.builder() .configure(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT, true) @@ -45,7 +49,8 @@ public class ProfileController extends HttpServlet { resp.sendError(SC_NOT_FOUND); } } else { - objectMapper.writeValue(writer, service.findAll()); + ProfileFilter filter = requestToProfileFilterMapper.map(req); + objectMapper.writeValue(writer, service.findAll(filter)); } } } diff --git a/src/ru/charm/back/dao/ProfileDao.java b/src/ru/charm/back/dao/ProfileDao.java index 651c47c..3080d86 100644 --- a/src/ru/charm/back/dao/ProfileDao.java +++ b/src/ru/charm/back/dao/ProfileDao.java @@ -4,38 +4,39 @@ import lombok.AccessLevel; import lombok.NoArgsConstructor; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; +import ru.charm.back.dto.ProfileFilter; +import ru.charm.back.dto.ProfileSelectQueryBuilder; +import ru.charm.back.dto.ProfileUpdateQueryBuilder; +import ru.charm.back.dto.Query; import ru.charm.back.model.Gender; import ru.charm.back.model.Profile; import ru.charm.back.model.Role; import ru.charm.back.model.Status; -import ru.charm.back.utils.ConfigFile; +import ru.charm.back.utils.ConfigFileUtils; +import ru.charm.back.utils.ConnectionManager; import java.sql.*; import java.sql.Date; import java.util.*; +import static ru.charm.back.utils.ConnectionManager.getConnection; + @Slf4j @NoArgsConstructor(access = AccessLevel.PRIVATE) public class ProfileDao { + public static final String INSERT = "INSERT INTO profile (email, password) VALUES (?, ?)"; private static final ProfileDao INSTANCE = new ProfileDao(); - public static final String URL = ConfigFile.get("app.datasource.url"); - public static final String USER = ConfigFile.get("app.datasource.username"); - public static final String PASSWORD = ConfigFile.get("app.datasource.password"); - public static final String DRIVER = ConfigFile.get("app.datasource.driver"); - @SneakyThrows public static ProfileDao getInstance() { - Class.forName(DRIVER); return INSTANCE; } public Profile save(Profile profile) { - String sql = "INSERT INTO profile(email, password) VALUES (?, ?)"; try ( - Connection connection = DriverManager.getConnection(URL, USER, PASSWORD); - PreparedStatement statement = connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS); + Connection connection = getConnection(); + PreparedStatement statement = connection.prepareStatement(INSERT, Statement.RETURN_GENERATED_KEYS); ) { statement.setString(1, profile.getEmail()); @@ -54,13 +55,15 @@ public class ProfileDao { } } + public Optional findById(Long id) { + Query query = new ProfileSelectQueryBuilder().addIdFilter(id).build(); + try ( - Connection connection = DriverManager.getConnection(URL, USER, PASSWORD); - Statement statement = connection.createStatement(); + Connection connection = getConnection(); + PreparedStatement statement = ConnectionManager.getPreparedStmt(connection, query); ) { - String sql = "SELECT * FROM profile WHERE id = '%s'".formatted(id); - ResultSet res = statement.executeQuery(sql); + ResultSet res = statement.executeQuery(); Profile profile = null; if (res.next()) { @@ -74,13 +77,24 @@ public class ProfileDao { } } - public List findAll() { + public List findAll(ProfileFilter filter) { + Query query = new ProfileSelectQueryBuilder() + .addEmailStartWithFilter(filter.getEmailStartWith()) + .addNameStartWith(filter.getNameStartWith()) + .addSurnameStartWith(filter.getSurnameStartWith()) + .addStatus(filter.getStatus()) + .addLTAge(filter.getLtAge()) + .addGTEAge(filter.getGteAge()) + .build(); + try ( - Connection connection = DriverManager.getConnection(URL, USER, PASSWORD); - Statement statement = connection.createStatement(); + Connection connection = ConnectionManager.getConnection(); + PreparedStatement statement = ConnectionManager.getPreparedStmt(connection, query); ) { - String sql = "SELECT * FROM profile" ; - ResultSet res = statement.executeQuery(sql); + statement.setFetchSize(ConnectionManager.FETCH_SIZE); + statement.setMaxRows(ConnectionManager.MAX_ROWS); + statement.setQueryTimeout(ConnectionManager.QUERY_TIMEOUT); + ResultSet res = statement.executeQuery(); List profiles = new ArrayList<>(); while (res.next()) { @@ -94,81 +108,32 @@ public class ProfileDao { } } - public Optional findByEmailAndPassword(String email, String password) { - try (Connection conn = DriverManager.getConnection(URL, USER, PASSWORD); - Statement stmt = conn.createStatement()) { - //language=POSTGRES-PSQL - String sql = "SELECT * FROM profile WHERE email = '%s' AND password = '%s'"; - - ResultSet rs = stmt.executeQuery(String.format(sql, email, password)); - - Profile profile = null; - if (rs.next()) { - profile = mapToProfile(rs); - } - return Optional.ofNullable(profile); - } catch (SQLException e) { - throw new RuntimeException(e); - } - } - public void update(Profile profile) { - try (Connection conn = DriverManager.getConnection(URL, USER, PASSWORD); - Statement stmt = conn.createStatement()) { - List args = new ArrayList<>(); - StringBuilder queryBuilder = new StringBuilder("UPDATE profile SET email = '%s', password = '%s'"); - args.add(profile.getEmail()); - args.add(profile.getPassword()); + Query query = new ProfileUpdateQueryBuilder() + .addEmail(profile.getEmail()) + .addPassword(profile.getPassword()) + .addName(profile.getName()) + .addSurname(profile.getSurname()) + .addBirthDate(profile.getBirthDate()) + .addAbout(profile.getAbout()) + .addGender(profile.getGender()) + .addStatus(profile.getStatus()) + .addPhoto(profile.getPhoto()) + .build(profile.getId()); - if (profile.getName() != null) { - queryBuilder.append(", name = '%s'"); - args.add(profile.getName()); - } - if (profile.getSurname() != null) { - queryBuilder.append(", surname = '%s'"); - args.add(profile.getSurname()); - } - if (profile.getBirthDate() != null) { - queryBuilder.append(", birth_date = '%s'"); - args.add(Date.valueOf(profile.getBirthDate())); - } - if (profile.getAbout() != null) { - queryBuilder.append(", about = '%s'"); - args.add(profile.getAbout()); - } - if (profile.getGender() != null) { - queryBuilder.append(", gender = '%s'"); - args.add(profile.getGender()); - } - if (profile.getStatus() != null) { - queryBuilder.append(", status = '%s'"); - args.add(profile.getStatus()); - } - if (profile.getPhoto() != null) { - queryBuilder.append(", photo = '%s'"); - args.add(profile.getPhoto()); - } - - queryBuilder.append(" WHERE id = %s"); - args.add(profile.getId()); - - String sql = queryBuilder.toString().formatted(args.toArray()); - log.debug("Final update sql: {}", sql); - - int updateCount = stmt.executeUpdate(sql); - log.debug("Update count: {}", updateCount); + try (Connection conn = ConnectionManager.getConnection(); + PreparedStatement stmt = ConnectionManager.getPreparedStmt(conn, query)) { + stmt.executeUpdate(); } catch (SQLException e) { throw new RuntimeException(e); } } public boolean delete(Long id) { - try (Connection conn = DriverManager.getConnection(URL, USER, PASSWORD); - Statement stmt = conn.createStatement()) { - //language=POSTGRES-PSQL - String sql = "DELETE FROM profile WHERE id = %s".formatted(id); - - int deleteCount = stmt.executeUpdate(sql); + String sql = "DELETE FROM profile WHERE id = ?"; + try (Connection conn = getConnection(); + PreparedStatement stmt = conn.prepareStatement(sql)) { + int deleteCount = stmt.executeUpdate(); log.debug("Delete count: {}", deleteCount); return deleteCount > 0; } catch (SQLException e) { @@ -178,7 +143,7 @@ public class ProfileDao { public Set getAllEmails() { try ( - Connection connection = DriverManager.getConnection(URL, USER, PASSWORD); + Connection connection = getConnection(); Statement statement = connection.createStatement(); ) { String sql = "SELECT email FROM profile" ; @@ -197,11 +162,11 @@ public class ProfileDao { } public Optional findByEmail(String email) { - String sql = "SELECT * FROM profile WHERE email = ?"; + Query query = new ProfileSelectQueryBuilder().addEmailFilter(email).build(); try ( - Connection connection = DriverManager.getConnection(URL, USER, PASSWORD); - PreparedStatement statement = connection.prepareStatement(sql); + Connection connection = ConnectionManager.getConnection(); + PreparedStatement statement = ConnectionManager.getPreparedStmt(connection, query); ) { statement.setString(1, email); ResultSet res = statement.executeQuery(); @@ -219,12 +184,13 @@ public class ProfileDao { } public Boolean existsByEmail(String email) { + Query query = new ProfileSelectQueryBuilder().addEmailFilter(email).build(); + try ( - Connection connection = DriverManager.getConnection(URL, USER, PASSWORD); - Statement statement = connection.createStatement(); + Connection connection = ConnectionManager.getConnection(); + PreparedStatement statement = ConnectionManager.getPreparedStmt(connection, query); ) { - String sql = "SELECT * FROM profile WHERE email = '%s'".formatted(email); - ResultSet res = statement.executeQuery(sql); + ResultSet res = statement.executeQuery(); return res.next(); diff --git a/src/ru/charm/back/dto/ProfileFilter.java b/src/ru/charm/back/dto/ProfileFilter.java new file mode 100644 index 0000000..d041066 --- /dev/null +++ b/src/ru/charm/back/dto/ProfileFilter.java @@ -0,0 +1,17 @@ +package ru.charm.back.dto; + +import lombok.AccessLevel; +import lombok.Data; +import lombok.experimental.FieldDefaults; +import ru.charm.back.model.Status; + +@Data +@FieldDefaults(level = AccessLevel.PRIVATE) +public class ProfileFilter { + String emailStartWith; + String nameStartWith; + String surnameStartWith; + Integer ltAge; + Integer gteAge; + Status status; +} diff --git a/src/ru/charm/back/dto/ProfileSelectQueryBuilder.java b/src/ru/charm/back/dto/ProfileSelectQueryBuilder.java new file mode 100644 index 0000000..396bedd --- /dev/null +++ b/src/ru/charm/back/dto/ProfileSelectQueryBuilder.java @@ -0,0 +1,115 @@ +package ru.charm.back.dto; + + +import ru.charm.back.model.Status; + +import java.sql.Date; +import java.util.ArrayList; +import java.util.List; + +import static ru.charm.back.utils.DateTimeUtils.getPastDate; + + +public class ProfileSelectQueryBuilder { + //language=POSTGRES-PSQL + public static final String SELECT_BASE = """ + SELECT id, email, password, "name", surname, birth_date, about, gender, photo, status, role + FROM profile + WHERE '' = '' + """; + + private final StringBuilder sb; + private final List args; + + public ProfileSelectQueryBuilder() { + this.sb = new StringBuilder(SELECT_BASE); + this.args = new ArrayList<>(); + } + + public ProfileSelectQueryBuilder addIdFilter(Long id) { + if (id == null) { + return this; + } + sb.append(" AND id = ?"); + args.add(id); + return this; + } + + public ProfileSelectQueryBuilder addEmailFilter(String email) { + if (email == null) { + return this; + } + sb.append(" AND email = ?"); + args.add(email); + return this; + } + + public ProfileSelectQueryBuilder addPasswordFilter(String password) { + if (password == null) { + return this; + } + sb.append(" AND password = ?"); + args.add(password); + return this; + } + + public ProfileSelectQueryBuilder addEmailStartWithFilter(String emailStartWith) { + if (emailStartWith == null) { + return this; + } + sb.append(" AND email like ?"); + args.add(emailStartWith + "%"); + return this; + } + + public ProfileSelectQueryBuilder addNameStartWith(String nameStartWith) { + if (nameStartWith == null) { + return this; + } + sb.append(" AND name like ?"); + args.add(nameStartWith + "%"); + return this; + } + + public ProfileSelectQueryBuilder addSurnameStartWith(String surnameStartWith) { + if (surnameStartWith == null) { + return this; + } + sb.append(" AND surname like ?"); + args.add(surnameStartWith + "%"); + return this; + } + + public ProfileSelectQueryBuilder addLTAge(Integer ltAge) { + if (ltAge == null) { + return this; + } + Date gtDate = getPastDate(ltAge); + sb.append(" AND birth_date > ?"); + args.add(gtDate); + return this; + } + + public ProfileSelectQueryBuilder addGTEAge(Integer gteAge) { + if (gteAge == null) { + return this; + } + Date lteDate = getPastDate(gteAge); + sb.append(" AND birth_date <= ?"); + args.add(lteDate); + return this; + } + + public ProfileSelectQueryBuilder addStatus(Status status) { + if (status == null) { + return this; + } + sb.append(" AND status = ?"); + args.add(status.toString()); + return this; + } + + public Query build() { + return new Query(sb.toString(), args); + } +} diff --git a/src/ru/charm/back/dto/ProfileUpdateQueryBuilder.java b/src/ru/charm/back/dto/ProfileUpdateQueryBuilder.java new file mode 100644 index 0000000..3427f96 --- /dev/null +++ b/src/ru/charm/back/dto/ProfileUpdateQueryBuilder.java @@ -0,0 +1,109 @@ +package ru.charm.back.dto; + +import ru.charm.back.model.Gender; +import ru.charm.back.model.Status; + +import java.sql.Date; +import java.time.LocalDate; +import java.util.ArrayList; +import java.util.List; + +public class ProfileUpdateQueryBuilder { + //language=POSTGRES-PSQL + public static final String UPDATE_BASE = "UPDATE profile SET id = id"; + + private final StringBuilder sb; + private final List args; + + public ProfileUpdateQueryBuilder() { + this.sb = new StringBuilder(UPDATE_BASE); + this.args = new ArrayList<>(); + } + + public ProfileUpdateQueryBuilder addEmail(String email) { + if (email == null) { + return this; + } + sb.append(", email = ?"); + args.add(email); + return this; + } + + public ProfileUpdateQueryBuilder addPassword(String password) { + if (password == null) { + return this; + } + sb.append(", password = ?"); + args.add(password); + return this; + } + + public ProfileUpdateQueryBuilder addName(String name) { + if (name == null) { + return this; + } + sb.append(", name = ?"); + args.add(name); + return this; + } + + public ProfileUpdateQueryBuilder addSurname(String surname) { + if (surname == null) { + return this; + } + sb.append(", surname = ?"); + args.add(surname); + return this; + } + + public ProfileUpdateQueryBuilder addBirthDate(LocalDate birthDate) { + if (birthDate == null) { + return this; + } + sb.append(", birth_date = ?"); + args.add(Date.valueOf(birthDate)); + return this; + } + + public ProfileUpdateQueryBuilder addAbout(String about) { + if (about == null) { + return this; + } + sb.append(", about = ?"); + args.add(about); + return this; + } + + public ProfileUpdateQueryBuilder addGender(Gender gender) { + if (gender == null) { + return this; + } + sb.append(", gender = ?"); + args.add(gender.toString()); + return this; + } + + public ProfileUpdateQueryBuilder addStatus(Status status) { + if (status == null) { + return this; + } + sb.append(", status = ?"); + args.add(status.toString()); + return this; + } + + public ProfileUpdateQueryBuilder addPhoto(String photo) { + if (photo == null) { + return this; + } + sb.append(", photo = ?"); + args.add(photo); + return this; + } + + public Query build(Long id) { + sb.append(" WHERE id = ?"); + args.add(id); + return new Query(sb.toString(), args); + } +} diff --git a/src/ru/charm/back/dto/Query.java b/src/ru/charm/back/dto/Query.java new file mode 100644 index 0000000..e73cffd --- /dev/null +++ b/src/ru/charm/back/dto/Query.java @@ -0,0 +1,6 @@ +package ru.charm.back.dto; + +import java.util.List; + +public record Query(String sql, List args) { +} diff --git a/src/ru/charm/back/mapper/RequestToProfileFilterMapper.java b/src/ru/charm/back/mapper/RequestToProfileFilterMapper.java new file mode 100644 index 0000000..cc84a61 --- /dev/null +++ b/src/ru/charm/back/mapper/RequestToProfileFilterMapper.java @@ -0,0 +1,54 @@ +package ru.charm.back.mapper; + +import jakarta.servlet.http.HttpServletRequest; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import ru.charm.back.dto.ProfileFilter; +import ru.charm.back.model.Status; + +import static ru.charm.back.utils.StringUtils.isBlank; + + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class RequestToProfileFilterMapper implements Mapper { + + private static final RequestToProfileFilterMapper INSTANCE = new RequestToProfileFilterMapper(); + + public static RequestToProfileFilterMapper getInstance() { + return INSTANCE; + } + + @Override + public ProfileFilter map(HttpServletRequest req) { + return map(req, new ProfileFilter()); + } + + @Override + public ProfileFilter map(HttpServletRequest req, ProfileFilter filter) { + String emailStartWithArg = req.getParameter("emailStartWith"); + String emailStartWith = isBlank(emailStartWithArg) ? null : emailStartWithArg; + filter.setEmailStartWith(emailStartWith); + + String nameStartWithArg = req.getParameter("nameStartWith"); + String nameStartWith = isBlank(nameStartWithArg) ? null : nameStartWithArg; + filter.setNameStartWith(nameStartWith); + + String surnameStartWithArg = req.getParameter("surnameStartWith"); + String surnameStartWith = isBlank(surnameStartWithArg) ? null : surnameStartWithArg; + filter.setSurnameStartWith(surnameStartWith); + + String ltAgeArg = req.getParameter("ltAge"); + Integer ltAge = isBlank(ltAgeArg) ? null : Integer.parseInt(ltAgeArg); + filter.setLtAge(ltAge); + + String gteAgeArg = req.getParameter("gteAge"); + Integer gteAge = isBlank(gteAgeArg) ? null : Integer.parseInt(gteAgeArg); + filter.setGteAge(gteAge); + + String statusArg = req.getParameter("status"); + Status status = isBlank(statusArg) ? null : Status.valueOf(statusArg); + filter.setStatus(status); + + return filter; + } +} diff --git a/src/ru/charm/back/service/ProfileService.java b/src/ru/charm/back/service/ProfileService.java index c71568e..ea4f731 100644 --- a/src/ru/charm/back/service/ProfileService.java +++ b/src/ru/charm/back/service/ProfileService.java @@ -4,10 +4,7 @@ import lombok.AccessLevel; import lombok.NoArgsConstructor; import lombok.SneakyThrows; import ru.charm.back.dao.ProfileDao; -import ru.charm.back.dto.LoginDto; -import ru.charm.back.dto.ProfileGetDto; -import ru.charm.back.dto.ProfileUpdateDto; -import ru.charm.back.dto.RegistrationDto; +import ru.charm.back.dto.*; import ru.charm.back.mapper.ProfileToProfileGetDtoMapper; import ru.charm.back.mapper.ProfileUpdateDtoToProfileMapper; import ru.charm.back.mapper.RegistrationDtoToProfileMapper; @@ -46,8 +43,8 @@ public class ProfileService { return dao.findById(id).map(profileToProfileGetDtoMapper::map); } - public List findAll() { - return dao.findAll().stream().map(profileToProfileGetDtoMapper::map).toList(); + public List findAll(ProfileFilter filter) { + return dao.findAll(filter).stream().map(profileToProfileGetDtoMapper::map).toList(); } @SneakyThrows diff --git a/src/ru/charm/back/utils/ConfigFile.java b/src/ru/charm/back/utils/ConfigFileUtils.java similarity index 71% rename from src/ru/charm/back/utils/ConfigFile.java rename to src/ru/charm/back/utils/ConfigFileUtils.java index 72d1200..a59ce3b 100644 --- a/src/ru/charm/back/utils/ConfigFile.java +++ b/src/ru/charm/back/utils/ConfigFileUtils.java @@ -7,20 +7,20 @@ import java.io.InputStream; import java.util.Properties; @UtilityClass -public class ConfigFile { +public class ConfigFileUtils { private static final Properties CONFIG = new Properties(); - + static { loadConfig(); } public static String get(String key) { - return CONFIG.getProperty(key); + return CONFIG.getProperty(key); } private static void loadConfig() { - try (InputStream resourceAsStream = ConfigFile.class.getClassLoader().getResourceAsStream("application.properties")) { + try (InputStream resourceAsStream = ConfigFileUtils.class.getClassLoader().getResourceAsStream("application.properties")) { CONFIG.load(resourceAsStream); } catch (IOException e) { throw new RuntimeException(e); diff --git a/src/ru/charm/back/utils/ConnectionManager.java b/src/ru/charm/back/utils/ConnectionManager.java new file mode 100644 index 0000000..aa276a0 --- /dev/null +++ b/src/ru/charm/back/utils/ConnectionManager.java @@ -0,0 +1,48 @@ +package ru.charm.back.utils; + +import lombok.SneakyThrows; +import lombok.experimental.UtilityClass; +import ru.charm.back.dto.Query; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.util.List; + +@UtilityClass +public class ConnectionManager { + public static final String URL = ConfigFileUtils.get("app.datasource.url"); + public static final String USER = ConfigFileUtils.get("app.datasource.username"); + public static final String PASSWORD = ConfigFileUtils.get("app.datasource.password"); + public static final String DRIVER = ConfigFileUtils.get("app.datasource.driver"); + private static final String FETCH_SIZE_STR = ConfigFileUtils.get("app.datasource.fetch-size"); + public static final int FETCH_SIZE = Integer.parseInt(FETCH_SIZE_STR != null ? FETCH_SIZE_STR : "100"); + private static final String MAX_ROWS_STR = ConfigFileUtils.get("app.datasource.max-rows"); + public static final int MAX_ROWS = Integer.parseInt(MAX_ROWS_STR != null ? MAX_ROWS_STR : "1000"); + private static final String QUERY_TIMEOUT_STR = ConfigFileUtils.get("app.datasource.query-timeout"); + public static final int QUERY_TIMEOUT = Integer.parseInt(QUERY_TIMEOUT_STR != null ? QUERY_TIMEOUT_STR : "10"); + + static { + if (DRIVER != null) { + try { + Class.forName(DRIVER); + } catch (ClassNotFoundException e) { + throw new RuntimeException(e); + } + } + } + + public static Connection getConnection() throws SQLException { + return DriverManager.getConnection(URL, USER, PASSWORD); + } + + public static PreparedStatement getPreparedStmt(Connection conn, Query query) throws SQLException { + PreparedStatement stmt = conn.prepareStatement(query.sql()); + List args = query.args(); + for (int i = 0; i < args.size(); i++) { + stmt.setObject(i + 1, args.get(i)); + } + return stmt; + } +} diff --git a/src/ru/charm/back/utils/DateTimeUtils.java b/src/ru/charm/back/utils/DateTimeUtils.java new file mode 100644 index 0000000..98a84bd --- /dev/null +++ b/src/ru/charm/back/utils/DateTimeUtils.java @@ -0,0 +1,25 @@ +package ru.charm.back.utils; + +import lombok.experimental.UtilityClass; + +import java.sql.Date; +import java.time.LocalDate; +import java.time.temporal.ChronoUnit; + +@UtilityClass +public class DateTimeUtils { + + public static int getAge(LocalDate birthDate) { + return Math.toIntExact(ChronoUnit.YEARS.between(birthDate, LocalDate.now())); + } + + public static Date getPastDate(int age) { + return Date.valueOf(LocalDate.now().minusYears(age)); + } + + public static boolean isValidAge(LocalDate birthDate) { + if (birthDate == null) return false; + int age = getAge(birthDate); + return age > 18 && age < 100; + } +}