Spring Boot 시작하기 #9

ims·2020년 9월 1일

Service

Express에서는 router -> controller -> model 의 흐름이라면
spring은 Controller -> Service -> (Jpa) 의 흐름이다.
Controller는 Routing의 역할만 하고 실제 Logic은 Service level에서 처리해준다.

@Service
public class UserApiLogicService implements CrudInterface<UserApiRequest, UserApiResponse> {

Controller 와 마찬가지로 ifs를 상속받는다. CRUD를 강제하기 위함이다.

Create

@Override
public Header<UserApiResponse> create(Header<UserApiRequest> request) {

    UserApiRequest requestData = request.getData();

    User newUser = User.builder()
            .account(requestData.getAccount())
            .password(requestData.getPassword())
            .status("승인")
            .email(requestData.getEmail())
            .phoneNumber(requestData.getPhoneNumber())
            .registeredAt(LocalDateTime.now())
            .build();

    User returnData = userRepository.save(newUser);

    return response(returnData);
}

Logic의 흐름

  1. Header의 T data 로부터 data를 추출해낸다.
  2. 추출해낸 data값을 user에 저장한다.
  3. userRepository.save(user)를 통해 DB에 값을 저장한다
  4. Header 형으로 return 해준다

response 같은 경우 CRUD 모두에서 쓰이기 때문에 method를 따로 정의해준다.

response method

public Header<UserApiResponse> response(User newUser){
    UserApiResponse userApiResponse = UserApiResponse.builder()
            .id(newUser.getId())
            .account(newUser.getAccount())
            .password(newUser.getPassword())
            .status(newUser.getStatus())
            .email(newUser.getEmail())
            .phoneNumber(newUser.getPhoneNumber())
            .registeredAt(newUser.getRegisteredAt())
            .build();

    return Header.OK(userApiResponse);
}

현재 Header형이 { "data":{} } 로 값을 받기 때문에 data를 명시해주어야 한다.

@Slf4j

@Slf4j
@RestController
@RequestMapping("/user")
public class UserController implements CrudInterface<UserApiRequest,UserApiResponse> {

    @Autowired
    UserApiLogicService userApiLogicService;

    @Override
    @PostMapping("")
    public Header<UserApiResponse> create(@RequestBody Header<UserApiRequest> userApiRequest)
    {
        log.info("{}",userApiRequest);
        return userApiLogicService.create(userApiRequest);
    }

logging을 해볼 수 있는 api.

2020-09-01 22:53:56.704  INFO 14548 --- [nio-8080-exec-4] c.e.s.controller.UserController          : Header(transactionTime=null, resultCode=null, description=null, data=UserApiRequest(id=null, account=임얼쑤, password=비밀번호, status=null, email=이메일, phoneNumber=null))

위와 같이 logging이 된다.

Read

Controller

@Override
@GetMapping("{id}")
public Header<UserApiResponse> read(@PathVariable(name="id") Long id) {
    return userApiLogicService.read(id);
}

Service

@Override
public Header<UserApiResponse> read(Long id) {
    Optional<User> getUser = userRepository.findById(id);

    return getUser.map(user->response(user)).orElseGet(()->Header.ERROR("데이터 없음"));
}

userRepository.findById() 가 return 형이 Optional이기 때문에 위의 코드를 다음과 같이 한줄로 줄일 수 있다.

@Override
public Header<UserApiResponse> read(Long id) {
    return userRepository.findById(id).map(user->response(user)).orElseGet(()->Header.ERROR("데이터 없음"));
}

Update

Controller

@Override
@PutMapping("")
public Header<UserApiResponse> update(@RequestBody Header<UserApiRequest> userApiRequest) {
    return userApiLogicService.update(userApiRequest);
}

Service

@Override
public Header<UserApiResponse> update(Header<UserApiRequest> request) {
    UserApiRequest requestData = request.getData();

    Optional<User> findUser = userRepository.findById(requestData.getId());

    return findUser.map(updatedUser->{
        updatedUser.
                setId(requestData.getId())
                .setAccount(requestData.getAccount())
                .setPassword(requestData.getPassword())
                .setPhoneNumber(requestData.getPhoneNumber())
                .setStatus(requestData.getStatus())
                .setEmail(requestData.getEmail());
        return updatedUser;
    }).map(user->userRepository.save(user))
            .map(user->response(user))
            .orElseGet(()->Header.ERROR("오류"));

}

Logic의 흐름

  1. create때와 마찬가지로 request값을 Header가 포함된 data로 부터 추출해낸다.
  2. DB에서 requestData.getId()를 통해 업데이트 할 데이터를 찾는다. update는 userId ( FK )와 같은 값을 업데이트 한다.
  3. user 값을 받은 값으로 설정하고, userRepository.save()를 통해 값을 저장해주고 reponse method를 통해 값을 return해준다

위는 Lamda와 map을 활용해서 짠 코드.

map은 객체 안에 있는 값들을 순회하면서 method가 끝날 때 return 값을 다음 map이 input으로 갖는다.

A

.map(user->{userRepository.save(user)})
.map(user->response(user))

B

.map(user->userRepository.save(user))
.map(user->response(user))

A와 B 코드는 다르다. A의 경우 Object를 return한다.

Delete

Service

@Override
public Header delete(Long id) {
    Optional<User> findUser = userRepository.findById(id);
    return findUser.map(user->{
        userRepository.delete(user);
        return Header.OK();
    }).orElseGet(()->Header.ERROR("에러"));
}

userRepository.findById의 return형은 Optional이다. 그런데 userRepository가 받는 parameter data type은 user이다. Optional은 User의 data가 포함된 형태의 객체이므로, Optional에서 map을 통해 user를 찾아서 userRepository에 넣어주어야 한다.

profile
티스토리로 이사했습니다! https://imsfromseoul.tistory.com/ + https://camel-man-ims.tistory.com/

0개의 댓글