개발자/Spring

[SPRING] Spring MVC // + Controller 자세히.

푸루닉 2022. 12. 27. 13:30

어제 spring의 Dispatcher Servlet에 대해서 간단히 알아 보았다. 이번에는 Spring MVC와 구성요소에 대해 다뤄 볼 것이다.

 

Spring MVC의 구조

의 주요구성요는 Model, View, Controller이지만, 3가지 구성요소가 유기적으로 동작하기 위해 다양한 구성요소가 함께한다.

  • DispatcherServlet(Front Controller)
  • Handler(Controller)
  • ModelAndView
  • ViewResolver

MVC 프레임워크와 Spring 프레임워크가 거의 동일하다.

MVC FrameWork


 

Handler(Controller)

동일한 형식에 대해 다른 controller

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ include file="header.jsp" %>

<form method="POST">
	<p><input type="text" name="name" placeholder="이름" required autofocus></p>
	<p><input type="number" name="age" placeholder="나이" required ></p>
	<p><input type="submit"></p>
</form>


</body>
</html>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ include file="header.jsp" %>

<h3>${msg }</h3>


</body>
</html>

 

데이터를 처리 하기 위한 Controller는 자바코드로 이루어진다.

1. JSP스러운 Spring 코드(Model)

package com.itbank.controller;

import java.io.IOException;

import javax.servlet.http.HttpServletRequest;

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

@Controller
public class Ex01Controller {
	
	@RequestMapping(value = "/ex01", method = RequestMethod.GET)
	public void ex01() {}
	
	// 가장 기본적인 반환형은 String이며, 포워딩할 jsp의 이름을 가리킨다
	// 반환형이 void라면, 요청주소 문자열을 활용하여 포워딩할 jsp의 이름을 찾는다
	// 주소 맨 앞의 /는 제거하고, /WEB-INF/views/ex01.jsp를 찾아서 포워드한다
	// 새로 추가된 함수는 반드시 톰캣을 재시작해야 함수가 매핑되어 올라간다 => 스프링은 프로젝트가 시작할때 모든 것이 준비되기 때문 
	
	// 같은 주소라도 요청 메서드에 따라서 서로 다른 작동으로 구분한다.
	
	@RequestMapping(value = "/ex01", method = RequestMethod.POST)
	public String ex01(HttpServletRequest request) throws IOException {
		
		String name = request.getParameter("name");
		int age = Integer.parseInt(request.getParameter("age"));
		
		String adult = age >= 20 ? "성인" : "미성년자";
		String msg = String.format("%s의 나이는 %d살이고, %s입니다", name, age, adult);
		
		request.setAttribute("msg", msg);
		
		return "ex01-result";
	}
}

위 보기와 같이 어노테이션을 RequestMapping을 이용하여 진행할경우, method형식을 지정해줘야한다. 

또한, request 모두를 받아서 사용하므로, String형식으로 변환을 해줘야하는 불편함도 존재한다.

 

2. Spring형식의 Controller

package com.itbank.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;

@Controller
public class Ex02Controller {
	// 1) @RequestMapping의 단축 어노테이션이 존재한다(GetMapping, PostMapping ...)
	// 2) request.getParameter() 대신 컨트롤러 메서드의 매개변수에 파라미터를 받을 수 있다.
	// 3) HttpServletRequest 대신 Model타입의 객체를 이용하여 attribute를 전달할 수 있다.
	
	@GetMapping("/ex02")
	public void ex02() {}

	@PostMapping("/ex02")
	public String ex02(String name, int age, Model model) {
		// primitive type + String 형식은 매개변수로 받으면 request.getParameter()가 필요없다.
		// HttpServletRequest는 파라미터 및 어트리뷰트만 처리하기에는 너무 무거운 객체이다
		// 어트리뷰트만 처리할 수 있는 간소화된 객체 Model을 사용한다 (스프링에서 사용하는 객체)
		
		// request.setCharacterEncoding("UTF-8"); 이 코드는 web xml에서 필터로 처리할 것임
		
		String adult = age >= 20 ? "성인" : "미성년자";
		String msg = String.format("%s의 나이는 %d살이고, %s입니다.", name, age, adult);
		model.addAttribute("msg", msg);
		
		return "ex02-result";
		
	}
}

