ilgolf / kotlinbank Goto Github PK
View Code? Open in Web Editor NEW코틀린 실습을 위한 간단한 토이프로젝트 저장소
코틀린 실습을 위한 간단한 토이프로젝트 저장소
FinAccount를 NH API에서 받아와 DB에 저장 후 잔액 조회 요청 시 Body에 담아 요청을 보내고 있는데 발급 받지 않은 핀 어카운트라는 응답을 받아 원인을 분석
원인 분석 결과
FinAccount를 다른 API를 통해 받아올 수 있고 현재 사용중인 API는 등록번호만 반환하고 있음.
목표
실패에 대한 케이스 추가로 작업
@PutMapping
fun updatePassword(
@Valid @RequestBody requestDto: PasswordApiUpdateRequestDto,
@AuthenticationPrincipal customUserDetails: CustomUserDetails
): ResponseEntity<Unit> {
check(requestDto.validPassword()) { throw MemberException.PhoneNumberMissMatchException(requestDto.password) }
passwordService.updatePassword(requestDto.password, customUserDetails.memberId)
return ResponseEntity.ok().build()
}
@PostMapping
fun publishTempPassword(
@Valid @RequestBody requestDto: PasswordApiFindPasswordRequestDto,
@AuthenticationPrincipal customUserDetails: CustomUserDetails
): ResponseEntity<TempPasswordApiResponseDto> {
check(requestDto.validPhone) { throw MemberException.PhoneConfirmDeniedException(requestDto.phoneNumber) }
return ResponseEntity.ok(passwordService.publishTempPassword(customUserDetails.memberId))
}
현재 코드의 문제점 : 비즈니스 로직에 대한 validation을 컨트롤러에서 하고 있다. 계속 해서 이러한 validation이 추가 될 때 마다 컨트롤러 로직이 오염될 수 있기 때문에 제거하도록 한다.
해결 방법 : 책임은 정보를 알고 있는 객체에게 넘기는게 맞으므로 DTO 에서 검증하고 Controller는 메서드만 호출하게 한다.
finAccount와 RegisterNumber를 농협 오픈 api에서 받아오고 있다. 농협에서 부하나 다른 이유로인해 장애발생할 것을 대비해 동작을 분리하여 의존성을 최소화한다.
금액 송금 시 또는 계좌 조회 시 내역을 조회할 수 있는 history table Entity를 개발한다.
https://stackoverflow.com/questions/32057910/custom-spring-aop-around-transactional
참고한 글
@Transactional
@Around("@annotation(me.golf.kotlin.domain.bank.RequireFinAccount)")
fun validateAndGet(joinPoint: ProceedingJoinPoint): Any? {
val method = (joinPoint.signature as MethodSignature).method
val lookupType = method.getAnnotation(RequireFinAccount::class.java).type
val args = joinPoint.args
return when (lookupType) {
LookupType.ONE -> validateAndGetOne(args, joinPoint)
LookupType.SEVERAL -> validateAndGetSeveral(args, joinPoint)
}
}
Around로 선언한 AOP에서 Order가 같아 스프링에서 뭘 먼저 실행해야하는지 몰라 Transactional 이 동작하지 않아 더티체킹이 일어나지 않음.
Transactional을 제거하고 QueryDSL로 update 쿼리를 직접 날려 해결하는 방향으로 개선
OSIV = true 로 설정해야 하므로 영속성 범위가 넓어져 DB connection을 오래 물고 있을 수 있음. 요청이 좀만 많아지면 데드락 발생 가능성도 고려 해봐야함
다른 더 나은 방안 고민중 ..
CRUD 기능 구현 및 테스트 케이스 별 코드 작성
삭제된 데이터는 조회될 때 제거되어야 한다.
RedisRepository는 유연하지 않고 버그가 있을 수 있어 redisTemplate으로 변경
Testcontainers 상속하지 않고 처음 테스트 시작 시 start하여 생명 주기를 테스트 시작부터 끝까지로 정한다. (@testcontainers 이용)
엔티티 개발
필요한 property
메시지 큐가 동작하는 중간에 서버가 닫히면 작업을 잃어버리는 경우가 생기기 때문에 안전하게 Message가 처리된 후 종료될 수 있도록 Graceful Shutdown 기능 추가
상속을 해야 테스트 컨테이너가 동작한다.
domain 로직 테스트 코드 작성 (단위)
swagger를 이용한 API 문서화 작업
sealed class를 이용하여 Exception 클래스 간소화
계좌 송금 서비스와 컨트롤러를 따로 빼서 개발
현재 농협 API 호출 시 4xx오류와 5xx오류 발생 하면 적당히 추상화 된 Error message가 필요함
데이터를 받아오는데 실패했습니다. 문의 바랍니다.
입니다.또한 농협에서 200 ok 임에도 불구하고 Rsms를 키 값으로 오류 메시지를 전송하는 경우가 있음
이 또한 오류 메시지를 받아와 따로 오류 처리 예정
사용자가 홈 화면에서 자신의 갖고있는 계좌에 대한 정보를 간략하게 볼 수 있습니다. 해당 서비스에 필요한 정보는 다음과 같습니다.
계좌 은행과 별칭은 memberId를 기준으로 List로 보여줍니다. 여기서 고민 point가 생겨납니다. 잔액 정보는 현재 외부 api 인 농협 api에 의존하고 있습니다. 외부 api에 완전한 의존은 예상치 못한 장애를 동반합니다. (예를 들어 우리만 요청을 보내고 있는 상황이 아니니 부하가 몰려 농협의 서비스가 장애가 나거나 해당 서버를 관리하다 예상치 못한 장애를 만나 서버에 문제가 생길 수 있습니다.) 이러한 이유로 외부 api는 철저히 주요 코어 비즈니스에는 영향을 줘선 안됩니다.
결국 최종적으로는 최대한 정확한 데이터를 클라이언트에게 보여주면서 외부 api 장애에 영향 받지 않는 비즈니스 로직을 구현하고 싶습니다.
이외에 다른 의견 있으시면 코멘트 부탁드립니다.
coolSMS를 이용 우리가 문자로 보낸 정보를 그대로
인증 후 비밀번호 변경
인증 후 비밀번호 임시 발급
컨트롤러 진입 전 Transaction 연산이 일어남 이는 너무 커넥션을 오래 물 수 있고 AOP 내부에서 reflection을 이용한 선언 순서를 검색하지 못해 같은 AOP인 Transactional이 동작하지 않는 이슈로 인해 AOP를 이용한 FinAccount 재전송 과정 구현은 어려움이 있다.
스프링에선 이러한 경우 별도의 관점 클래스를 추가하여 리팩터링하라고 권장하고 있다. 그래서 별도 클래스로 분리하여 관리할 예정이다.
농협상호금융의 이름의 Enum 값을 추가한다.
농협 API를 받아오던 중 Json 형식에 문제가 생기는 이슈가 발생
ex)
{
"Header": {
"Trtm": "003544",
"Rsms": "정상처리 되었습니다.",
"ApiNm": "CheckOpenFinCardDirect",
"IsTuno": "201911240000000001",
"Tsymd": "20191129",
"FintechApsno": "001",
"Iscd": "900001",
"Rpcd": "00000",
"ApiSvcCd": "DrawingTransferA"
},
"FinAcno": "00820100000190001639",
"RgsnYmd": "20191124"
}
기본적으로 성공했을 땐 이렇게 오지만 실패한다면 다음과 같이 온다.
{
"Header": {
"Trtm": "003544",
"Rsms": "핀-어카운트 등록 정보가 잘못됐습니다.",
"ApiNm": "CheckOpenFinCardDirect",
"IsTuno": "201911240000000001",
"Tsymd": "20191129",
"FintechApsno": "001",
"Iscd": "900001",
"Rpcd": "00000",
"ApiSvcCd": "DrawingTransferA"
}
}
이 때 FinAcno field가 누락되어 있기 때문에 Jackson을 이용했을 때 오류가 난다.
물론 Jackson도 JsonNode로 가능하지만, Gson은 이러한 매핑 과정에서 없는 field를 무시하고 매핑하기 때문에 간편성 측면에서 훨씬 좋다. 그래서 도입하였다.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.