본문 바로가기

프레임워크/Spring

[프레임워크] <Spirng>〈Maven〉Spring에서의 MVC2 구조

기본 MVC2 구조의 흐름

브라우저

  ⇩

요청

  ⇩

요청정보를 FrontController==Dispatcher에서 받아서 요청을 확인

  ⇩

HandlerMapping으로 해당 요청에 대해서 어떤 Controller가 필요한지 확인 

팩토리 패턴을 활용하여 요청(String)을 받으면 Controller(객체)를 반환

  ⇩

◎ Controller는 메서드를 수행 ➠ Service ➠ DAO String을 반환

       ⇩

Action을 수행하면 ActionForward==ViewResolver를 사용하여 응답

ViewResolver가 Controller에서 반환된 String을 보고 사용자에게 VEIW 페이지를 응답


의존관계 

◎ Dispathcer-Servlet

   ⇨ HandlerMapping, ViewResolver

   ⇨ init()  메서드로 의존주입(DI)

 

◎ HandlerMapper

   ⇨ Map<String, Controller> : 팩토리 패턴을 활용하기 위한 컬렉션

 

◎ ViewResolver

   ⇨ prefix, suffix

   ⇨ setter로 의존 주입


패키지 관리

클래스의 타입(자료형) 중심 VS 기능 중심

   ⇨ 어느쪽으로 할지는 프로젝트 마다 조율이 필요하다.


FrontController

MVC2에서의 핵심은 FrontController이다.

  ⇨ 유일한 서블릿이다.

 

Spring에서는 FrontController 대신 DispatcherServlet을 사용한다.

 


Type01

◎ 개발자가 직접만든 DispatcherServlet 사용한다.

   ⇨ com.spring.controller.common.DispatcherServlet

 

// FrontController
// @ ▶ .xml : 서블릿 컨테이너(톰캣, 웹 서버)
public class DispatcherServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;

	private HandlerMapping handler;
	private ViewResolver viewResolver;
	
	//1. 멤버변수 초기화하는 역할
	//2. 생성자
	//3. setter
	//4. @Autowired
	//5. DI
	//6. init메서드
	public void init() {
		handler=new HandlerMapping();
		viewResolver=new ViewResolver();
		viewResolver.setPrefix("./");
		viewResolver.setSuffix(".jsp");
	}

	protected void doGet(HttpServletRequest request, HttpServletResponse response) 
    							throws ServletException, IOException {
		doAction(request, response);
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response) 
    							throws ServletException, IOException {
		doAction(request, response);
	}

	private void doAction(HttpServletRequest request, HttpServletResponse response) 
    							throws ServletException, IOException {

		String uri=request.getRequestURI();
		String cp=request.getContextPath();
		String commend=uri.substring(cp.length());
		System.out.println("FC : "+commend);

		Controller controller=handler.getController(commend);
		String view = controller.execute(request, response);

		if(view.contains(".do")) {
			view=viewResolver.getView(view);
		}
		response.sendRedirect(view);

	}
}

 

◎ web.xml 설정

 

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
		xmlns="http://java.sun.com/xml/ns/javaee"
		xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
		                    http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5">
	
	<servlet>
		<servlet-name>dispatcherServlet</servlet-name>
		<servlet-class>com.spring.controller.common.DispatcherServlet</servlet-class>
	</servlet>
	<servlet-mapping>
		<servlet-name>dispatcherServlet</servlet-name>
		<url-pattern>*.do</url-pattern>
	</servlet-mapping>
	
</web-app>

 


 

Type02

◎ Spring 프레임워크에서 제공하는 DispatcherServlet 사용한다.

   ⇨ org.springframework.web.servlet.DispatcherServlet

    ➔ DI(의존주입,init())을 위한 .xml(설정파일)이 필요하다.

      ➔ dispatcher-servlet.xml

      ➔ presentation layer(표현 계층)이 생긴다.

 

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
		xmlns="http://java.sun.com/xml/ns/javaee"
		xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
			            http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5">
	
	<servlet>
		<servlet-name>dispatcher</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
	</servlet>
	<servlet-mapping>
		<servlet-name>dispatcher</servlet-name>
		<url-pattern>*.do</url-pattern>
	</servlet-mapping>
