[프론트 컨트롤러 패턴]
프론트 컨트롤러 : 그냥 서블릿. 클라이언트의 요청을 받고 요청에 맞는 컨트롤러 찾아서 호출
나머지 컨트롤러는 서블릿을 사용하지 않아도됨- 왜냐면 클라이언트에서 요청이 오면 와스서버에서 처음 들어간 데가 서블릿인데 그거를 프론트 컨트롤러라 대신 해주니까. 서블릿을 통해서 요청 매핑을 했는데 프론트 컨트롤러가 해주니까(서블릿은 url매핑해서 요청이 오면 서블릿에 처음응로 들어가는곳 )
[프론트컨트롤러 도입-v1]
1. 클라이언트가 http요청을 하면 (컨트롤러 맵을 통해서 어떤 컨트롤러가 호출되는지 찾아)프론트 컨트롤러가 요청을 받고 http매핑 정보를 가지고 컨트롤러를 매핑정보에 넣어놔. 그래서 요청이 오면 매핑 정보를 뒤져서
2. 어떤 컨트롤러를 호출할지 찾아서 호출
3.컨트롤러는 자기 로직 수행하고 jsp호출 하고 응답
[프론트컨트롤러 도입]
<Controllerv1> - 인터페이스로 해서 구현을 여러개(저장,리스트~).
public interface ControllerV1 {
void process(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException;
}
<MemberFormControllerV1> - 회원등록 컨트롤러 (Controllerv1를 구현)
public class MemberformControllerV1 implements ControllerV1{
@Override
public void process(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String viewPath="/WEB-INF/views/new-form.jsp";
RequestDispatcher dispatcher=req.getRequestDispatcher(viewPath); //controller에서 view로 이동
dispatcher.forward(req,resp);
}
}
<MemberSaveControllerV1> - 회원 저장 컨트롤러
public class MemberSaveControllerV1 implements ControllerV1{
private MemberRepository memberRepository = MemberRepository.getInstance();
@Override
public void process(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String username = req.getParameter("username");
int age = Integer.parseInt(req.getParameter("age"));
Member member = new Member(username, age);
System.out.println("member = " + member);
memberRepository.save(member);
//Model에 데이터를 보관한다.
req.setAttribute("member", member);
String viewPath = "/WEB-INF/views/save-result.jsp";
RequestDispatcher dispatcher = req.getRequestDispatcher(viewPath);
dispatcher.forward(req, resp);
}
}
<MemberListControllerV1> -회원목록 컨트롤러
public class MemberListControllerV1 implements ControllerV1 {
private MemberRepository memberRepository = MemberRepository.getInstance();
@Override
public void process(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("MvcMemberListServlet.service");
List<Member> members = memberRepository.findAll();
req.setAttribute("members", members);
String viewPath = "/WEB-INF/views/members.jsp";
RequestDispatcher dispatcher = req.getRequestDispatcher(viewPath);
dispatcher.forward(req, resp);
}
}
<FrontControllerServletV1>
@WebServlet(name = "frontControllerServletV1", urlPatterns = "/front-controller/v1/*")
public class FrontControllerServletV1 extends HttpServlet {
//키(url) 값
private Map<String, ControllerV1> controllerMap = new HashMap<>();
public FrontControllerServletV1(){
//얘가 호출되면 애를 꺼내서 써(객체 인스턴스가 반환됨)
controllerMap.put("front-controller/v1/members/new-form",new MemberformControllerV1());
controllerMap.put("front-controller/v1/members/save",new MemberSaveControllerV1());
controllerMap.put("front-controller/v1/members",new MemberListControllerV1());
}
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("FrontControllerServletV1.service");
//front-controller/v1/members->new MemberListControllerV1가 꺼내져
String requestURI = req.getRequestURI(); //주소를 얻어낼 수 있음
//ControllerV1 controller = MemberListControllerV1 다형성
ControllerV1 controller = controllerMap.get(requestURI); //호출되면 그 객체를 반환헤
if (controller == null) {
resp.setStatus(HttpServletResponse.SC_NOT_FOUND); //not found 404error
return;
}
controller.process(req, resp); //인터페이스 호출
}
}
url이 호출되면 v1컨트롤러를 호출해
controllerMap : 매핑정보, 컨트롤러 맵을 통해서 어떤 컨트롤러가 호출되는지 찾아서 호출하고
private Map controllerMap = new HashMap<>(); public FrontControllerServletV1() {
//// 이 키를 넣으면 값이 애가 꺼내져
controllerMap.put("/front-controller/v1/members/new-form", new MemberFormControllerV1());
controllerMap.put("/front-controller/v1/members/save", new MemberSaveControllerV1());
controllerMap.put("/front-controller/v1/members", new MemberListControllerV1());
}
request.getRequestURI() : "/front-controller/v1/members/new-form" 이주소를 얻어낼 수 있어 이 url이 요청 됐으면 new MemberFormControllerV1()); 이 객체 인스턴스가 반환됨
controllerv1 인터페이스에 맞춰서 다 구현~~ : 다형성에 의해(MemberListControllerV1의 부모가 ControllerV1 요거라서) 오버라이드 된 메서드 호출
ControllerV1 controller = controllerMap.get(requestURI) = ControllerV1 controller = new MemberListControllerV1()
[VIew 분리-V2] 화면을 렌더링 하기 위한 MyVIew
모든 컨트롤러에서 뷰로 이동하는 부분에 중복. 별도로 뷰를 처리하는 객체를 만들기
String viewPath = "/WEB-INF/views/new-form.jsp";
RequestDispatcher dispatcher = request.getRequestDispatcher(viewPath);
dispatcher.forward(request, response);
1.클라이언트가 http요청을 하면 프론트컨트롤러가 매핑 정보를 보고 컨트롤러를 찾아와서 컨트롤러 호출
2. 이전에는 그 컨트롤러에서 jsp를 직접 불렀다면 MYView라는 객체를 만들어서 반환하면
3.프론트컨트롤러가 대신 MyView의 render를 호출하면
5.MyView가 jsp를 호출
<MyView>
public class MyView {
private String viewPath; ///WEB-INF/views/new-form.jsp
public MyView(String viewPath) {
this.viewPath = viewPath;
}
//jsp로 이동,view가 동작하도록하는
public void render(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
RequestDispatcher dispatcher = request.getRequestDispatcher(viewPath);
dispatcher.forward(request, response);
}
//View만드는걸 렌더링
public void render(Map<String, Object> model, HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException{
modelToRequestAttribute(model,req);
RequestDispatcher dispatcher = req.getRequestDispatcher(viewPath);
dispatcher.forward(req, resp);
}
private void modelToRequestAttribute(Map<String, Object> model, HttpServletRequest request) {
model.forEach((key, value) -> request.setAttribute(key, value));
}
}
<ControllerV2>
public interface ControllerV2 {
MyView process( HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException;
}
반환을 MyView로!
<MemberFormControllerV2> - 회원등록 폼(중복 제거됨)
public class MemberFormControllerV2 implements ControllerV2 {
@Override
public MyView process(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
return new MyView("/WEB-INF/views/new-form.jsp");
}
}
MyView myView = new MyView("/WEB-INF/views/new-form.jsp") 를 return new MyView("/WEB-INF/views/new-form.jsp")
<MemberSaveControllerV2>
public class MemberSaveControllerV2 implements ControllerV2 {
private MemberRepository memberRepository = MemberRepository.getInstance();
@Override
public MyView process(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String username = req.getParameter("username");
int age = Integer.parseInt(req.getParameter("age"));
Member member = new Member(username, age);
System.out.println("member = " + member);
memberRepository.save(member);
//Model에 데이터를 보관한다.
req.setAttribute("member", member);
String viewPath = "/WEB-INF/views/save-result.jsp";
RequestDispatcher dispatcher = req.getRequestDispatcher(viewPath);
dispatcher.forward(req, resp);
return new MyView("/WEB-INF/views/save-result.jsp");
}
}
<MemberListControllerV2>
public class MemberListControllerV2 implements ControllerV2 {
private MemberRepository memberRepository = MemberRepository.getInstance();
@Override
public MyView process(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
List<Member> members = memberRepository.findAll();
request.setAttribute("members", members);
return new MyView("/WEB-INF/views/members.jsp");
}
}
<FontControllerV2>
@WebServlet(name = "frontControllerServletV2", urlPatterns = "/front-controller/v2/*")
public class FrontControllerServletV2 extends HttpServlet {
private Map<String, ControllerV2> controllerMap = new HashMap<>();
public FrontControllerServletV2() {
controllerMap.put("front-controller/v2/members/new-form",new MemberFormControllerV2());
controllerMap.put("front-controller/v2/members/save",new MemberSaveControllerV2());
controllerMap.put("front-controller/v2/members",new MemberListControllerV2());
}
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("FrontControllerServletV2.service");
//front-controller/v2/members->new MemberListControllerV1가 꺼내져
String requestURI = req.getRequestURI(); //주소를 얻어낼 수 있음
//ControllerV1 controller = MemberListControllerV1 다형성
ControllerV2 controller = controllerMap.get(requestURI); //호출되면 그 객체를 반환헤
if (controller == null) {
resp.setStatus(HttpServletResponse.SC_NOT_FOUND); //not found 404error
return;
}
//반환결과가 /WEB-INF/views/new-form.jsp
MyView view = controller.process(req, resp);
view.render(req, resp);
}
}
반환타입이 MyView면 View로 반환
[Model추가 V3]
컨트롤러 입장에서 HttpServletRequest, HttpServletResponse이 꼭 필요없음.response,request정보가 필요한게 아니라 파라미터 정보가 필요! ->요청 파라미터 정보는 자바의 Map으로 대신 넘기도록(프론트컨트롤러에서 맵으로 바꿔서 컨트롤러에 대신 넘기도록할거임)
그리고
컨트롤러에서 지정하는 뷰 이름에 중복이 있음. -> 컨트롤러는 뷰의 논리 이름(전체 경로가 아닌 그냥 new-form딱 이렇게만)을 반환하고, 실제 물리 위치의 이름은 프론트 컨트롤러에서 처리하도록 단순화할거임. 그러면 향후 뷰의 폴더 위치가 함께 이동해도 프론트 컨트롤러만 고치면됨
1.http요청이 오면 매핑정보를 가져왔고
2.컨트롤러 호출
3.이전에는 view를 반환했지만 이제는 modelview객체를 반환 할거임
4.논리경로를 물리 경로로 바꾸는 걸 viewResolver에서 해결해서 MyView를 반환해줘
6.그리고 렌더를 호출
<ModelView> - 모델에 원하는 데이터를 넣어두면 꺼내서 jsp에서 쓸수 있도록 해줘.
public class ModelView {
private String viewName; //view논리이름에 관한것
private Map<String, Object> model = new HashMap<>(); //model에 관한것
public ModelView(String viewName) {
this.viewName = viewName;
}
public String getViewName() {
return viewName;
}
public void setViewName(String viewName) {
this.viewName = viewName;
}
public Map<String, Object> getModel() {
return model;
}
public void setModel(Map<String, Object> model) {
this.model = model;
}
}
<ControllerV3> - 서블릿에 종속이 아닌 우리가 만든 프레임워크에 종속적
public interface ControllerV3 {
ModelView process(Map<String, String> paramMap); //서블릿에 종속적이지 않음
}
<MemberFormControllerV3> - 전체 path를 넣는게 아닌 논리적인 이름만 넣어
public class MemberFormControllerV3 implements ControllerV3 {
@Override
public ModelView process(Map<String, String> paramMap) {
return new ModelView("new-form");
}
}
<MemberSaveControllerV3>
public class MemberSaveControllerV3 implements ControllerV3 {
private MemberRepository memberRepository = MemberRepository.getInstance();
@Override
public ModelView process(Map<String, String> paramMap) {
String username = paramMap.get("username");
int age = Integer.parseInt(paramMap.get("age"));
Member member = new Member(username, age);
memberRepository.save(member);
ModelView mv = new ModelView("save-result");
mv.getModel().put("member", member);
return mv;
}
}
String username = paramMap.get("username"); //httpServletRequest에서 꺼내는게 아니라,(getparam에서 꺼내는게 아닌) 프론트컨트롤러에서 다 처리하고 맵에다가 요청 parameter다 넣어서 처리해줄거임.
<MemberListControllerV3>
public class MemberListControllerV3 implements ControllerV3 {
private MemberRepository memberRepository = MemberRepository.getInstance();
@Override
public ModelView process(Map<String, String> paramMap) {
List<Member> members = memberRepository.findAll(); //members가져오고
ModelView mv = new ModelView("members");
mv.getModel().put("members", members);
return mv;
}
}
<FrontControllerServletV3>
@WebServlet(name = "frontControllerServletV3", urlPatterns = "/front-controller/v3/*")
public class FrontControllerServletV3 extends HttpServlet {
private Map<String, ControllerV3> controllerMap = new HashMap<>();
public FrontControllerServletV3() {
controllerMap.put("front-controller/v3/members/new-form",new MemberFormControllerV3());
controllerMap.put("front-controller/v3/members/save",new MemberSaveControllerV3());
controllerMap.put("front-controller/v3/members",new MemberListControllerV3());
}
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("FrontControllerServletV3.service");
//front-controller/v2/members->new MemberListControllerV1가 꺼내져
String requestURI = req.getRequestURI(); //주소를 얻어낼 수 있음
//ControllerV1 controller = MemberListControllerV1 다형성
ControllerV3 controller = controllerMap.get(requestURI); //호출되면 그 객체를 반환헤
if (controller == null) {
resp.setStatus(HttpServletResponse.SC_NOT_FOUND); //not found 404error
return;
}
//paramap을 넘겨줘
Map<String, String> paramMap = createParamMap(req);
ModelView mv = controller.process(paramMap);
String viewName = mv.getViewName(); //논리이름 new-form으로 반환
MyView view = viewResolver(viewName);
view.render(mv.getModel(), req, resp);
}
private Map<String, String> createParamMap(HttpServletRequest request) {
Map<String, String> paramMap = new HashMap<>();
request.getParameterNames().asIterator()
.forEachRemaining(paramName -> paramMap.put(paramName,
request.getParameter(paramName)));
return paramMap;
}
private MyView viewResolver(String viewName) {
return new MyView("/WEB-INF/views/" + viewName + ".jsp");
}
}
Map paramMap = createParamMap(request);
ModelView mv = controller.process(paramMap); //이거는 뷰의 논리이름만 아는 것
String viewName = mv.getViewName();
MyView view = viewResolver(viewName);
view.render(mv.getModel(), request, response); }
private Map createParamMap(HttpServletRequest request) {
Map paramMap = new HashMap<>(); //paramMap 만들고
request.getParameterNames().asIterator() //모든 파라미터 이름 다 가져오고
.forEachRemaining(paramName
paramMap.put(paramName, request.getParameter(paramName))); //모든 파라미터 값 다 꺼내오면서 paramMap 에 다 넣어
return paramMap; }
<MyView>에 뷰리졸버 추가
public void render(Map<String, Object> model, HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException{
modelToRequestAttribute(model,req);
RequestDispatcher dispatcher = req.getRequestDispatcher(viewPath);
dispatcher.forward(req, resp);
}
private void modelToRequestAttribute(Map<String, Object> model, HttpServletRequest request) {
model.forEach((key, value) -> request.setAttribute(key, value));
}
render를 호춣하면서 model을 넘겨, model에 담긴 데이터를 꺼내서 request.setAttribute에 다 넣어
정리
localhost:8080/front-controller/v3/members/new-form로 치면 frontControllerServletV3에 들어와서 MemberFormControllerV3()가 호출.
1) 근데 이거 호출 전에 createParaMap(request)를 가지고 파라미터를 가져가서 paraMap을 만들어서 반환
논리이름 반환
[실용적 컨트롤러 V4] -
2.프론트컨트롤러에서 컨트롤러 호출 할때 모델도 같이 넘겨줘
<ControllerV4>
public interface ControllerV4 {
String process(Map<String,String>paramMap,Map<String,Object>model);
}
이전과 다르게 model이 파라미터에 넘어와
<MemberFormControllerV4> modelView를 만들필요가 없음
public class MemberFormControllerV4 implements ControllerV4 {
@Override
public String process(Map<String, String> paramMap, Map<String, Object> model) {
return "new-form";
}
}
<MemberSaveControllerV4>
public class MemberSaveControllerV4 implements ControllerV4 {
private MemberRepository memberRepository = MemberRepository.getInstance();
@Override
public String process(Map<String, String> paramMap, Map<String, Object> model) {
String username = paramMap.get("username");
int age = Integer.parseInt(paramMap.get("age"));
Member member = new Member(username, age);
memberRepository.save(member);
model.put("member",member);
return "save-result";
}
}
<MemberListControllerV4>
public class MemberListControllerV4 implements ControllerV4 {
private MemberRepository memberRepository = MemberRepository.getInstance();
@Override
public String process(Map<String, String> paramMap, Map<String, Object> model) {
List<Member> members = memberRepository.findAll();
model.put("members",members);
return "members";
}
}
<FrontControllerServletV4>
@WebServlet(name = "frontControllerServletV4", urlPatterns = "/front-controller/v4/*")
public class FrontControllerServletV4 extends HttpServlet {
private Map<String, ControllerV4> controllerMap = new HashMap<>();
public FrontControllerServletV4() {
controllerMap.put("front-controller/v4/members/new-form",new MemberFormControllerV4());
controllerMap.put("front-controller/v4/members/save",new MemberSaveControllerV4());
controllerMap.put("front-controller/v4/members",new MemberListControllerV4());
}
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("FrontControllerServletV4.service");
//front-controller/v2/members->new MemberListControllerV1가 꺼내져
String requestURI = req.getRequestURI(); //주소를 얻어낼 수 있음
//ControllerV1 controller = MemberListControllerV1 다형성
ControllerV4 controller = controllerMap.get(requestURI); //호출되면 그 객체를 반환헤
if (controller == null) {
resp.setStatus(HttpServletResponse.SC_NOT_FOUND); //not found 404error
return;
}
//paramap을 넘겨줘
Map<String, String> paramMap = createParamMap(req);
Map<String, Object> model = new HashMap<>(); //model추가됨
String viewName= controller.process(paramMap,model); //view의 논리이름 직접 반환
MyView view = viewResolver(viewName);
view.render(model, req, resp);
}
private Map<String, String> createParamMap(HttpServletRequest request) {
Map<String, String> paramMap = new HashMap<>();
request.getParameterNames().asIterator()
.forEachRemaining(paramName -> paramMap.put(paramName,
request.getParameter(paramName)));
return paramMap;
}
private MyView viewResolver(String viewName) {
return new MyView("/WEB-INF/views/" + viewName + ".jsp");
}
}
[어댑터 패턴]
지금까지 우리가 개발한 프론트 컨트롤러는 한가지 방식의 컨트롤러 인터페이스만 사용할 수 있다. ControllerV3 , ControllerV4 는 완전히 다른 인터페이스이다. 따라서 호환이 불가능하다. 마치 v3는 110v이고, v4는 220v 전기 콘센트 같은 것이다. 이럴 때 사용하는 것이 바로 어댑터이다. 어댑터 패턴을 사용해서 프론트 컨트롤러가 다양한 방식의 컨트롤러를 처리할 수 있도록 변경
2.핸들러어뎁터 목록 : 컨트롤러3을 처리할 수 있는 어뎁터, 컨트롤러4를 처리할 수 있는 어뎁터를 찾아와서
3.컨트롤러를 바로 호출하는 기존과는 다르게 중간에 어뎁터를 통해서 호출해야됨. 어뎁터한테 컨트롤러를 넘겨줘
* 핸들러 어댑터: 중간에 어댑터 역할을 하는 어댑터가 추가되었는데 이름이 핸들러 어댑터이다. 여기서 어댑터 역할을 해주는 덕분에 다양한 종류의 컨트롤러를 호출할 수 있음
* 핸들러: 컨트롤러의 이름을 더 넓은 범위인 핸들러로 변경했다. 이제 어댑터가 있기 때문에 꼭 컨트롤러의 개념 뿐만 아니라 어떠한 것이든 해당하는 종류의 어댑터만 있으면 다 처리할 수 있기 때문
<MyHandlerAdapter>
public interface MyHandlerAdapter {
boolean supports(Object handler);
ModelView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws ServletException, IOException;
}
boolean supports(Object handler)는 프론트 컨트롤러가 핸들러 어뎁터 목록을 뒤져서 찾을 때 V3를 처리할 수 있는 어뎁터를 꺼낼 수 있게함. 어댑터가 해당 컨트롤러를 처리할 수 있는지 판단하는 메서드
ModelView handle(HttpServletRequest request, HttpServletResponse response, Object handler)는 핸들러는 호출해주고 맞는 컨트롤러를 넘겨주면 어뎁터가 대신 호출학 해줌
<ControllerV3HandlerAdapter> - V3를 지원하는 어뎁터
//handler를 호출해주고 결과오면 반환타입을 맞춰서 반환시켜줘
public class ControllerV3HandlerAdapter implements MyHandlerAdapter {
@Override
public boolean supports(Object handler) {
return (handler instanceof ControllerV3);
}
@Override
public ModelView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws ServletException, IOException {
ControllerV3 controller = (ControllerV3) handler;
Map<String, String> paramMap = createParamMap(request);
ModelView mv = controller.process(paramMap);
return mv;
}
//parameterMap필요
private Map<String, String> createParamMap(HttpServletRequest request) {
Map<String, String> paramMap = new HashMap<>();
request.getParameterNames().asIterator()
.forEachRemaining(paramName -> paramMap.put(paramName,
request.getParameter(paramName)));
return paramMap;
}
}
* public boolean supports(Object handler) { return (handler instanceof ControllerV3); } : ControllerV3 을 처리할 수 있는 어댑터
* ControllerV3 controller = (ControllerV3) handler; Map paramMap = createParamMap(request); ModelView mv = controller.process(parmMap); return mv : handler를 컨트롤러 V3로 변환한 다음에 V3 형식에 맞도록 호출
<FrontControllerServletV5>
@WebServlet(name = "frontControllerServletV5", urlPatterns = "/front-controller/v5/*")
public class FrontControllerServletV5 extends HttpServlet {
private final Map<String,Object> handlerMappingMap=new HashMap<>(); //특정이 아닌 다 집어넣을 수 있기 위해 Object를 사용
private final List<MyHandlerAdapter> handlerAdapters=new ArrayList<>(); //여러 어뎁터중 하나 찾아써야하니까 리스트
//초기화
public FrontControllerServletV5() {
initHandlerMappingMap(); //핸들러 매핑 초기화
iniHandlerAdapters(); //어댑터 초기화
}
private void initHandlerMappingMap() {
handlerMappingMap.put("front-controller/v5/v3/members/new-form",new MemberFormControllerV3());
handlerMappingMap.put("front-controller/v5/v3/members/save",new MemberSaveControllerV3());
handlerMappingMap.put("front-controller/v5/v3/members",new MemberListControllerV3());
//V4추가
handlerMappingMap.put("front-controller/v5/v4/members/new-form",new MemberFormControllerV4());
handlerMappingMap.put("front-controller/v5/v4/members/save",new MemberSaveControllerV4());
handlerMappingMap.put("front-controller/v5/v4/members",new MemberListControllerV4());
}
private void iniHandlerAdapters(){
handlerAdapters.add(new ControllerV3HandlerAdapter());
handlerAdapters.add(new ControllerV4HandlerAdapter());
}
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//MemberFromControllerV3가 반환됨
//1. 핸들러 찾아옴
Object handler= getHandler(req); //handler찾네!호출->v3처리 가능한 헨들러 어뎁터를 찾아와
if (handler == null) {
resp.setStatus(HttpServletResponse.SC_NOT_FOUND); //not found 404error
return;
}
//ControllerV3HandlerAdapter가 반환
//2. 핸들러 어뎁터 찾아옴
MyHandlerAdapter adapter= getHandlerAdapter(handler); //handler adapter를 가져와
ModelView mv=adapter.handle(req,resp,handler); //handle호출_>v3로 바꾸고 adapter도 modelview를 바꿔
String viewName = mv.getViewName(); //논리이름 new-form으로 반환
MyView view = viewResolver(viewName); //viewResolver호출
view.render(mv.getModel(), req, resp);
}
private Object getHandler(HttpServletRequest request){
String requestURI = request.getRequestURI();
return handlerMappingMap.get(requestURI);
}
private MyHandlerAdapter getHandlerAdapter(Object handler) {
for (MyHandlerAdapter adapter : handlerAdapters) {
if (adapter.supports(handler)) {
return adapter;
}
}
throw new IllegalArgumentException("handler adapter를 찾을 수 없습니다. handler="+handler);
}
private MyView viewResolver(String viewName) {
return new MyView("/WEB-INF/views/" + viewName + ".jsp");
}
}
핸들러를 처리할 수 있는 어댑터 조회 : MyHandlerAdapter adapter = getHandlerAdapter(handler) for (MyHandlerAdapter adapter : handlerAdapters) { if (adapter.supports(handler)) { return adapter; } }
1. 클라이언트 요청이 오면 핸들러 매핑 정보를 뒤져서
2. 핸들러에 던지면서 3처리할 수 있는 어댑터를 가져와서
3. 핸들러 어댑터 호출
4. 핸들러 호출
5.뷰리졸버 호출
[유연 컨트롤러] - V4추가 (프론트컨트롤러에 핸들러 V4가 없어서)
<ControllerV4HandlerAdapter>
public class ControllerV4HandlerAdapter implements MyHandlerAdapter {
@Override
public boolean supports(Object handler) {
return (handler instanceof ControllerV4);
}
@Override
public ModelView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws ServletException, IOException {
ControllerV4 controller = (ControllerV4) handler;
Map<String, String> paramMap = createParamMap(request);
Map<String, Object> model = new HashMap<>();
String viewName = controller.process(paramMap, model);
ModelView mv = new ModelView(viewName);
mv.setModel(model);
return mv;
//returm viewName이 아닌이유(adapter의 역할):adpater에서 modelview를 생성해줘
}
private Map<String, String> createParamMap(HttpServletRequest request) {
Map<String, String> paramMap = new HashMap<>();
request.getParameterNames().asIterator()
.forEachRemaining(paramName -> paramMap.put(paramName,
request.getParameter(paramName)));
return paramMap;
}
}
1.핸들러 매핑정보를 찾아서 "/front-controller/v5/v4/members/new-form" 호출하고 MemberFormControllerV4()가 반환됨
2.어뎁터를 찾는데 프론트컨트롤러에서 initHandlerAdapters() 이 메서드에서 ControllerV4HandlerAdapter()를 호출해줘
3.그 후에 ViewName을 만들고 넘겨줘
5.인터페이스에 맞게 반환해서 (모델뷰로 전환해서 )
*프론트컨트롤러는 핸들러 어댑터 인터페이스에만 의존, 그래서 구현 클래스가 뭐가 들어오던 상관없음.
[정리]
V1 : 프론트 컨트롤러 도입
V2 : view 포워드 반복 로직분리
V3 : model추가해서 값을 넣는거로 httpservletre빼고
V4 : 실용적 컨트롤러(modelview를 직접 생성해서 반환하지 않음 )
V5 : 유연 컨트롤러(어댑터 도입)
'Spring 강의 > springMVC' 카테고리의 다른 글
springMVC 활용 - (7) 스프링 기능 (0) | 2022.05.11 |
---|---|
springMVC 활용 - (6) MVC프레임워크 구조 (0) | 2022.05.11 |
springMVC 활용 - (4) 회원관리 웹 애플리케이션 (0) | 2022.03.26 |
springMVC 활용 - (2) 서블릿 & Request (0) | 2022.03.26 |
springMVC 기본 - (9) 빈스코프 (0) | 2022.03.13 |