[0603] 자바 웹 개발 과정🌞

파일 업로드

하나의 파일 업로드

  • upload.html
<!DOCTYPE html>
<html>
<head>
<meta charset="EUC-KR">
<title>Insert title here</title>
</head>
<body>
	<form action="/admin/notice/reg" method="post" enctype="multipart/form-data">
		<input type="file" name="file"><br>
		<input type="submit" value="전송">
	</form>
</body>
</html>
  • HomeController
@PostMapping("upload") 
public String upload(/*@RequestParam(name="file1")*/ MultipartFile file, /*file이라는 같은 변수명으로 받으려면 name 속성도 같은 이름("file")이어야함, name 속성 이름이 다르다면 RequestParam을 써줘야함*/
		HttpServletRequest request) {
	
	String fileName = file.getOriginalFilename(); // file 이름 얻기
	
	ServletContext application = request.getServletContext();
	String path = "/upload";
	String realPath = application.getRealPath(path);
	
	File pathFile = new File(realPath);
	if(!pathFile.exists())
		pathFile.mkdirs();
	
	String filePath = realPath + File.separator + fileName;
	
	File saveFile = new File(filePath); // 저장할 파일
	
	try {
		file.transferTo(saveFile); // 이 메소드에 의해 저장 경로에 실질적으로 파일이 생성됨, 저장하려고 한 파일이 저장되는 것임
	} catch (IllegalStateException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	} catch (IOException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	} 
	
	return "ok";
}

여러 개의 파일 업로드

  • upload.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<form action="/admin/upload" method="post" enctype="multipart/form-data">
		<input type="file" name="files"><br>
		<input type="file" name="files"><br>
		<input type="submit" value="전송">
	</form>
</body>
</html>
  • HomeController
@PostMapping("upload") // 비동기적으로 파일 업로드하기
public String upload(MultipartFile[] files, /*file이라는 같은 변수명으로 받으려면 name 속성도 같은 이름("file")이어야함, name 속성 이름이 다르다면 RequestParam을 써줘야함*/
	HttpServletRequest request) {
	
	for(MultipartFile file : files) {
		
		String fileName = file.getOriginalFilename(); // file 이름 얻기
		
		ServletContext application = request.getServletContext();
		String path = "/upload"; 
		String realPath = application.getRealPath(path);
		
		File pathFile = new File(realPath);
		if(!pathFile.exists())
			pathFile.mkdirs();
		
		String filePath = realPath + File.separator + fileName;
		
		File saveFile = new File(filePath); // 저장할 파일, 파일에 대한 정보 구조가 메모리에만 생기는 것
		
		try {
			file.transferTo(saveFile); // 이 메소드에 의해 저장 경로에 실질적으로 파일이 생성됨, 저장하려고 한 파일이 저장되는 것임
		} catch (IllegalStateException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} 
	}
	
	return "ok";
}

Tiles


타일즈는 웹 페이지의 상단이나 하단 메뉴와 같이 반복적으로 사용되는 부분들에 대한 코드를 분리해 한 곳에서 관리를 가능하게 해준다.

지시사항 작성

  • layout.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="tiles" uri="http://tiles.apache.org/tags-tiles"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
      
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link href="../../css/style.css" type="text/css" rel="stylesheet">
    
    <c:set var="title" value="${title }"></c:set> <!-- SubLayoutPreparer에서 심어준 title -->
    <title>${title}</title> 
    
    <!-- tiles.xml에서 설정한 값 출력 -->
    <c:set var="js"><tiles:getAsString name="js" /></c:set> <!-- 태그가 태그를 감싸지 않게 하기 -->    
    <script type="text/javascript" src="/js/admin/notice/${js}"></script>
</head>

<body>
    <div id="root">
        <!-- header 영역 -->
        <tiles:insertAttribute name="header" />

        <div id="visual">
            <div class="float-content"></div>
        </div>

        <div id="body">
            <div class="float-content">
               <!-- asdie 영역, admin에서만 사용할 aside이므로 admin/inc 안에 두기 -->
			   <tiles:insertAttribute name="aside" />
				

               <!-- main 영역 -->
			   <tiles:insertAttribute name="main" />               
            </div>
        </div>

        <!-- footer 영역 -->
	    <tiles:insertAttribute name="footer" />
    </div>
