Sangwon Coding

6. 스프링 MVC의 Controller (3) 본문

Spring/코드로 배우는 스프링 웹 프로젝트

6. 스프링 MVC의 Controller (3)

SW1 2019. 11. 14. 02:09

안녕하세요! 저번 포스팅에 이어서 바로 시작하도록 하겠습니다.

 

 

스프링 MVC의 구조가 기존의 상속과 인터페이스에서 어노테이션을 사용하는 방식으로 변한 이후에 가장 큰 변화 중 하나는 리턴 타입이 자유로워 졌다는 점입니다.

 

Controller의 메서드가 사용할 수 있는 리턴 타입은 주로 다음과 같습니다.

 

  • String : jsp를 이용하는 경우에는 jsp파일의 경로와 파일이름을 나타내기 위해서 사용함.
  • void : 호출하는 URL과 동일한 이름의 jsp를 의미함.
  • VO,DTO 타입 : 주로 JSON 타입의 데이터를 만들어서 반환하는 용도로 사용함.
  • ResponseEntity 타입 : response 할 때 Http헤더 정보와 내용을 가공하는 용도로 사용함.
  • Model, ModelAndView : Model로 데이터를 반환하거나 화면까지 같이 지정하는 경우에 사용함.(최근에는 많이 사용하지 않음)
  • HttpHeaders : 응답에 내용 없이 Http헤더 메시지만 전달하는 용도로 사용함.

메서드의 리턴 타입을 void로 지정하는 경우 일반적인 경우에는 해당 URL의 경로를 그대로 jsp파일의 이름으로 사용하게 됩니다.

 

SampleController클래스에 코드를 추가해 보겠습니다.

 

@GetMapping("/ex05")

    public void ex05() {

        System.out.println("ex05");

    }

 

브라우저에서 SampleController의 경로 에 ex05( )의 경로를 합쳐 '/sample/ex05'를 호출하면 다음과 같은 결과를 보게 됨.

 

 

에러 메세지를 자세히 보면 에러 메세지의 원인이 '/WEB-INF/view/sample/ex05.jsp'가 존재하지 않아서 생기는 문제라는 것을 볼 수 있습니다. 이것은 servlet-context.xml의 아래 설정과 같이 맞물려 URL 경로를 View로 처리하기 때문에 생기는 결과입니다.

 

<!-- Resolves views selected for rendering by @Controllers to .jsp resources in the /WEB-INF/views directory -->

    <beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">

        <beans:property name="prefix" value="/WEB-INF/views/" />

        <beans:property name="suffix" value=".jsp" />

    </beans:bean>

 

void 타입과 더불어서 가장 많이 사용하는 것은 String 타입입니다. String 타입은 상황에 따라 다른 화면을 보여줄 필요가 있을 경우에 유용하게 사용합니다(if~else와 같은 처리가 필요한 상황). 일반적으로 String 타입은 현재 프로젝트의 경우 JSP파일의 이름을 의미합니다. 프로젝트 생성 시 기본으로 만들어진 HomeController의 코드를 보면 String을 반환 타입으로 사용하는 것을 볼 수 있습니다.

 

String 타입에는 다음과 같은 특별한 키워드를 붙여서 사용할 수 있습니다.

  • redirect : 리다이렉트 방식으로 처리하는 경우
  • forward : 포워드 방식으로 처리하는 경우

 

controller의 메서드 리턴 타입을 VO(Value Object)나 DTO(Data Transfer Object)타입 등 데이터가 들어간 객체 타입으로 지정할 수 있는데, 이 경우 주로 JSON 데이터를 만들어 내는 용도로 사용합니다.  

 

우선 이를 위해서는 jackson-databind 라이브러리를 pom.xml에 추가합니다.

 

<dependency>

    <groupId>com.fasterxml.jackson.core</groupId>

    <artifactId>jackson-databind</artifactId>

    <version>2.9.4</version>

</dependency>

 

SamplController에는 아래와 같은 메서드를 생성합니다.

 

@GetMapping("/ex06")

    public @ResponseBody SampleDTO ex06() {

        System.out.println("ex06...............");

        SampleDTO dto =new SampleDTO();

        dto.setAge(10);

        dto.setName("노상원");

        

        return dto;

    }

 

스프링 MVC는 자동으로 브라우저에 JSON타입으로 객체를 변환해서 전달하게 됩니다.

 

 

Web을 다루다 보면 HTTP프로토콜의 헤더를 다루는 경우도 종종 있습니다. 스프링MVC의 사상은 HttpServletRequest나 HttpServletReponse를 직접 핸들링하지 않아도 이런 작업이 가능하도록 작성되었기 때문에 이러한 처리를 위해 ResponseEntity를 통해서 원하는 헤더 정보나 데이터를 전달할 수 있습니다.

 

	@GetMapping("/ex07")
	public ResponseEntity<String> ex07() {
		System.out.println("ex07...............");
		// {"name":"노상원"}
		String msg = "{\"name\":\"노상원\"}";

		HttpHeaders header = new HttpHeaders();
		header.add("Content-Type", "application/json;charset=UTF-8");
		return new ResponseEntity<>(msg, header, HttpStatus.OK);
	}

 

ResponseEntity는 HttpHeaders 객체를 같이 전달할 수 있고, 이를 통해서 원하는 HTTP 헤더 메세지를 가공하는 것이 가능합니다. ex07()의 경우 브라우저에는 JSON타입이라는 헤더 메세지와 200 OK상태 코드를 전송합니다. 

 

 

