계좌등록 서비스 코드
package shop.mtcoding.bank.service;
import java.util.Optional;
import javax.validation.constraints.Digits;
import javax.validation.constraints.NotNull;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
import shop.mtcoding.bank.domain.account.Account;
import shop.mtcoding.bank.domain.account.AccountRepository;
import shop.mtcoding.bank.domain.user.User;
import shop.mtcoding.bank.domain.user.UserRepository;
import shop.mtcoding.bank.handler.ex.CustomApiException;
@RequiredArgsConstructor
@Transactional(readOnly = true)
@Service
public class AccountService {
private final UserRepository userRepository;
private final AccountRepository accountRepository;
@Transactional
public AccountSaveResponseDto 계좌등록(AccountSaveRequestDto accountSaveRequestDto, Long userId) {
// 1. User DB 검증
User userPS = userRepository.findById(userId).orElseThrow(
() -> new CustomApiException("유저를 찾을 수 없습니다. "));
// 2. 계좌 DB 중복 여부 검증
Optional<Account> accountOP = accountRepository.findByNumber(accountSaveRequestDto.getNumber());
if (accountOP.isPresent()) {
throw new CustomApiException("해당 계좌가 이미 존재합니다. ");
}
// 3. 계좌 등록
Account accountPS = accountRepository.save(accountSaveRequestDto.toEntity(userPS));
// 4. DTO
return new AccountSaveResponseDto(accountPS);
}
@Getter
@Setter
public static class AccountSaveResponseDto {
private Long id;
private Long number;
private Long balance;
public AccountSaveResponseDto(Account account) {
this.id = account.getId();
this.number = account.getNumber();
this.balance = account.getBalance();
}
}
@Getter
@Setter
public static class AccountSaveRequestDto {
@NotNull
@Digits(integer = 4, fraction = 4)
private Long number;
@NotNull
@Digits(integer = 4, fraction = 4)
private Long password;
public Account toEntity(User user) {
return Account.builder()
.number(number)
.password(password)
.balance(1000L)
.user(user)
.build();
}
}
}
이제 컨트롤러 코드를 만들어보자
package shop.mtcoding.bank.web;
import javax.validation.Valid;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import lombok.RequiredArgsConstructor;
import shop.mtcoding.bank.config.auth.LoginUser;
import shop.mtcoding.bank.dto.ResponseDto;
import shop.mtcoding.bank.dto.account.AccountRequestDto.AccountSaveRequestDto;
import shop.mtcoding.bank.dto.account.AccountResponseDto.AccountSaveResponseDto;
import shop.mtcoding.bank.service.AccountService;
@RequiredArgsConstructor
@RequestMapping("/api")
@RestController
public class AccountController {
private final AccountService accountService;
@PostMapping("/")
public ResponseEntity<?> saveAccount(@RequestBody @Valid AccountSaveRequestDto accountSaveRequestDto,
BindingResult bindingResult,
@AuthenticationPrincipal LoginUser loginUser) {
AccountSaveResponseDto accountSaveResponseDto = accountService.계좌등록(accountSaveRequestDto,
loginUser.getUser().getId());
return new ResponseEntity<>(new ResponseDto<>(1, "계좌등록 성공", accountSaveResponseDto), HttpStatus.CREATED);
}
}
LoginUser 에는 id, role 만 존재 : JwtAuthorizationFilter 확인
DTO의 경우는 dto로 옮기기
package shop.mtcoding.bank.dto.account;
import javax.validation.constraints.Digits;
import javax.validation.constraints.NotNull;
import lombok.Getter;
import lombok.Setter;
import shop.mtcoding.bank.domain.account.Account;
import shop.mtcoding.bank.domain.user.User;
public class AccountRequestDto {
@Getter
@Setter
public static class AccountSaveRequestDto {
@NotNull
@Digits(integer = 4, fraction = 4)
private Long number;
@NotNull
@Digits(integer = 4, fraction = 4)
private Long password;
public Account toEntity(User user) {
return Account.builder()
.number(number)
.password(password)
.balance(1000L)
.user(user)
.build();
}
}
}
package shop.mtcoding.bank.dto.account;
import lombok.Getter;
import lombok.Setter;
import shop.mtcoding.bank.domain.account.Account;
public class AccountResponseDto {
@Getter
@Setter
public static class AccountSaveResponseDto {
private Long id;
private Long number;
private Long balance;
public AccountSaveResponseDto(Account account) {
this.id = account.getId();
this.number = account.getNumber();
this.balance = account.getBalance();
}
}
}
이거를 POST맨으로 하려면 회원가입 로그인 까지 항상 해야하기 때문에 너무 귀찮다. 따라서 더미 데이터를 넣어준다.
package shop.mtcoding.bank.config.dummy;
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import shop.mtcoding.bank.domain.user.User;
import shop.mtcoding.bank.domain.user.UserRepository;
@Configuration
public class DummyDevInit extends DummyObject {
@Profile("dev") // dev만 동작, prod는 실행 안되야함
@Bean
CommandLineRunner init(UserRepository userRepository) {
return (args) -> {
// 서버 실행 시, 무조건 실행
User ssar = userRepository.save(newUser("ssar", "쌀"));
};
}
}
dev를 TRACE로 해서 내용을 볼 수 있다.
insert 쿼리 1개
회원가입 필요없이 로그인이 바로가능하다
베리어 토큰과 같이 보내면
쿼리를 보면
서비스단에서 user 찾는 부분
계좌 찾는 부분
계좌 insert
주목할 점
Account를 가보면 user와 LAZY상태로 되어있다. 따라서 알수 있듯이 user 데이터를 가져오지 않는다. 만약 account.getUser().아무 필드 를 하는 순간 User가 LAZY하게 발동이 된다.