</web-app>

 

◎ Spring 프레임워크에서 제공하는 인코딩 필터 사용한다.

  ⇨ not POJO(Servlet,Filter,Listener) 에 대한 객체등록은 서블릿 컨테이너가 담당한다.

    ➔ 서블릿 컨테이너의 설정파일인 web.xml 에 등록해야한다.

  ※ 중프때했던 비동기 Action(Servlet) ➠ 최프때 일반 Controller(POJO) 로 변경예정이다.

◎ 내가 등록(메몰에 load, 적재, new, <bean>, @Component)하려는 클래스의 타입을 확인한다.

 

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
		xmlns="http://java.sun.com/xml/ns/javaee"
		xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
			            http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5">
	
	<servlet>
		<servlet-name>dispatcher</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
	</servlet>
	<servlet-mapping>
		<servlet-name>dispatcher</servlet-name>
		<url-pattern>*.do</url-pattern>
	</servlet-mapping>
	
	<filter>
		<filter-name>encodingFilter</filter-name>
		<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
		<init-param>
			<param-name>encoding</param-name>
			<param-value>UTF-8</param-value>
		</init-param>
	</filter>
	<filter-mapping>
		<filter-name>encodingFilter</filter-name>
		<url-pattern>*.do</url-pattern>
	</filter-mapping>
	
</web-app>

 


HandlerMapping

Type01

◎ 개발자가 직접만든 HandlerMapper를 사용한다.

◎ DI 로 생성자 주입을 사용한다.

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

import com.spring.controller.member.LoginController;

public class HandlerMapping {
	private Map<String,Controller> mappings;
	
	public HandlerMapping() {
		mappings=new HashMap<String,Controller>();
		
		mappings.put("/main.do", new LoginController());
	}
	
	public Controller getController(String commend) {
		return mappings.get(commend);
	}
}

 

Type02

 Spring 프레임워크에서 제공하는 HandlerMapper 를 사용한다.

   org.springframework.web.servlet.handler.SimpleUrlHandlerMapping

 DI 로 setter 주입을 사용한다.

   주입하는 객체는 Map이다.

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

import org.springframework.stereotype.Controller;

public class HandlerMapping {
	private Map<String,Controller> mappings;
	
	public HandlerMapping() {
		
        mappings=new HashMap<String,Controller>();
		
	}
	
	public Controller getController(String commend) {
		return mappings.get(commend);
	}
}

 

 bean 설정

 

<?xml version="1.0" encoding= "UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation= "http://www.springframework.org/schema/beans
      http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
	
	<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
		<property name="mappings">
			<props>
				<prop key="/login.do">login</prop>
				<prop key="/main.do">main</prop>
			</props>
		</property>
	</bean>
	
</beans>

 

Type03

 @RequestMapping 으로 요청을 매핑한다.

    output 으로 String 을 권장한다.

    요청메서드가 GET, POST, ... 등을 작성하는 것을 권장한다.

    ➔ member.do GET --->> SELECTONE

                                                       SELECT 검색기능

    ➔ member.do POST --->> UPDATE

                                                          CUD 정보변경

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;

import com.spring.biz.member.MemberDAO;
import com.spring.biz.member.MemberDTO;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;

@Controller("login")
public class LoginController {

	@RequestMapping(value="/login.do", method=RequestMethod.POST)
	public String login(HttpServletRequest request, HttpServletResponse response) throws Exception {
		ModelAndView mav=new ModelAndView();
		
		MemberDAO mDAO=new MemberDAO();
		MemberDTO mDTO=new MemberDTO();
		mDTO.setMid(request.getParameter("mid"));
		mDTO.setPassword(request.getParameter("password"));
		mDTO=mDAO.selectOne(mDTO);
		if(mDTO != null) {
			HttpSession session=request.getSession();
			session.setAttribute("member", mDTO.getMid());

			return "redirect:main.do";
		}
		else {
			mav.addObject("msg", "로그인에 실패했습니다...");

			return "goback.do";
		}		
	}
	
