본문 바로가기
Spring/스프링 MVC

[스프링 MVC 1편] 4 - (4) 프론트 컨트롤러 - v4

by Poorm 푸름 2023. 11. 10.

 *  스프링 입문 = window, 스프링 MVC 1편 = Mac 으로 진행합니다

 *  진도 : 섹션4 - (5)

 *          : 자바 클래스명,         : 코드,         : 단축키

 

1. 프론트 컨트롤러_구현 4단계 

 

  • ModelView 를 없애보자! Map 으로 별도 설정

 

1) 인터페이스
 [ src - java - hello.servlet - web - frontcontroller .v4 - ControllerV4 ]

public interface ControllerV4 {
    String process(Map<String, String> paramMap,Map<String, Object> model);
}

 

  

  1. ModelView없이 진행

    1. 서블릿과 앞부분 이름 차이
      protected void service  String process

  2. Map<> paramMap / model  맵 2개 추가

  3. 프론트 컨트롤러는 이 인터페이스를 호출해서 로직의 일관성을 가져갈 수 있다
    인터페이스는 어딘가에 상속 혹은 종속 되어있지 않아서 extend나 implements 사용 X

더보기

 < 기존의 ControllerV3 인터페이스에서 삭제한 코드 >

  • ModelView 
public interface ControllerV3 {
    ModelView process(Map<String, String> paramMap);

 

 3) 회원 등록
 [ src - java - hello .servlet - web - frontcontroller .v4 - controller - MemberFormControllerV4 ]

public class MemberFormControllerV4 implements ControllerV4 {
    @Override
    public String process(Map<String, String> paramMap, Map<String, Object> model) {
        return "new-form";
    }
}

 

  • 상속 implements ControllerV4 ~ @Override (option + enter)

    • 이제는 HttpServlet Re~ 코드가 아닌 맵이 자동으로 생성이 된다

  • 뷰 영역 return "// 논리적 이름 //"  

    • 논리적 이름 = "new-form"

더보기

 < 기존의 MemberSaveControllerV3 클래스에서 삭제한 코드 >

  • ModelView 부분
public class MemberFormControllerV3 implements ControllerV3 {
    @Override
    public ModelView process(Map<String, String> paramMap) {
        return new ModelView("new-form");
    }
}

 

 4) 회원 저장
[ src - java - hello .servlet - web - frontcontroller .v4 - controller - 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";
    }
}

 

  • 상속 implements ControllerV4 ~ @Override (option + enter)

    • 이제는 HttpServlet Re~ 코드가 아닌 맵이 자동으로 생성이 된다

  • 리포지토리 가져오기 private MemberRepository.getInstance (서블릿 방식 때랑 같음)

  • form data 값 읽어오기 paramMap.get()  (command + option + v)
    ( age만 int로 추가 변경 )

    • 파라미터에서 값(username, age) 꺼내오기

  • Member 객체 생성 및 저장 (서블릿 방식 때랑 같음)

  • Map model에 값 넣기  model.put("member", member)

  • 출력 return "save-result"

더보기

 < 기존의 MemberSaveControllerV3 클래스에서 삭제한 코드 >

 

  • ModelView 부분
    • ModelView mv = new ModelView()
    • mv.getModel().put()
    • return mv
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;
    }
}

 

 5) 회원 목록 
 [ src - java - hello .servlet - web - frontcontroller .v4 - controller - 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";
    }
}

 

  • 상속 implements ControllerV4 ~ @Override (option + enter)

    • 이제는 HttpServlet Re~ 코드가 아닌 맵이 자동으로 생성이 된다

  • 리포지토리 가져오기private MemberRepository.getInstance(서블릿 방식 때랑 같음)

  • 데이터 조회 memberRepository.findAll() (option + command + v) (서블릿 방식 때랑 같음)

  • Map model에 값 넣기  model.put("member", member)

  • 출력 return "members"

더보기

 < 기존의 MemberSaveControllerV3 클래스에서 삭제한 코드 >

 

  • ModelView 부분
    • ModelView mv = new ModelView()
    • mv.getModel().put()
    • return mv
public class MemberListControllerV3 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;
    }
}

 

 5) 프론트 컨트롤러 
[ src - java - hello.servlet - web - frontcontroller. v4 - FrontControllerServletV4 ]

