From ae6f837b1febf1dd6a63bba7809472d143b0ad39 Mon Sep 17 00:00:00 2001 From: codingbaraGo Date: Thu, 15 Jan 2026 15:28:09 +0900 Subject: [PATCH 1/3] =?UTF-8?q?feat(app):=20User=20=EB=A0=88=ED=8F=AC?= =?UTF-8?q?=EC=A7=80=ED=86=A0=EB=A6=AC=20=EC=B6=94=EA=B0=80=20-=20UserRepo?= =?UTF-8?q?sitory=20=ED=81=B4=EB=9E=98=EC=8A=A4=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/app/db/UserRepository.java | 11 +++++++++++ src/main/java/app/model/User.java | 3 +++ src/main/java/config/AppConfig.java | 22 ++++++++++++---------- 3 files changed, 26 insertions(+), 10 deletions(-) create mode 100644 src/main/java/app/db/UserRepository.java diff --git a/src/main/java/app/db/UserRepository.java b/src/main/java/app/db/UserRepository.java new file mode 100644 index 00000000..d87b525d --- /dev/null +++ b/src/main/java/app/db/UserRepository.java @@ -0,0 +1,11 @@ +package app.db; + +import app.model.User; +import database.ConnectionManager; +import database.CrudRepository; + +public class UserRepository extends CrudRepository { + public UserRepository(ConnectionManager connectionManager) { + super(connectionManager, User.class); + } +} diff --git a/src/main/java/app/model/User.java b/src/main/java/app/model/User.java index 936b915e..7a1dd54b 100644 --- a/src/main/java/app/model/User.java +++ b/src/main/java/app/model/User.java @@ -14,6 +14,9 @@ public User(String password, String nickname, String email, String userRole) { this.userRole = userRole; } + public User() { + } + public Long getId() { return id; } diff --git a/src/main/java/config/AppConfig.java b/src/main/java/config/AppConfig.java index bc5c4a9c..3fb39162 100644 --- a/src/main/java/config/AppConfig.java +++ b/src/main/java/config/AppConfig.java @@ -1,5 +1,6 @@ package config; +import app.db.UserRepository; import app.handler.*; import database.ConnectionManager; import database.H2DbManager; @@ -120,8 +121,7 @@ public RegisterWithGet registerWithGet() { public RegisterWithPost registerWithPost() { return getOrCreate( "registerWithPost", - RegisterWithPost::new - ); + () -> new RegisterWithPost(userRepository())); } public LoginWithPost loginWithPost() { @@ -233,8 +233,8 @@ public QueryParamsResolver queryParamsResolver() { } public MultipartFormResolver multipartFormResolver(){ - return getOrCreate("multipartFormResolver", () -> - new MultipartFormResolver(multipartFormParser())); + return getOrCreate("multipartFormResolver", + () -> new MultipartFormResolver(multipartFormParser())); } public MultipartFormParser multipartFormParser(){ @@ -250,10 +250,7 @@ public ExceptionHandlerMapping exceptionHandlerMapping() { List.of( serviceExceptionHandler(), errorExceptionHandler(), - unhandledErrorHandler() - ) - ) - ); + unhandledErrorHandler()))); } public ServiceExceptionHandler serviceExceptionHandler() { @@ -325,8 +322,13 @@ public H2DbManager h2DbManager(){ } public DdlGenerator ddlGenerator(){ - return getOrCreate(DdlGenerator.class.getSimpleName(), () -> - new DdlGenerator(connectionManager())); + return getOrCreate(DdlGenerator.class.getSimpleName(), + () -> new DdlGenerator(connectionManager())); + } + + public UserRepository userRepository(){ + return getOrCreate(UserRepository.class.getSimpleName(), + ()-> new UserRepository(connectionManager())); } } From fdfdf13fdfea081ba37240e6a638574def99b54f Mon Sep 17 00:00:00 2001 From: codingbaraGo Date: Thu, 15 Jan 2026 15:29:33 +0900 Subject: [PATCH 2/3] =?UTF-8?q?feat(app):=20=ED=9A=8C=EC=9B=90=EA=B0=80?= =?UTF-8?q?=EC=9E=85=20=ED=95=B8=EB=93=A4=EB=9F=AC=EC=97=90=20=EC=9C=A0?= =?UTF-8?q?=ED=9A=A8=EC=84=B1=20=EA=B2=80=EC=82=AC=20=EB=A1=9C=EC=A7=81=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80=20-=20=ED=9A=8C=EC=9B=90=EA=B0=80=EC=9E=85?= =?UTF-8?q?=20=ED=95=B8=EB=93=A4=EB=9F=AC=EC=97=90=20=EA=B8=B8=EC=9D=B4=20?= =?UTF-8?q?=EB=B0=8F=20=EC=A4=91=EB=B3=B5=20=EC=9C=A0=ED=9A=A8=EC=84=B1=20?= =?UTF-8?q?=EA=B2=80=EC=82=AC=20=EB=A1=9C=EC=A7=81=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/app/handler/RegisterWithPost.java | 54 ++++++++++++++++--- src/main/java/config/VariableConfig.java | 7 +++ src/main/java/exception/ErrorCode.java | 7 +++ .../handler/ErrorExceptionHandler.java | 4 +- 4 files changed, 63 insertions(+), 9 deletions(-) diff --git a/src/main/java/app/handler/RegisterWithPost.java b/src/main/java/app/handler/RegisterWithPost.java index 066683b9..410dc497 100644 --- a/src/main/java/app/handler/RegisterWithPost.java +++ b/src/main/java/app/handler/RegisterWithPost.java @@ -1,7 +1,8 @@ package app.handler; -import app.db.Database; +import app.db.UserRepository; import app.model.User; +import config.VariableConfig; import exception.ErrorCode; import exception.ServiceException; import http.HttpMethod; @@ -14,19 +15,58 @@ import web.response.RedirectResponse; public class RegisterWithPost extends SingleArgHandler { + private static final String EMAIL = "email"; + private static final String NICKNAME = "nickname"; + private static final String PASSWORD = "password"; + private static final Logger log = LoggerFactory.getLogger(RegisterWithPost.class); - public RegisterWithPost() { + private final UserRepository userRepository; + + public RegisterWithPost(UserRepository userRepository) { super(HttpMethod.POST, "/user/create"); + this.userRepository = userRepository; } @Override public HandlerResponse handle(QueryParameters params) { - String email = params.getQueryValue("email").orElseThrow(()-> new ServiceException(ErrorCode.MISSING_REGISTER_TOKEN, "email required")); - String nickname = params.getQueryValue("nickname").orElseThrow(()-> new ServiceException(ErrorCode.MISSING_REGISTER_TOKEN, "nickname required")); - String password = params.getQueryValue("password").orElseThrow(()-> new ServiceException(ErrorCode.MISSING_REGISTER_TOKEN, "password required")); - Database.addUser(new User(password, nickname, email, UserRole.MEMBER.toString())); - log.info("Registered - password:{}, nickname:{}, email:{}", password, nickname, email); + String email = getRequired(params, EMAIL); + String nickname = getRequired(params, NICKNAME); + String password = getRequired(params, PASSWORD); + + validate(email, nickname, password); + + User saved = userRepository.save( + new User(password, nickname, email, UserRole.MEMBER.toString())); + + log.info("Registered id:{}, email:{}, nickname:{}, password:{}", + saved.getId(), email, nickname, password); return RedirectResponse.to("/login"); } + + private void validate(String email, String nickname, String password) { + validateDuplicate(email, nickname); + validateLength(email, VariableConfig.EMAIL_MIN, VariableConfig.EMAIL_MAX, ErrorCode.EMAIL_LENGTH_INVALID); + validateLength(nickname, VariableConfig.NICKNAME_MIN, VariableConfig.NICKNAME_MAX, ErrorCode.NICKNAME_LENGTH_INVALID); + validateLength(password, VariableConfig.PASSWORD_MIN, VariableConfig.PASSWORD_MAX, ErrorCode.PASSWORD_LENGTH_INVALID); + } + + private String getRequired(QueryParameters params, String key) { + return params.getQueryValue(key) + .orElseThrow(() -> new ServiceException(ErrorCode.MISSING_REGISTER_TOKEN, key + " required")); + } + + private void validateLength(String value, int min, int max, ErrorCode code) { + int len = value.length(); + if (len < min || len > max) + throw new ServiceException(code); + } + + private void validateDuplicate(String email, String nickname) { + if (!userRepository.findByColumn(EMAIL, email).isEmpty()) + throw new ServiceException(ErrorCode.EMAIL_ALREADY_EXISTS); + + if (!userRepository.findByColumn(NICKNAME, nickname).isEmpty()) + throw new ServiceException(ErrorCode.NICKNAME_ALREADY_EXISTS); + } } diff --git a/src/main/java/config/VariableConfig.java b/src/main/java/config/VariableConfig.java index 3b74e0c2..962ef6ff 100644 --- a/src/main/java/config/VariableConfig.java +++ b/src/main/java/config/VariableConfig.java @@ -12,4 +12,11 @@ public class VariableConfig { public static final long IDLE_MS = 30*60*100; public static final long ABSOLUTE_MS = 180*60*100; + + public static final int EMAIL_MAX = 50; + public static final int EMAIL_MIN = 4; + public static final int NICKNAME_MAX = 12; + public static final int NICKNAME_MIN = 4; + public static final int PASSWORD_MAX = 16; + public static final int PASSWORD_MIN = 4; } diff --git a/src/main/java/exception/ErrorCode.java b/src/main/java/exception/ErrorCode.java index 2a541fdc..56f2d4fe 100644 --- a/src/main/java/exception/ErrorCode.java +++ b/src/main/java/exception/ErrorCode.java @@ -9,6 +9,13 @@ public enum ErrorCode { HttpStatus.BAD_REQUEST, "400_MISSING_REGISTER_TOKEN", "회원가입에 필요한 토큰이 누락되었습니다."), LOGIN_FAILED( HttpStatus.BAD_REQUEST, "400_LOGIN_FAILED", "아이디 혹은 비밀번호가 잘못되었습니다."), + EMAIL_LENGTH_INVALID(HttpStatus.BAD_REQUEST, "400_EMAIL_LENGTH_INVALID", "이메일은 4 ~ 50글자 사이여야합니다."), + NICKNAME_LENGTH_INVALID(HttpStatus.BAD_REQUEST, "400_NICKNAME_LENGTH_INVALID", "닉네임은 4 ~ 12글자 사이여야합니다."), + PASSWORD_LENGTH_INVALID(HttpStatus.BAD_REQUEST, "400_PASSWORD_LENGTH_INVALID", "비밀번호는 4 ~ 16글자 사이여야합니다."), + + + EMAIL_ALREADY_EXISTS(HttpStatus.CONFLICT, "409_EMAIL_ALREADY_EXISTS", "이미 가입된 Email입니다."), + NICKNAME_ALREADY_EXISTS(HttpStatus.CONFLICT, "409_NICKNAME_ALREADY_EXISTS", "이미 사용중인 닉네임입니다."), /* Internal Error */ INTERNAL_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "500_INTERNAL", "서버 내부 오류가 발생했습니다."), diff --git a/src/main/java/exception/handler/ErrorExceptionHandler.java b/src/main/java/exception/handler/ErrorExceptionHandler.java index 82c0eea1..47c306a8 100644 --- a/src/main/java/exception/handler/ErrorExceptionHandler.java +++ b/src/main/java/exception/handler/ErrorExceptionHandler.java @@ -24,11 +24,11 @@ public boolean support(Throwable e) { @Override public void handle(Throwable t, Socket connection) { ErrorException error = (ErrorException) t; - logger.debug(error.getThrowable().toString()); + logger.debug("{} - {}", error.getMessage(), error.getThrowable().toString()); ErrorCode errorCode = error.getErrorCode(); HttpStatus status = errorCode.getStatus(); - String body = toJson(errorCode.getCode(), error.getMessage()); + String body = toJson(errorCode.getCode(), errorCode.getMessage()); byte[] bodyBytes = body.getBytes(StandardCharsets.UTF_8); StringBuilder sb = new StringBuilder(); From 22f8a71514aaf564a6518d611925475602e22094 Mon Sep 17 00:00:00 2001 From: codingbaraGo Date: Thu, 15 Jan 2026 15:30:23 +0900 Subject: [PATCH 3/3] =?UTF-8?q?enhance(database):=20SQL=20=EC=9E=90?= =?UTF-8?q?=EB=8F=99=EC=83=9D=EC=84=B1=EC=8B=9C=20=EC=BB=AC=EB=9F=BC=20?= =?UTF-8?q?=EB=84=A4=EC=9E=84=EC=97=90=20Snake=20case=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/config/DdlGenerator.java | 7 ++++++- src/main/java/database/CrudRepository.java | 19 ++++++++++++------- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/src/main/java/config/DdlGenerator.java b/src/main/java/config/DdlGenerator.java index 3dfb27db..0d06d7d7 100644 --- a/src/main/java/config/DdlGenerator.java +++ b/src/main/java/config/DdlGenerator.java @@ -57,7 +57,7 @@ private String buildDdlForEntity(Class entityClass, String tableName) { continue; } - String columnName = field.getName(); + String columnName = toColumnName(field.getName()); Class fieldType = field.getType(); if (!firstColumn) { @@ -108,4 +108,9 @@ private String toTableName(Class clazz) { } return name; } + + private String toColumnName(String str){ + String snake = str.replaceAll("(? findAll() { } public List findByColumn(String columnName, Object value) { - String sql = "SELECT * FROM " + tableName + " WHERE " + columnName + " = ?"; + String sql = "SELECT * FROM " + tableName + " WHERE " + toColumnName(columnName) + " = ?"; try (Connection conn = connectionManager.getConnection(); PreparedStatement pstmt = conn.prepareStatement(sql)) { @@ -145,7 +145,7 @@ public List findByColumn(String columnName, Object value) { } } catch (SQLException e) { - throw new ErrorException("엔티티 조회 중 오류 (column=" + columnName + ", value=" + value + ")", e); + throw new ErrorException("엔티티 조회 중 오류 (column=" + toColumnName(columnName) + ", value=" + value + ")", e); } } @@ -167,10 +167,10 @@ public void update(T entity) { if (Modifier.isStatic(field.getModifiers())) { continue; } - if ("id".equals(field.getName())) { + if ("id".equals(toColumnName(field.getName()))) { continue; } - sql.append(field.getName()).append(" = ?, "); + sql.append(toColumnName(field.getName())).append(" = ?, "); updateFields.add(field); } @@ -264,7 +264,7 @@ private T mapRow(ResultSet resultSet) { continue; } - String columnName = field.getName(); + String columnName = toColumnName(field.getName()); field.setAccessible(true); Class fieldType = field.getType(); @@ -311,4 +311,9 @@ private String toTableName(Class clazz) { } return name; } + + private String toColumnName(String str){ + String snake = str.replaceAll("(?