	@RequestMapping(value="/logout.do", method=RequestMethod.GET)
	public String logout(HttpServletRequest request, HttpServletResponse response) throws Exception {
		ModelAndView mav=new ModelAndView();
		mav.addObject("msg", "로그아웃이 완료되었습니다! :D");
		
		HttpSession session=request.getSession();
		session.removeAttribute("member");
		
		return "alert.do";
	}

}

 


Controller(Action)


Type01  : JSP

사용자 요청  FrontController  Action  ActionForward  응답

◎ 개발자가 직접만든 Controller 인터페이스 사용한다.

   output 이 ActionForward 이었는데 ViewResolver 가 등장하면서, String 으로 변경된다.
    ※ 어디로(경로), 어떻게(방식:리다이렉트,포워드)

 

public interface Controller {

	// ActionForward → String
	String execute(HttpServletRequest request, HttpServletResponse response) 
    					throws ServletException, IOException;
	
}
public class LoginController implements Controller {

	@Override
	public String execute(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		MemberDAO mDAO=new MemberDAO();
		MemberDTO mDTO=new MemberDTO();
		mDTO.setMid(request.getParameter("mid"));
		mDTO.setPassword(request.getParameter("password"));
		mDTO=mDAO.selectOne(mDTO);
		if(mDTO != null) {
			HttpSession session=request.getSession();
			session.setAttribute("member", mDTO.getMid());

			return "redirect:main.do";
		}
		else {
			request.setAttribute("msg", "로그인에 실패했습니다...");

			return "goback.do";
		}

	}

}

 


Type02 : Spring

요청  DispatcherServlet  HandlerMapping  Controller  String(페이지 이름)  응답

   DispatcherServlet 의 멤버변수 HandlerMapping , ViewResolver == 의존관계 == 의존주입 필요

 


Type03 : Spring 프레임워크에서 제공하는 Controller 인터페이스 사용

 Spring 프레임워크에서 제공하는 Controller 인터페이스를 사용

   output이 MAV

Spring 프레임워크에서 제공하는 Controller 를 impl(구현,상속) 하여 사용한다.

  ⇨ org.springframework.web.servlet.mvc.Controller

기존에는 request(not POJO) 객체를 통해 데이터를 전달 무거움

         ⇩

     현재는 ModelAndView(mav, POJO) 객체를 통해 데이터를 전달 가벼움

import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;

import com.spring.biz.member.MemberDAO;
import com.spring.biz.member.MemberDTO;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;

public class LoginController implements Controller {

	@Override
	public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) 
    									throws Exception {
                                                    
		ModelAndView mav=new ModelAndView();
		
		MemberDAO mDAO=new MemberDAO();
		MemberDTO mDTO=new MemberDTO();
		mDTO.setMid(request.getParameter("mid"));
		mDTO.setPassword(request.getParameter("password"));
		mDTO=mDAO.selectOne(mDTO);
		if(mDTO != null) {
			HttpSession session=request.getSession();
			session.setAttribute("member", mDTO.getMid());

			mav.setViewName("redirect:main.do");
		}
		else {
			mav.addObject("msg", "로그인에 실패했습니다...");

			mav.setViewName("goback.do");
		}
		
		return mav;
	}

}

 

bean 설정

 

<?xml version="1.0" encoding= "UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation= "http://www.springframework.org/schema/beans
      http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
	
	<bean id="login" class="com.spring.controller.member.LoginController" />

</beans>

 


Type04  : Spring 프레임워크에서 제공하는 @Controller를 사용

◎ <bean> @

@Component + implements Controller @Controller

인터페이스가 없다 

  ⇨ 메서드 시그니쳐의 강제성이 없다

  ⇨ output이 String이 가능해진다.   

   하나의 Controller 에서 여러 기능(서로 관련된)을 작성할 수 있다.

   코드의 응집도를 높일 수 있다.

