Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
2abbfa0
feature: Handler 어노테이션 추가
devjun10 Feb 19, 2024
afb76b7
refactor: 빈 등록/빈 조회 메서드 추가
devjun10 Feb 19, 2024
98e6bc9
feature: 사용자 정보 업데이트 기능 개발
devjun10 Feb 19, 2024
fecc578
refactor: Path 명시
devjun10 Feb 19, 2024
18841b9
refactor: Http setAttribute 기능 추가
devjun10 Feb 19, 2024
3afbe3a
refactor: DispatcherServlet 빈 초기화 방식 변경
devjun10 Feb 19, 2024
fb5b15b
refactor: 세션 로직 변경
devjun10 Feb 20, 2024
be7ed0a
refactor: 에러 응답
devjun10 Feb 19, 2024
c0c7c64
chore: task 의존성 변경
devjun10 Mar 26, 2024
2956fb8
docs: README.md 업데이트
devjun10 Mar 26, 2024
023b4b5
refactor: 인터셉터 경로 추가
devjun10 Mar 26, 2024
424e277
feat: Application/Json 타입 사용자 정보 업데이트 API 개발
devjun10 Mar 26, 2024
fcef502
refactor: 로그인 컨트롤러 log 제거
devjun10 Mar 26, 2024
49547fa
test: @AfterEach -> @BeforeEach로 변경
devjun10 Mar 26, 2024
4350b67
feat: Application/Json을 처리하기 위한 어노테이션 추가
devjun10 Mar 26, 2024
045c610
feat: 임시 커밋 추가
devjun10 Mar 26, 2024
53aa75f
refactor: 기본 포트 8080으로 변환
devjun10 Mar 26, 2024
947a8c7
docs: README.md 내용 추가
devjun10 Mar 26, 2024
eb19568
test: 깨진 테스트 복구
devjun10 Mar 26, 2024
9959627
refactor: CheckStyle, PMD 설정 적용
devjun10 Mar 26, 2024
8b65cdb
docs: README.md 내용 추가
devjun10 Mar 26, 2024
fec3b99
refactor: 미 반영사항 적용
devjun10 Apr 2, 2024
4313365
chore: schema 추가
devjun10 Apr 7, 2024
c38b3d4
docs: README.md 내용 추가
devjun10 Apr 7, 2024
a00907a
refactor: 일급 컬렉션에서 쿠키를 추출하도록 로직 변경
devjun10 May 10, 2024
1fccab2
docs: README.md 수정
devjun10 Jun 22, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package project.server.app.common.configuration;

import project.server.app.common.configuration.interceptor.SessionCheckHandlerInterceptor;
import project.server.app.core.web.user.application.UserLoginUseCase;
import project.server.app.core.web.user.presentation.validator.UserValidator;
import project.server.mvc.springframework.annotation.Component;
import static project.server.mvc.springframework.context.ApplicationContext.getBean;
import static project.server.mvc.springframework.context.ApplicationContext.register;
import project.server.mvc.springframework.web.InterceptorRegistry;
import project.server.mvc.springframework.web.WebMvcConfigurer;

@Component
public class WebConfiguration implements WebMvcConfigurer {

private final UserValidator validator;
private final UserLoginUseCase loginUseCase;

public WebConfiguration(
UserValidator validator,
UserLoginUseCase loginUseCase
) {
this.validator = validator;
this.loginUseCase = loginUseCase;
register(new InterceptorRegistry());
addInterceptors(getBean(InterceptorRegistry.class));
}

@Override
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

인터셉터를 직접 구현하셨군요! 인터셉터를 구현하신 이유가 있나요? 인터셉터의 역할은 무엇인가요?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

각 컨트롤러에서 권한 체크를 하니, 로직의 중복이 발생했는데요, 이를 제거하기 위해 인터셉터를 만들었습니다. 즉, 권한 체크가 인터셉터의 역할입니다.

public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new SessionCheckHandlerInterceptor(validator, loginUseCase))
.addPathPatterns("/my-info.html", "/my-info");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package project.server.app.common.configuration.interceptor;

