티스토리 뷰
MVC모델 쓰는 이유
1.분업
2.소스코드 간결화 > 모듈화
모듈 : 부품
각각의 목적에 맞게끔 클래스를 만들어서 분리를 하자
수직관계로 분리 > 티어(Tier)
3-tier
스프링 프로젝트는 3-tier 방식으로 구성한다.
[Presentation Tier - 화면 계층]
화면에 보여주는 기술을 사용하는 영역.
컨트롤러에서 사용자의 요청에 맞는 응답처리를 진행하며, HTML엔진(Thymeleaf), HTML등이 담당하는 영역이다.
화면 구성이 이에 속한다.
[Business Tier - 비지니스 계층]
순수한 비지니스 로직을 담고 있는 영역.
고객이 원하는 요구사항을 반영하는 계층이기 때문에 서비스에 있어서 가장 중요한 영역이다.
이 영역의 설계는 고객의 요구 사항과 정확히 일치해야 하며, 서비스 영역이다.
[Persistence Tier - 영속 계층 혹은 데이터 계층]
데이터를 어떤 방식으로 보관하고, 사용하는 가에 대한 설계가 들어가는 계층.
일반적으로 DBMS를 많이 이용하지만, 상황에 따라서 네트워크 호출 혹은 원격 호출 등의 기술이 접목될 수 있다.
각 영역은 독립적으로 설계되어 나중에 특정한 기술이 변하더라도 필요한 부분을 전자제품의 부품처럼
쉽게 교환할 수 있게 하자는 방식이다. 각 연결 부위는 인터페이스를 이용해서 설계하는 것이 일반적인 구성 방식이다.
Persentation ↔ Business ↔ Persistence ↔ DBMS
↑ ↑ ↑
Controller Service(I) Mapper(I)
Persistence티어에서 핵심적인 역할을 하는 프레임워크 : MyBatis
mapper.xml 에 쿼리를 작성
mapper.java 인터페이스와 연결 >> 통로
DBMS 데이터들을 Mapper 인터페이스를 사용해서 자바쪽으로 가져올 수 있다.
매퍼와 다오가 Persistence 티어에 속한다.
다오는 디비조회만 해야 함.
Persistence티어에는 매퍼인터페이스로 연결되어있어서 매퍼를 다오로 바꿔줘야 함.
매퍼를 바로 쓰면 안됨. 한번 더 자바스럽게 정제를 해주는 것이 다오!
다오에서 매퍼를 쓰는 것임. 다오는 자바스럽게 바뀜. reigster, find, save ...
DAO를 바로 Business에서 쓰지 않음.
주로 실무에서 Service를 인터페이스로 만듦.
ex.결제 서비스가 한군데에서만 일어나지 않기 때문.
인터페이스의 특징 1. 강제성 2. 재사용성
결제하는 방식이 페이지마다 다를테니 구현체를 만들지 않고 인터페이스로 만든 다음,
필요한 서비스 지정받아 직접 만든 다음에 거기서 구현을 한다.
포인트, 돈 등 각각 접근하는 테이블이 달라짐. 미리 구현체를 만들어놓을 수가 없음. 상황에 따라서 구현을 따로 해야 함.
대신 틀은 똑같으니 결제 서비스를 만들어놓고, 결제 메소드를 지정받은 클래스에서
원하는 대로 알맞는 디비를 다오로 접근하는 것임.
비지니스 계층
프레젠테이션 계층과 영속 계층의 중간 다리 역할을 한다.
영속 계층은 DBMS를 기준으로, 비지니스 계층은 로직을 기준으로 처리한다.
예를 들어 쇼핑몰에서 상품 구매 시 포인트 적립을 한다고 가정한다면,
영속 계층의 설계는 '상품', '회원'으로 나누어 설계하지만 비지니스 계층은
상품 영역과 회원 영역을 동시에 사용해서 하나의 로직을 처리하게 된다.
이 때 하나의 서비스에 필요한 여러 개의 쿼리 메소드를 하나로 묶어주는 역할이 필요한데,
이를 Service 객체로 사용한다.
서비스는 지정받아 구현된 구현체가 여러개가 있음.
구현체가 비지니스의 컨트롤러에 쓰이는 것임.
컨트롤러에서는 서비스를 주입받음.
서비스는 여러 구현체가 있다 = 자식이 여러개가 있다 > @Qualifier(퀄리파이어)를 사용해서
정확하게 내가 원하는 것을 호출한다.
패러다임의 불일치
RDBMS의 패러다임: 두 테이블에 연관관계를 맺을 때 PK 하나로 양방향 간의 조회가 가능하다.
↕
OOP(객체지향)의 패러다임: 양방향의 조회를 하기 위해서는 다른 방법을 써야 한다.
=> 문법이 서로 달라서 일치할 수가 없다. 불일치하는 것을 일치시키기 위해서 탄생한 것이 JPA이다.
스프링은 단위테스트가 있기 때문에 WAS에 종속적이지 않다.
단위테스트에서 메소드를 썼을 때 해당 쿼리가 나오고, 결과값이 나오는지만 확인하면 됨.
단위별로 티어별로 확인을 하고 넘어가야 나중에 복잡한 오류를 해결할 일이 없다.
오류가 점점 간소화되는 것임. 오류가 생기면 못 넘어가니까 꼬이는 상황이 줄어듬.
자바 폴더와 동일하게 TEST 자바 폴더에서 만들어서 클래스 이름 뒤에 Test를 붙인다.
@SpringBootTest
@Slf4j > log출력할 수 있게 해줌
클래스 위에 어노테이션 붙이기
클래스 안에는 스프링(프록시)으로 구현한 인터페이스가 들어옴.
인터페이스일지라도 @Autowired 주입이 가능함.
@Test
메소드 단위테스트 진행 > 옆에 초록색화살표 클릭!
SPY라이브러리를 통해 눈으로 발생된 쿼리를 볼 수 있다.
Assertions.assertNotNull();
Assertions : 제유닛(junit)이라는 단위테스트에서 제공하는 라이브러리
assertNotNull(), equal() ... 여러 가지를 비교할 수 있음.
오류가 발생했을 때 설명을 너무 잘 해줘서 단위테스트 때 많이 사용함.
@Repository >> DAO를 스프링에 알려주는 어노테이션!
@RequiredArgsConstructor >> 매퍼를 사용해야 하니까 생성자 주입!
public class DAO{
private final Mapper mapper; >> final을 써줘야 생성자로 들어가서 초기화가 된다.
Mapper에 있는 것을 그대로 써주되,
메소드 이름을 바꿔주기
}
=> 자바스럽게 만들기 위해서 중간에 필터를 만들어준다!
PK로 조회할 땐 메소드 이름뒤에 ById를 붙인다.
@Service
public interface Service{
일반인이 봐도 이해할만한 이름으로 메소드명 변경하기
}
=> interface 매퍼에서는 스프링이 구현해줬지만(프록시 주입X), 서비스에서는 우리가 직접 구현해줌. 구현체를 우리가 만듦.
서비스에 어떤 쿼리가 날라가야 할 지 우리가 알기 때문에
인터페이스를 지정받아서 클래스를 직접 만들어줘야 함.
인터페이스로 한 이유? 1.강제성 2.재사용
지정받은 구현 클래스에도 @Service 붙여주기
@Service
@RequiredArgsConstructor >> 생성자 주입
public class Service implements Service{
private final DAO dao; >> final 왜 쓰냐? 수정막기 위해서. 스프링에서 주입받은 애가 달라지면 안 된다.
}
지정받아 구현한 클래스 중에 디폴트 클래스에 어노테이션 붙이기
@Qualifier("community") @Primary
ServiceTest에서 주입 요청은 인터페이스로 받고, 거기에 구현된 클래스가 주입될 것임.
controller 패키지명을 web이라고 하기도 함. 회사마다 다름.
→ |
디폴트 클래스 안받으려면 직접 써야함. 디폴트된 구현체 받는 거면 안 써도 됨.
@Autowired는 생성자 위에 ! >> @RequiredArgsConstructor 를 붙이면 @Autowired는 지워도 된다.
@Qualifier("")는 해당 객체 위에 !
@RequestMapping("경로")는 클래스 위에 !
@GetMapping("경로"), @PostMapping("경로")는 메소드 위에 !
화면으로 메소드를 전달하기 위해서는 데이터 전달자가 필요함.
데이터 전달자 => Model
//게시글 목록
@GetMapping("/list")
public void list(Model model){
model.addAttribute("boards", boardService.show());
}
전송방식 forward / redirect
화면으로 이동할 때는 문제가 없는데
컨트롤러에서 컨트롤러로 이동하면 기존에 받았던 데이터 때문에 꼬일 수가 있음.
그래서 중간에 request 초기화를 하고 가는 것임.
redirect 방식은 컨트롤러로 이동할 때 사용한다. 무조건!
방법1(선호). return new RedirectView("url");
방법2. return "redirect: url";
model 객체가 request scope 사용.
redirect 방식일 때 파라미터 전달 방법 2가지
방법1. | 쿼리스트링 | request에 담으면 초기화가 되는데 param scope는 전달된다. 컨트롤러에서 사용. |
controller -> controller -> html param은 다음 컨트롤러에서 쓸 수 있다. |
||
redirectAttributes.addAttribute( , )는 알아서 경로 뒤에 쿼리스트링을 만들어준다. | ||
다른 컨트롤러로 이동할 때에는 쿼리스트링으로 전달해야 한다. | ||
방법2. | session에 담기 | 컨트롤러로 안가고 마지막 최종 화면으로 간다. |
controller -> controller -> html 무조건 화면에서만 쓸 수 있다. |
||
redirectAttributes.addFlashAttribute( , )는 컨트롤러에 도착하지 않고 화면에서만 사용 가능하다. | ||
session에 flash영역을 빌린다. req객체를 session flash에 담아놨다가 초기화된 다음에 session flash에 있던 것을 다시 req에 주입해주는 방식. flash는 응답이 끝나면 자동으로 비워진다. |
||
화면에서만 사용할 때에는 Flash 영역을 사용하여 전달해야 한다. |
두 가지 방법을 모두 제공해주는 객체가 있다. => RedirectAttributes
Model 객체는 forward방식으로 전달할 때 사용(model.addAttribute( , ))
RedirectAttributes 객체는 redirect방식으로 전달할 때 사용
- 쿼리(redirectAttributes.addAttribute( , ))
- 세션(redirectAttributes.addFlashAttribute( , ))
테스트 할 때, 가짜 WAS를 직접 만들어준다.
WAS가 관리하는 webApplicationContext 객체를 우리가 직접 따와서 마치 WAS의 환경인 것처럼 java로 구현할 것임.
경로를 메소드에 전달하면 콘솔창에서 요청,응답이 됨. 그래서 WAS 없이도 돌아감.
단위테스트가 모두 통과가 되면, 화면으로 옮기고, url을 브라우저에 치면 끝!!
컨트롤러 단위테스트 할 때,
'2022 > spring boot' 카테고리의 다른 글
IntelliJ +new project (0) | 2022.11.04 |
---|---|
Favicon (0) | 2022.11.04 |
day03[day02복습] (0) | 2022.11.03 |
day02[spring MVC1] (0) | 2022.11.03 |
day02[Proxy(프록시)] (0) | 2022.11.03 |