Controller의 많은 작업은 스프링 MVC를 통해서 처리하기 때문에 개발자는 자신이 해야 하는 역할에만 집중해서 코드를 작성할 수 있지만, 조금 신경 써야 하는 부분이 있다면 파일을 업로드하는 부분에 대한 처리일 것입니다. 파일 업로드를 하기 위해서는 전달되는 파일 데이터를 분석해야 하는데, 이를 위해서 Servlet3.0전까지는 commons의 파일업로드를 이용하거나 cos.jsr 등을 이용해서 처리를 해 왔습니다. Servlet 3.0이후 (Tomcat7.0)에는 기본적으로 업로드되는 파일을 처리할 수 있는 기능이 추가 되어 있으므로 더 이상 추가적인 라이브러리가 필요하지 않습니다.

 

조금아쉬운 점은 'Spring Legacy Project'로 생성되는 프로젝트의 경우 Servlet 2.5를 기준으로 생성되기 때문에 3.0이후에 지원되는 설정을 사용하기 어렵다는 점입니다. 3.0이상의 파일 업로드 방식은 후반부에 별도 파트에서 다루도록 하고 예제는 일반적으로 많이 사용하는 commons-fileupload를 이용하도록 하겠습니다.

 

<dependency>

    <groupId>commons-fileupload</groupId>

    <artifactId>commons-fileupload</artifactId>

    <version>1.3.3</version>

</dependency>

 

라이브러리를 추가한 후 파일이 임시로 업로드될 폴더를 C드라이브 아래 upload/tmp 로 작성합니다.

 

 

servlet-context.xml은 스프링 MVC의 특정한 객체(빈)를 설장해서 파일을  처리합니다. 다른 객체(Bean)를 설정하는 것과 달리 파일 업로드의 경우에는 반드시 id 속성의 값을 'multiparResolver'로 정확하게 지정해야 하므로 주의가 필요합니다.  

 

<beans:bean id="mutipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">

    <beans:property name="defaultEncoding" value="utf-8"></beans:property>

    <!-- 1024 * 1024 * 10 bytes 10 MB -->

    <beans:property name="maxUploadSize" value="104857560"></beans:property>

    <!--1024 * 1024 * 2 bytes 2MB  -->

    <beans:property name="maxUploadSizePerFile" value="2097152"></beans:property>

    <beans:property name="uploadTempDir" value="file:/C:/upload/tmp"></beans:property>

    <beans:property name="maxInMemorySize" value="10485756"></beans:property>
    
</beans:bean>

 

maxUploadSize는 한 번의  Request로 전달될 수 있는 최대의 크기를 의미하고, maxUploadSizePerFile은 하나의 파일 최대크기, maxInMemorySize는 메모리 상에서 유지하는 최대의 크기를 의미합니다. 만일 이 크기 이상의 데이터는 uploadTempDir에 임시 파일의 형태로 보관됩니다. uploadTempDir에서 절대 경로를 이용하려면 URI 형태로 제공해야하기 때문에 'file:/'로 시작하도록 합니다. defaultEncoding은 업로드하는 파일의 이름이 한글일 경우 깨지는 문제를 처리합니다.

 

SampleController에서는 다음과 같이 get방식으로 파일을 업로드할 화면을 처리합니다.

 

    @GetMapping("/exUpload")
    public void exUpload() {
        log.info("/exUpload...................");
    }

 

파일 업로드를 해 볼 '/WEB-INF/views/sample/exUpload.jsp' 파일을 작성합니다.

 

 

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>

<!DOCTYPE HTML>

<html>

<head>

<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">

<title>title is title</title>

</head>

<body>

	<form action="/sample/exUploadPost" method="post"
		enctype="multipart/form-data">

		<div>

			<input type='file' name='files'>

		</div>

		<div>

			<input type='file' name='files'>

		</div>

		<div>

			<input type='file' name='files'>

		</div>

		<div>

			<input type='file' name='files'>

		</div>

		<div>

			<input type='file' name='files'>

		</div>

		<div>

			<input type='submit'>

		</div>

	</form>

</body>

</html>

 

exUpload.jsp는 여러 개의 파일을 한꺼번에 업로드하는 예제로 작성해 보겠습니다. <form>태그의 action속성, method속성, enctype속성에 주의 해서 작성해야합니다.

브라우저는 아래와 같은 모습입니다.

 

 

ex07.jsp의 action 속성값은 '/sample/exUploadPost'로 작성되었으므로, 이에 맞는 메서드를 SampleController에 추가합니다. 그리고 추가적으로 exUpload 메서드를 PostMapping으로 수정해줍니다.

 

    @PostMapping("/exUploadPost")
    public void exUploadPost(ArrayList<MultipartFile> files) {
        files.forEach(file->{
            System.out.println("----------------------------------------");
            System.out.println("name:"+file.getOriginalFilename());
            System.out.println("size:"+file.getSize());
        });
    }

 

스프링 MVC는 전달되는 파라미터가 동일한 이름으로 여러 개 존재하면 배열로 처리가 가능하므로 파라미터를 MultiparFile의 배열 타입으로 작성합니다. 실제로 파일을 업로드해 보면 아래와 같은 결과를 볼 수 있습니다. 현재 설정은 한 파일의 최대 크기가 2MB이므로 그보다 작은 크기의 파일을 지정해서 업로드를 테스트합니다.

 

 

그림 중간에서 보이는 로그는 SampleController에서 업로드 정보가 올버르게 처리되는 것을 보여주고 있습니다. 

 

 

이상으로 포스팅 마치고 다음 포스팅부터 본격적으로 기본적인 웹 게시물을 관리해보겠습니다!

Comments