[Spring] 서비스(Service) 레이어

류재성's avatar
Mar 20, 2024
[Spring] 서비스(Service) 레이어
 

1. 서비스(Service) 레이어란?

 
💡
서비스(Service) 레이어는 소프트웨어 아키텍처에서 중요한 부분 중 하나로, 애플리케이션의 비즈니스 로직을 구현하는 계층이다. 이 계층은 사용자 인터페이스(UI) 레이어와 데이터 액세스 레이어(DAL) 사이에 위치하여, 애플리케이션의 핵심 기능을 담당한다.
 
notion image
 
그림에서 서비스 레이어는 계좌이체 로직의 역할을 한다. 계좌 이체는 하나의 메서드로 구성된 것이 아니라 여러 메서드를 조합한 실제 기능을 의미한다.
 
💡
서비스 레이어는 하나의 트랜잭션 내에서 레파지토리의 여러 메서드를 조합해서 사용한다. 서비스 레이어에서 트랜잭션을 관리함으로써, 이러한 복잡한 비즈니스 로직을 효과적으로 처리하고, 필요한 경우 롤백을 수행하여 데이터의 일관성을 보장할 수 있다.
 

2. 서비스 레이어 만들기

 
package shop.mtcoding.blog.user; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import shop.mtcoding.blog._core.err.exception.Exception400; import shop.mtcoding.blog._core.err.exception.Exception401; import shop.mtcoding.blog._core.err.exception.Exception404; import java.util.Optional; @RequiredArgsConstructor @Service //ioc 등록 public class UserService { private final UserJPARepository userJPARepository ; @Transactional public void 회원가입(UserRequest.JoinDTO requestDTO){ //1.유효성검사(컨트롤러 책임) //2. 중복검사 Optional<User> userOP = userJPARepository.findByUsername(requestDTO.getUsername()); if(userOP.isPresent()){ //아이디가 중복된다면 throw new Exception400("중복된 유저네임입니다."); } userJPARepository.save(requestDTO.toEntity()); } public User 로그인(UserRequest.LoginDTO requestDTO){ User sessionUser = userJPARepository.findByUsernameAndPassword(requestDTO.getUsername(),requestDTO.getPassword()) .orElseThrow(() -> new Exception401("인증되지 않았습니다.")); // 조회했을 때 값이 NULL 일때 THROW 를 날림 return sessionUser ; } public User 회원수정폼(int boardId){ //예외처리 User user = userJPARepository.findById(boardId).orElseThrow(() -> new Exception404("회원정보를 찾을 수 없습니다.")); return user; } @Transactional public User 회원수정(int id,UserRequest.UpdateDTO requestDTO){ User user = userJPARepository.findById(id) .orElseThrow(() -> new Exception404("회원정보를 찾을 수 없습니다.")); user.setPassword(requestDTO.getPassword()); user.setEmail(requestDTO.getEmail()); return user ; } }
 
💡
서비스 레이어는 JPARepository를 의존한다.

3. JPARepository

 
package shop.mtcoding.blog.user; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.repository.query.Param; import java.util.Optional; public interface UserJPARepository extends JpaRepository<User,Integer> { // <오브젝트 타입, pk의 타입> Optional<User> findByUsernameAndPassword(@Param("username") String username, @Param("password") String password); Optional<User> findByUsername(@Param("username")String username); }
 
💡
Optional 을 사용해 null 체크를 직접적으로 수행할 필요 없이, 값이 있을 때만 특정 연산을 수행하도록 할 수 있다.
 

4. 컨트롤러

 
package shop.mtcoding.blog.user; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpSession; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; @RequiredArgsConstructor @Controller public class UserController { private final UserService userService; private final HttpSession session; @PostMapping("/join") public String join(UserRequest.JoinDTO requestDTO){ userService.회원가입(requestDTO); return "redirect:/"; } @PostMapping("/login") public String login(UserRequest.LoginDTO requestDTO){ User sessionUser =userService.로그인(requestDTO); session.setAttribute("sessionUser",sessionUser); return "redirect:/"; } @GetMapping("/join-form") public String joinForm() { return "user/join-form"; } @GetMapping("/login-form") public String loginForm() { return "user/login-form"; } @GetMapping("/user/update-form") public String updateForm(HttpServletRequest request) { User sessionUser = (User) session.getAttribute("sessionUser"); User user = userService.회원수정폼(sessionUser.getId()); request.setAttribute("user",user); return "user/update-form"; } @PostMapping("/user/update") public String update(UserRequest.UpdateDTO requestDTO){ User sessionUser = (User) session.getAttribute("sessionUser"); User user = userService.회원수정(sessionUser.getId(),requestDTO); session.setAttribute("sessionUser",user); return "redirect:/"; } @GetMapping("/logout") public String logout() { session.invalidate(); return "redirect:/"; } }
 
💡
컨트롤러에서 수행하던 기능들을 서비스 레이어에 위임해, 컨트롤러는 본인만 수행할 수 있어 코드가 간결해졌다.
Share article
RSSPowered by inblog