</body>
</html>
  • tiles.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE tiles-definitions PUBLIC
       "-//Apache Software Foundation//DTD Tiles Configuration 3.0//EN"
       "http://tiles.apache.org/dtds/tiles-config_3_0.dtd">
<tiles-definitions>
  <definition name="admin.notice.list" template="/WEB-INF/view/admin/inc/layout.jsp"> <!-- name은 url 본떠서 작성하기 -->
    <put-attribute name="header" value="/WEB-INF/view/inc/header.jsp" />
    <put-attribute name="aside" value="/WEB-INF/view/admin/inc/aside.jsp" />
    <put-attribute name="main" value="/WEB-INF/view/admin/notice/list.jsp" />
    <put-attribute name="footer" value="/WEB-INF/view/inc/footer.jsp" />
  </definition>
</tiles-definitions>

Tiles를 객체화하기 위한 코드

  • 스프링이 시작되자마자 Tiles는 객체화되어야 하므로 메모리에 올려줘야 한다
  • 내가 만든 클래스를 메모리에 올릴 수 있고, 남이 만든 클래스를 메모리에 올릴 수 있다
  • 내가 만든 클래스는 @Configuration을 붙여주면 된다
  • 남이 만든 코드는 내가 직접 new로 생성한 후에 반환값을 통해 메모리에 올려주자(@Bean 이용)
package com.newlecture.web.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;
import org.springframework.web.servlet.view.tiles3.TilesView;
import org.springframework.web.servlet.view.tiles3.TilesViewResolver;

//@Controller/@RestController
//@Service
//@Repository(DAO)
//@Configuration
//(Component == 위 4개)식별할 때 더 잘 식별하기 위해 역할에 따른 객체를 선택적으로 사용 가능

@Configuration 
// 객체를 담고 있는 것은 빈을 담고 있다고 해서 Bean Container(콩자루, 콩보따리)라고 함: IoC Container
// 다섯 개 중 아무 거나 붙이면 톰캣이 실행되면서 TilesConfig를 객체화하게 됨
public class TilesConfig /* tilesConfig라는 이름으로 참조변수가 됨 */ { // 2. 이게 먼저 인스턴스화되어야 함
	
	@Bean
	public TilesConfigurer tilesConfigurer() {
		TilesConfigurer configurer = new TilesConfigurer();
		
		return configurer;
	}

	@Bean // 얘도 콩이라고, 객체라고 알려주는 것
	// 누군가가 호출해서 사용하는 함수가 아니라 config로서 메모리에 올리기 위한 변수, tilesViewResolver가 콩자루에 들어가는 식별명
	public TilesViewResolver tilesViewResolver() { // 1. 이게 인스턴스화되려면
	
		TilesViewResolver resolver = new TilesViewResolver();
		resolver.setViewClass(TilesView.class);
		resolver.setOrder(1);
		
		return resolver; // bean은 실행해서 반환하는 이 객체를 콩자루에 담게 해줌
						 // resolver가 tilesViewResolver라는 이름으로 콩자루에 들어감
	}
	// tilesViewResolver = resolver;
}

🐥마무리

1차 프로젝트를 진행할 때, 반복되는 header, aside, footer를 한번에 수정하는 법을 몰라 똑같은 코드를 몇 번이고 고치곤 했었는데 오늘 드디어 동일한 레이아웃을 집중화하는 밥법에 대해 알아보았다.
바로 Tiles를 사용하는 방법인데, 먼저 Tiles를 객체화하기 위한 코드를 작성한 후 어떤 레이아웃 페이지에 header, aside, main, footer를 합칠 것인지에 대한 지시서를 작성한다. 또한 레이아웃 페이지에는 tiles jstl 표기를 사용해 header, aside, main, footer를 name으로 명시해준다. 이렇게 몇 단계의 과정만 거치면 동일한 코드를 반복적으로 고치지 않고 쉽게 수정할 수 있다!

참고 사이트

타일즈란? Tiles

좋은 웹페이지 즐겨찾기