-
Notifications
You must be signed in to change notification settings - Fork 0
[ALL] 프로젝트 패키지 구조 변경 #25
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
96a93c7
dca7e16
cd6784d
f391917
c478ced
acfcdc2
67c50a8
0a7cc20
6c07dc3
7db1099
5f846ed
ae9a404
a89a6c4
45b5c7e
63306c6
7c3ef19
ba49f70
4a9b6ec
9900f74
7fc82cc
e08f705
bbbe0d5
9b8e68d
e1ea87b
577acc7
9e9b479
319ded6
72bf62f
0176b22
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| package app.handler; | ||
|
|
||
| import app.db.Database; | ||
| import app.model.User; | ||
| import http.HttpMethod; | ||
| import http.request.HttpRequest; | ||
| import web.handler.DynamicViewHandler; | ||
| import web.response.ViewResponse; | ||
|
|
||
| public class RegisterHandlerImpl extends DynamicViewHandler { | ||
| public RegisterHandlerImpl() { | ||
| super(HttpMethod.GET, | ||
| "/create"); | ||
| } | ||
|
|
||
| @Override | ||
| public ViewResponse handle(HttpRequest request) { | ||
| String userId = request.getQueryValue("userId"); | ||
| String password = request.getQueryValue("password"); | ||
| String name = request.getQueryValue("name"); | ||
| String email = request.getQueryValue("email"); | ||
| Database.addUser(new User(userId, password, name, email)); | ||
| return ViewResponse.of("/login"); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,4 @@ | ||
| package model; | ||
| package app.model; | ||
|
|
||
| public class User { | ||
| private String userId; | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,14 +1,20 @@ | ||
| package webserver; | ||
| package bootstrap; | ||
|
|
||
| import java.net.ServerSocket; | ||
| import java.net.Socket; | ||
| import java.util.concurrent.ExecutorService; | ||
| import java.util.concurrent.Executors; | ||
|
|
||
| import config.DependencyLoader; | ||
| import org.slf4j.Logger; | ||
| import org.slf4j.LoggerFactory; | ||
| import web.dispatch.ConnectionHandler; | ||
|
|
||
| public class WebServer { | ||
| private static final Logger logger = LoggerFactory.getLogger(WebServer.class); | ||
| private static final int DEFAULT_PORT = 8080; | ||
| private static final DependencyLoader LOADER = new DependencyLoader(); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. static 필드로 DependencyLoader를 선언하는 것은 문제가 될 수 있습니다. 클래스 로딩 시점에 모든 의존성이 초기화되므로, 향후 의존성 주입 패턴 도입 시나 테스트 시 수정하기 어렵습니다. 가능하면 main 메서드 내에서 인스턴스화하고 필요한 의존성만 전달하는 방식을 고려하세요." |
||
| private static final ExecutorService executor = Executors.newFixedThreadPool(32); | ||
|
|
||
| public static void main(String args[]) throws Exception { | ||
| int port = 0; | ||
|
|
@@ -25,8 +31,15 @@ public static void main(String args[]) throws Exception { | |
| // 클라이언트가 연결될때까지 대기한다. | ||
| Socket connection; | ||
| while ((connection = listenSocket.accept()) != null) { | ||
| Thread thread = new Thread(new RequestHandler(connection)); | ||
| thread.start(); | ||
| Socket singleConnection = connection; | ||
| executor.submit(() -> { | ||
| ConnectionHandler connectionHandler = new ConnectionHandler(LOADER.dispatcher, | ||
| LOADER.exceptionHandlerMapping, | ||
| LOADER.httpResponseConverter, | ||
| LOADER.httpRequestConverter, | ||
| singleConnection); | ||
| connectionHandler.run(); | ||
| }); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,94 @@ | ||
| package config; | ||
|
|
||
| import app.handler.RegisterHandlerImpl; | ||
| import exception.ExceptionHandlerMapping; | ||
| import exception.handler.ErrorExceptionHandler; | ||
| import exception.handler.ServiceExceptionHandler; | ||
| import exception.handler.UnhandledErrorHandler; | ||
| import http.request.HttpBufferedReaderRequestConverter; | ||
| import http.request.HttpRequestConverter; | ||
| import http.response.HttpBufferedStreamResponseConverter; | ||
| import http.response.HttpResponseConverter; | ||
| import web.dispatch.Dispatcher; | ||
| import web.handler.StaticContentHandler; | ||
| import web.handler.WebHandler; | ||
| import web.posthandler.StaticContentResponseHandler; | ||
| import web.posthandler.ViewResponseHandler; | ||
| import web.posthandler.WebHandlerResponseHandler; | ||
|
|
||
| import java.util.List; | ||
|
|
||
| public class AppConfig { | ||
| //Http | ||
| public HttpBufferedReaderRequestConverter httpBufferedReaderRequestConverter(){ | ||
| return new HttpBufferedReaderRequestConverter(); | ||
| } | ||
|
|
||
| public HttpBufferedStreamResponseConverter httpBufferedStreamResponseConverter(){ | ||
| return new HttpBufferedStreamResponseConverter(); | ||
| } | ||
|
|
||
| public HttpRequestConverter httpRequestConverter(){ | ||
| return httpBufferedReaderRequestConverter(); | ||
| } | ||
| public HttpResponseConverter httpResponseConverter(){ | ||
| return httpBufferedStreamResponseConverter(); | ||
| } | ||
|
|
||
|
|
||
| //Web | ||
| public Dispatcher wasServlet(){ | ||
| return new Dispatcher( | ||
| webHandlerList(), | ||
| webHandlerResponseHandlerList() | ||
| ); | ||
| } | ||
|
|
||
| private List<WebHandler> webHandlerList(){ | ||
| return List.of( | ||
| staticContentHandler(), | ||
| registerHandlerImpl() | ||
| ); | ||
| } | ||
| private RegisterHandlerImpl registerHandlerImpl(){ | ||
| return new RegisterHandlerImpl(); | ||
| } | ||
|
|
||
| private List<WebHandlerResponseHandler> webHandlerResponseHandlerList(){ | ||
| return List.of( | ||
| staticContentResponseHandler(), | ||
| viewResponseHandler() | ||
| ); | ||
| } | ||
| private StaticContentHandler staticContentHandler(){ | ||
| return new StaticContentHandler(); | ||
| } | ||
| private ViewResponseHandler viewResponseHandler(){ | ||
| return new ViewResponseHandler(); | ||
| } | ||
| private StaticContentResponseHandler staticContentResponseHandler(){ | ||
| return new StaticContentResponseHandler(); | ||
| } | ||
|
|
||
|
|
||
| //Exception | ||
| public ExceptionHandlerMapping exceptionHandlerMapping(){ | ||
| return new ExceptionHandlerMapping( | ||
| List.of( | ||
| serviceExceptionHandler(), | ||
| errorExceptionHandler(), | ||
| unhandledErrorHandler() | ||
| ) | ||
| ); | ||
| } | ||
|
|
||
| private ServiceExceptionHandler serviceExceptionHandler(){ | ||
| return new ServiceExceptionHandler(); | ||
| } | ||
| private UnhandledErrorHandler unhandledErrorHandler(){ | ||
| return new UnhandledErrorHandler(); | ||
| } | ||
| private ErrorExceptionHandler errorExceptionHandler(){ | ||
| return new ErrorExceptionHandler(); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| package config; | ||
|
|
||
| import exception.ExceptionHandlerMapping; | ||
| import http.request.HttpRequestConverter; | ||
| import http.response.HttpResponseConverter; | ||
| import web.dispatch.Dispatcher; | ||
|
|
||
| public class DependencyLoader { | ||
| private final AppConfig appConfig; | ||
|
|
||
| public final HttpRequestConverter httpRequestConverter; | ||
| public final HttpResponseConverter httpResponseConverter; | ||
| public final ExceptionHandlerMapping exceptionHandlerMapping; | ||
| public final Dispatcher dispatcher; | ||
|
|
||
| public DependencyLoader(){ | ||
| this.appConfig = new AppConfig(); | ||
| this.httpRequestConverter = appConfig.httpRequestConverter(); | ||
| this.httpResponseConverter = appConfig.httpResponseConverter(); | ||
| this.exceptionHandlerMapping = appConfig.exceptionHandlerMapping(); | ||
| this.dispatcher = appConfig.wasServlet(); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| package config; | ||
|
|
||
| import java.util.List; | ||
|
|
||
| public class VariableConfig { | ||
| public static final List<String> STATIC_RESOURCE_ROOTS = List.of( | ||
| "./src/main/resources", | ||
| "./src/main/resources/static"); | ||
|
Comment on lines
+6
to
+8
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 하드코딩된 경로는 상대 경로로 시스템 동작에 따라 불안정할 수 있습니다. 프로젝트 루트 기준으로 경로를 동적으로 계산하거나, 환경 변수/설정 파일에서 읽도록 변경하세요. 현재는 서버가 다른 디렉토리에서 실행될 경우 리소스를 찾지 못할 수 있습니다." |
||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,44 @@ | ||
| package exception; | ||
|
|
||
|
|
||
| import http.HttpStatus; | ||
|
|
||
| public enum ErrorCode { | ||
| /* Internal Error */ | ||
| INTERNAL_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "500_INTERNAL", "서버 내부 오류가 발생했습니다."), | ||
|
|
||
| /* Request Error */ | ||
| INVALID_INPUT(HttpStatus.BAD_REQUEST, "400_INVALID_INPUT", "입력 값이 올바르지 않습니다."), | ||
| MISSING_PARAMETER(HttpStatus.BAD_REQUEST, "400_MISSING_PARAM", "필수 파라미터가 누락되었습니다."), | ||
| VALIDATION_FAILED(HttpStatus.BAD_REQUEST, "400_VALIDATION_FAIL", "유효성 검증에 실패했습니다."), | ||
|
|
||
| FORBIDDEN(HttpStatus.FORBIDDEN, "403_FORBIDDEN", "권한이 없습니다."), | ||
|
|
||
| NO_SUCH_RESOURCE(HttpStatus.NOT_FOUND, "404_NO_SUCH_RESOURCE", "요청한 리소스를 찾을 수 없습니다."), | ||
|
|
||
| METHOD_NOT_ALLOWED(HttpStatus.METHOD_NOT_ALLOWED, "405_METHOD_NOT_ALLOWED", "허용되지 않은 HTTP 메서드입니다."), | ||
| ; | ||
|
|
||
|
|
||
| private final HttpStatus status; | ||
| private final String code; | ||
| private final String message; | ||
|
|
||
| public HttpStatus getStatus() { | ||
| return status; | ||
| } | ||
|
|
||
| public String getCode() { | ||
| return code; | ||
| } | ||
|
|
||
| public String getMessage() { | ||
| return message; | ||
| } | ||
|
|
||
| ErrorCode(HttpStatus status, String code, String message) { | ||
| this.status = status; | ||
| this.code = code; | ||
| this.message = message; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| package exception; | ||
|
|
||
| public class ErrorException extends RuntimeException { | ||
| private final ErrorCode errorCode; | ||
| private final Throwable throwable; | ||
|
|
||
| public ErrorException(String message) { | ||
| super(message); | ||
| this.errorCode = ErrorCode.INTERNAL_ERROR; | ||
| this.throwable = null; | ||
| } | ||
|
|
||
| public ErrorException(String message, Throwable t) { | ||
| super(message); | ||
| this.errorCode = ErrorCode.INTERNAL_ERROR; | ||
| this.throwable = t; | ||
| } | ||
|
|
||
| public ErrorCode getErrorCode() { | ||
| return errorCode; | ||
| } | ||
|
|
||
| public Throwable getThrowable() { | ||
| return throwable; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| package exception; | ||
|
|
||
| import java.net.Socket; | ||
|
|
||
| public interface ExceptionHandler { | ||
| boolean support(Throwable e); | ||
| void handle(Throwable e, Socket connection); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| package exception; | ||
|
|
||
| public class ServiceException extends RuntimeException { | ||
| private final ErrorCode errorCode; | ||
|
|
||
| public ServiceException(ErrorCode errorCode) { | ||
| super(errorCode.getMessage()); | ||
| this.errorCode = errorCode; | ||
| } | ||
|
|
||
| public ServiceException(ErrorCode errorCode, String customMsg) { | ||
| super((customMsg == null || customMsg.isBlank()) ? errorCode.getMessage() : customMsg); | ||
| this.errorCode = errorCode; | ||
| } | ||
|
|
||
| public ErrorCode getErrorCode() { | ||
| return errorCode; | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
사용자 입력값(userId, password, name, email)에 대한 유효성 검증이 없습니다. 빈 문자열, null, SQL 인젝션 패턴 등을 검증하지 않으면 런타임 오류나 데이터 무결성 문제가 발생할 수 있습니다. \n\n최소한 다음을 추가하세요:\n
java\nif (userId == null || userId.isBlank()) throw new ServiceException(ErrorCode.MISSING_PARAMETER);\n\n\n또한 RegisterHandlerImpl의 필드명과 HTML 폼의 name 속성이 불일치합니다(nickname vs name)."