MVC 프레임워크

junheelee·2022년 10월 5일
0

SpringMVC

목록 보기
8/19

하나의 입구(Front-Controller)

입구를 통제하는 컨트롤러를 만들고 생성된 컨트롤러에서 요청에 맞는 컨트롤러를 호출

클라이언트 - HTTP 요청 - FrontController - 필요 Controller 호출

Controller Interface

package hello.servlet.web.frontcontroller.v;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public interface Controller {

    void process(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException;
    //각 컨트롤러는 인터페이스를 구현하여 구체화하여 사용한다

}

회원등록 Controller

package hello.servlet.web.frontcontroller.v.controller;

import hello.servlet.web.frontcontroller.v.ControllerV1;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class MemberFormController implements ControllerV {
    @Override
    public void process(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String viewPath = "/WEB-INF/views/new-form.jsp";

        RequestDispatcher dispatcher = request.getRequestDispatcher(viewPath);

        dispatcher.forward(request, response);
    }
}

회원저장 Controller

package hello.servlet.web.frontcontroller.v.controller;

import hello.servlet.domain.member.Member;
import hello.servlet.domain.member.MemberRepository;
import hello.servlet.web.frontcontroller.v1.ControllerV1;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class MemberSaveController implements ControllerV {

    private MemberRepository memberRepository = MemberRepository.getInstance();

    @Override
    public void process(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        String username = request.getParameter("username");
        int age = Integer.parseInt(request.getParameter("age")); //웹에서 전송 받은 데이터 형식을 정수형으로 반환

        //웹에서 전송받은 데이터를 저장 로직
        Member member = new Member(username, age);
        System.out.println("member = " + member);
        memberRepository.save(member);

        //데이터 보관
        //request 객체에 데이터를 보관하여 뷰에 전달
        request.setAttribute("member", member);

        String viewPath = "/WEB-INF/views/save-result.jsp";
        RequestDispatcher dispatcher = request.getRequestDispatcher(viewPath);
        dispatcher.forward(request, response);
    }
}

회원 리스트 Controller

package hello.servlet.web.frontcontroller.v.controller;

import hello.servlet.domain.member.Member;
import hello.servlet.domain.member.MemberRepository;
import hello.servlet.web.frontcontroller.v1.ControllerV1;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;

public class MemberListController implements ControllerV {

    private MemberRepository memberRepository = MemberRepository.getInstance();

    @Override
    public void process(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        List<Member> members = memberRepository.findAll();

        request.setAttribute("members", members);

        String viewPath = "/WEB-INF/views/members.jsp";
        RequestDispatcher dispatcher = request.getRequestDispatcher(viewPath);
        dispatcher.forward(request, response);
    }
}

FrontController

package hello.servlet.web.frontcontroller.v;

import hello.servlet.web.frontcontroller.v.controller.MemberFormControllerV;
import hello.servlet.web.frontcontroller.v.controller.MemberListControllerV;
import hello.servlet.web.frontcontroller.v.controller.MemberSaveControllerV;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

// *: 하위 모든 컨트롤러 호출
@WebServlet(name = "frontControllerServletV", urlPatterns = "/front-controller/v/*")
public class FrontControllerServletV extends HttpServlet {

    private Map<String, ControllerV> controllerVMap = new HashMap<>();

    // cmd + n : constructor none
    public FrontControllerServletV() {
        controllerVMap.put("/front-controller/v/members/new-form", new MemberFormControllerV());
        controllerVMap.put("/front-controller/v/members/save", new MemberSaveControllerV());
        controllerVMap.put("/front-controller/v/members", new MemberListControllerV());
    }

    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("FrontControllerServletV1.service");

        String requestURI = request.getRequestURI();
        ControllerV1 controllerV1 = controllerV1Map.get(requestURI);

        if (controllerV == null){
            response.setStatus(HttpServletResponse.SC_NOT_FOUND);
            return;
        }

        controllerV.process(request, response);
    }
}

🪴 FrontController를 사용하여 입구를 하나로 만들어 다형성을 구현, 하지만 View의 코드가 중복

작성한 Controller 수정

View Controller

package hello.servlet.web.frontcontroller;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class MyView {
    private String viewPath;

    public MyView(String viewPath) {
        this.viewPath = viewPath;
    }

    public void render(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
        RequestDispatcher dispatcher = request.getRequestDispatcher(viewPath);
        dispatcher.forward(request, response);
    }
}

회원등록 Controller 수정

package hello.servlet.web.frontcontroller.v.controller;

import hello.servlet.web.frontcontroller.MyView;
import hello.servlet.web.frontcontroller.v.ControllerV;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class MemberFormControllerV implements ControllerV {
    @Override
    public MyView process(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        MyView myView = new MyView("/WEB-INF/views/new-form.jsp");
        return myView;
    }
}

회원저장 Controller 수정

package hello.servlet.web.frontcontroller.v.controller;

import hello.servlet.domain.member.Member;
import hello.servlet.domain.member.MemberRepository;
import hello.servlet.web.frontcontroller.MyView;
import hello.servlet.web.frontcontroller.v.ControllerV;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class MemberSaveControllerV2implements ControllerV {

    private MemberRepository memberRepository = MemberRepository.getInstance();
    @Override
    public MyView process(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String username = request.getParameter("username");
        int age = Integer.parseInt(request.getParameter("age")); //웹에서 전송 받은 데이터 형식을 정수형으로 반환

        //웹에서 전송받은 데이터를 저장 로직
        Member member = new Member(username, age);
        memberRepository.save(member);

        //데이터 보관
        //request 객체에 데이터를 보관하여 뷰에 전달
        request.setAttribute("member", member);

        return new MyView("/WEB-INF/views/save-result.jsp");
    }
}

회원리스트 Controller

