본문 바로가기

학원/복기

[Spring] MVC2 예제 (어노테이션 이용)

web.xml에 등록되어 있는 front controller를 이용해 만들어 줄 것이다.

 

web.xml

 

 

 

servlet-context.xml은 appServlet 이름의 서블릿(Front Controller)에게 제공될 Spring Bean을 등록하기 위한 Bean Configuration File이다. 

 

InternalResourceViewResolver 객체

: 클라이언트 요청에 의해 호출되는 요출 처리 메소드의 반환값(View name)을 제공받아 응답 처리할 JSP 문서로 변환하여 반환하는 기능을 제공한다.

 

component-scan 엘리먼트

: 스프링 컨테이너가 클래스에서 사용한 스프링 어노테이션을 검색하여 패키지를 제공해준다.

  • base-package 속성 : 스프링 어노테이션을 사용한 클래스가 선언된 패키지를 설정한다. 

annotation-driven 엘리먼트

: @Controller 어노테이션으로 등록된 Spring Bean에서 @RequestMapping 어노테이션으로 등록된 요청 처리 메소드를 클라이언트 요청에 의해 호출되어 실행될 수 있도록 설정한다.

  • HandlerMapping 객체를 사용하지 않아도 클라이언트 요청에 의해 Controller 클래스의 요청 처리 메소드가 호출되도록 매핑 설정해준다. 

 

servlet-context.xml

 


 

 

controller 패키지에 요청 처리 클래스(Controller 클래스)를 작성해보자

 

 

@Controller 어노테이션를 이용해 요청 처리 클래스를 Spring Bean으로 등록한다.

  • 클래스의 이름은 Spring Bean의 식별자(beanName)으로 자동 설정된다. (첫문자는 소문자로 변환)
  • value 속성을 사용하여 Spirng Bean의 식별자(beanName)를 변경 할 수 있다. 
  • @Controller 어노테이션을 사용하면 Controller 인터페이스를 상속받지 않아도 요청 처리 클래스로 처리가 가능하다.
    • @RequestMapping 어노테이션을 사용하여 메소드를 요청 처리 메소드로 처리되도록 작성할 수 있다.
    • @RequestMapping 어노테이션을 사용하여 요청 처리 메소드를 여러개 선언할 수 있다. Contoller 클래스를 여러 개 만들지 않아도 되기 때문에 편리하다.

 

@RequestMapping은 클라이언트 요청을 처리하기 위한 메소드를 선언하기 위한 어노테이션이다.

  • 기본적으로 클라이언트의 모든 요청방식(Method - GET, POST, PUT, CATCH, DELETE)에 의해 호출되는 요청 처리 메소드를 작성할 경우 사용한다. 
  • 클라이언트의 요청방식을 구분하여 요청 처리 메소드를 호출하고자 할 경우 @RequestMapping 대신  @GetMapping, @PostMapping, @PutMapping, @PatchMapping, @DeleteMapping 등의 어노테이션을 사용할 수 있다. (주로 REST 프로그램 만들 때 사용) 
  • value 속성에 클라이언트 요청 정보(URL 주소)를 반드시 설정해주어야 한다.
    • 클라이언트의 요청 URL 주소로 Front Controller에 의해 요청 처리 메소드가 자동으로 호출된다. (요청 처리)
    • 다른 속성이 없는 경우 속성값만 설정 가능하다.
    • 다른 요청 처리 메소드의 value 속성값과 중복될 경우 WAS 프로그램 시작시 에러가 발생한다.

 

요청 처리 메소드 안에 요청 처리 명령을 작성할 때 일반적으로 Service 클래스의 메소드를 호출한다.

예제에서는 Service 클래스가 없으므로 log로 작성할 것이다.

 

@Controller
public class HelloController {
    //@RequestMapping를 반드시 선언해주어야 한다 
    @RequestMapping(value = "/hello")//클라이언트가 hello라고 요청했을 때 실행
    public void hello() {//요청 처리 메소드
    //요청 처리 명령 작성 - Service 클래스의 메소드 호출
    log.info("[/hello] 페이지 요청 : HelloController 클래스의 hello() 메소드 호출");
    }
...
}

 

 

요청 처리 메소드는 Front Controller에게 반드시 뷰이름(ViewName)을 제공해야 한다.

→ Front Controller는 제공받은 뷰이름을 이용하여 ViewResolver 객체로 응답 처리되도록 변환할 것이다. 

 

1. 메소드의 반환형을 [void]로 설정한 경우 Front Controller에게 메소드의 이름을 뷰이름으로 제공한다. (예제의 경우 hello가 뷰이름이 된다) 

 

hello.jsp

hello.jsp 파일이 존재해야 응답이 가능하다.

 

hello.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>SPRING</title>
</head>
<body>
	<h1>Hello, Srping!</h1>
	<hr>
