코드 그라데이션

Model 추가 v3 본문

Spring/MVC 1

Model 추가 v3

완벽한 장면 2023. 9. 26. 00:37

Model 추가

서블릿 종속성 제거

 

뷰 이름 중복 제거

 

V3 구조

 

 

ModelView

  • sevlet의 종속성을 제거 -> request가 쓸모가 없으니까.
@Getter
@Setter
public class ModelView {
    private String viewName; //뷰의 논리적 이름
    private Map<String, Object> model = new HashMap<>(); // 모델 직접 생성
    //이렇게 모델에다가 내가 원하는 데이터를 넣어두면 나중에 꺼내서 jsp에서 쓸 수 있도록 후처리 해줄 예정

    public ModelView(String viewName) {
        this.viewName = viewName;
    }

}

 

 

 

ControllerV3 - 인터페이스

public interface ControllerV3 {

    ModelView process(Map<String, String> paramMap);
    // 얘는 서블릿 기술들이 구현되어있지 않음(v2까지는 있었던 것에 비해)
    // 프레임워크에 종속적이지, 서블릿에 종속적이지 않다.
}

 

MemberFormControllerV3 - 회원 등록 폼

public class MemberFormControllerV3 implements ControllerV3 {

    @Override
    public ModelView process(Map<String, String> paramMap) {
    
        // 새로운 ModelView 객체를 생성하고 "new-form"이라는 논리적인 뷰 이름을 설정
        // ModelView 객체는 뷰의 경로 및 모델 데이터를 포함하는 객체
        return new ModelView("new-form"); // 전체 경로를 넣지 않고, 논리이름만 넣는다!
    }
}

 

이 코드의 주요 목적은 "new-form"이라는 논리적인 뷰 이름을 가진 ModelView 객체를 생성하여 컨트롤러의 동작을 나타내는 것.

뷰의 실제 경로는 다른 구성 요소에서 설정하거나 결정될 수 있다.

 

 

MemberSaveControllerV3 - 회원 저장 클래스

public class MemberSaveControllerV3 implements ControllerV3 {

    private MemberRepository memberRepository = MemberRepository.getInstance();

    @Override
    public ModelView process(Map<String, String> paramMap) {
        /*
        HttpServletRequest에서 getAttribute 해서 막 이렇게 복잡하게 꺼내는 게 아니라
        그 작업은 다 프론트 컨트롤러에서 처리하고
        Map에다가 요청 파라미터 정보들을 다 담아서 넘겨줄 것이다.
        그럼 단순히 여기서는 꺼내서 쓰기만 하면 된다.
         */
        // 파라미터에서 "username"과 "age" 값을 추출
        String username = paramMap.get("username");
        int age = Integer.parseInt(paramMap.get("age")); // 문자로 오므로 숫자로 바꿔줘야 한다.

		// 회원 객체를 생성하고 회원 저장소에 저장
        Member member = new Member(username, age);
        memberRepository.save(member);

		// 결과를 나타내는 ModelView 객체 생성
        
        ModelView mv = new ModelView("save-result"); // 모델 뷰 생성
        mv.getModel().put("member", member); // 멤버 집어넣고
        return mv; //리턴
    }
}

 

 

MemberListControllerV3 - 회원 목록

public class MemberListControllerV3 implements ControllerV3 {

    private final MemberRepository memberRepository = MemberRepository.getInstance();

    // ControllerV3 인터페이스의 메서드를 구현
    @Override
    public ModelView process(Map<String, String> paramMap) {
        // 회원 저장소에서 모든 회원을 조회하여 리스트로 얻어옴
        List<Member> members = memberRepository.findAll();

        // 결과를 나타내는 ModelView 객체 생성
        ModelView mv = new ModelView("members"); // 모델 뷰 생성
        mv.getModel().put("members", members); // 모델에 회원 목록을 추가
        return mv; // ModelView 객체 반환
    }
}

 

 

 

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

		// 요청 URI를 기반으로 해당 컨트롤러를 가져옴
        String requestURI = request.getRequestURI();

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

