
Express에서는 router -> controller -> model 의 흐름이라면
spring은 Controller -> Service -> (Jpa) 의 흐름이다.
Controller는 Routing의 역할만 하고 실제 Logic은 Service level에서 처리해준다.
@Service
public class UserApiLogicService implements CrudInterface<UserApiRequest, UserApiResponse> {
Controller 와 마찬가지로 ifs를 상속받는다. CRUD를 강제하기 위함이다.
@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의 흐름
- Header의 T data 로부터 data를 추출해낸다.
- 추출해낸 data값을 user에 저장한다.
- userRepository.save(user)를 통해 DB에 값을 저장한다
- Header 형으로 return 해준다
response 같은 경우 CRUD 모두에서 쓰이기 때문에 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
@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이 된다.
@Override
@GetMapping("{id}")
public Header<UserApiResponse> read(@PathVariable(name="id") Long id) {
return userApiLogicService.read(id);
}
@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("데이터 없음"));
}
@Override
@PutMapping("")
public Header<UserApiResponse> update(@RequestBody Header<UserApiRequest> userApiRequest) {
return userApiLogicService.update(userApiRequest);
}
@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의 흐름
- create때와 마찬가지로 request값을 Header가 포함된 data로 부터 추출해낸다.
- DB에서 requestData.getId()를 통해 업데이트 할 데이터를 찾는다. update는 userId ( FK )와 같은 값을 업데이트 한다.
- 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한다.
@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에 넣어주어야 한다.