JSP형식과 동일하게 출력되나 실제 코드는 많이 줄어든 모습을 확인할 수 있다.

 

Spring으로 오며 변경된 점 : 

1) @RequestMapping의 단축 어노테이션이 존재한다(GetMapping, PostMapping ...)

2) request.getParameter() 대신 컨트롤러 메서드의 매개변수에 파라미터를 받을 수 있다.

3) HttpServletRequest 대신 Model타입의 객체를 이용하여 attribute를 전달할 수 있다.

 

 

3. ModelAndView 형식

package com.itbank.controller;

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

@Controller
@RequestMapping("/ex03")	// 주소만 ex03이면 모두 해당
public class Ex03Controller {
	
	@GetMapping	// 같은 주소에서 요청 메서드에 따라 구분(GET)
	public void ex03() {}
	
	@PostMapping // 같은 주소에서 요청 메서드에 따라 구분(POST)
	public ModelAndView ex03(String name, int age) {	// 사용자 입력에 의해 들어오는 값만 매개변수
		ModelAndView mav = new ModelAndView();	// Model model
							// String viewName
		// 고정값일 경우 주로 이용
		mav = new ModelAndView("ex03-result");	// 생성자 매개변수로 viewName을 전달하기
		
		// 변동값일 경우 주로 이용
		mav.setViewName("ex03-result");	// setter로 viewName을 전달하기(포워드시킬 jsp의 이름)
		
		String adult = age >= 20 ? "성인" : "미성년자";
		String msg = String.format("%s의 나이는 %d살이고, %s입니다", name, age, adult);
		
		mav.addObject("msg", msg);	// jsp 에게 넘길 attribute(object)
		
		return mav;
	}

}

앞서 코드와 달라진 점 : 

1) 데이터 처리 후 model에 넣기

2) Model을 넣을 view 이름을 지정해준다.

3) Model과 viewname을 감싼 ModelAndView '객체'를 DispatcherServlet으로 보낸다.

 

4. Spring 커멘드 객체 활용

package com.itbank.controller;

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

import com.itbank.model.Ex04DTO;

@Controller
@RequestMapping("/ex04")
public class Ex04Controller {
	
	@GetMapping
	public void abcd() {}
	// 컨트롤러의 함수 이름은 개발자가 구분하기 쉬운 이름이면 된다.
	// 컨트롤러의 함수 이름은 viewName에 전형 영향을 주지 않는다.
	
	@PostMapping
	public ModelAndView ex04(Ex04DTO user) {	// 스프링 커맨드 객체 활용
		ModelAndView mav = new ModelAndView("ex04-result");
		mav.addObject("user",user);
		
		return mav;
	}

}

위와 같은 경우 jsp때와 비슷하게 DTO를 만들어줘서 Controller로 넘겨준다

package com.itbank.model;

public class Ex04DTO {	// 개별 데이터를 나타내기 위한 클래스
	
	// 싱글톤 적용하면 안된다. 같은 형식이라도 서로 다른 데이터를 나타낼 수 있어야 한다
	// 따라서, 스프링 빈으로 등록하지 않는다.
	
	private String name;
	private int age;
	
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}

}

이후 변경된 result.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ include file="header.jsp" %>

<h3>
	${user.name }의 나이는
	${user.age }살이고,
	${user.age >= 20 ? '성인' : '미성년자' }입니다. 
</h3>


</body>
</html>

EL태그로 데이터를 바로 끌고 올 수 있다.

 

Handler(Controller)

  • 코드상으로 완벽히 화면구현과 데이터처리 과정이 완벽히 분리된다.
  • Java(Back-End : 데이터 처리만을 처리
  • <-> 서로 정보를 전달 받고 뿌려주기만 한다.
  • JSP(Front-End) : 화면구현만을 처리