-
Notifications
You must be signed in to change notification settings - Fork 175
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
[Spring 지하철 경로 조회 - 1, 2단계] 검프(김태정) 미션 제출합니다. #100
Conversation
검프 학습로그관계설정
하지만 이는 다형성이라는 특징 덕분임. 즉. 객체 서로가 구현에 의존하는 것이 아닌 역할에 의존한다면, 역할을 구현하는 방법이 바뀌더라도, 상대 객체에는 아무런 영향을 주지 않음. 또한, 객체를 사용하는 클라이언트를 변경하지 않아도, 새로운 기능을 제공할 수 있다는 장점을 얻을 수 잇음. 대체가능성과 확장성을 얻음. 제어의 역전서비스를 2개의 영역으로 나눠보면 사용 영역, 구성 영역으로 나눌 수 있어요. 제어가 역전됐다는 것은 프로그램의 제어 흐름 구조가 뒤 바뀐 것이라 할 수 있어요. 일반적인 프로그램은 main() 메소드와 같이 프로그램이 시작되는 지점에서 다음에 사용할 객체를 결정하고, 결정할 객체를 생성하고, 만들어진 객체에 있는 메소드를 호출하고 등의 작업이 반복되요. 즉, 모든 종류의 작업을 사용 영역에서 제어하는 구조에요. 제어의 역전이란 이런 제어 흐름의 개념을 거꾸로 뒤집는 것이에요. 제어의 역전에서는 객체가 자신이 사용할 오브젝트를 스스로 선택하지 않고, 생성하지도 않아요. 또한 자신이 어떻게 만들어지고 어디서 사용되는지를 알 수 없어요. 모든 제어 권한을 자신이 아닌 다른 대상에게 위임하기 때문이에요. 즉, 모든 종류의 작업을 구성 영역에서 제어하는 구조에요. 라이브러리와 프레임워크의 차이가 여기서 나요
반면에
즉, 애플리케이션 코드는 프레임워크가 짜놓은 틀에서 수동적으로 동작해야해요. 금방 작성했던 코드도 IoC를 적용한 것이에요. # 구성영역
public class DaoFactory {
public UserDao userDao() {
return new UserDao(connections());
}
public AccountDao accountDao() {
return new AccountDao(connections());
}
public MessageDao messageDao() {
return new MessageDao(connections());
}
private Connections connections() {
return new DConnections();
}
} # 사용영역
public class UserDaoTest {
public static void main(String[] args) {
UserDao userDao = new DaoFactory().userDao();
}
} |
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.
검프 안녕하세요! 리뷰를 맡게된 데이브 입니다!
리뷰가 늦었네요 🙇♂️
몇가지 피드백 남겼어요. 확인 부탁드릴게요!
궁금한 점 있으면 언제든 편하게 질문 주세요 :)
@ExceptionHandler({AuthException.class}) | ||
public ResponseEntity<String> authException(RuntimeException exception) { | ||
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(exception.getMessage()); |
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.
👍
return ResponseEntity.ok().build(); | ||
} | ||
|
||
// TODO: 구현 하기 | ||
@DeleteMapping("/members/me") | ||
public ResponseEntity<MemberResponse> deleteMemberOfMine() { | ||
public ResponseEntity<MemberResponse> deleteMemberOfMine(@AuthenticationPrincipal LoginMember loginMember) { |
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.
noContent 면 응답을 Void로 해놓아도 좋을 것 같아요 :)
public ResponseEntity<MemberResponse> deleteMemberOfMine(@AuthenticationPrincipal LoginMember loginMember) { | |
public ResponseEntity<Void> deleteMemberOfMine(@AuthenticationPrincipal LoginMember loginMember) { |
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.
body를 포함하지 않는 메소드, 전체 Void를 반환하도록 변경했습니다 :)
// TODO: 유효한 로그인인 경우 LoginMember 만들어서 응답하기 | ||
return null; | ||
String token = AuthorizationExtractor.extract(Objects.requireNonNull(webRequest.getNativeRequest(HttpServletRequest.class))); | ||
return authService.findByToken(token); |
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.
지금 같은 경우 @AuthenticationPrincipal
어노테이션이 있을때만 로그인 검증을 할 텐데 intercepter 를 사용해서 @AuthenticationPrincipal
를 사용하지 않는 api 들도 인증한 사용자인지 체크하도록 해보면 좋을 것 같아요!
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.
@AuthenticationPrincipal을 사용하지 않는 api또한 인증된 사용자인지 체크하도록 변경했어요 😊
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoginInterceptor(authService))
.addPathPatterns("/**")
.excludePathPatterns("/login/token", "/members");
}
여기서 질문이 있어요..!
저는 post의 /members만 inteceptor의 영향을 받고싶지 않은데,
지금 같은경우는 members의 path는 메소드에 상관없이 다 허용하고있어요.
이런경우 어떻게 해야하는걸까요...?
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.
인터셉터는 Path로만 제어 가능 한 것으로 알고 있어요 😭
아래 링크 처럼 인터셉터 동작 후 처리 하던가, 원하지 않는 api의 path를 변경 해야 할 것 같네요.
https://stackoverflow.com/questions/48306597/spring-mvc-interceptor-pattern
body: JSON.stringify(jsonData) | ||
}; | ||
|
||
const response = await fetch("http://localhost:8080/login/token", option); |
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.
http://localhost:8080
같은경우 환경에 따라 달라질 수 있기 때문에 보통 Path로만 요청하고 있어요 :)
const response = await fetch("http://localhost:8080/login/token", option); | |
const response = await fetch("/login/token", option); |
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.
view.config의 수정을 통해, path로 요청할 수 있게 번경했습니다.
const path = require('path');
module.exports = {
outputDir: path.resolve(__dirname, '../src/main/resources/static/'),
devServer: {
proxy: {
'/api': {
target: 'http://localhost:8080/',
ws: true,
changeOrigin: true,
},
},
historyApiFallback: true,
},
transpileDependencies: [
'vuetify'
]
}
또한 기본 path에 /api를 추가했어요.
const response = await fetch("http://localhost:8080/login/token", option); | ||
let resJson = await response.json(); | ||
const accessToken = resJson.accessToken; | ||
this.$store.commit(SET_ACCESS_TOKEN, accessToken); |
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.
오호.. store!
store에 토큰을 저장 할 경우 새로고침하면 store가 초기화 되지 않나요? 🤔
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.
새로고침을 전혀 생각하지 않았네요..!
vuex-persistedstate를 사용하며,
실질적으로 사용하는 member, auth 모듈의 state만 저장되게 번경햇습니다.😊
좋은 피드백 감사합니다!
|
||
@RestControllerAdvice | ||
public class GlobalExceptionHandler { | ||
@ExceptionHandler({AuthException.class}) |
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.
지금 미션과 상관은 없지만 Exception.class 를 처리하는 handler도 만들어보면 좋을 것 같아요 :)
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.
사용자 잘못이 아닌, 서버 자체의 예외 처리를 말씀하시는 거죠..?
우선 이번 서비스에서 중요 로직을 담당하는 데이터베이스의 예외를 잡기위해
DataAccesException으로 서버 내부 예외에 대한 처리를 완료했어요. 😊
@ExceptionHandler({DataAccessException.class})
public ResponseEntity<String> databaseException(RuntimeException exception) {
logger.info(exception.getMessage());
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(exception.getMessage());
}
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.
DataAccesException.class 이외의 에러가 발생했을때는 어떻게 해야할까요?
보통 @ExceptionHandler({Exception.class})
을 만들어서 개발자가 예상하지 못한 에러가 발생시 처리해주고 있어요 :)
@PutMapping("/members/me") | ||
public ResponseEntity<MemberResponse> updateMemberOfMine() { | ||
public ResponseEntity<TokenResponse> updateMemberOfMine(@AuthenticationPrincipal LoginMember loginMember, @RequestBody MemberRequest request ) { |
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.
@Valid
어노테이션을 이용해서 MemberRequest
의 유효성 체크도 해보면 좋을 것 같아요 :)
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.
spring starterr의 validatiion의존성을 추가해, 바인딩시 유효셩 검사를 진행했어요.
public void updateMember(Long id, MemberRequest memberRequest) { | ||
memberDao.update(new Member(id, memberRequest.getEmail(), memberRequest.getPassword(), memberRequest.getAge())); | ||
} | ||
|
||
public void deleteMember(Long id) { | ||
memberDao.deleteById(id); | ||
} | ||
|
||
public Member findMemberByEmail(TokenRequest request) { |
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.
TokenRequest 채로 받는게 맞을지 고민되네요 🤔
email로만 Member를 조회하고 login 메소드에서 비밀번호 체크하는건 어떠신가요?
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.
Service와 도메인의 책임을 더 생각해보게 됐어요..!
수정했습니다..! 좋은 피드백 감사합니다.
안녕하세요 데이브! 두번째 pr요청입니다..! 질문 사항은 👀 를 통해 남겼어요.. |
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.
검프 안녕하세요!
피드백 반영 한 부분 확인했어요 👍
질문 주신 부분에 대해서도 답변 남겼어요. 확인 부탁드릴게요!
이번 단계는 이만 머지할게요 :)
안녕하세요 데이브..! 처음뵙겠습니다. 잘부탁드립니다.
vue.js는 처음이네요.. 프론트 코드를 이해하는데도 꽤나 시간이 걸린거 같아요 😂
백엔드 코드는 기본적인 스켈레톤 코드가 작성되어 있어서 수월했어요.
주로 작성한 부분은.
전역적 ExceptionHandler 처리.
레이어별 테스트 등입니다.
피드백을 통해 성장하겠습니다..! 많은 피드백 기다리겠습니다 감사합니다