//        MyView view = controller.process(request, response);
//        view.render(request, response); 이거 아님.

		// HTTP 요청에서 파라미터를 추출하여 paramMap에 저장
        Map<String, String> paramMap = createParamMap(request); // 디테일하니까 메서드로 분리
        ModelView mv = controller.process(paramMap); // 여기서 받기
        // 컨트롤러를 실행하고, 실행 결과로 ModelView 객체를 얻음

        String viewName = mv.getViewName(); // 이 부분에서는 논리이름만 얻음
        
        // 논리 뷰 이름을 실제 뷰 경로로 변환 (뷰 리졸버 역할)
        MyView view = viewResolver(viewName); // 뷰 리졸버가 객체까지 만들어주는 것. 설계상 메서드 분리
//      위 코드가 바로 이 것. new MyView("/WEB-INF/views/" + viewName + ".jsp")

        // 모델을 render에 같이 넘겨줘야 함.
        // Model 데이터를 함께 렌더링에 전달하여 화면에 표시
        view.render(mv.getModel(), request, response); // MyView에 아랫쪽에 있는 render(~);
    }

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

	// HTTP 요청에서 파라미터를 추출하여 paramMap에 저장하는 메서드
    private Map<String, String> createParamMap(HttpServletRequest request) {
        Map<String, String> paramMap = new HashMap<>(); // Map 만들기
        request.getParameterNames() // 모든 파라미터 다 가져오기
                .asIterator() // 돌면서 Map에다가 값을 다 넣어주기
                .forEachRemaining(paramName -> paramMap.put(paramName, request.getParameter(paramName)));
        return paramMap;
    }
}

 

 

MyView 설명 추가 및 수정

 public class MyView {

 	private String viewPath;

    public MyView(String viewPath) { // 생성자: 뷰 경로를 인스턴스 변수에 저장
        this.viewPath = viewPath;
    }

	// HttpServletRequest와 HttpServletResponse를 받아서 JSP로 포워드
    public void render(HttpServletRequest request, HttpServletResponse response) 
    	throws ServletException, IOException {
        
        RequestDispatcher dispatcher = request.getRequestDispatcher(viewPath);
        dispatcher.forward(request, response);
    }
 
 	/*
    위의 render 메서드와 유사하게 HttpServletRequest와 HttpServletResponse 객체를 받지만, 
    더 많은 파라미터로 Map<String, Object> model도 받습니다. 
    이 메서드는 modelToRequestAttribute 메서드를 호출하여 
    모델에 있는 데이터를 HttpServletRequest 객체의 attribute로 설정한 다음, JSP 파일로 포워드합니다. 
    이렇게 하면 JSP 파일에서 모델의 데이터를 사용할 수 있게 됩니다.
    */
 	// 모델 데이터와 HttpServletRequest, HttpServletResponse를 받아서 JSP로 포워드
 	public void render(Map<String, Object> model, HttpServletRequest request, ]
    	HttpServletResponse response) throws ServletException, IOException {
    	
        // 모델 데이터를 HttpServletRequest의 attribute로 설정
        modelToRequestAttribute(model, request); 
        // 모델에 있는 데이터를 requestAttribute로 바꾼다.

    	// modelToRequestAttribute가 다 끝나고 여기 오면 jsp가 getAttribute해서 값을 쓰겠죠.
        // 설정된 데이터와 함께 JSP로 포워드
   		RequestDispatcher dispatcher = request.getRequestDispatcher(viewPath);
    	dispatcher.forward(request, response);
  	}

	 // 모델 데이터를 HttpServletRequest의 attribute로 설정하는 메서드
  	private void modelToRequestAttribute(Map<String, Object> model,
    	HttpServletRequest request) {
    	
        // 모델의 각 항목을 반복하며 HttpServletRequest의 attribute로 설정
        model.forEach((key, value) -> request.setAttribute(key, value)); 
        // 랜더가 오면 다 돌면서 리퀘스트의 키, 밸류를 다 담아놓는다.(setAttribute)
    	// jsp는 여기서 값을 꺼내기 때문에 이 작업이 필요하다.
  }
}

 

 

뷰 리졸버

 

 

 

 

실행

등록: http://localhost:8080/front-controller/v3/members/new-form
목록: http://localhost:8080/front-controller/v3/members

 

등록

2개 저장하고 조회해보면

728x90

'Spring > MVC 1' 카테고리의 다른 글

유연한 컨트롤러(1) - v5  (0) 2023.09.27
단순하고 실용적인 컨트롤러 - v4  (0) 2023.09.26
View 분리 - v2  (0) 2023.09.25
프론트 컨트롤러 도입 - v1  (0) 2023.09.24
프론트 컨트롤러 패턴 소개  (0) 2023.09.24
Comments