package hello.servlet.web.frontcontroller.v.controller;

import hello.servlet.domain.member.Member;
import hello.servlet.domain.member.MemberRepository;
import hello.servlet.web.frontcontroller.MyView;
import hello.servlet.web.frontcontroller.v.ControllerV;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;

public class MemberListControllerV implements ControllerV {

    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");
    }
}

View를 나누어 Controller의 코드가 간결해지고 하나의 동작을 할 수 있는 밑거름을 마련하지만 Controller 입장에서는 HttpServlet 정보가 꼭 필요하지 않을 수 있다. (파라미터를 Map으로 전달 필요)

📋 1. 뷰 이름의 중복 제거: 논리이름으로 반환
📋 2. Controller에 HttpServletRequest: Model에 request.setAttribute를 model 생성하여 분리

Moder View Class 생성

package hello.servlet.web.frontcontroller;

import java.util.HashMap;
import java.util.Map;

public class ModelView {
    private String viewName;
    private Map<String, Object> model = new HashMap<>();

    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;
    }
}

Controller 수정

package hello.servlet.web.frontcontroller.v;

import hello.servlet.web.frontcontroller.ModelView;

import java.util.Map;

public interface ControllerV {

    ModelView process(Map<String, String> paramMap);
}

회원등록 Controller 수정

package hello.servlet.web.frontcontroller.v3.controller;

import hello.servlet.web.frontcontroller.ModelView;
import hello.servlet.web.frontcontroller.v3.ControllerV3;

import java.util.Map;

public class MemberFormControllerV3 implements ControllerV3 {
    @Override
    public ModelView process(Map<String, String> paramMap) {
        //논리 이름 반환
        return new ModelView("new-form");
    }
}

회원저장 Controller 수정

package hello.servlet.web.frontcontroller.v3.controller;

import hello.servlet.domain.member.Member;
import hello.servlet.domain.member.MemberRepository;
import hello.servlet.web.frontcontroller.ModelView;
import hello.servlet.web.frontcontroller.v3.ControllerV3;

import java.util.Map;

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;
    }
}

회원리스트 Controller 수정

package hello.servlet.web.frontcontroller.v.controller;

import hello.servlet.domain.member.Member;
import hello.servlet.domain.member.MemberRepository;
import hello.servlet.web.frontcontroller.ModelView;
import hello.servlet.web.frontcontroller.v.ControllerV3;

import java.util.List;
import java.util.Map;

public class MemberListControllerV implements ControllerV3 {

    private MemberRepository memberRepository = MemberRepository.getInstance();
    @Override
    public ModelView process(Map<String, String> paramMap) {
        List<Member> members = memberRepository.findAll();
        ModelView mv = new ModelView("members");

        //컨트롤러에 필요한 파라미터를 넘겨준다
        mv.getModel().put("members", members);
        return mv;
    }
}

Front Controller 수정

package hello.servlet.web.frontcontroller.v;

import hello.servlet.web.frontcontroller.ModelView;
import hello.servlet.web.frontcontroller.MyView;
import hello.servlet.web.frontcontroller.v.ControllerV;
import hello.servlet.web.frontcontroller.v.controller.MemberFormControllerV;
import hello.servlet.web.frontcontroller.v.controller.MemberListControllerV;
import hello.servlet.web.frontcontroller.v.controller.MemberSaveControllerV;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

// *: 하위 모든 컨트롤러 호출
@WebServlet(name = "frontControllerServletV3", urlPatterns = "/front-controller/v/*")
public class FrontControllerServletV extends HttpServlet {

    private Map<String, ControllerV> controllerV1Map = new HashMap<>();

    // cmd + n : constructor none
    public FrontControllerServletV() {
        controllerV1Map.put("/front-controller/v/members/new-form", new MemberFormControllerV());
        controllerVMap.put("/front-controller/v/members/save", new MemberSaveControllerV());
        controllerVMap.put("/front-controller/v/members", new MemberListControllerV());
    }

    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("FrontControllerServletV.service");

        String requestURI = request.getRequestURI();

        ControllerV controllerV = controllerV1Map.get(requestURI);

        if (controllerV == null){
            response.setStatus(HttpServletResponse.SC_NOT_FOUND);
            return;
        }

        //1. paramMap 넘겨주기
        Map<String, String> paramMap = createParamMap(request);
      ModelView mv = controllerV.process(paramMap);


        //2. url 맵핑
        String viewName = mv.getViewName();//논리이름

        MyView view = viewResolver(viewName);
        view.render(mv.getModel(), request, response);

    }

    //파라미터를 넘겨주기 위한 로직 함수 생성
    private Map<String, String> createParamMap(HttpServletRequest request) {
        Map<String, String> paramMap = new HashMap<>(); //map 객체 생성
        request.getParameterNames().asIterator() //request 의 모든 Parameter 모두 꺼내오기
                .forEachRemaining(paramName -> paramMap.put(paramName, request.getParameter(paramName)));
        return paramMap;
    }

    private MyView viewResolver(String viewName) {
        // 폴더 경로가 바뀌어도 한번만 수정하면 된다.
        return new MyView("/WEB-INF/views/" + viewName + ".jsp");
    }
}

📋 정리

FrontController: 입구를 하나로 만들어 요청에 맞는 컨트롤러 찾아서 호출

view 분리: FrontController에서 호출된 요청에 맞는 컨트롤러의 뷰를 보여줌

Model 추가: 서블릿의 종속 제거, view 이름 반환, HttpServletRequest의 정보는 Map(ParamMap으로 호출)

viewResolver: 컨트롤러가 반환해준 논리 뷰 이름을 물리 경로로 변경

viewRender: HTML의 화면 렌더링, Attribute 세팅으로 JSP에 데이터 전달

profile
Study of beginner dev

0개의 댓글