ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • ModelAndView
    JAVA 2021. 7. 25. 14:37

    DispatcherServlet

    Spring 에서는 FrontController 를 DispatcherServlet 이라는 클래스로 정의해놓았다.
    dispatcher : 배달 보내는 사람, 운행 관리원

    Servlet 처음 할 때 사용한 MVC 모델 순서

    1. 요청이 옴
    2. FrontContoller 가 먼저 요청을 받는다.
    3. 요청사항(요청명) 에 따라 control 을 짝 지어 요청(request)을 넘긴다. (control 의 메서드에 매개변수로 넘긴다.)
    (control 들이 공통 구현한 인터페이스 하나로 다향성을 이용하자)
    4. 짝 지어진 control 이 요청에 맞는 업무 즉, model 을 사용한다.(등록폼관련 control은 model 사용안할 수도 있다.)
    그리고 매개변수로 받은 요청에 값을 저장해준다.
    또한 이 작업한 model 값이 나타날 view 를 지정해 FrontController 에 return 한다.
    5. model 값은 request 로 저장했고, view 이름도 받은 FrontController 가 해당 view 로 forward 한다.
    6. view 에서 값을 받아 인터페이스(화면)를 구현한다.
    7. view 에서 다른 view 로(등록폼도 포함) 가는 경우에도 control을 거쳐야 하므로 다시 1번부터 반복한다.
    위의 문제점은 FrontController 가 control 들에게 request를 통째로 준다는 점이다.
    필요한 control 도 있겠지만 필요한 값이 몇개 정해진 control 들도 있는데 정보를 통째로 주면
    데이터를 잘못 건드리거나, request, response 의 이해도가 낮은 사람들에게 어려움을 준다.

    Spring 에서 사용할 MVC 모델

    1. ModelAndView

    전제사항: ModelAndView 라는 클래스를 만든다.

    역할은 데이터를 전송시킬 수 있는 리턴 타입 자리를 맡는다.

    ModelAndView 클래스
    멤버변수 : viewName, HashMap<String, Object>
    메서드 : setViewName(), getViewName(), addObject(key, value)

    2. 진행 순서

    1. 요청이 옴
    2. FrontController 가 먼저 요청을 받는다.
    3. 요청사항(요청명) 에 따라 control 을 짝 지어 요청(request)을 넘긴다. (control 의 메서드에 매개변수로 넘긴다.)
    (control 들이 공통 구현한 인터페이스 하나로 다향성을 이용하자)
    4. control 인 메서드의 반환값은 ModelAndView 클래스로,
    객체 생성한 후 위에 정리한 메서드를 사용하여 멤버변수에 값을 저장하고 리턴한다.
    5. FrontController 에 반환된 ModelAndView 클래스로 저장한 viewName 을 꺼내고 map 을 EntrySet(위 EntrySet 참고) 으로 만들어
    값을 request 에게 set시킨다.
    6. 반환된 viewName 을 이용해 view로 request 를 forward 시킨다.
    7. view 에서 값을 받아 인터페이스(화면)를 구현한다.
    8. view 에서 다른 view 로(등록폼도 포함) 가는 경우에도 control을 거쳐야 하므로 다시 1번부터 반복한다.

    MVC 실습 (직접 ModelAndView 만들어보기)

    >> ModelAndView.java

    public class ModelAndView {
    
    	// 같은 패키지안의 controller 들이 사용하기 때문에 get 없이 바로 멤버변수로 참고하자.
    	String viewName = null;
    	// 마찬가지로 직접 멤버변수를 참고하여 entry - Set을 만들 것이다.
    	HashMap<String, Object> model = new HashMap<String, Object>();
    	
    	public void setViewName(String viewName) {
    		this.viewName = viewName;
    	}
    	
    	public void addObject(String key , Object val) {
    		model.put(key, val);
    	}
    }

    >> IControl.java (control 들의 다형성을 위한 인터페이스)

    public interface IControl {
    	
    	// view 이름 요청처리 // 입력: 일단 넓게 일반적으로 요청객체로 대신
    	ModelAndView process(HttpServletRequest request, HttpServletResponse response);
    }

    >> 게시물등록준비.java

    public class 게시물등록준비 implements IControl{
    
    	public ModelAndView process(HttpServletRequest request, HttpServletResponse response) {
    		// 요청
    		// 업무	
    
    		// 경로 지정
    		ModelAndView mv = new ModelAndView();
    		mv.setViewName("게시물등록창");
    		
    		return mv;
    	}
    
    }

    >> 게시물등록.java (control 임!)

    public class 게시물등록 implements IControl {
    	//@Autowired-DI
    	IBoardDAO boardDAO = new BoardDAO();
    	
    	//@RuquestMapping("add_board") 스프링. 아래처럼 가능해진다.
    	// public ModelAndView process(String 제목, String 내용){}
    	public ModelAndView process(HttpServletRequest request, HttpServletResponse response) {
    		// 요청
    		String 제목 = request.getParameter("title");
    		String 내용 = request.getParameter("contents");
    		Board board = new Board();
    		board.setTitle(제목);
    		board.setContents(내용);
    		
    		ModelAndView mv = new ModelAndView();
    		// 업무
    		
    		HttpSession session = request.getSession(false);//없으면 null 값을 준다.
    		boolean 로그인 = true;
    		if (!(session != null && session.getAttribute("no") != null)) {
    			로그인 = false;
    			//test - 추후 삭제
    			session = request.getSession();
    			session.setAttribute("no", 1);
    			로그인 = true;
    		};
    		
    		if(!로그인)		
    		{
    			mv.setViewName("forward:/로그인준비");
    			mv.addObject("msg", "로그인 후 세개시물 작성 가능합니다.");
    			return mv;
    		}
    		int 로그인한회원번호 = (Integer)session.getAttribute("no");
    		Member 작성한회원 = new Member();
    		작성한회원.setNo(로그인한회원번호);
    		board.setWriter(작성한회원);
    		boardDAO.save(board);
    		
    		// 경로지정
    		mv.addObject("board", board);
    		mv.setViewName("게시물등록결과통보");
    		return mv;
    	}
    
    }

    >> ControlProvider.java ( control 을 FrontController 에서 생성하지 않고 이 클래스를 통해 얻어낸다.)

    1. 요청명을 key 로 , 요청명의 Control 을 value 로 HashMap 을 만든다. (생성시 별도의 메서드 사용없이 들어가 있도록 생성자에 넣기)

    2. 해당 HashMap 을 요청명 (key) 값으로 Control 을 얻는 getControl(String work) 메서드를 만든다.

    3. getControl() 메서드를 객체 생성 후 써야하면 복잡하니까(생성자에 put되있으니 static선언해서 사용하면 값이 없다.)

    이 클래스를 static 멤버변수로 만들어 객체를 생성하고 이 객체를 꺼낼 static 메서드를 만든다.

    class BasicControlProvider {
    	
    	HashMap<String, IControl> controls = new HashMap<String, IControl>();
    	
    	BasicControlProvider(){
    		controls.put("prepare_board", new 게시물등록준비());
    		controls.put("add_board", new 게시물등록());
    	}
    	
    	public IControl getControl(String work) {
    		return controls.get(work);
    	}
    }
    
    public class ControlProvider {
    	
    	static BasicControlProvider controlProvider = new BasicControlProvider();
    	
    	public static BasicControlProvider getControlProvider() {
    		return controlProvider;
    	}
    }

    >> FrontController.java

    //FrontController
    @WebServlet("/") // 이 웹서버에 아무거나 요청해도 이 Servlet 이 반환.
    public class ForntController extends HttpServlet {
    
    	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    
    		// 요청과 컨트롤 객체 매핑
    		String 요청작업 = request.getRequestURI().substring("/AboutSerlvet/".length());
    		
    		IControl control = ControlProvider.getControlProvider().getControl(요청작업);
    		
    		// 해당 컨르롤 요청처리
    		ModelAndView 모델과지정된뷰명 = control.process(request,response);
    		Set<Entry<String, Object>> entry들 = 모델과지정된뷰명.model.entrySet();
    		for (Entry<String, Object> entry : entry들) {
    			request.setAttribute(entry.getKey(), entry.getValue());
    		}
    		
    		// forward
    		RequestDispatcher rd = request.getRequestDispatcher(ViewResolver.getJspViewName(모델과지정된뷰명.viewName));
    		rd.forward(request, response);
    	}
    
    	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    		doGet(request,response);
    	}
    
    }

    댓글

Designed by Tistory.