For Programmer

Part2 - 스프링 MVC 의 Controller(1) 본문

Spring/스프링 프로젝트

Part2 - 스프링 MVC 의 Controller(1)

유지광이 2020. 8. 20. 01:23
728x90

스프링 MVC를 이용하는 경우 작성도는 Controller는 다음과 같은 특징이 있습니다.

-HttpServletRequest,HttpServletResponse를 거의 사용할 필요 없이 필요한 기능 구현

-다양한 타입의 파라미터 처리,다양한 타입의 리턴 타입 사용 가능

-GET 방식, POST방식 등 전송 방식에 대한 처리를 어노테이션으로 처리 가능

-상속/인터페이스 방식 대신에 어노테이션만으로도 필요한 설정 가능

 

1. @Controller, @RequestMapping

package org.zerock.controller;

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

@Controller
@RequestMapping("/sample/*")
public class SampleController {
	
}

@Controller 어노테이션

servlet-context.xml 일부

<context:component-scan base-package="org.zerock.controller" />

에서 controller패키지를 스캔하고 있기 때문에 Controller어노테이션이 달린 클래스들을 개체(Bean)로 관리할 수 있습니다.

@RequestMapping은 현재 클래스의 모든 메서들의 기본적인 URL경로가 됩니다. 예르르들어 SampleController 클래스를 다음과 같이 '/sample/*'이라는 경로로 지정했다면 다음과 같은 URL은 모두 SampleController에서 처리됩니다.(ex: /sample/aaa , /sample/bbb)

또한 @RequestMapping은 클래스이 선언 뿐만아니라 메서드 선언에도 사용할 수 있습니다.

package org.zerock.controller;

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

@Controller
@RequestMapping("/sample/*")
public class SampleController {
	
	@RequestMapping("/hello")
	public void basic() {
		
	}
}

*이렇게 메서드에도 설정할 경우 URL을 /sample/hello 로 해당 메서드에 직접적으로 설정이 가능합니다.

@RequestMapping의 변화

RequestMapping은 메서드에서 선언할 경우 GET방식,POST방식을 지정해줄 수 있으며 둘다 표현도 가능하다.

@RequestMapping(value="/hello",method = {RequestMethod.GET,RequestMethod.POST})
	public String basic() {
		return "home";
	}

스프링4.3 버젼부터는 @RequestMapping을 줄여서 사용할 수 있는 @GetMapping , @PostMapping을 사용할 수 있다.

	@GetMapping("/get")
	public void get() {
		
	}
	
	@PostMapping("/post")
	public void post() {
		
	}

2. Controller의 파라미터 수집

org.zerock.domain 이라는 패키지를 작성하고, SampleDTO클래스를 만들기

package org.zerock.domain;

import lombok.Data;

@Data
public class SampleDTO {

	private String name;
	private int age;
}

*@Data는 lombok에서 제공하는 라이브러리인데 @Data를 이용하게 되면 getter/setter,equals(), toString() 등의 메서드를 자동생성해준다.

SampleController 클래스에 다음과 같이 메서드를 만들어준다.

package org.zerock.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.zerock.domain.SampleDTO;

import lombok.extern.log4j.Log4j;

@Controller
@RequestMapping("/sample")
@Log4j
public class SampleController {

	@GetMapping("/ex01")
	public String ex01(SampleDTO dto) {

		log.info(dto);

		return "ex01";
	}

}

 톰캣 서버를 실행 시킨 후 http://localhost:8090/sample/ex01?name=AAA&age=10 로 들어가보면 로그창에 

다음과 같이 파라미터를 잘 가져온다.

또는 따로 클래스를 생성하지 않고 기본자료형이나 문자열 등에도 파라미터의 타입만을 맞게 선언해주는 방식을 이용할 수 있다.

@GetMapping("/ex02")
	public String ex02(@RequestParam("name") String name, @RequestParam("age") int age) {

		log.info("name: " + name);
		log.info("age: " + age);

		return "ex02";
	}

다음과 같이 직접 기본자료형 앞에 RequestParam 설정이 가능하다. 톰캣 서버를 실행 시킨 후 http://localhost:8090/sample/ex02?name=AAA&age=10 로 들어가보면 로그창에 

다음과 같이 발생한다.

