포스팅의 목차는 다음과 같다.
1. 수행 행동 정리
2. Front Controller 생성
3. interface생성
4. contorller생성
5. HandlerMapping생성
6.ViewResolver생성
7. 초기화
1. 수행 행동 정리
MVC패턴을 적용하여 페이지를 구현함에 앞서 생성해야할 클래스와 내용들을 정리해보았다.
1) Front Controller(이하 DS)에서 요청을 모아다가 HandlerMapping(이하 HM)클래스한테 물어봄
2) HandlerMapping클래스 생성 : 어떤 요청처리 로직을 가진 클래스(Action클래스)가 필요한지 찾아주는 클래스
-> 각 로직클래스의 초기화를 스프링 컨테이너가 해줄 수 있도록 함
-> new어쩌구 액션을 서블릿에서 개발자가 직접 하지 않을 수 있도록 하기 위함-> 스프링 컨테이너가 함
3) HandlerMapping이 00컨트롤러(어쩌구Action의 역할) 써! 라고 알려주면 DS가 해당 컨트롤러(로직 클래스)를 씀
4) 불려온 controller가 DS한테 어디로 갈지까지 알려줌
5) DS가 그런 경로를 View Resolver에게 전달하면, 이 친구가 이제 다음 실행될 jsp경로를 생성하고 이동 시켜줌
2. Front Controller(DS) 생성
controller의 역할을 수행하기 위해 생성되는 클래스들을 패키지에 분리하여 보관
Dispatcher Servlet이라는 이름의 서블릿 파일을 생성(어노테이션의 설정을 *.do로 해야한다)하게 되면, 처음에 web.xml파일 내의 내용을 지웠음에도 서블릿 파일 생성과 동시에 설정 정보를 포함하는 내용이 자동으로 작성되는 것을 확인할 수 있다. 이때 해당 파일에서 url패턴에 대한 설정을 이미 자동으로 마쳤기 때문에 서블릿 파일에서 어노테이션이 확인되지 않는다.
생성된 DS파일을 아래와 같이 가공한다.
package com.test.app.controller;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
// DS는 FC의 역할을 한다.
public class DispatcherServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
// 기본 생성자
public DispatcherServlet() {
super();
}
// 기존 메서드
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doAction(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doAction(request, response);
}
// 새로 만든 메서드
protected void doAction(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 1. 사용자의 요청을 추출
String uri=request.getRequestURI();
String command=uri.substring(uri.lastIndexOf("/"));
System.out.println(command);
//2. 요청을 분기처리
if(command.equals("/login.do")) {
System.out.println("FC: 로그인 요청");
}else if(command.equals("/search.do")) {
System.out.println("FC: 검색 요청");
}else if(command.equals("/logout.do")) {
System.out.println("FC: 로그아웃 요청");
}else if(command.equals("/insertBoard.do")) {
System.out.println("FC: 게시글 등록 요청");
}else if(command.equals("/main.do")) {
System.out.println("FC: 메인페이지 이동 요청");
}else if(command.equals("/updateBoard.do")) {
System.out.println("FC: 게시글 수정 요청");
}else if(command.equals("/deleteBoard.do")) {
System.out.println("FC: 게시글 삭제 요청");
}else if(command.equals("/board.do")) {
System.out.println("FC: 게시글 상세보기 요청");
}
}
}
* xml에서 하는 장점 : 한 페이지에서 모두 볼 수 있다 / 단점 : 태그 언어가 낯설어 설정이 복잡해지면 분석이 어렵다 *
* @의 장점 : 파악이 되게 쉽다 / 단점 : 어디 달렸는지 일일이 달린 파일을 확인해보아야하니까 분석이 불리하다. *
- 서블릿 페이지에서 모든 요청을 처리한다.
- 이때 Action 클래스들을 설계해서, 요청을 처리하는 로직을 서블릿 페이지로부터 분리해야한다.
3. interface생성
모든 controller파일에서 사용될 메서드들 강제하기 위한 목적으로 interface를 생성한다.
package com.test.app.controller;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
// Action의 역할 : controller
public interface Controller {
// ActionForward의 역할 : String(경로) -> viewResolver한테 전달하면 알아서 방식을 이해하고 전송
// execute의 역할 : handelRequest
String handleRequest(HttpServletRequest req, HttpServletResponse res);
}
output으로는 경로와 방식을 지정해주어야한다.
이때 viewResolver가 어떻게 보내야하는지를 이해할 능력이 있기 때문에, 경로만 output으로 주면 되므로 output은 문자열로 설정한다.
4. 각 contorller생성
위에서 생성한 interface를 implements한다.
스프링 자체제공 클래스와 직접 생성한 클래스 중 선택이 가능한데, 직접 생성한 클래스로 임폴트 한다.
요청처리 로직을 담을 클래스들은 별도 패키지에 보관한다.
코드의 첨부이다. 경로만을 반환해주면 된다.
package com.test.app.controller.member;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.test.app.controller.Controller;
import com.test.app.member.MemberVO;
import com.test.app.member.impl.MemberDAO;
public class LoginController implements Controller{
@Override
public String handleRequest(HttpServletRequest req, HttpServletResponse res) {
// 1. 사용자의 입력 가져옴
String id=req.getParameter("id");
String password=req.getParameter("password");
// 2. VO->dao == DB연동
MemberVO vo=new MemberVO();
vo.setId(id);
vo.setPassword(password);
MemberDAO dao=new MemberDAO();
vo=dao.getMember(vo);
// 3. 결과화면으로 이동
if(vo==null) {
return "login";//경로를 반환
}else {
// session.setAttribute("member", vo);
return "main.do";
}
}
}
5. HandlerMapping생성
- 해당 클래스는 DS가 경로를 요청하면 controller류를 반환하는 역할을 한다.
- 입력에 따른 컨트롤러를 map을 활용하여 한 세트로 묶어준다. (경로, controller)
- map에 값 세팅 진행!
- 이때 객체가 멤버변수이기 때문에 new를 해주어야한다.
- 생성자를 통해 객체화 후 값 세팅
package com.test.app.controller;
import java.util.HashMap;
import java.util.Map;
import com.test.app.controller.member.LoginController;
// 어떤 요청처리 로직을 가진 클래스(controller류)를 반환해야하는지 알려주는 클래스
public class HandlerMapping {
// 객체가 멤버변수이므로 초기화(new)해야함
private Map<String, Controller> mappings;
// 생성자를 활용하여 멤버변수 초기화와 map에 값 세팅
public HandlerMapping() {
mappings=new HashMap<String, Controller>();
mappings.put("/login.do", new LoginController());
//아래로 각 경로들에 대한 초기화 진행
}
public Controller getController(String path) {
return mappings.get(path);
}
}
6.ViewResolver생성
- 해당 클래스의 핵심 기술은 경로를 만들어주는 것이다.
- 각 controller류(요청처리 로직)가 어떤 view로 이동해야하는지 반환하는데, 그 반환값이 getView메서드의 input이다.
- getView의 output은 다음 실행될 jsp이름이다.(멤버변수를 통해 알아서 가공됨)
package com.test.app.controller;
// 스프링 프레임워크에서 제공되는 툴에 맞춰 작성
public class ViewResolver {
private String prefix;
private String suffix;
public String getPrefix() {
return prefix;
}
public void setPrefix(String prefix) {
this.prefix = prefix;
}
public String getSuffix() {
return suffix;
}
public void setSuffix(String suffix) {
this.suffix = suffix;
}
// 핵심 기능
public String getView(String viewName) {
return prefix + viewName + suffix; //알아서 경로를 완성해줌"/main.jsp"이런 식
}
}
7. 초기화
위에서 생성한 각 클래스들(DS, C여러개, HM, VR)을 사용하기 위해서는 초기화가 필수로 진행되어야한다.
DS를 축으로 두고(먼저 존재하고) 그 내부에서 HM, VR의 메서드를 수행한다는 것을 보아 즉, 의존관계임을 추측할 수 있다. 이는 즉, DI를 해야한다는 의미가 된다.
DS가 먼저 초기화, 이후 HM, VR등이 초기화(DI작업)된다. 진행 방법은 다양하나, HM은 생성자가 있기 때문에 생성자주입, VR은 setter가 있으므로 setter주입 방식으로 초기화 하는 것이 용이한 방법이다.
해당 내용에 따라 생성되었던 DS의 코드를 변경하면 다음과 같다.
package com.ham.app.controller;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.ham.app.controller.HandlerMapping;
import com.ham.app.controller.ViewResolver;
public class DispatcherServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
// 의존성 주입
private HandlerMapping handlerMapping;
private ViewResolver viewResolver;
// 두 클래스는 스프링상에서 init을 통해 초기화됨
public void init() {
handlerMapping=new HandlerMapping();// 기본생성자가 호출되며 controller류가 전부 초기화
viewResolver=new ViewResolver(); // 기본생성자가 작성되어있지 않아 각 setter들을 set해주어야한다.
viewResolver.setPrefix("./");
viewResolver.setSuffix(".jsp");
}
public DispatcherServlet() {
super();
// TODO Auto-generated constructor stub
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doAction(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doAction(request, response);
}
private void doAction(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 1. 사용자의 요청을 추출
String uri=request.getRequestURI();
String command=uri.substring(uri.lastIndexOf("/"));
// 2. 요청을 분기처리 ! 싱글톤 패턴을 유지할 수 있으며, 가독성이 향상된다.
// 사용자의 요청사항을 받아다가 HM가서 처리 해줄 Controller누군지 알아옴
// 다양한 컨트롤러들을 하나의 이름으로 받아줄 수 있는 상위 개념의 ctrl!
Controller ctrl=handlerMapping.getController(command);
// 해당 요청을 처리해 줄 컨트롤러가 로직을 수행하고, 경로를 가져옴
String viewName=ctrl.handleRequest(request, response);
// .do가 아니야? 그럼 너 로직 수행 되었겠네!
// 성의없이 준 경로에 .jsp를 붙여주자
if(!viewName.contains(".do")) {
viewName=viewResolver.getViewName(viewName);
}
// 다 됐으면 이제 이동해!
response.sendRedirect(viewName);
}
}
오늘 포스팅의 내용을 총 정리하면 다음과 같다.
1) 클라이언트가 login.do요청하면
2) .do라서 DS가 받음
3) DS는 HM을 통해 controller객체를 반환받는다.(loginController을 반환)
4) 반환된 loginController가 handleRequest()메서드를 호출한다. (경로:String을 반환)
5) DS는 VR를 통해 .jsp를 붙이거나 다음 이동할 페이지를 생성하고 보낸다.
'Spring' 카테고리의 다른 글
[IoC] XML파일 @로 바꾸기 : Controller_2 (0) | 2022.04.01 |
---|---|
[IoC] MVC패턴 이해 실습_2 : Spring제공 클래스 사용 (0) | 2022.03.31 |
[IoC] 스프링, DB연동_service (0) | 2022.03.29 |
[IoC] 의존성 주입과 어노테이션 (0) | 2022.03.29 |
[개요] 설치와 Spring Framwork의 이해 (0) | 2022.03.28 |