import org.springframework.stereotype.Controller;
import org.springframework.web.servlet.ModelAndView;

import com.spring.biz.member.MemberDAO;
import com.spring.biz.member.MemberDTO;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;

@Controller("login")
public class LoginController {

	public ModelAndView login(HttpServletRequest request, HttpServletResponse response) throws Exception {
		ModelAndView mav=new ModelAndView();
		
		MemberDAO mDAO=new MemberDAO();
		MemberDTO mDTO=new MemberDTO();
		mDTO.setMid(request.getParameter("mid"));
		mDTO.setPassword(request.getParameter("password"));
		mDTO=mDAO.selectOne(mDTO);
		if(mDTO != null) {
			HttpSession session=request.getSession();
			session.setAttribute("member", mDTO.getMid());

			mav.setViewName("redirect:main.do");
		}
		else {
			mav.addObject("msg", "로그인에 실패했습니다...");

			mav.setViewName("goback.do");
		}
		
		return mav;
	}
	
	public ModelAndView logout(HttpServletRequest request, HttpServletResponse response) throws Exception {
		ModelAndView mav=new ModelAndView();
		mav.addObject("msg", "로그아웃이 완료되었습니다! :D");
		mav.setViewName("alert.do");
		
		HttpSession session=request.getSession();
		session.removeAttribute("member");
		
		return mav;
	}

}

 


ViewResolver

◎ ActionForward가 필요 없어진다.


Type01

◎ 개발자가 직접만든 ViewResolver을 사용한다.

  DI 로 setter 주입을 사용한다.

package com.spring.controller.common;

// ActionForward 가 필요없어짐!
public class ViewResolver {
	public String prefix;
	public String suffix;
	public void setPrefix(String prefix) {
		this.prefix = prefix;
	}
	public void setSuffix(String suffix) {
		this.suffix = suffix;
	}
	
	public String getView(String view) {
		return prefix+view+suffix;
	}
}
public class DispatcherServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;

	private HandlerMapping handler;
	private ViewResolver viewResolver;
	
	//1. 멤버변수 초기화하는 역할
	//2. 생성자
	//3. setter
	//4. @Autowired
	//5. DI
	//6. init메서드
	public void init() {
		handler=new HandlerMapping();
		viewResolver=new ViewResolver();
		viewResolver.setPrefix("./");
		viewResolver.setSuffix(".jsp");
	}

 


Type02

Spring 프레임워크에서 제공하는 ViewResolver를 사용한다.

  ⇨ org.springframework.web.servlet.view.InteralResourceViewResolver

◎ DI 로 setter 주입을 사용한다.

※ 특정 페이지의 URL 을 알면, 별도의 권한이 없어도 접근이 가능한 경우가 있다.
    이 경우를 막기위해서는 C 파트에서 별도의 접근권한 유효성검사를 구현해야만한다.
    Spring 에서는, 애초에 페이지를 WEB-INF 폴더에 은닉(하이딩)하여 저장한다.
    WEB-INF 폴더의 하위는 오직 VR 를 통해서만 접근가능함을 이용한 것이다.

 

package com.spring.controller.common;

// ActionForward 가 필요없어짐!
public class ViewResolver {
	public String prefix;
	public String suffix;
	public void setPrefix(String prefix) {
		this.prefix = prefix;
	}
	public void setSuffix(String suffix) {
		this.suffix = suffix;
	}
	
	public String getView(String view) {
		return prefix+view+suffix;
	}
}

 

dispatcher-servlet 설정

 

<?xml version="1.0" encoding= "UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation= "http://www.springframework.org/schema/beans
      http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
	
	<bean id="viewResolver" class="org.springframework.web.servlet.view.InteralResourceViewResolver">
		<property name="prefix" value="/WEB-INF/views/" />
		<property name="suffix" value=".jsp" />
	</bean>

</beans>