2-1.리스트,배열 처리

	@GetMapping("/ex03List")
	public String ex03List(@RequestParam("ids") ArrayList<String> ids) {

		log.info("ids: " + ids);

		return "ex01";
	}

-다음과 같이 List형으로 설정한 후에 톰캣 서버를 실행 시킨 후 http://localhost:8090/sample/ex03List?ids=AAA&ids=10&ids=333 로 들어가보면 로그창에

다음과 같이 표시된다.

배열의 경우에도

	@GetMapping("/ex03Array")
	public String ex03Array(@RequestParam("ids") String[] ids) {

		log.info("array ids: " + Arrays.toString(ids));

		return "ex03Array";
	}

로 컨트롤러에서 설정해주고 톰캣 서버를 실행 시킨 후에 http://localhost:8090/sample/ex03Array?ids=AAA&ids=10&ids=333로 들어가보면 로그창에

다음과 같이 표시된다.

2-2.객체리스트

다음과 같이 객체를 리스트에 담는 클래스 생성(SampleDTOList.java)

package org.zerock.controller;

import java.util.ArrayList;
import java.util.List;

import org.zerock.domain.SampleDTO;

import lombok.Data;

@Data
public class SampleDTOList {

	private List<SampleDTO> list;

	public SampleDTOList() {
		list = new ArrayList<>();
	}
}

SampleController에 다음과 같은 메소드 추가

	@GetMapping("/ex03Bean")
	public String ex03Bean(SampleDTOList list) {

		log.info("list dtos: " + list);

		return "ex03Array";
	}

http://localhost:8090/sample/ex03Bean?list[0].name=aaa&list[2].name=bbb  다음과 같은 요청 주소를 보내고 싶지만 Tomcat은 버젼에 따라서  특수문자를 지원하지 않는다. 따라서 [ = %5B , ] = %5D 로 치환해서 요청한다.

http://localhost:8090/sample/ex03Bean?list%5B0%5D.name=aaa&list%5B2%5D.name=bbb

그 결과 로그창에

다음과 같이 표시된다.

3. InitBinder

파라미터의 수집을 다른용어로는 binding(바인딩)이라고 합니다. 변환이 가능한 데이터는 자동으로 변환이 되지만 경우에 따라서는 파라미터를 변환해서 처리해야 하는 경우도 존재합니다. 예를들어, 화면에서 2018-01-01과 같이 문자열로 전달된 데이터를 java.util.Date 타입으로 변환하는 작업이 그러합니다. 스프링 Controller에서는 파라미터를 바인딩할 때 자동으로 호출되는 @InitBinder를 이용해서 이러한 변환을 처리할 수 있습니다.

 

TodoDTO 클래스 만들기

package org.zerock.domain;

import java.util.Date;

import lombok.Data;

@Data
public class TodoDTO {

	private String title;
	private Date dueDate;
}

 SampleController 일부

	@InitBinder
	public void initBinder(WebDataBinder binder) {
		SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
		binder.registerCustomEditor(java.util.Date.class, new CustomDateEditor(dateFormat, false));
	}

	@GetMapping("/ex04")
	public String ex04(TodoDTO todo) {

		log.info("todo: " + todo);

		return "ex04";
	}

http://localhost:8090/sample/ex04?title=test&dueDate=2018-01-01 로 요청해보면 다음과같이 로그창에 

입력됩니다.(해당 InitBinder작업을 하지 않을 경우 400에러 발생)

 

@DateTimeFormat 을 이용하여 파라미터로 사용되는 인스턴스 변수에 @DateTimeFormat을 적용해도 변환이 가능합니다.

TodoDTO클래스일부

package org.zerock.domain;

import java.util.Date;

import org.springframework.format.annotation.DateTimeFormat;

import lombok.Data;

@Data
public class TodoDTO {

	private String title;
	
	@DateTimeFormat(pattern = "yyyy/MM/dd")
	private Date dueDate;
}

SampleController클래스 일부

	@GetMapping("/ex04")
	public String ex04(TodoDTO todo) {

		log.info("todo: " + todo);

		return "ex04";
	}

http://localhost:8090/sample/ex04?title=test&dueDate=2018/01/01 로 요청해보면 같은 결과가 발생한다.

단, 직접적으로 변수에 @DateTimeFormat을 설정해주는 경우 initBinder작업은 필요하지 않다.

4. Model이라는 데이터 전달자

