spring - 스프링 MVC 기능

오늘·2021년 5월 27일
0

웹 페이지 연습

목록 보기
21/35

MVC

스프링에서 웹 프로그램 개발에 필요한 기능을 제공하는데, 그 중 하나

MVC 기능의 특징

스프링에서 지원하는 MVC 기능의 특징

  • 모델 2 아키텍쳐를 지원한다
  • 스프링과 다른 모듈과의 연계가 용이
  • 타일즈(tiles)나 사이트메시(sitemesh) 같은 View 기술과의 연계가 용이
  • 태그 라이브러리를 통해 메시지 출력, theme 적용 그리고 입력 폼을 보다 쉽게 구현할 수 있다.

스프링 프레임워크 MVC 구성요소


MVC 기능 수행 과정

  1. 브라우저가 DispatcherServlet에 URL로 접근하여 해당 정보를 요청합니다.
  2. 핸들러 매핑에서 해당 요청에 대해 매핑된 컨트롤러가 있는지 요청합니다.
  3. 매핑된 컨트롤러에 대해 처리를 요청합니다.
  4. 컨트롤러가 클라이언트의 요청을 처리한 결과와 View 이름을 ModelAndView에 저장해서 DispatcherServlet으로 반환합니다.
  5. DispatcherServlet에서는 컨트롤러에서 보내온 View 이름을 ViewResolver로 보내 해당 View를 요청합니다.
  6. ViewResolver는 요청한 View를 보냅니다.
  7. View의 처리 결과를 DispatcherServlet으로 보냅니다.
  8. DispatcherServlet은 최종 결과를 브라우저로 전송합니다.

SimpleUrlController 실행 과정

  1. 브라우저에서 http://localhost:0000/pro21/test/index.do로 요청
  2. DispatcherServlet은 요청에 대해 미리 action-servlet.xml에 매핑된 SimpleUrlController를 요청
  3. 컨트롤러는 요청에 대해 test 폴더에 있는 index.jsp를 브라우저로 전송

실습

  1. 파일구조

    실습에 필요한 파일 설명

  2. web.xml 작성

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://xmlns.jcp.org/xml/ns/javaee"
	xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
	id="WebApp_ID" version="3.1">
	
	<servlet>
		<servlet-name>action</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<!-- 값이 1 이상이면 톰캣 실행시 DispatherServlet을 미리 메모리에 로드
			  지정하지 않거나 음수로 지정시에는 브라우저세어 요청할 때메모리에 로드
			  그니까 음수로 하면 필요할 때만 로드 시켜 사용할 수 있다 -->
		<load-on-startup>1</load-on-startup>
	</servlet>
	
	<servlet-mapping>
		<servlet-name>action</servlet-name>
		<url-pattern>*.do</url-pattern>
	</servlet-mapping>
