파일 업로드 처리를 하기 위해서는 전달되는 파일 데이터를 분석해야하는데, 이를 위해서 Servlet3.0전까지는 commons의 파일
업로드를 이용하거나 cos.jar등을 이용해서처리를 해왔다. servlet 3.0 이후(Tomcat7.0) 에는 기본적으로 업로드 되는 파일을
처리할 수있는 기능이 추가되어있으므로 더이상 추가적인라이브러리가 필요로 하지않다.
spring legacy project로 생성되는 프로젝트의 경우 Serlvet 2.5를 기준으로 생성되기 때문에 3.0이후에 지원되는 설정을 사
용하기 어렵다.
3.0이상의 파일 업로드 방식은 후반부에 별도 파트에서 다루도록하고 예제는 일반적으로 많이 사용하는 commons-fileupload
를 이용한다.
maven repository 에서 common-file검색 후 사용자 수가 많은 코드를 가져왔다.
아래코드를 pom.xml에 추가해준다.
<!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
파일이 임시로 업로드될 폴더를 c드라이브 아래 upload/tmp로 작성한다.
ex01부터
servlet-context.xml 작성
<beans:bean id= "multipartResolver" 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:/upload/tmp"></beans:property>
<beans:property name="maxInMemorySize" value="10485756"></beans:property>
</beans:bean>
maxUplodSize는 한 번의 Request로 전달될 수 있는 최대의 크기를 의미
maxUploadSizePerFile은 하나의 파일 최대 크기.
maxInMemorySize는 메모리상에서 유지하는 최대의크기.
이 크기 이상의 데이터는 uploadTempDir에 임시파일의 형태로 보관.
uploadTempDir에서 절대 경로를 이용하려면 URL형태로 제공해야 하기 때문에 'file:/'로 시작하도록 한다.
defaultEncoding 은 업로드 하는 파일의 이름이 한글일 경우 깨지는 문제를 처리한다.
SampleController에 아래코드를 추가해준다.
@GetMapping("/exUpload")
public void exUpload() {
log.info("/exUpload.......................");
}
파일을 업로드해 볼 /WEB-INF/views/smaple/exUpload.jsp파일을 만들어준다.
view/sample/exUpload.jsp
exUpload.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>
<form action="/sample/exUploadPost" methos="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>
추가) 책의코드대로 쳐서는 정상적으로 작동하지 않는다 ! -> 왜냐? enctype을 빼먹었기때문에
꼭 enctype을 적어주어야한다.
* enctype이란?
<form>태그의 enctype 속성은 폼데이터 (form data)가 서버로 제출될때 해당 데이터가 인코딩 되는 방법을 명시.
이 속성은 <form> 요소의 method 속성값이 "post" 인 경우에만 사용할수 있다.
exUpload.jsp는 여러 개의 파일을 한꺼번에 업로드하는 예제로 작성한다.
<form>태그의 action속성, method속성, enctype속성에 주의해서 작성한다.
exUpload.jsp의 action 속성값은 'sample/exUploadPost'로 작성되었으므로 이에 맞는 메서드를 SampleController에 추가한다.
@PostMapping("/exuploadPost")
public void exUploadPost(ArrayList<MultipartFile> files) {
files.forEach(file ->{
log.info("-------------------------------");
log.info("name: " + file.getOriginalFilename());
log.info("size: " + file.getSize());
});
}
file -> 는 람다식일까?
람다식이란?
java8 부터 추가된 기능으로 익명객체를 생성하기 위한 표현식.
람다식의 표현식
매개변수 -> 함수몸체
고로 위예문의 file -> {}는 람다식이다.
이어서...
스프링 MVC는 전달되는 파라미터가 동일한 이름으로 여러 개 존재하면 배열로 처리가 가능하므로 파라미터를 MultipartFile의 배열 타입으로 작성한다.
Java 설정을 이용하는 경우
Java설정을 이용하는 경우 @Bean을 이용해서 처리하기는 하지만, id속성을 같이 부여한다.
ServletConfig.class파일에
아래 코드를 추가해 준다.
@Bean(name="multipartResolver")
public CommonsMultipartResolver getResolver() throws Exception{
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("C:\\upload\\temp"));
resolver.setDefaultEncoding("utf-8");
return resolver;
Controller의 Exception처리
Controller를 작성 할때 예외 상황을 고려하면 처리해야하는 작업이 늘어날수 밖에 없다.
스프링 MVC 에서는
- @ExceptionHandler와 @ControllerAdvice를 이용한 처리
- @ResponseEntity를 이용하는 예외 메세지 구성
을 통해 처리 할 수있다.
@ControllerAdvice
AOP(Aspect-Oriented-Programming) 을 이용하는 방식
프로그램에서 필요한 공통적인 관심사(cross-concern)는 분리하자는 개념
AOP를 이용하면 공통적인 예외사항에 대해서는 별도로 @ControllerAdvice를 이용해서 분리하는 방식.
org.zerock.exception 패키지를 생성하고
CommonExceptionAdvice 클래스를 생성한다.
package org.zerock.exception;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import lombok.extern.log4j.Log4j;
@ControllerAdvice // 해당 객체가 스프링의 컨트롤러에서 발생하는 예외를 처리하는 존재임을 명시.
@Log4j
public class CommonExceptionAdvice { //@ControllerAdvice 어노테이션을 적용하지만 예외처리르 목적으로 생성하는 클래스이므로 별도의로직을 처리하지는 않는다.
@ExceptionHandler(Exception.class) //@ExceptionHandler 해당 메서드가() 들어가는 예외 타입을 처리한다는 것을 의미
public String except(Exception ex,Model model) {
log.error("Exception ......" + ex.getMessage());
model.addAttribute("exception",ex);
log.error(model);
return "error_page";
}
}
@ControllerAdvice, @ExceptionHandler 라는 어노테이션을 사용하고 있다.
@ControllerAdvice는 해당 객체가 스프링의컨트롤러에서 발생하는 예외를 처리하는 존재임을 명시.
(
@Controller 즉, 전역에서 발생할 수 있는 예외를 잡아 처리해주는 annotation이다.
출처: https://jeong-pro.tistory.com/195 [기본기를 쌓는 정아마추어 코딩블로그]
)
@ExceptionHandler라는 어노테이션을 쓰고 인자로 캐치하고 싶은 예외클래스를 등록해주면 끝난다.
출처: https://jeong-pro.tistory.com/195 [기본기를 쌓는 정아마추어 코딩블로그]
또한 @ExceptionHandler 어노테이션의 속성으로는 Exception클래스 타입을 지정할 수 있다.
위 코드와 같은경우 Exception.class를 지정하였으므로 모든 예외에 대한 처리를 except()만을 이용해서
처리 할 수 있다.
만일 특정 타입의 예외를 다루고 싶다면 Exception.class대신에 구체적인 예외의 클래스를 지정한다.
JSP 화면에서도 구체적인 메세지를 보고 싶다면 Model을 이용해서 전달하는것이 좋다.
org.zerock.exception 패키지는 servlet-context.xml에서 인식하지 않기 때문에 <component-scan>을 이용해서 패키지의내용을 조사하도록 해야한다.
<context:component-scan base-package="org.zerock.exception"/>
위 코드를 해당위치에 넣어준다.
CommonExceptionAdvice의 except()의 리턴값은 문자열이므로 JSP파일의 경로가 된다.
JSP는 error_page.jsp이므로 /WEB-INF/views 폴더내에 작성해야한다.
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page session ="false" import="java.util.*" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h4><c:out value="${exception.getMessage() }"></c:out></h4>
<ul>
<c:forEach items="${exception.getStackTrace() }" var="stack">
<li><c:out value="${stack }"></c:out></li>
</c:forEach>
</ul>
</body>
</html>
http://localhost:8080/sample/ex04?name=aaa&age=bbb&page=9
Java 설정을 이용하는 경우
SerlvetConfig 클래스에 'org.zerock.exception' 패키지를 인식해야하므로 'org.zerock.exception' 패키지를 추가한다.
404에러 패키지
WAS 의 구동 중 가장 흔한 에러와 관련된 HTTP 상태코드는 '404' 와 '500' 에러코드이다.
500에러메세지는 'Internal Server Error'이므로 @ExceptionHandler를 이요해서 처리되지만
잘못된 URL을 호출할 때 보이는 404 에러메세지의 경우 다르게 처리해야한다.
서블릿이나 JSP를 이용했던 개발시에는 web. xml을 이용해 별도의에러 페이지를 지정할 수있다.
에러발생시 추가적 작업을 하기는 어렵기에 스프링을 이용해서 404와 같이 WAS 내부에서 발생하는 에러를 처리하는 방식을 알
알아보자.
스프링 MVC의 모든 요청은 DispatcherServlet을 이용해서 처리되므로 404 에러도 같이 처리할 수 있도록
web.xml을 수정한다.
<init-param>
<param-name>throwExceptionIfNoHandlerFound</param-name>
<param-value>true</param-value>
</init-param>
view폴더 밑에 custom404.jsp를 만들어준다.
<h1>해당 URL은 존재하지 않습니다.</h1>
Java 설정을 사용하는 경우
web.xml에 설정한 throwExceptionIfNoHandlerFound를 설정 하기 위해서는
서블릿3.0 이상을 이용해야만 하고
WebConfig 클래스를 아래와 같이 수정해야한다.
WebConfig클래스
@Override
protected void customizeRegistration(ServletRegistration.Dynamic registration) {
registration.setInitParameter("thorwExceptionIfNoHandlerFound","true");
}
코드를 추가 해준다.
'web' 카테고리의 다른 글
spring - 엑셀파일 업로드db에 저장 poi 3.12 (0) | 2020.11.22 |
---|---|
Part3 기본적인 웹게시물 관리 - 코드로배우는 스프링 웹프로젝트 (0) | 2020.10.29 |
코드로 배우는 스프링 웹프로젝트 - 6.5 Controller의 리턴타입 (0) | 2020.10.20 |
코드로 배우는 스프링웹프로젝트 - 06 스프링 MVC의 Controller (1) | 2020.10.19 |
코드로 배우는 스프링 웹프로젝트 -스프링 MVC의 기존 구조 (0) | 2020.10.05 |