모델2 방식에서 사용하는 request.setAttribute()와 유사한 역할을 합니다. 모델 2에서는 request.setAttribute("serverTime",new java.util.Data()); 로 보냈다면 스프링에서는

public String home(Model model) {
		model.addAllAttributes("serverTime",new java.util.Date());
		return "home";
	}

다음과 같이 보냅니다.

메서드의 파라미터를 Model 타입으로 선언하게 되면 자동으로 스프링MVC에서는 Model타입의 객체를 만들어 주기 때문에 개발자의 입장에서는 필요한 데이터를 담아주는 작업만으로 모든 작업이 완료됩니다. Model을 사용해야 하는 경우는 주로 Controller에 전달된 데이터를 이용해서 추가적인 데이터를 가져와야 하는 상황입니다.(예를 들면 리스트 페이지번호를 파라미터로 전달받고, 실제 데이터를 View로 전달해야 하는경우, 파라미터들에 대한 처리 후 결과를 전달 해야 하는 경우 등등...)

@ModelAttribute 어노테이션

스프링MVC의 Controller는 기본적으로 Java Beans 규칙에 맞는 객체는 다시 화면으로 객체를 전달합니다. 좁은 의미에서 Java Beans의 규칙은 단순히 생성자가 없거나 빈 생성자를 가져야 하며, getter/setter를 가진 클래스의 객체들을 의미합니다. 앞의 예제에서 파라미터로 사용된 SampleDTO의 경우는 Java Bean의 규칙에 맞기 때문에 자동으로 다시 화면까지 전달됩니다. 전달될 때에는 클래스명의 앞글자는 소문자로 처리됩니다. 반면 기본 자료형의 경우는 파라미터로 선언하더라도 기본적으로 화면까지 전달 되지 않습니다.

SampleController에 추가

@GetMapping("/ex05")
	public String ex05(SampleDTO dto, int page) {

		log.info("dto: " + dto);
		log.info("page: " + page);

		return "/sample/ex05";
	}

ex05.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<h2>SAMPLEDDTO ${sampleDTO }</h2>
	<h2>PAGE ${page}</h2>
</body>
</html>

톰캣 서버를 실행하고 브라우저를 통해서 http://localhost:8090/sample/ex05?name=aaa&age=11&page=9 와 같이 호출하면 int 타입으로 선언된 page는 전달되지않습니다.

이러한 int 형 기본자료형을 전달하고 싶다면 @ModelAttribute 어노테이션을 이용하면 됩니다. @ModelAttribute는 강제로 전달받은 파라미터를 Model에 담아서 전달해주는데 @ModelAttribute가 걸린 파라미터는 타입에 관계없이 무조건 Model에 담아서 전달되므로, 파라미터로 전달된 데이터를 다시 화면에서 사용해야 할 경우에 유용하게 사용됩니다.

SampleController일부

@GetMapping("/ex05")
	public String ex05(SampleDTO dto, @ModelAttribute("page") int page) {

		log.info("dto: " + dto);
		log.info("page: " + page);

		return "/sample/ex05";
	}

*또한 SampleDTO dto 파라미터도 이름을 변경하여 view단에 보내고 싶다면 앞에 @ModelAttribute("dto") SampleDto dto 로 변경하게되면 이름이 dto로 변경되어 view단으로 넘어간다.

4-1.RedirectAttributes

Model타입과 더불어서 스프링 MVC가 자동으로 전달해주는 타입중에는 RedirectAttributes 타입이 존재합니다. RedirectAttributes는 조금 특별하게도 일회성으로 데이터를 전달하는 용도로 사용됩니다. RedirectAttributes는 기존에 Servlet에서는 response.sendRedirect()를 사용할 때와 동일합니다.

Servlet에서 redirect방식

response.sendRedirect("/home?name=aaa&age=10");

스프링 MVC를 이용하는 경우

	rttr.addFlashAttribute("name","AAA");
	rttr.addFlashAttribute("age",10);
    return "redirect:/";

RedirectAttributes는 Model과 같이 파라미터로 선언해서 사용하고, addFlashAttribute(이름,값) 메서드를 이용해서 화면에 한번만 사용하고 다음에는 사용되지 않는 데이터를 전달하기 위해 사용합니다.

 

5.Controller의 리턴 타입 부터는 다음 게시물에서 이어집니다.

728x90
Comments