static file 처리와 FileUpload, JUnit & Spring-Test
*22년 4월 한 달간 한국이러닝협회의 '실전 개발자를 위한 Spring Framework'를 수강하고 정리한 내용입니다
1. static file 처리와 FileUpload
1) Static Resource 처리
(1) Static Web Resource 처리하기
- 서버의 처리가 필요 없는 static web resources는 요청 시 서버를 거치지 않고 곧바로 응답해야 함
- 특정 URL로 요청이 오면 static resource로 인식하고 바로 응답 수행
(2) <mvc:resources mapping = "/resources/**" location = "/WEB-INF/resources/" />
- mapping: HTTP 요청 URL
- location: 실제 응답할 파일이 있는 위치
예시) 요청: http://localhost:8080/hello/resources/scripts/jQuery.js
응답: /WEB-INF/resources/scripts/jQuery.js
2) 파일 업로드
(1) 파일 업로드 시 HTML 파일
<form method="post" enctype="multipart/form-data">
....
</form>
(2) 멀티파트 지원 기능 사용을 위해, MultipartResolver를 스프링 설정으로 등록
- MultipartResolver는 encType이 multipart/form-data 형식으로 데이터가 전송되었을 경우,
해당 데이터를 Spring MVC에서 사용할 수 있도록 변환해준다.
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="104857600" /><!-- 100MB -->
<property name="defaultEncoding" value="UTF-8" />
</bean
프로퍼티 | 타입 | 설명 |
maxUploadSize | long | 최대 업로드 가능한 바이트 크기. -1은 제한이 없음을 의미한다.기본값은 -1이다. |
maxInMemorySize | int | 디스크에 임시 파일을 생성하기 전에 메모리에 보관할 수 있는 최대 바이트 크기. 기본값은 10240이다. |
defaultEncoding | String | 요청을 파싱할 때 사용할 캐릭터 인코딩. 지정하지 않을 경우, HttpServletRequest.setCharacterEncoding() 메서드로 지정한 캐릭터 셋이 사용된다. 아무 값도 없을 경우, ISO-8859-1을 사용한다. |
(3) Dependency 추가
- CommonsMultipartResolver는 Apache Commons FileUpload를 사용
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
- Form 작성
<form method="post" enctype="multipart/form-data" action="/bbs/upload">
<input type="text" name="name" />
<input type="file" name"file" />
<input type="submit" value="전송" />
</form>
(4) Controller File Upload Logic 추가
@RequestMapping("/upload")
public String doUpload(@RequestParam("name") String name,
@RequestParam("file") MultipartFile file,
Model model {
if (!file.isEmpty()) {
File tmpFile = new File("c:\\",file.getOriginal Filename());
file.transferTo(tmpFile);
}
Model.addAttribute("fileNamek", name);
return "upload_ok";
}
(5) MultipartFile의 주요 메소드
프로퍼티 | 설명 |
String getName() | 파라미터 이름을 구한다. |
String getOriginalFileName() | 업로드한 파일의 이름을 구한다. |
Boolean isEmpty() | 업로드한 파일이 존재하지 않는 경우 true를 리턴한다. |
Long getSize() | 업로드한 파일의 크기를 구한다. |
Byte[] getBytes() throws IOException |
업로드한 파일의 데이터를 구한다. |
InputStream getInputStream() throws IOException |
업로드한 파일 데이터를 읽어오는 InputStream을 구한다. InputStream의 사용이 끝나면 알맞게 종료해주어야 한다. |
void transferTo(File dest) throws IOException |
업로드한 파일 데이터를 지정한 파일에 저장한다. |
(6) Command 객체로 받아오기
- 일반 HttpServlerRequest와 동일하게 MultipartFile도 Command 객체로 받아올 수 있음
- 멤버변수의 타입이 MultipartFile로 선언되어야 함
private String name;
private MultipartFile file;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public MultipartFile getFile() {
return file;
}
public void setFile(MultipartFile file) {
this.file = file;
}
- 일반 HttpServlerRequest와 동일하게 MultipartFile도 Command 객체로 받아올 수 있음
- 멤버변수의 타입이 MultipartFile로 선언되어야 함
@RequestMapping("/doUpload")
public ModelAndView doUpload(UploadCommand command)
throws illegalStateException, IOException {
MultipartFile uploadedFile = command.getFile();
if(!uploadedFile.isEmpty()) {
File file = new File("c:\\", uploadedFile.getOriginalFilename());
}
ModelAndView view = new ModelAndView();
view.setViewName("test/fileUpload");
return view;
}
(7) 파일 저장 시 보안 사항
- 업로드 된 파일 이름을 그대로 사용해서 저장을 하게 되면, 추후 파일 다운로드 및 보안사항에 문제 발생
- 아래 표처럼, 파일 이름은 숨기고 실제 파일명은 난수화시켜 저장
Display File Name | Real File NAme |
Toad-trial.exe | 812478112359871234 |
Eclipse.zip | 1224433415312389711 |
Oracle.exe | 18217481234781872 |
* Display File Name과 Real file Name은 모두 Database에 저장되는 항목
* 위의 파일들을 다운받으려면 Real File Name을 요청해야 한다.
2. JUnit
1) JUnit의 개요
- Java에서 독립된 단위 테스트(Unit Test)를 지원해주는 프레임워크
- 보이지 않고 숨겨진 단위 테스트를 끌어내어 정형화시켜, 단위 테스트를 쉽게 만들어줌
* 단위 테스트(Unit Test)란?
-> 소스 코드의 특정 모듈이 의도된 대로 정확히 작동하는지 검증하는 절차,
즉, 모든 함수와 메소드에 대한 테스트 케이스(Test Case)를 작성하는 절차
2) Junit의 특징
- TDD의 창시자인 Kent Beck과 디자인 패턴 책의 저자인 Erich Gamma가 작성
- 단정(assert) 메소드로 테스트 케이스의 수행 결과 판별
예) assertEquals(예상 값, 실제 값)
- jUnit4부터는 테스트를 지원하는 어노테이션 제공
어노테이션(Annotation) | 설명 |
@Test | @Test가 선언된 메소드는 테스트 수행하는 메소드가 됨 JUnit은 각각의 테스트가 서로 영향을 주지 않고 독립적으로 실행됨을 원칙으로 하므로, @Test마다 객체를 생성함 |
@Ignore | @Ignore가 선언된 메소드는 테스트를 실행하지 않게 함 |
@Before | @Before가 선언된 메소드는 @Test가 선언된 메소드가 실행되기 전에 반드시 실행됨 @Test 메소드에서 공통으로 사용하는 코드를 @Before 메소드에 선언하여 사용하면 됨 |
@After | @After가 선언된 메소드는 @Test가 선언된 메소드가 실행된 후 실행됨 |
@BeforeClass | @BeforeClass 어노테이션은 @Test가 선언된 메소드보다 먼저 한 번만 수행되어야 할 경우에 사용 |
@AfterClass | @AfterClass 어노테이션은 @Test가 선언된 메소드보다 나중에 한 번만 수행되어야 할 경우에 사용 |
- 각 @Test 메소드가 호출할 때 마다 새로운 인스턴스를 생성하여 독립적인 테스트가 이루어지도록 함
3) 테스트 결과를 확인하는 단정(assert) 메소드
*이외에도 다양한 assert 메소드 존재
: http://junit.sourceforge.net/javadoc/org/junit/Assert.html
assertEquals(a, b); | 객체 a와 b의 값이 일치함을 확인한다. |
assertArrayEquals(a, b); | 배열 a와 b가 일치함을 확인한다. |
assertSame(a, b); | 객체 a와 b의 레퍼런스가 일치함을 확인한다.(==연산자) |
assertTrue(a); | 조건 a가 참인지 확인한다. |
assertNotNull(a); | 객체 a가 null이 아님을 확인한다. |
3. Spring-Test
- Spring-Test에서 테스트를 지원하는 어노테이션(Annotation)
@RunWith(SpringJUnit4ClassRunner.class) | - JUnit 프레임워크의 테스트 실행방법을 확장할 때 사용 - SpringJUnit4ClassRunner라는 클래스를 지정해주면 JUnit이 테스트 진행 도중에 ApplicationContext를 만들고 관리하는 작업을 진행해줌 - 각각의 테스트별로 객체가 생성되더라도 싱글톤(Singleton)의 ApplicationContext를 보장함 |
@ContextConfiguration | - 스프링 빈(Bean) 설정 파일의 위치를 지정할 때 사용 |
@Autowired | - 스프링 DI에서 사용됨 (특별함) - 해당 변수에 자동으로 빈(Bean)을 매핑해줌 - 스프링 빈(Bean) 설정 파일을 읽기 위해 굳이 GenericXmlApplicationContext를 사용할 필요 없음 |