스프링 패키지 + JPA 구조에 대해 알아보기 전에 먼저 MVC패턴에 대해 알아보자.
Model, View, Controller 의 약자. 프로젝트를 구성할 때 그 구성요소를 세가지 역할로 구분한 패턴.

사용자가 Controller를 조작하면 Controller는 Model을 통해 데이터를 가져오고 그 데이터를 바탕으로 View를 통해 화면을 보여줍니다.
사용자 인터페이스로부터 비즈니스 로직을 분리하여 애플리케이션의 시작적 요소나 그 이면에서 실행되는 비즈니스 로직을 서로 영향 없이 쉽게 고칠 수 있는 애플리케이션을 만들 수 있게 됩니다.
웹에서 MVC 패턴 사용 예
1. 사용자가 웹사이트에 접속
2. Controller는 사용자가 요청한 웹페이지를 위해 모델을 호출
3. Model은 DB같은 데이터 소스를 제어한 후 return
4. Controller는 Model이 return한 결과를 view에 반영
5. View는 사용자에게 보여짐
데이터를 가진 객체.(변수, 상수, 초기화값 등등)
데이터 및 객체의 입출력 담당.(input 텍스트 같은 사용자 인터페이스. 즉, 화면)
모델과 뷰를 있는 다리역할. 사람으로 치면 뇌를 담당

역할을 확실하게 구분하여, 유지보수, 확장성를 용이하게 하는 패턴
컨트롤러 : 조작
모델 : 데이터 객체
뷰 : 화면
이러한 MVC패턴을 적용한 다양한 프레임워크중 대표적인것이 스프링이다.
스프링부트는 목적에 따라 패키지를 생성해서 프로젝트를 관리하는데 기본적인 구성은
다음과 같다.

클라이언트의 요청과 응답을 처리하는 클래스로 맨 앞단.
@Controller
@RequestMapping("/hello")
public class hello {
@GetMapping(value = "/view")
public String view(Model model, @RequestParam(value = "userName", required = true) String userName){
User user = userService.retrieveUserInfo(userName);
model.addAttribute("user", user);
return "/user/userView";
}
}
클라이언트가 HTTP요청을 하면 그 요청을 담당하는 Controller를 찾고 그 Controller가 담당해서 응답한다.
MVC패턴의 Model에 해당하는 부분.
DB 테이블과 직접 매핑되는 클래스. JPA 사용 시 Annotation을 이용하여 테이블, 필드 등을 설정한다. 또한 도메인과 클라이언트를 직접 연동하지 않기 위해 DTO를 분리하는데 이유는 아래와 같다
예
@Entity
@Getter
@NoArgsConstructor
public class Board{
// id, 제목, 작성자명, 작성 날짜, 비밀번호, 내용
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY) // insert에 pk가 빠지고 데이터베이스의 auto_increment 동작이 수행
private Long id;
@Column(nullable = false)
private String title;
@Column(nullable = false)
private String userName;
@Column(nullable = false)
private String password;
@Column(nullable = false)
private String content;
@Builder
public Board(String title, String userName, String password, String content) {
this.title = title;
this.userName = userName;
this.password = password;
this.content = content;
}
}
Data Transfer Object. "데이터 전송 객체"
Domain은 DB테이블에 대한 정보를 모두 가지고 있는 클래스이고, DTO는 CRUD를 위한 특정 필드를 담은 데이터 전송을 위한 객체라고 보면 된다. Controller, Service, Repository사이에서 사용
예시
@Getter
@NoArgsConstructor
public class BoardDTO{
private Long id;
private String title;
private String userName;
private String password;
private String content;
private LocalDateTime createdAt;
private LocalDateTime modifiedAt;
@Builder
public BoardDTO(Long id, String title, String userName, String password, String content, LocalDateTime createdAt, LocalDateTime modifiedAt) {
this.id = id;
this.title = title;
this.userName = userName;
this.password = password;
this.content = content;
this.createdAt = createdAt;
this.modifiedAt = modifiedAt;
}
public Board build(){
return Board.builder()
.id(id)
.title(title)
.userName(userName)
.password(password)
.content(content)
.build();
}
}
// 게시글 저장
@Service
@Transactional
public class BoardService{
public BoardDTO save(BoardDTO boardDTO) {
boardRepo.save(boardDTO.build());
return boardDTO;
}
}
위 처럼 요청에 필요한 필드만 담아서 생성한다.
DB에 접근하는 소스코드를 모아둔 인터페이스.JpaRepository interface를 상속받아서 관리하고자 하는 클래스, ID 필드 타입을 JpaRepository<Entity Class, PK type>
같이 넣어주면 자동으로 DB와 CRUD 연결을 할 수 있는 메소드를 생성해준다.
ublic interface BoardRepository extends JpaRepository<Member, Long> {
}
Repository와 DTO를 통한 CRUD나 예외처리 등 로직을 담당한다.
public Long delete(Long id, String password) {
if(boardRepo.findByIdAndPassword(id, password).isPresent()){
boardRepo.deleteById(id);
return id;
} else {
return null;
}
}
위 코드는 게시글을 삭제할 때 비밀번호를 입력받아 일치하는 경우 삭제시키는 로직이다. 이처럼 비밀번호를 입력하는 상황을 짜야하는(로직)이 필요한 경우 Service에서 작성한다.