import lombok.extern.slf4j.Slf4j;
import project.server.app.common.login.LoginUser;
import project.server.app.common.login.Session;
import static project.server.app.common.utils.HeaderUtils.getSessionId;
import project.server.app.core.web.user.application.UserLoginUseCase;
import project.server.app.core.web.user.presentation.validator.UserValidator;
import project.server.mvc.servlet.HttpServletRequest;
import project.server.mvc.servlet.HttpServletResponse;
import project.server.mvc.springframework.handler.HandlerInterceptor;
import project.server.mvc.springframework.web.servlet.ModelAndView;

@Slf4j
public class SessionCheckHandlerInterceptor implements HandlerInterceptor {

private final UserValidator validator;
private final UserLoginUseCase loginUseCase;

public SessionCheckHandlerInterceptor(
UserValidator validator,
UserLoginUseCase loginUseCase
) {
this.validator = validator;
this.loginUseCase = loginUseCase;
}

@Override
public boolean preHandle(
HttpServletRequest request,
HttpServletResponse response,
Object handler
) {
Long sessionId = getSessionId(request.getCookies());
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getSessionId를 HeaderUtils에 선언하셨던데 HeaderUtils에 선언하기로 결정한 이유에 대해서 들을 수 있을까요?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Header에서 여러 유형의 값들을 파싱할 수 있다고 판단해서 별도의 파싱 클래스를 생성했습니다. Session 이외에도 여러 값들을 파싱할 수 있기 때문입니다.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

그럼 그건 HttpHeaders가 가질 수 있는 책임 아니였을까요??
HeaderUtils의 디렉토리 위치를 보면 common필드 내부에 존재하는데 HeaderParser와 같은 클래스를 정의해서 HeaderUtils의 필드로 넣거나, 혹은 HeaderUtils의 내부 메서드로 정의하는게 더 이상적인 방식이라고 느껴서요.

HttpHeaders 클래스에 존재하는

public int getContentLength() {
        List<HttpHeader> headers = this.headers.getOrDefault(
            CONTENT_LENGTH, List.of(new HttpHeader(CONTENT_LENGTH, "0"))
        );
        return Integer.parseInt(headers.get(0).getValue());
    }

위 메서드는 headers중에 contentLength를 찾아서 반환하는데 이것이 session과 관련된 메서드를 찾아서 가져오는 것과 어떤 차이가 있나요? 비슷한 성질의 역할을 하는 메서드인데 contentLength를 찾아오는 메서드는 HttpHeaders에 존재하고 sessionId를 찾아오는 메서드는 HeadersUtils에 존재하는 것이 납득되지 않습니다.

또한 common 패키지 밑에 HeadersUtils가 들어가는 것도 이해가 잘 안됩니다.
HeadersUtils는 util클래스라 명명되어 있지만, HttpHeaders라는 객체에 관련된 일만 할 것이 명백한 상황입니다.
그렇다면 적어도 HttpHeaders와 같은 디렉토리인 http 패키지 아래로 들어가는 것이 더 이상적인 구조지 않았을까요?

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sessionId로 UUID가 아니라 Long을 사용하신 이유가 궁금합니다.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이거 userId 같은데 제 실수 같네요. 수정하겠습니다!

validator.validateSessionId(sessionId, response);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

validateSessionId를 보면 파라미터로 userId가 선언되어있는데..
잘못 된거 아닌가요?

image

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

맞습니다. 위에 변수명 실수 같아요.


Session findSession = loginUseCase.findSessionById(sessionId);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

findSession에서 find의 수동태는 found라 foundSession이 맞지않나요?

저는 그냥 session이라 선언해도 의미 전달에 전혀 문제가 없다 느껴져요. 굳이 변수명이 길어지는 것 보다는 session으로 두는 것이 더 낫다고 생각하는데 어떻게 생각하시나요?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

그것도 괜찮죠. 다만 찾아온 값들의 접두사로 find{$NAME} 형태로 사용하다보니 전체를 이렇게 통일했습니다.

log.info("Session:{}", findSession);
validator.validateSession(findSession, response);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

image
invalid일 경우 응답을 내릴 때, max-age=0;으로 응답을 내리던데 max-age를 왜 0으로 설정하는시 설명부탁드립니다.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

쿠키 만료 시간을 0으로 해야 브라우저에 저장된 값을 삭제할 수 있기 때문입니다.


LoginUser loginUser = new LoginUser(findSession);
request.setAttribute("loginUser", loginUser);
return false;
}

@Override
public void postHandle(
HttpServletRequest request,
HttpServletResponse response,
Object handler,
ModelAndView modelAndView
) {
HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
}

@Override
public void afterCompletion(
HttpServletRequest request,
HttpServletResponse response,
Object handler
) {
HandlerInterceptor.super.afterCompletion(request, response, handler);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package project.server.app.core.web.user.application;

import project.server.app.common.login.LoginUser;

public interface UserUpdateUseCase {
void update(LoginUser loginUser, String password);
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,13 @@
import project.server.app.core.web.user.application.UserDeleteUseCase;
import project.server.app.core.web.user.application.UserSaveUseCase;
import project.server.app.core.web.user.application.UserSearchUseCase;
import project.server.app.core.web.user.application.UserUpdateUseCase;
import project.server.app.core.web.user.exception.DuplicatedUsernameException;
import project.server.app.core.web.user.exception.UserNotFoundException;
import project.server.mvc.springframework.annotation.Service;

@Service
public class UserService implements UserSaveUseCase, UserSearchUseCase, UserDeleteUseCase {
public class UserService implements UserSaveUseCase, UserSearchUseCase, UserUpdateUseCase, UserDeleteUseCase {

private final UserRepository userRepository;

Expand Down Expand Up @@ -43,6 +44,16 @@ public User findById(Long userId) {
return findUser;
}

@Override
public void update(
LoginUser loginUser,
String password
) {
User findUser = userRepository.findById(loginUser.getUserId())
.orElseThrow(UserNotFoundException::new);

}

@Override
public void delete(LoginUser loginUser) {
User findUser = userRepository.findById(loginUser.getUserId())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import project.server.app.core.web.user.application.UserDeleteUseCase;
import project.server.app.core.web.user.application.UserSaveUseCase;
import project.server.app.core.web.user.application.UserSearchUseCase;
import project.server.app.core.web.user.application.UserUpdateUseCase;
import project.server.jdbc.core.exception.DataAccessException;
import static project.server.jdbc.core.transaction.DefaultTransactionDefinition.createTransactionDefinition;
import project.server.jdbc.core.transaction.PlatformTransactionManager;
Expand All @@ -18,7 +19,7 @@

@Slf4j
@Component
public class UserServiceProxy implements UserSaveUseCase, UserSearchUseCase, UserDeleteUseCase {
public class UserServiceProxy implements UserSaveUseCase, UserSearchUseCase, UserUpdateUseCase, UserDeleteUseCase {

private final PlatformTransactionManager txManager;
private final UserService target;
Expand Down Expand Up @@ -70,6 +71,24 @@ public User findById(Long userId) {
}
}

@Override
public void update(
LoginUser loginUser,
String password
) {
TransactionStatus txStatus = getTransactionStatus(true);
log.debug("txStatus:[{}]", txStatus.getTransaction());
try {
target.update(loginUser, password);
txManager.commit(txStatus);
log.debug("Transaction finished.");
} catch (BusinessException | DataAccessException exception) {
txManager.rollback(txStatus);
log.error("{}", exception.getMessage());
throw exception;
}
}

@Override
public void delete(LoginUser loginUser) {
TransactionStatus txStatus = getTransactionStatus(false);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package project.server.app.core.web.user.presentation;

import lombok.extern.slf4j.Slf4j;
import project.server.app.common.login.LoginUser;
import project.server.app.core.web.user.application.UserLoginUseCase;
import project.server.app.core.web.user.application.UserUpdateUseCase;
import project.server.app.core.web.user.presentation.validator.UserValidator;
import project.server.mvc.servlet.HttpServletRequest;
import project.server.mvc.servlet.HttpServletResponse;
import static project.server.mvc.servlet.http.HttpStatus.OK;
import project.server.mvc.springframework.annotation.Controller;
import project.server.mvc.springframework.web.servlet.Handler;
import project.server.mvc.springframework.web.servlet.ModelAndView;

@Slf4j
@Controller
public class UserInfoUpdateController implements Handler {

private final UserValidator validator;
private final UserLoginUseCase loginUseCase;
private final UserUpdateUseCase userUpdateUseCase;

public UserInfoUpdateController(
UserValidator validator,
UserLoginUseCase loginUseCase,
UserUpdateUseCase userUpdateUseCase
) {
this.validator = validator;
this.loginUseCase = loginUseCase;
this.userUpdateUseCase = userUpdateUseCase;
}

@Override
public ModelAndView process(
HttpServletRequest request,
HttpServletResponse response
) {
LoginUser loginUser = (LoginUser) request.getAttribute("loginUser");
userUpdateUseCase.update(loginUser, (String) request.getAttribute("password"));

response.setStatus(OK);
return null;
}
}
3 changes: 1 addition & 2 deletions mvc/src/main/java/project/server/mvc/Application.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,7 @@ public Application(
}

private void initContext(String packages) throws Exception {
ApplicationContext context;
context = new ApplicationContext(packages);
ApplicationContext context = new ApplicationContext(packages);
ApplicationContextProvider provider = new ApplicationContextProvider();
provider.setApplicationContext(context);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
package project.server.mvc.springframework.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Component
@Documented
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Controller {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package project.server.mvc.springframework.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import project.server.mvc.servlet.http.HttpMethod;

@Documented
@Retention(RetentionPolicy.RUNTIME)
@RequestMapping(method = HttpMethod.DELETE)
@Target({ElementType.TYPE_USE, ElementType.METHOD})
public @interface DeleteMapping {

@AliasFor(annotation = RequestMapping.class)
String name() default "";

@AliasFor(annotation = RequestMapping.class)
String[] value() default {};

@AliasFor(annotation = RequestMapping.class)
String path() default "";

@AliasFor(annotation = RequestMapping.class)
String[] params() default {};

@AliasFor(annotation = RequestMapping.class)
String[] headers() default {};

@AliasFor(annotation = RequestMapping.class)
String[] consumes() default {};

@AliasFor(annotation = RequestMapping.class)
String[] produces() default {};
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
String[] value() default {};

@AliasFor(annotation = RequestMapping.class)
String[] path() default {};
String path() default "";

@AliasFor(annotation = RequestMapping.class)
String[] params() default {};
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package project.server.mvc.springframework.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import project.server.mvc.servlet.http.HttpMethod;

@Documented
@Retention(RetentionPolicy.RUNTIME)
@RequestMapping(method = HttpMethod.POST)
@Target({ElementType.TYPE_USE, ElementType.METHOD})
public @interface PostMapping {

@AliasFor(annotation = RequestMapping.class)
String name() default "";

@AliasFor(annotation = RequestMapping.class)
String[] value() default {};

@AliasFor(annotation = RequestMapping.class)
String path() default "";

@AliasFor(annotation = RequestMapping.class)
String[] params() default {};

@AliasFor(annotation = RequestMapping.class)
String[] headers() default {};

@AliasFor(annotation = RequestMapping.class)
String[] consumes() default {};

@AliasFor(annotation = RequestMapping.class)
String[] produces() default {};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package project.server.mvc.springframework.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import project.server.mvc.servlet.http.HttpMethod;

@Documented
@Retention(RetentionPolicy.RUNTIME)
@RequestMapping(method = HttpMethod.PUT)
@Target({ElementType.TYPE_USE, ElementType.METHOD})
public @interface PutMapping {

@AliasFor(annotation = RequestMapping.class)
String name() default "";

@AliasFor(annotation = RequestMapping.class)
String[] value() default {};

@AliasFor(annotation = RequestMapping.class)
String[] put() default {};

@AliasFor(annotation = RequestMapping.class)
String path() default "";

@AliasFor(annotation = RequestMapping.class)
String[] params() default {};

@AliasFor(annotation = RequestMapping.class)
String[] headers() default {};

@AliasFor(annotation = RequestMapping.class)
String[] consumes() default {};

@AliasFor(annotation = RequestMapping.class)
String[] produces() default {};
}
Loading