Chapter 6-5

ChangWoo·2023년 8월 11일
post-thumbnail

Part 6. 스프링 MVC의 Controller

6.5 Controller의 리턴 타입

  • 스프링 MVC의 구조가 기존의 상속과 인터페이스에서 어노테이션을 사용하는 방식으로 변한 이후에 가장 큰 변화 중 하나는 리턴 타입이 자유로워 졌다는 점이다,
  • Controller의 메서드가 사용할 수 있는 리턴 타입은 주로 다음과 같다.
    • String : jsp를 이용하는 경우에는 jsp 파일의 경로와 파일이름을 나타내기 위해 사용한다.
    • void : 호출하는 URL과 동일한 이름의 jsp를 의미한다.
    • VO, DTD 타입 : 주로 JSON 타입의 데이터를 만들어 반환하는 용도로 사용한다.
    • ResponseEntity 타입 : response 할 때 Http 헤더 정보와 내용을 가공하는 용도로 사용한다.
    • Model, ModelAndView : Model로 데이터를 반환하거나 화면까지 같이 지정하는 경우에 사용한다.
    • HttpHeaders : 응답에 내용 없이 Http 헤더 메시지만 전달하는 용도로 사용한다.

6.5.1 void 타입

  • 메서드의 리턴 타입을 void로 지정하는 경우 일반적인 경우에는 해당 URL의 경로를 그대로 jsp 파일의 이름으로 사용하게 된다.
< Sample Controller >
	@GetMapping("/ex05")
	public void ex05() {
		log.info("/ex05..........");
	}
  • 브라우저에서 SampleController의 경로에 ex05()의 경로를 합쳐 '/sample/ex05'를 호출하면 다음과 같은 결과를 보게 된다.
  • 에러 메시지의 원인이 '/WEB-INF/views/sample/ex05.jsp가 존재하지 않아서 생기는 문제라는 것을 볼 수 있다.
  • 이것은 servlet-context.xml의 아래 설정과 같이 맞물려 URL 경로를 View로 처리하기 때문에 생기는 결과다.
< servlet-context.xml >
	<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>

6.5.2 String 타입

  • void 타입과 더불어 가장 많이 사용하는 것은 String 타입이다.
  • String 타입은 상황에 따라 다른 화면을 보여줄 필요가 있을 경우에 유용하게 사용한다. (if ~ else와 같은 처리가 필요한 상황)
  • 일반적으로 String 타입은 현재 프로젝트의 경우 JSP 파일의 이름을 의미한다.
  • 프로젝트 생성 시 기본으로 만들어진 HomeController의 코드를 보면 String을 반환타입으로 사용하는 것을 볼 수 있다.
< HomeController >
	@RequestMapping(value = "/", method = RequestMethod.GET)
	public String home(Locale locale, Model model) {
		logger.info("Welcome home! The client locale is {}.", locale);		
		Date date = new Date();
		DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, locale);		
		String formattedDate = dateFormat.format(date);
      	model.addAttribute("serverTime", formattedDate );
		return "home";
	}
  • home() 메서드는 'home'이라는 문자열을 리턴했기 때문에 경로는 '/WEB-INF/views/home.jsp' 경로가 된다.
  • String 타입에는 다음과 같은 특별한 키워드를 붙여 사용할 수 있다.
    • redirect : 리다이렉트 방식으로 처리하는 경우
    • forward : 포워드 방식으로 처리하는 경우

6.5.3 객체 타입

  • Controller의 메서드 리턴 타입을 VO나 DTO타입 등 복합적인 데이터가 들어간 객체 타입으로 지정할 수 있는데, 이 경우는 주로 JSON 데이터를 만들어 내는 용도로 사용한다.
  • 우선 이를 위해 jackson-databind 라이브러리를 pom.xml에 추가한다.
< pom.xml에 추가되는 Jackson-databind 라이브러리 >
	<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
		<dependency>
			<groupId>com.fasterxml.jackson.core</groupId>
			<artifactId>jackson-databind</artifactId>
			<version>2.9.4</version>
		</dependency>
  • SampleController에는 아래와 같은 메서드를 생성한다.
< SampleController >
	@GetMapping("/ex06")
	public @ResponseBody SampleDTO ex06() {
		log.info("/ex06..........");
		SampleDTO dto = new SampleDTO();
		dto.setAge(10);
		dto.setName("홍길동");		
		return dto;
	}
  • 스프링 MVC는 자동으로 브라우저에 JSON 타입으로 객체를 변환해서 전닫ㄹ하게 된다.
  • 개발자 도구를 통해 살펴보면 서버에서 전송하는 MIME 타입이 'application/json'으로 처리되는 것을 볼 수 있다.
  • 만일 Jackson-databind 라이브러리가 포함되지 않았다면 다음과 같은 에러 화면이 나타난다.
  • 스프링 MVC는 리턴 타입에 맞게 데이터를 변환해 주는 역할을 지정할 수 있는데 기본적으로 JSON은 처리가 되므로 별도의 설정이 필요하지 않다.

6.5.4 ResponseEntity 타입

  • Web을 다루다 보면 HTTP 프로토콜의 헤더를 다루는 경우도 종종 있다.
  • 스프링 MVC의 사상은 HttpServletRequest나 HttpServletResponse를 직접 핸들링하지 않아도 이런 작업이 가능하도록 작성되었기 때문에 이러한 처리를 위해 ResponseEntity를 통해 원하는 헤더 정보나 데이터를 전달할 수 있다.