</web-app>
  1. action-servlet.xml 작성
    action-servlet에 필요한 빈들
  2. SimpleUrlController 클래스에 대해 id가 SimpleController인 빈 생성
  3. SimpleUrlHandlerMapping 클래스 빈을 생성하면
    요청명/test/index.do 에 대해 처리하는 컨트롤러를 Simple UrlController로 설정
  • 설정 파일 이름은 반드시 web.xml의 서블릿 매핑 시 사용했던 <servlet-name> 태그 값인 action으로 시작해야 합니다(pro21에서는 web.xml에서 태그 값을 action으로 설정했으므로 action1-servlet.xml로 지정하면 톰캣 실행 시 오류가 발생
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:p="http://www.springframework.org/schema/p"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xmlns:context="http://www.springframework.org/schema/context"
	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
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<!-- 위는 필요 태그 목록 -->




<!-- id가 simpleUrlController인 빈을 생성 -->
<bean id="simpleUrlController" class="com.spring.ex01.SimpleUrlController"/>
<!-- SimpleUrlHandlerMapping 클래스를 이용해
	/test/index.do로 요청시 simpleUrlController를 호출하도록 매핑 -->
<bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
	<property name="mappings">
		<props>
			<prop key="/test/index.do">simpleUrlController</prop>
		</props>
	</property>
</bean>
</beans>
  1. SimpleUrlController 클래스 작성
    매핑된 요청에 대해 컨트롤러의 기능을 수행한다
package pro21.com.spring.ex01;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

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

// 매핑된 요청에 대해 컨트롤러의 기능을 수행하는 곳
// 스프링에서 제공하는 Controller 인터페이스 구현
public class SimpleUrlController implements Controller {
	@Override
	public ModelAndView handleRequest(HttpServletRequest arg0, HttpServletResponse arg1) throws Exception {
		// 작업을 마친 후 뷰 이름을 ModelAndView에 index.jsp로 설정하여 반환
		return new ModelAndView("index.jsp");
	}
}
  1. index.jsp
<%@ page language="java" contentType="text/html; charset=utf-8" isCLIgnore="false" %>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title> spring 테스트</title>
</head>
<body>
	<h1>index.jsp 파일부분</h1>
	<p> Hello Spring!! </p>
</body>
</html>
  1. 요청(실행)하는 방법
    톰캣 서버를 실행시키고 크롬이나 내부 창에 localhost:포트번호/파일이름/test/index.do를 타이핑

    위 처럼 나와야 하는데 안나온다. 연결이 어딘가 잘 못 된듯

MultiActionController

여러 요청명에 대해 한 개의 컨트롤러에 구현된 각 메소드로 처리할 수 있다

실습 01

파일 모양

사용되는 스프링 클래스

  1. web.xml
    브라우저에서 *.do로 요청시 스프링의 DispatcherServlet 클래스가 요청받을 수 있게 서블릿 매핑을 설정하는 부분
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
   <servlet>
      <servlet-name>action</servlet-name>
      <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
      <load-on-startup>1</load-on-startup>
   </servlet>

   <servlet-mapping>
      <servlet-name>action</servlet-name>
      <url-pattern>*.do</url-pattern>
   </servlet-mapping>
</web-app>
  1. action-servlet.xml
    스프링에서 필요한 빈들을 설정
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:p="http://www.springframework.org/schema/p"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xmlns:context="http://www.springframework.org/schema/context"
	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
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<!-- 위는 필요 태그 목록 -->



<!-- 컨트롤러에서  ModelAndView 인자로 뷰 이름이 반환되면 InternalResourceViewResolver의 -->
 	<bean id="viewResolver"
		class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<property name="viewClass"
			value="org.springframework.web.servlet.view.JstlView" />
		<!-- 프로퍼티 prefix 속성에 지정된 /test 폴더에서 ModeView 인자로 넘어온 view 이름에 해당되는 jsp를 선택해
			DispatcherServlet으로 보낸다 -->
		<property name="prefix" value="/test/" />
		<property name="suffix" value=".jsp" />
	</bean>

	<bean id="userUrlMapping"
		class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
		<property name="mappings">
			<props>
				<!-- 1. url요청명이 /test/*.do 로 시작되면 userController 요청 -->
				<prop key="/test/*.do">userController</prop>
			</props>
		</property>
	</bean>

	<!-- 2. userController가 요청되면 -->
	<bean id="userController" class="com.spring.ex02.UserController">
		<!-- 3. methodNameResolver프로퍼티에 ref local을 주입해 직접 메소드를 호출-->
		<property name="methodNameResolver">
			<ref local="userMethodNameResolver" />
		</property>
	</bean>

	<!-- 4. 호출되면 PropertiesMethodNameResolver를 이용해-->
	<bean id="userMethodNameResolver"
		  class="org.springframework.web.servlet.mvc.multiaction.PropertiesMethodNameResolver">
		<property name="mappings">
			<props>
				<!-- 5. /test/login.do로 요청하면 userController의 login 메소드 호출 -->
				<prop key="/test/login.do">login</prop>
			</props>
		</property>
	</bean>

</beans>
  1. UserController 클래스 작성
    매핑된 요청에 대해 컨트롤러의 기능을 수행
package com.spring.ex02;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.multiaction.MultiActionController;

// 설정파일(action-servlet)의 userMethodNameResolver 프로퍼티를 사용하려면
// 반드시 MultiActionController를 상속받아야 한다
public class UserController extends MultiActionController {
	public ModelAndView login(HttpServletRequest request,
				HttpServletResponse response) throws Exception {
		String userID = "";
		String passwd = "";
		
		ModelAndView mav = new ModelAndView();
		
		request.setCharacterEncoding("utf-8");
		
		userID = request.getParameter("userID");
		passwd = request.getParameter("passwd");
		
		// ModelAndView에 로그인 정보를 붙이기
		mav.addObject("userID", userID);
		mav.addObject("passwd", passwd);
		// ModelAndView 객체에 포워딩할 jsp 이름을 설정
		// -> 응답해줄 파일 명을 적어주면 된다
		mav.setViewName("result");
		
		return mav;
	}
}
  1. loginForm
    로그인 폼
<%@ page language="java" contentType="text/html; charset=utf-8"
	pageEncoding="utf-8" isELIgnored="false"%>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>    
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<c:set var="contextPath"  value="${pageContext.request.contextPath}"  />
<% request.setCharacterEncoding("utf-8"); %>

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>로그인 창</title>
</head>
<body>
	<!-- /test/login.do로 디스팩쳐서블릿에 요청 -->
	<form name="frmLogin" method="post" action="${contextPath}/test/login.do">
		<table border="0" width="80%" align="center">
			<tr align="center">
				<td> 아이디 </td>
				<td> 비밀번호 </td>
			</tr>
			
			<tr align="center">
				<!-- UserController에 적어줬던 변수명으로 name 설정하기 -->
				<td><input type="text" name="userID" value="" size="20"></td>
				<td><input type="password" name="passwd" value="" size="20"></td>
			</tr>
			
			<tr align="center">
				<td colspan="2">
					<input type="submit" value="로그인" > 
					<input type="reset"  value="다시입력" > 
				</td>
			</tr>
		</table>
	</form>
</body>
</html>
  1. result
    로그인 결과 보여주기
<%@ page language="java" contentType="text/html; charset=utf-8"
	pageEncoding="UTF-8" isELIgnored="false" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>    
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<% request.setCharacterEncoding("UTF-8"); %>
 
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>결과 창</title>
</head>
<body>
	<table border="1" width="50%" align="center">
		<tr align="center">
			<td> 아이디 </td>
			<td> 비밀번호 </td>
		</tr>
		
		<tr align="center">
			<td> ${userID} </td>
			<td> ${passwd} </td>
		</tr>
	</table>
</body>
</html>

서버를 실행 시킨 후 http://localhost:포트번호/test/loginForm.jsp 로 페이지를 요청하면 실행이 된다. 첫 화면에 아이디/비밀번호를 입력한 뒤
로그인을 누르면 입력한 값이 출력된다
입력값과 출력값이 달라보이는건 오류가 나서 중간에 수정했기 때문에..


실습 02

회원 정보 입력창에서 회원정보 입력시, 전송된 회원 정보 출력하기
파일 모양

1. 회원 정보를 표시하기 위해 action-servlet.xml에 내용 추가

<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:p="http://www.springframework.org/schema/p"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xmlns:context="http://www.springframework.org/schema/context"
	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
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">

 	<bean id="viewResolver"
		class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<property name="viewClass"
			value="org.springframework.web.servlet.view.JstlView" />
		<property name="prefix" value="/test/" />
		<property name="suffix" value=".jsp" />
	</bean>

	<bean id="userUrlMapping"
		class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
		<property name="mappings">
			<props>
				<prop key="/test/*.do">userController</prop>
			</props>
		</property>
	</bean>

	<bean id="userController" class="com.spring.ex02.UserController">
		<property name="methodNameResolver">
			<ref local="userMethodNameResolver" />
		</property>
	</bean>

	<bean id="userMethodNameResolver"
		  class="org.springframework.web.servlet.mvc.multiaction.PropertiesMethodNameResolver">
		<property name="mappings">
			<props>
				<prop key="/test/login.do">login</prop>
				<prop key="/test/memberInfo.do">memberInfo</prop> 
			</props>
		</property>
	</bean>
</beans>
  1. UserController.java 내용 수정 및 추가
package com.spring.ex02;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.multiaction.MultiActionController;

public class UserController extends MultiActionController {
	public ModelAndView memberInfo(HttpServletRequest request,
			HttpServletResponse response) throws Exception {
		
		request.setCharacterEncoding("utf-8");
		
		String id = request.getParameter("id");
		String pw = request.getParameter("pw");
		String name = request.getParameter("name");
		String email = request.getParameter("email");
		
		ModelAndView mav = new ModelAndView();

		mav.addObject("id", id);
		mav.addObject("pw", pw);
		mav.addObject("name", name);
		mav.addObject("email", email);
		
		mav.setViewName("memberInfo");
		
		return mav;
	}
}
  1. memberForm.jsp
    회원가입창에서 회원정보 입력시 /test/memberInfo.do로 요청하도록 action 속성에 설정
<%@ page language="java" contentType="text/html; charset=utf-8"
	pageEncoding="utf-8" isELIgnored="false"%>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<c:set var="contextPath" value="${pageContext.request.contextPath}" />
<% request.setCharacterEncoding("utf-8"); %>

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>회원가입</title>
</head>
<body>
	<form method="post" action="${contextPath}/test/memberInfo.do">
		<h1 class="text_center">회원 가입창</h1>
		<table align="center">
			<tr>
				<td width="200"><p align="right">아이디</td>
				<td width="400"><input type="text" name="id"></td>
			</tr>

			<tr>
				<td width="200"><p align="right">비밀번호</td>
				<td width="400"><input type="password" name="pw"></td>
			</tr>
			<tr>
				<td width="200"><p align="right">이름</td>
				<td width="400"><p>
						<input type="text" name="name"></td>
			</tr>
			<tr>
				<td width="200"><p align="right">이메일</td>
				<td width="400"><p>
						<input type="text" name="email"></td>
			</tr>
			<tr>
				<td width="200"><p>&nbsp;</p></td>
				<td width="400"><input type="submit" value="가입하기"><input
					type="reset" value="다시입력"></td>
			</tr>
		</table>
	</form>
</body>
</html>
  1. memberInfo.jsp
    UserController의 memberInfo()메소드에서 바인딩해 전달된 정보를 화면에 출력하는 곳!
<%@ page language="java" contentType="text/html; charset=UTF-8" 
	pageEncoding="UTF-8" isELIgnored="false" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>    
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
 
<html>
<head>
<meta charset="UTF-8">
<title>회원 정보 출력창</title>
</head>
<body>
<table border="1" align="center" width="100%" >
   <tr align=center   bgcolor="lightgreen">
      <td ><b>아이디</b></td>
      <td><b>비밀번호</b></td>
      <td><b>이름</b></td>
      <td><b>이메일</b></td>
   </tr>
   <tr align="center">
      <td>${id}</td>
      <td>${pw}</td>
      <td>${name}</td>
      <td>${email}</td>
    </tr>
</table>
</body>
</html>

실행된 화면에 정보를 입력 후

가입하기를 누르면 /test/memberInfo.do로 요청한 후 입력된 정보가 그대로 출력된다


메소드 이름 설정 방법

MutilActionController와 ProperiesMethodNameResolver를 이용한 메소드 이름 설정 방법

-> 이것을 이용하면 요청명과 같은 이름으로 메소드를 설정할 수 있어 코드 가독성이 좋아진다! (근데 아직 이해 못함)

  • UserController 클래스
    변경한 부분은 이와 같다
    String vieName = getViewName(request); 부분을 추가해주고
    출력파일을 찾는 mav.setViewName("result") 부분을 mav.setViewName(viewName)으로 변경해주었다.

또 getViewName 이라고 사용자가 메소드를 만들었으니
private String getViewName 부분 추가해 내용 작성!

package com.spring.ex02;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.multiaction.MultiActionController;

public class UserController extends MultiActionController {
	public ModelAndView memberInfo(HttpServletRequest request,
			HttpServletResponse response) throws Exception {
		
		request.setCharacterEncoding("utf-8");
		
		String viewName = getViewName(request);
		String id = request.getParameter("id");
		String pw = request.getParameter("pw");
		String name = request.getParameter("name");
		String email = request.getParameter("email");

		ModelAndView mav = new ModelAndView();

		mav.addObject("id", id);
		mav.addObject("pw", pw);
		mav.addObject("name", name);
		mav.addObject("email", email);
		
		mav.setViewName(viewName);
		System.out.println("ViewName: "+viewName);
		
		return mav;
	}

	private String getViewName(HttpServletRequest request) throws Exception{
		String contextPath = request.getContextPath();
		String uri = (String)request.getAttribute("javax.servlet.include.request_uri");
		if(uri == null || uri.trim().equals("")) {
			uri = request.getRequestURI();
		}
		
		int begin = 0;
		if( !((contextPath == null) || ("".equals(contextPath)))) {
			begin = contextPath.length();
		}
		
		int end;
		if(uri.indexOf(";") != -1) {
			end = uri.indexOf(";");
		} else if (uri.indexOf("?") != -1) {
			end = uri.indexOf("?");
		} else {
			end = uri.length();
		}
		
		String fileName = uri.substring(begin, end);
		if(fileName.indexOf(".") != -1) {
			fileName = fileName.substring(0, fileName.lastIndexOf("."));
		}
		if (fileName.lastIndexOf("/") != -1) {
			fileName = fileName.substring(fileName.lastIndexOf("/"), fileName.length());
		}
		return fileName;
	}
}

0개의 댓글