</body>
</html>

 

HelloController을 실행하고 http://localhost:8000/controller/hello 로 주소 설정해주면

 

 

잘 출력되는 것을 확인할 수 있다.

 

 

src/main/resources의 log4j.xml 파일에서 "xyz.itwill10.controller" 패키지에서 info 레벨 이상의 로그만 출력하도록 지정할 수 있다.

 

 

 

2. 메소드의 반환형을 [String]로 설정한 경우 Front Controller에게 메소드의 반환값(문자열)을 뷰이름으로 제공한다.

 

	@RequestMapping("/helloViewName")
	public String helloViewName() {
		log.info("[/helloViewName] 페이지 요청 : HelloController 클래스의 helloViewName() 메소드 호출");
		return "hello";
	}

 

 

 

3. 메소드의 반환형을 [ModelAndView]로 작성한 경우 반환된 ModelAndView 객체에 뷰이름을 저장하여 제공한다.

 

ModelAndView : 처리결과를 속성값으로 저장하고 뷰이름(ViewName)을 저장하기 위한 객체

	@RequestMapping("/helloMav")
	public ModelAndView helloModelAndView() {
		log.info("[/helloMav] 페이지 요청 : HelloController 클래스의 helloModelAndView() 메소드 호출");		
		
		//ModelAndView modelAndView=new ModelAndView();
		//modelAndView.setViewName("hello");//Setter 메소드 뷰이름 변경

		ModelAndView modelAndView=new ModelAndView("hello");//생성자로 뷰이름 변경 
		
		return modelAndView;
	}

 

 

세 가지 방법 중에서는 String을 가장 많이 사용한다.

 

 

Front Controller가 InternalResourceViewResolver를 사용한 경우 뷰이름으로 생성된 JSP 문서로 응답하지만

Front Controller가 BeanNameViewResolver를 사용한 경우 Spring Bean으로 응답 처리할 수 있도록 만들 수 있다.

→ 요청 처리 메소드의 반환형을 Map 인터페이스 또는 Model 인터페이스로 설정할 수 있다. 

(추후 BeanNameViewResolver 배운 뒤 볼 것임)

 

 


요청 처리 메소드에 의해 처리될 결과를 뷰(JSP 문서)에게 제공하는 방법

 

 

1.ModelAndView 객체의 addObject 메소드를 호출하여 처리결과를 속성값으로 저장하여 제공할 수 있다.

 

 

ModelAndView.addObject(String attributeName, Object attributeValue) 

  • ModelAndView 객체에 처리결과를 속성값으로 저장하는 메소드 - Request Scope
  • 뷰(JSP 문서)에서는 EL 또는 JSTL를 사용하여 속성명으로 속성값을 제공받아 사용할 수 있다.
//요청 처리 메소드에 의해 처리될 결과를 뷰(JSP 문서)에게 제공하는 방법

//요청 처리 클래스 - Spring Bean으로 등록
@Controller
public class ResultController {
	@RequestMapping("/resultMav")
	public ModelAndView modelAndViewResult() {
		ModelAndView modelAndView=new ModelAndView("result_display");
		
		//ModelAndView 객체에 처리결과를 속성값으로 저장
		modelAndView.addObject("mavName", "홍길동");
		return modelAndView;
	}
}

 

result_display.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>SPRING</title>
</head>
<body>
	<h1>출력페이지</h1>
	<hr>
	<h2>ModelAndView = ${mavName }</h2>
</body>
</html>

 

 

 

요청 처리 메소드는직접 호출하는 것이 아니라 Front Controller에 의해 자동 호출되는 메소드이다. 

요청 처리 메소드에 매개변수를 작성하면 Front Controller는 스프링 컨테이너(WebApplicationContext 객체)에게 매개변수에 저장 가능한 객체(Spring Bean)를 제공받아 저장할 수 있다.

	@RequestMapping("/resultMav")
	public ModelAndView modelAndViewResult(ModelAndView modelAndView) {
		modelAndView.setViewName("result_display");
		modelAndView.addObject("mavName", "홍길동");
		return modelAndView;
	}

 

 

2.HttpServletRequest 객체의 setAttribute() 메소드를 호출하여 처리결과를 속성값으로 저장하여 제공힌다.

 

HttpServletRequest.setAttribute(String attribute, Object attributeValue)

: HttpServletRequest 객체에 처리결과를 속성값으로 저장하는 메소드 - Request Scope 

 

    @RequestMapping("/resultRequest")
	public String requestResult(HttpServletRequest request) {
		request.setAttribute("requestName", "임꺽정");
		return "result_display";
	}

 

result_display.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>SPRING</title>
</head>
<body>
	<h1>출력페이지</h1>
	<hr>
	<h2>ModelAndView = ${mavName }</h2>
	<h2>HttpServletRequest = ${requestName }</h2>