< Sample Controller >
	@GetMapping("/ex07")
	public ResponseEntity<String> ex07() {
		log.info("/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라는 상태 코드를 전달한다.

6.5.5 파일 업로드 처리

  • 파일 업로드를 하기 위해서는 전달되는 파일 데이터를 분석해야 하는데 이를 위해서는 Servlet 3.0 전까지는 commons의 파일 업로드를 이용하거나 cos.jar 등을 이용해 처리해 왔다.
  • Servlet 3.0 이후에는 기본적으로 업로드되는 파일을 처리할 수 있는 기능이 추가되어 있으므로 더 이상 추가적인 라이브러리가 필요하지 않다.
  • Spring Legacy Project로 생성되는 프로젝트의 경우 Servlet 2.5를 기준으로 생성되므로 3.0 이후에 지원되는 설정을 사용하기 어렵다.
  • 예제는 일반적으로 많이 사용하는 commons-fileupload를 이용한다.
< pom.xml에 추가되는 commons-fileupload 라이브러리 >
		<dependency>
			<groupId>commons-fileupload</groupId>
			<artifactId>commons-fileupload</artifactId>
			<version>1.3.3</version>
		</dependency>
  • 라이브러리를 추가한 후 파일이 임시로 업로드될 폴더를 D드라이브 아래 upload/tmp로 작성한다.

servlet-context.xml 설정

  • servlet-context.xml은 스프링 MVC의 특정한 객체를 설정해서 파일을 처리한다.
  • 다른 객체를 설정하는 것과 달리 파일 업로드의 경우에는 반드시 id 속성의 값을 multipartResolver로 정확하게 지정해야 한다.
< servlet-context.xml >
	<beans:bean id="multiparResolver" class="org.springframework.web.multipart.commons/CommonsMultipartResolver">
		<beans:property name ="defaultEncoding" value="utf-8"></beans:property>
		<!-- 1024 * 1024 * 10 bytes 10MB -->
		<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:/D:/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 방식으로 파일을 업로드할 화면을 처리한다.
< SampleController >
	@GetMapping("/exUpload")
		public void exUpload() {
		log.info("/exUpload........");
	}
  • 파일 업로드를 해볼 /WEB-INF/views/sample/exUpload.jsp 파일을 작성한다.
< exUpload.jsp >
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equive="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</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 속성에 주의해 작성해야 한다.
  • 브라우저는 아래와 같은 모습으로 보인다.
  • exUpload.jsp의 action 속성값은 '/sample/exUploadPost'로 작성되었으므로, 이에 맞는 메서드를 SampleController에 추가한다.
< SampleController >
	@PostMapping("/exUploadPost")
	public void exUploadPost(ArrayList<MultipartFile> files) {
		files.forEach(file -> {
			log.info("-----------------------------------------");
			log.info("name:" + file.getOriginalFilename());
			log.info("size:" + file.getSize());
		});
  • 스프링 MVC는 전달된는 파라미터가 동일한 이름으로 여러 개 존재하면 배열로 처리가 가능하므로 파라미터를 MultipartFile의 배열 타입으로 작성한다.
  • 실제로 파일을 업로드해 보면 아래와 같은 결과를 볼 수 있다.
  • 현재 설정은 한 파일의 최대 크기가 2MB이므로 그보다 작은 크기의 파일을 지정해 업로드를 테스트한다.
INFO : org.zerock.controller.SampleController - -----------------------------------------
INFO : org.zerock.controller.SampleController - name:ex01.txt
INFO : org.zerock.controller.SampleController - size:0
INFO : org.zerock.controller.SampleController - -----------------------------------------
INFO : org.zerock.controller.SampleController - name:ex02.txt
INFO : org.zerock.controller.SampleController - size:0
INFO : org.zerock.controller.SampleController - -----------------------------------------
INFO : org.zerock.controller.SampleController - name:ex03.txt
INFO : org.zerock.controller.SampleController - size:0
INFO : org.zerock.controller.SampleController - -----------------------------------------
INFO : org.zerock.controller.SampleController - name:ex04.txt
INFO : org.zerock.controller.SampleController - size:0
INFO : org.zerock.controller.SampleController - -----------------------------------------
INFO : org.zerock.controller.SampleController - name:ex05.txt
INFO : org.zerock.controller.SampleController - size:0

  • 위의 그림에서 중간에 보이는 로그는 SampleController에서 업로드 정보가 올바르게 처리되는 것을 보여주고 있다.
  • 최종 byte[]를 처리해야 하는데 예제는 아직 처리하지 않은 상태다.

Java 설정을 이용하는 경우

  • Java 설정을 이용하는 경우에는 @Bean을 이용해서 처리하기는 하지만, id 속성값을 같이 부여한다.
  • servlet-context.xml과 관련된 설정이므로 ServletConfig 클래스를 이용해서 처리한다.
< ServletConfig >
	@Bean(name = "multipartResolver")
	public CommonsMultipartResolver getResolver() throws IOException {
		CommonsMultipartResolver resolver = new CommonsMultipartResolver();		
		// 10MB
		resolver.setMaxUploadSize(1024 * 1024 * 10);	
		// 2MB
		resolver.setMaxUploadSizePerFile(1024 * 1024 * 2
		// 1MB
		resolver.setMaxInMemorySize(1024 * 1024);
		// temp upload
		resolver.setUploadTempDir(new FileSystemResource("D:\\upload\\tmp"));
		resolver.setDefaultEncoding("UTF-8");
		return resolver;
	}
profile
한 걸음 한 걸음 나아가는 개발자

0개의 댓글