* 어제에 이어서 파일 업로드 배워봅시다!
@Log4j2
@NoArgsConstructor
@RequestMapping("/fileupload/")
@Controller
public class FileUploadController {
// Mapping URI : /fileupload/page
@GetMapping("/page")
public void fileUploadPage() {
log.trace("fileUploadPage() invoked.");
} // fileUploadPage
@PostMapping("/doit")
public void DoFileUpload(
String myName, String myAge,
// MultipartFile[] files) { // OK : 배열로 달라!
// List<MultipartFile> files) { // OK : List 객체로 달라!
// Set<MultipartFile> files) { // XX : Set 객체로 달라!
// @RequestParam("files") Set<MultipartFile> files) { // OK : @RequestParam 붙이면 해결됨
@RequestParam("files") List<MultipartFile> files) throws ControllerException { // OK : ?
log.trace("DoFileUpload(myName, myAge, files) invoked.");
log.info("\t+ myName : {}, myAge : {}", myName, myAge);
// log.info("\t+ files : {}", Arrays.toString(files));
log.info("\t+ files : {}", files);
try {
for( MultipartFile file : files ) {
String targetDir = "C:/Temp/upload/";
log.info("\t =========================");
log.info("\t+ 1. name : {}", file.getName());
log.info("\t+ 2. originalFilename : {}", file.getOriginalFilename());
log.info("\t+ 3. contentType : {}", file.getContentType());
log.info("\t+ 4. empty : {}", file.isEmpty());
log.info("\t+ 5. size : {}", file.getSize());
log.info("\t+ 6. resource : {}", file.getResource());
String targetFile = targetDir + file.getOriginalFilename();
log.info("\t+ 7. targetFile : {}", targetFile);
file.transferTo( new File(targetFile) );
} // enhanced for
throw new IllegalStateException("TEST"); // 에러를 임의대로 만들어서 예외처리 배워보자
} catch (IllegalStateException | IOException e) {
throw new ControllerException(e);
} // try-catch
} // DoFileUpload
} // end class
FileUploadController.java (위에 있는 메소드를 보세요!)
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>File Upload</title>
</head>
<body>
<h1>WEB-INF/views/fileupload/page.jsp</h1>
<hr>
<form action="/fileupload/doit" method="POST" enctype="multipart/form-data">
<div> Name : <input type="text" size="10" name="myName"> </div>
<div> Age : <input type="text" size="5" name="myAge"> </div>
<br>
<div>1. <input type="file" name="files"></div>
<div>2. <input type="file" name="files"></div>
<div>3. <input type="file" name="files"></div>
<div>4. <input type="file" name="files"></div>
<div>5. <input type="file" name="files"></div>
<br>
<div><input type="submit" name="Upload"></div>
</form>
</body>
</html>
page.jsp
* 파일시스템에 파일을 저장하려면 아래의 2단계 절차에 따라 하는 것이 안전합니다.
1) 임시 폴더에 쓰기 작업이 끝나면
2) 최종 저장폴더로 임시저장파일을 이동시킴(move) (이 move 작업은 원자적이다.(atomic))
왜? 파일로 데이터를 쓰는 중간에 이 파일을 읽어갈 수도 있다.
=> 불완전하게 파일 데이터를 읽어가게 됨!!
---
컨트롤러의 예외(Exception)처리
@ExceptionHandler와 @ControllerAdvice를 이용한 처리
@ResponseEntity를 이용하는 예외 메시지 구성
@Log4j2
@NoArgsConstructor
@RequestMapping("/fileupload/")
@Controller
public class FileUploadController {
// Mapping URI : /fileupload/page
@GetMapping("/page")
public void fileUploadPage() {
log.trace("fileUploadPage() invoked.");
} // fileUploadPage
@PostMapping("/doit")
public void DoFileUpload(
String myName, String myAge,
// MultipartFile[] files) { // OK : 배열로 달라!
// List<MultipartFile> files) { // OK : List 객체로 달라!
// Set<MultipartFile> files) { // XX : Set 객체로 달라!
// @RequestParam("files") Set<MultipartFile> files) { // OK : @RequestParam 붙이면 해결됨
@RequestParam("files") List<MultipartFile> files) throws ControllerException { // OK : ?
log.trace("DoFileUpload(myName, myAge, files) invoked.");
log.info("\t+ myName : {}, myAge : {}", myName, myAge);
// log.info("\t+ files : {}", Arrays.toString(files));
log.info("\t+ files : {}", files);
try {
for( MultipartFile file : files ) {
String targetDir = "C:/Temp/upload/";
log.info("\t =========================");
log.info("\t+ 1. name : {}", file.getName());
log.info("\t+ 2. originalFilename : {}", file.getOriginalFilename());
log.info("\t+ 3. contentType : {}", file.getContentType());
log.info("\t+ 4. empty : {}", file.isEmpty());
log.info("\t+ 5. size : {}", file.getSize());
log.info("\t+ 6. resource : {}", file.getResource());
String targetFile = targetDir + file.getOriginalFilename();
log.info("\t+ 7. targetFile : {}", targetFile);
file.transferTo( new File(targetFile) );
} // enhanced for
throw new IllegalStateException("TEST"); // 에러를 임의대로 만들어서 예외처리 배워보자
} catch (IllegalStateException | IOException e) {
throw new ControllerException(e);
} // try-catch
} // DoFileUpload
} // end class
FileUploadController.java (맨 밑 메소드를 보세요!)
@Log4j2
@NoArgsConstructor
@ControllerAdvice
public class CommonExceptionHandler {
@ExceptionHandler(ControllerException.class)
public String handleControllerException(Exception e , Model model) {
log.trace("handleControllerException() invoked.", e, model);
model.addAttribute("_EXCEPTION_", e);
return "errorPage"; // 뷰의 이름 반환
} // handleControllerException
@ExceptionHandler (NoHandlerFoundException.class)
public String handleNoHandlerFoundException(Exception e, Model model) {
log.trace("handleNoHandlerFoundException() invoked.", e, model);
model.addAttribute("_EXCEPTION_", e);
return "errorPage"; // 뷰의 이름 반환
} // handleNoHandlerFoundException
@ExceptionHandler ( Exception.class)
public String handleException(Exception e, Model model) { // 모든 예외의 처리 핸들러
log.trace("handleException() invoked.", e, model);
model.addAttribute("_EXCEPTION_", e);
return "errorPage"; // 뷰의 이름 반환
} // handleException
} // end class
CommonExceptionHandler
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>errorPage</title>
</head>
<body>
<h1>/WEB-INF/views/errorPage.jsp</h1>
<hr>
<p>${_EXCEPTION_}</p>
<ol>
<c:forEach var="element" items="${ _EXCEPTION_.getStackTrace() }" >
<li>at ${element}</li>
</c:forEach>
</ol>
<hr>
<p>Caused by ${ _EXCEPTION_.getCause() }</p>
<ol>
<c:forEach var="oelement" items="${ _EXCEPTION_.getCause().getStackTrace() }" >
<li>at ${oelement}</li>
</c:forEach>
</ol>
</body>
</html>
errorPage.jsp
---
part03
목차
스프링 MVC를 이용하는 웹 프로젝트 전체 구조에 대한 이해
개발의 각 단계에 필요한 설정 및 테스트 환경
기본적인 등록, 수정, 삭제, 조회, 리스트 구현
목록(리스트) 화면의 페이징(paging) 처리
검색 처리와 페이지 이동
프로젝트의 구성
각 영역의 네이밍 규칙
xxxController
스프링 MVC에서 동작하는 Controller 클래스
xxxSerivce, xxxServiceImpl
비즈니스 영역을 담당하는 인터페이스는 ‘xxxService’라는 방식을 사용하고, 인터페이스를 구현한 클래스는 ‘xxxServiceImpl’이라는 이름을 사용
xxxDAO, xxxRepository
DAO(Data-Access-Object)나 Repository(저장소)라는 이름으로 영역을 따로 구성하는 것이 보편적. 예제에서는 별도의 DAO를 구성하는 대신에 MyBatis의 Mapper 인터페이스를 활용.
VO, DTO
VO의 경우는 주로 Read Only의 목적이 강하고, 데이터 자체도 Immutable(불변)하게 설계. DTO는 주로 데이터 수집의 용도
프로젝트 패키지의 구성
---
Spring Framework 기반으로 웹 서비스를 개발할 때에는 웹 3계층을 거꾸로 개발 (뒤에서 앞으로)
1) 영속성 계층구현 -> 2) 비지니스 계층구현 -> 3) 표현계층구현
반드시 설정이든 구현인든 새로운 것을 만들거나 설정하면 제대로 기능이 동작하는지 테스트하고 지나가야합니다. (테스트 주도 개발, TDD, Test-Driven Development)
따라서 점진적 개발을 수행함. 이러한 방식이 시간이 더 오래 걸릴 것 같지만 실제로는 버그를 줄여줘서 개발 기간이 더 빨라짐!!!
---
'국비학원' 카테고리의 다른 글
[국비지원] KH 정보교육원 108일차 (0) | 2022.08.31 |
---|---|
[국비지원] KH 정보교육원 102~106일차 (0) | 2022.08.31 |
[국비지원] KH 정보교육원 100일차 (0) | 2022.08.19 |
[국비지원] KH 정보교육원 99일차 (0) | 2022.08.18 |
[국비지원] KH 정보교육원 98일차 (0) | 2022.08.17 |