1) 브라우저(Client, 사용자)에서 서버로 요청
- request(※jsp의 내장객체 request가 아님. 그냥 키워드)
2) .do로 요청이 왔으니 DispatcherServlet 서블릿을 생성해야함
- 의존주입(DI)를 필요로함
- 스프링에서 기본제공하는 DispatcherServlet을 사용중
- DispatcherServlet-servlet.xml을 참고하여 DI해줌
- 스프링컨테이너가 구동됨
- 프레젠테이션 레이어 (그냥 컨트롤러 파트 : .do로 요청이 와서 DispatcherServlet을 생성 하고 의존주입 하는 부분 )
3) 요청에 맞는 Controller 객체를 호출하여 사용
- C, DAO, VO, Model ...
- Command 객체
※ 1) 서버에서는 DBMS 변경이 자주 발생함; DBMS가 가장 많이 바뀜; 조금이라도 싸면 그쪽으로 넘어감
즉, DAO 변경 이 자주 발생함
DAO를 직접 이용하고 있으므로, ★결합도★가 높아서 유지보수가 불리함 (뭔가 객체를 직접 이용하면 ★결합도★가 높아짐)
다른 DAO로의 변경이 매우 불리한 상태
※ 2) AOP 적용이 불가능한 상태
AOP : xxxService 류에만 호출가능함
( AOP를 사용하면 로그, 보안, 권한확인, ... 등을 자동호출할수있음 )
( 위의 코드를 별도로 분리해서 관리 할 수 있기때문에 응집도가 높아짐 )
( 유지보수 유리)
매번 로그, 보안, 권한확인, ... 등을 직접 처리해야하므로 응집도가 낮음
유지보수 불리한 상태
package com.spring.biz.board;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
//메모리에로딩한다
@Service("boardService")
public class BoardServiceImpl implements BoardService {
// Service 레이어가 관념적으로 존재하는데, 그것을 구현한 클래스
// Service 레이어에서는 DAO를 사용함
// == C 파트
// : DAO를 사용할것이기때문에
// DAO와 메서드 시그니처를 맞추면 유리함
// 아~~ 메서드 시그니처를 강제하고싶다!
// => 인터페이스
@Autowired //의존주입
private BoardDAO boardDAO;
// 의존관계 -> DI
@Override
public BoardVO selectOne(BoardVO bVO) {
return boardDAO.selectOne(bVO);
}
@Override
public List<BoardVO> selectAll(BoardVO bVO) {
return boardDAO.selectAll(bVO);
}
@Override
public boolean insert(BoardVO bVO) {
return boardDAO.insert(bVO);
}
@Override
public boolean update(BoardVO bVO) {
return boardDAO.update(bVO);
}
@Override
public boolean delete(BoardVO bVO) {
return boardDAO.delete(bVO);
}
}
package com.spring.view.controller;
import java.util.HashMap;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import com.spring.biz.board.BoardService;
import com.spring.biz.board.BoardVO;
import com.spring.biz.member.MemberVO;
@Controller
public class BoardController {
@Autowired
private BoardService boardService;
@ModelAttribute("searchMap")
public Map<String,String> searchMap(){
Map<String,String> map=new HashMap<String,String>();
map.put("제목", "TITLE");
map.put("작성자", "WRITER");
return map;
}
@RequestMapping(value="/main.do")
public String main(@ModelAttribute("mem")MemberVO mVO, BoardVO bVO, Model model) {
System.out.println("searchCondition: "+bVO.getSearchCondition());
System.out.println("searchContent: "+bVO.getSearchContent());
mVO.setMid("test");
mVO.setMpw("1234");
System.out.println("MainController 로그");
// model.addAttribute("mem", mVO);
model.addAttribute("datas", boardService.selectAll(bVO));
return "main.jsp";
}
//HandlerMapping이라 web.xml에서 .do 해서 여기로 옴
@RequestMapping(value="/board.do")
public String selectBoard(BoardVO bVO, Model model) {
System.out.println("BoardController 로그");
model.addAttribute("data", boardService.selectOne(bVO));
boardService.update(bVO);
return "board.jsp";
}
@RequestMapping(value="/updateBoard.do")
public String updateBoard(BoardVO bVO) {
System.out.println("BoardController 로그");
boardService.update(bVO);
return "board.do";
}
@RequestMapping(value="/deleteBoard.do")
public String deleteBoard(BoardVO bVO) {
System.out.println("BoardController 로그");
if(boardService.delete(bVO)){
return "redirect:main.do";
}
else{
return "board.do";
}
}
@RequestMapping(value="/insertBoard.do", method=RequestMethod.GET)
public String insertBoardPage() {
System.out.println("InsertBoardPageController 로그");
return "redirect:insertBoard.jsp";
}
@RequestMapping(value="/insertBoard.do", method=RequestMethod.POST)
public String insertBoard(BoardVO bVO) {
System.out.println("InsertBoardController 로그");
if(boardService.insert(bVO)){
return "redirect:main.do";
}
else{
return "redirect:insertBoard.jsp";
}
}
}
1) C의 메서드 인자로 존재하던 DAO를 제거
2) DAO를 대신 사용해줄 Service를 멤버변수로 추가
DAO의 메서드와 Service의 메서드는 동일
똑같이 BoardDAO사용하고 있어서 MainController랑 InsertBoardController에 있는 메서드를 가져다 BoardController로 줌
통합이 가능해짐
(Service가 DAO를 대신 사용하는것이기 때문에)
(DAO를 안쓰는것은 아님)
3) 이제는 DAO가 자주 변경되더라도 Service 내부의 멤버변수만 변경하면 됨
- 결합도가 낮아지므로 유지보수가 유리함
4) 멤버변수로 추가한 Service가 메서드 수행 주체로써 사용됨
- 의존관계임
- 의존주입(DI)해야함
- 그래서 @Autowired 써야함
5) BeanCreationException 발생!
BoardController를 못만든다고합니다...ㅠㅠ
boardService를 메모리에서 찾을수가 없어서...ㅠㅠ
어노테이션 Autowired및 Component다 붙어있는데 못만들어요
boardService가 메모리에 없다는건
@Service가 Component임 얘가 new임; 얘가 안됬다는거
6) boardService가 메모리에 없다는건 @Service가 동작하지 않았다는거. applicationContext에서 component scan의 영역이 아니였다는것
우리는 DispatcherServlet-servlet.xml을 쓰고 있는데 여기서 component-scan을 한적이 없다 !
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd">
<context:component-scan base-package="com.spring.biz" />
</beans>
7) applicationContext.xml에서 미리 DAO, Service 류의 객체들을 생성하고,
web.xml로 DispatcherServlet 생성하고,
DispatcherServlet.xml로 Controller를 호출할수있게 할 예정!!
8) applicationContext.xml을 추가; DAO랑 Service류를 미리 new 해주려고 추가
스프링 컨테이너 추가 한다는걸 (루트컨테이너라고도함) (DS도 스프링컨테이너임)
비즈니스(서비스) 레이어를 추가한다고 함
9) 루트 컨테이너로써 "서버가 시작될때" applicationContext.xml을 구동시켰으면 좋겠다!
서버 시작을 감지(모니터링)
서블릿을 상속받은 리스너(not pojo) --->> new IoC => web.xml
서블릿류는 죄다 web.xml에다 쓰는겁니다
<listener>도 스프링에서 제공하는 걸 쓸거임
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee https://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<servlet> <!-- bean역할; 이 순간부터 DS.xml이 있어야 함; 그래야 웹이 동작 -->
<servlet-name>DispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>DispatcherServlet</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
<filter>
<filter-name>characterEncoding</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>characterEncoding</filter-name>
<url-pattern>*.do</url-pattern>
</filter-mapping>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
</web-app>
결론 : 루트 컨테이너(applicationContext.xml, 스프링 컨테이너, 비즈니스 레이어)가 객체들을 메모리에 new
서블릿 컨테이너(web.xml)가 DispatcherServlet을 메모리에 new
스프링 컨테이너(DS-servlet.xml,프레젠테이션 레이어)가 Controller를 호출하여 요청 처리 함
==>> 2-Layered 아키텍쳐 스타일
.do요청 -> web.xml이 반응(서블릿 컨테이너)
web.xml이 동작을 하려면 web.xml이라는 서블릿컨테이너의 객체인 DispatcherServlet이 생성(new)되어야 함
-> DispatcherServlet 서블릿을 new해라!
DS를 new하려면 DS-servlet.xml이 필요하다고함...
-> 그래서 만들었음
-> DS 내부에 HM,C,VR,... POJO들을 new해야함
.do->C String->VIEW
(DS내부에 있는 HandlerMapping, Controller, ViewResolver 모두 사용할거임)
-> 그러면 스프링 컨테이너가 필요함 (일반 POJO(HM,C,VR)를 new하니깐)
C가 DAO를 직접사용중
Service를 끼워서 쓰려면??
DAO,Service를 미리 new를 했었어야함
"서버가 시작될때"
서버시작을 감지==리스너 (리스너는서블릿임)
web.xml에 등록
DAO,Service가 POJO니까 새로운 xxx.xml이 필요 (서블릿컨테이너로 못함)
applicationContext.xml(루트 스프링 컨테이너)
컨테이너 == 객체생성의 주체
new를 개발자대신 해줌
IoC
※HM과 VR은 태그로 해도 되고 어노테이션으로 해도 되고
※HM : 요청에대해 알맞는 C반환; 어떤 .do가 어떤 C인지 처리매핑
※VR : 보여주는 역할
※1 xml : 1 컨테이너
※서블릿 컨테이너 : 톰캣
※DS는 서블릿 컨테이너의 객체
리스너는 서블릿이니까 web.xml