기본 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>
'프레임워크 > Spring' 카테고리의 다른 글
[프레임워크] <Spring>〈Gradle〉프로젝트 특징 (0) | 2024.03.07 |
---|---|
[프레임워크] <Spring>〈Maven〉Command객체를 활용한 Controller (0) | 2024.03.07 |
[프레임워크] <Spring>〈Maven〉Transaction (0) | 2024.03.04 |
[프레임워크] <Spring>〈Maven〉JDBCTempalete을 활용한 DAO (0) | 2024.03.04 |
[프레임워크] <Spring>〈Maven〉Advice의 @어노테이션화 (0) | 2024.03.01 |