</body>
</html>

 

 

3.Model 객체의 addAttribute() 메소드를 호출하여 처리결과를 속성값으로 저장하여 제공한다.

 

Model 객체 : 처리결과를 속성값으로 저장하여 뷰에게 제공하기 위한 객체 

model.addAttribute() : Model 객체에 처리결과를 속성값으로 저장하는 메소드 - Request Scope

 

	@RequestMapping("/resultModel")
	public String modelResult(Model model) {
		model.addAttribute("modelName", "전우치");
		return "result_display";
	}

 

result_display.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>SPRING</title>
</head>
<body>
	<h1>출력페이지</h1>
	<hr>
	<h2>ModelAndView = ${mavName }</h2>
	<h2>HttpServletRequest = ${requestName }</h2>
	<h2>Model = ${modelName }</h2>
</body>
</html>

 


ModelController

@Controller
public class ModelController {
	@RequestMapping("/display1")
	public String display1(Model model) {
		model.addAttribute("name", "홍길동");
		model.addAttribute("now", new SimpleDateFormat("yyyy년 MM월 dd일 HH시 mm분 ss초").format(new Date()));
		return "model_display";
	}
	
	@RequestMapping("/display2")
	public String display2(Model model) {
		model.addAttribute("name", "임꺽정");
		model.addAttribute("now", new SimpleDateFormat("yyyy년 MM월 dd일 HH시 mm분 ss초").format(new Date()));
		return "model_display";
	}
	
	@RequestMapping("/display3")
	public String display3(Model model) {
		model.addAttribute("name", "전우치");
		model.addAttribute("now", new SimpleDateFormat("yyyy년 MM월 dd일 HH시 mm분 ss초").format(new Date()));
		return "model_display";
	}
}

 

model_display.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>SPRING</title>
</head>
<body>
	<h1>출력페이지</h1>
	<hr>
	<h2>이름 = ${name }</h2>
	<h2>현재 날짜와 시간 = ${now }</h2>
</body>
</html>

 

 

 

model.addAttribute("now", new SimpleDateFormat("yyyy년 MM월 dd일 HH시 mm분 ss초").format(new Date()));

 

>> 해당 부분이 겹치기 때문에 비효율적이다.

 

 

이를 한꺼번에 처리하는 방법에 대해 알아보자

 

 

@ModelAttribute

  • 메소드에 @ModelAttribute 어노테이션을 사용하면 메소드에 반환되는 객체(값)을 현재 Controller 클래스에 작성된 모든 요청 처리 메소드의 뷰에게 제공해준다.
  • 요청 처리 메소드에 의해 응답 처리될 뷰에서 공통적으로 사용되는 객체(값)를 제공할 목적으로 사용한다. 
  • value 속성에 메소드에 의해 반환된 객체(값)을 뷰에서 사용하기 위한 이름(속성명)을 설정한다. (다른 속성이 없으면 속성값만 설정 가능하다.)
@Controller
public class ModelController {
	...
	
	//메소드에 반환되는 객체(값)을 현재 Controller 클래스에 작성된 모든 요청 처리 메소드의 뷰에게 제공
	@ModelAttribute(value = "now")
	//시스템의 현재 날짜와 시간을 문자열로 반환하는 메소드
	public String getNow() {
		return new SimpleDateFormat("yyyy년 MM월 dd일 HH시 mm분 ss초").format(new Date());
	}
}

 

 

전체 소스코드

package xyz.itwill10.controller;

import java.text.SimpleDateFormat;
import java.util.Date;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class ModelController {
	@RequestMapping("/display1")
	public String display1(Model model) {
		model.addAttribute("name", "홍길동");
		//model.addAttribute("now", new SimpleDateFormat("yyyy년 MM월 dd일 HH시 mm분 ss초").format(new Date()));
		return "model_display";
	}
	
	@RequestMapping("/display2")
	public String display2(Model model) {
		model.addAttribute("name", "임꺽정");
		//model.addAttribute("now", new SimpleDateFormat("yyyy년 MM월 dd일 HH시 mm분 ss초").format(new Date()));
		return "model_display";
	}
	
	@RequestMapping("/display3")
	public String display3(Model model) {
		model.addAttribute("name", "전우치");
		//model.addAttribute("now", new SimpleDateFormat("yyyy년 MM월 dd일 HH시 mm분 ss초").format(new Date()));
		return "model_display";
	}
	
	//메소드에 반환되는 객체(값)을 현재 Controller 클래스에 작성된 모든 요청 처리 메소드의 뷰에게 제공
	@ModelAttribute(value = "now")
	//시스템의 현재 날짜와 시간을 문자열로 반환하는 메소드
	public String getNow() {
		return new SimpleDateFormat("yyyy년 MM월 dd일 HH시 mm분 ss초").format(new Date());
	}
}