@WebServlet(name = "frontControllerServiceV4", urlPatterns = "/front-controller/v4/*")
public class FrontControllerServiceV4 extends HttpServlet {

    private Map<String, ControllerV4> controllerMap = new HashMap<>();

    public FrontControllerServiceV4() {
        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 request, HttpServletResponse response) throws ServletException, IOException {

        String requestURI = request.getRequestURI();
        ControllerV4 controller = controllerMap.get(requestURI);
        if(controller==null){
            response.setStatus(HttpServletResponse.SC_NOT_FOUND);
            return;
        }

        Map<String, String> paramMap = createParamMap(request);
        Map<String, Object> model = new HashMap<>();
        String viewName = controller.process(paramMap, model);

        MyView view = viewResolver(viewName);
        view.render(model, request, response);
    }

    private static MyView viewResolver(String viewName) {
        return new MyView("/WEB-INF/views/" + viewName + ".jsp");
    }

    private static 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. 상속 extends HttpServlet

 

2. 서블릿 생성@WebServlet


3. 서비스 생성 protected service

 

4. 맵 생성 private Map

 

  • key = url, value = ControllerV4
  • 매핑 정보 담을 공간 = controllerMap

5. 매핑 정보 public FrontControllerServiceV4()

  • command + n 하고 constructor 클릭 → Select None 클릭
  • 매핑정보를 담기!
  • key 값이 요청되면 value를 실행하게끔 설정

6. URI 주소 가져오기 request.getRequestURI (option + command + v)

7. 맵에서 URI 찾아 컨트롤러 반환 controllerMap.get(requestURI)(option + command + v)

  1. 예외처리는 404 출력 SC_NOT_FOUND

8. 인터페이스, 회원 등록/저장/목록 컨트롤러에서 사용한 맵 2개 등록

  • Map<String, String> paraMap = new HashMap<>()

  • Map<String, Object> model = new HashMap<>()

 

9. 파라미터네임 꺼내기 request.getParameterName

  • request.getParameter() : ("파라미터 이름")을 작성하면 값을 꺼낼 수 있다
  • asIterator() : iterator 인터페이스형으로 바꿔서 반환
  • Iterator.forEachRemaining() : Iterator의 forEachRemaining() 메서드를 사용하여 키-값 쌍을 콘솔에 출력
  • paramName -> parammap.put(paramName, request.getParameter(paramName))
    • key = paraName, value = request.getParameter(paramName)

 너무 길어서 따로 메서드로 뽑는게 좋다!
         Map<String, String> paraMap부터 request.getParameterName 까지 드래그 후
         option + command + m하고 createParamMap 입력하기 

 

 

10. 파라미터 받기  controller.process(paramMap) (option + command + v)

 

 11. 뷰 설정 (프론트컨트롤러v3 랑 같음)

  • new MyView("/WEB-INF/views/" + viewName + ".jsp") (option + command + v) 하고
     option + command + m
     해서 viewResolver(viewName) 입력하기 
    •  컨트롤러가 반환한 논리 뷰 이름을 실제 물리 뷰 경로로 변경, 실제 물리 경로가 있는 MyView 객체를 반환

      논리 뷰 이름: members
      물리 뷰 경로: /WEB-INF/views/members.jsp


  • 렌더 호출 view.render(model, request, respontse)

더보기

< 기존의 FrontControllerService3 클래스에서 삭제한 코드 >

 

@WebServlet(name = "frontControllerServiceV3", urlPatterns = "/front-controller/v3/*")
public class FrontControllerServiceV3 extends HttpServlet {

    private Map<String, ControllerV3> controllerMap = new HashMap<>();

    public FrontControllerServiceV3() {
        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 request, HttpServletResponse response) throws ServletException, IOException {

        String requestURI = request.getRequestURI();
        ControllerV3 controller = controllerMap.get(requestURI);
        if(controller==null){
            response.setStatus(HttpServletResponse.SC_NOT_FOUND);
            return;
        }

        Map<String, String> paramMap = createParamMap(request);

        ModelView mv = controller.process(paramMap);

        String viewName = mv.getViewName();

        MyView view = viewResolver(viewName);

        view.render(mv.getModel(), request, response);
    }

    private static MyView viewResolver(String viewName) {
        return new MyView("/WEB-INF/views/" + viewName + ".jsp");
    }

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