[SPRING]#31 도서 쇼핑몰 구현 (파일 업로드5)

2024. 1. 12. 00:35·SPRING
반응형

도서 이미지 파일 업로드

커맨드 객체를 사용해서 도서 페이지에서 이미지 사진을 업로드하고 처리하는 것을

구현해보도록 하겠습니다.


pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/maven-v4_0_0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.springmvc</groupId>
	<artifactId>controller</artifactId>
	<name>BookMarket</name>
	<packaging>war</packaging>
	<version>1.0.0-BUILD-SNAPSHOT</version>
	<properties>
		<java-version>11</java-version>
		<org.springframework-version>5.3.19</org.springframework-version>
		<org.aspectj-version>1.9.9.1</org.aspectj-version>
		<org.slf4j-version>1.7.36</org.slf4j-version>
		<security.version>5.6.3</security.version>
		<commons-fileupload-version>1.4</commons-fileupload-version>
		<commons-io-version>2.11.0</commons-io-version>
	</properties>
	<dependencies>
		<!-- Spring -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>${org.springframework-version}</version>
			<exclusions>
				<!-- Exclude Commons Logging in favor of SLF4j -->
				<exclusion>
					<groupId>commons-logging</groupId>
					<artifactId>commons-logging</artifactId>
				 </exclusion>
			</exclusions>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-webmvc</artifactId>
			<version>${org.springframework-version}</version>
		</dependency>
		
		<!-- Spring Security -->
        <dependency>
        	<groupId>org.springframework.security</groupId>
        	<artifactId>spring-security-web</artifactId>
        	<version>${security.version}</version>
    	</dependency>
    	<dependency>
        	<groupId>org.springframework.security</groupId>
        	<artifactId>spring-security-config</artifactId>
        	<version>${security.version}</version>
    	</dependency>
    	
    	<!-- File Upload -->
    	<dependency>
    		<groupId>commons-fileupload</groupId>
    		<artifactId>commons-fileupload</artifactId>
    		<version>${commons-fileupload-version}</version>
    	</dependency>
    	<dependency>
    		<groupId>commons-io</groupId>
    		<artifactId>commons-io</artifactId>
    		<version>${commons-io-version}</version>
    	</dependency>
    
    		
		<!-- AspectJ -->
		<dependency>
			<groupId>org.aspectj</groupId>
			<artifactId>aspectjrt</artifactId>
			<version>${org.aspectj-version}</version>
		</dependency>	
		
		<!-- Logging -->
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-api</artifactId>
			<version>${org.slf4j-version}</version>
		</dependency>
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>jcl-over-slf4j</artifactId>
			<version>${org.slf4j-version}</version>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-log4j12</artifactId>
			<version>${org.slf4j-version}</version>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>log4j</groupId>
			<artifactId>log4j</artifactId>
			<version>1.2.15</version>
			<exclusions>
				<exclusion>
					<groupId>javax.mail</groupId>
					<artifactId>mail</artifactId>
				</exclusion>
				<exclusion>
					<groupId>javax.jms</groupId>
					<artifactId>jms</artifactId>
				</exclusion>
				<exclusion>
					<groupId>com.sun.jdmk</groupId>
					<artifactId>jmxtools</artifactId>
				</exclusion>
				<exclusion>
					<groupId>com.sun.jmx</groupId>
					<artifactId>jmxri</artifactId>
				</exclusion>
			</exclusions>
			<scope>runtime</scope>
		</dependency>

		<!-- @Inject -->
		<dependency>
			<groupId>javax.inject</groupId>
			<artifactId>javax.inject</artifactId>
			<version>1</version>
		</dependency>
				
		<!-- Servlet -->
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>servlet-api</artifactId>
			<version>2.5</version>
			<scope>provided</scope>
		</dependency>
		<dependency>
			<groupId>javax.servlet.jsp</groupId>
			<artifactId>jsp-api</artifactId>
			<version>2.1</version>
			<scope>provided</scope>
		</dependency>
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>jstl</artifactId>
			<version>1.2</version>
		</dependency>
	
		<!-- Test -->
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>4.7</version>
			<scope>test</scope>
		</dependency>        
	</dependencies>
    <build>
        <plugins>
            <plugin>
                <artifactId>maven-eclipse-plugin</artifactId>
                <version>2.9</version>
                <configuration>
                    <additionalProjectnatures>
                        <projectnature>org.springframework.ide.eclipse.core.springnature</projectnature>
                    </additionalProjectnatures>
                    <additionalBuildcommands>
                        <buildcommand>org.springframework.ide.eclipse.core.springbuilder</buildcommand>
                    </additionalBuildcommands>
                    <downloadSources>true</downloadSources>
                    <downloadJavadocs>true</downloadJavadocs>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.5.1</version>
                <configuration>
                    <source>1.6</source>
                    <target>1.6</target>
                    <compilerArgument>-Xlint:all</compilerArgument>
                    <showWarnings>true</showWarnings>
                    <showDeprecation>true</showDeprecation>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>exec-maven-plugin</artifactId>
                <version>1.2.1</version>
                <configuration>
                    <mainClass>org.test.int1.Main</mainClass>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

앞서 배운 예제와 마찬가지로 파일 업로드 관련 의존 라이브러리를 등록해줍니다.


servlet-context.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/mvc"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:beans="http://www.springframework.org/schema/beans"
	xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd
		http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">

	<!-- DispatcherServlet Context: defines this servlet's request-processing infrastructure -->
	
	<!-- Enables the Spring MVC @Controller programming model -->
	<annotation-driven enable-matrix-variables="true"/>

	<!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources directory -->
	<resources mapping="/resources/**" location="/resources/" />

	<!-- Resolves views selected for rendering by @Controllers to .jsp resources in the /WEB-INF/views directory -->
	<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>
	
	<context:component-scan base-package="com.springmvc.*" />
	
	<beans:bean id="multipartResolver"
				class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
		<beans:property name="maxUploadSize" value="10240000"/>			
	</beans:bean>
	
</beans:beans>

업로드할 파일의 최대 크기를 설정해줍니다.

도서 등록 페이지에서는 파일의 최대 크기를 10,240,000 바이트로 설정하였습니다.


C드라이브에 upload 폴더를 만들어줍니다.

지난 예제에 만들어놓은 upload 폴더가 있기 때문에 이 폴더에서 도서별 이미지 파일을 저장할 것입니다.

파일 이름은 마찬가지로 도서ID.png로 설정합니다.


Book.java

package com.springmvc.domain;

import org.springframework.web.multipart.MultipartFile;

public class Book {
	private String bookId;
	private String name;
	private int unitPrice;
	private String author;
	private String description;
	private String publisher;
	private String category;
	private long unitsInStock;
	private String releaseDate;
	private String condition;
	private MultipartFile bookImage;
	
	public Book() {
		super();
		// TODO Auto-generated constructor stub
	}
	public Book(String bookId, String name, int unitPrice) {
		super();
		this.bookId = bookId;
		this.name = name;
		this.unitPrice = unitPrice;
	}
	
	public String getBookId() {
		return bookId;
	}
	public void setBookId(String bookId) {
		this.bookId = bookId;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getUnitPrice() {
		return unitPrice;
	}
	public void setUnitPrice(int unitPrice) {
		this.unitPrice = unitPrice;
	}
	public String getAuthor() {
		return author;
	}
	public void setAuthor(String author) {
		this.author = author;
	}
	public String getDescription() {
		return description;
	}
	public void setDescription(String description) {
		this.description = description;
	}
	public String getPublisher() {
		return publisher;
	}
	public void setPublisher(String publisher) {
		this.publisher = publisher;
	}
	public String getCategory() {
		return category;
	}
	public void setCategory(String category) {
		this.category = category;
	}
	public long getUnitsInStock() {
		return unitsInStock;
	}
	public void setUnitsInStock(long unitsInStock) {
		this.unitsInStock = unitsInStock;
	}
	public String getReleaseDate() {
		return releaseDate;
	}
	public void setReleaseDate(String releaseDate) {
		this.releaseDate = releaseDate;
	}
	public String getCondition() {
		return condition;
	}
	public void setCondition(String condition) {
		this.condition = condition;
	}
	public MultipartFile getBookImage() {
		return bookImage;
	}
	public void setBookImage(MultipartFile bookImage) {
		this.bookImage = bookImage;
	}
}

Book 클래스에 도서 이미지에 대해 MultipartFile 타입인 bookImage를 추가하고

마찬가지로 Setter(), Getter() 메소드를 작성해줍니다.


BookController.java

package com.springmvc.controller;

import java.io.File;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.MatrixVariable;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.ModelAndView;

import com.springmvc.domain.Book;
import com.springmvc.service.BookService;

@Controller
@RequestMapping("/books")
public class BookController {
	@Autowired
	private BookService bookService;
	
	@RequestMapping
	public String requestBookList(Model model) {
		List<Book> list = bookService.getAllBookList();
		model.addAttribute("bookList", list);
		return "books";
	}
	
	@RequestMapping("/all")
	public ModelAndView requestAllBooks() {
		ModelAndView modelAndView = new ModelAndView();
		List<Book> list = bookService.getAllBookList();
		modelAndView.addObject("bookList", list);
		modelAndView.setViewName("books");
		return modelAndView;
	}
	
	@RequestMapping("/{category}")
	public String requestBooksByCategory(@PathVariable("category") String bookCategory, Model model) {
		List<Book> booksByCategory = bookService.getBookListByCategory(bookCategory);
		model.addAttribute("bookList", booksByCategory);
		return "books";
	}
	
	@RequestMapping("/filter/{bookFilter}")
	public String requestBooksByFilter(
			@MatrixVariable(pathVar="bookFilter") Map<String, List<String>> bookFilter, Model model) {
		Set<Book> booksByFilter = bookService.getBookListByFilter(bookFilter);
		model.addAttribute("bookList", booksByFilter);
		return "books";
	}
	
	@RequestMapping("/book")
	public String requestBookById (
			@RequestParam("id") String bookId, Model model) {
		Book bookById = bookService.getBookById(bookId);
		model.addAttribute("book", bookById);
		return "book";
	}
	
	@RequestMapping("/add")
	public String requestAddBookForm(@ModelAttribute("NewBook") Book book) {
		return "addBook";
	}
	
	@PostMapping("/add")
	public String submitAddNewBook(@ModelAttribute("NewBook") Book book) {
		MultipartFile bookImage = book.getBookImage();
		
		String saveName = bookImage.getOriginalFilename();
		File saveFile = new File("C:\\upload",saveName);
		
		if(bookImage!=null && !bookImage.isEmpty()) {
			try {
				bookImage.transferTo(saveFile);
			} catch(Exception e) {
				throw new RuntimeException("도서 이미지 업로드가 실패하였습니다",e);
			}
		}
		bookService.setNewBook(book);
		return "redirect:/books";
	}
	
	@ModelAttribute
	public void addAttribute(Model model) {
		model.addAttribute("addTitle", "신규 도서 등록");
	}
	
	@InitBinder
	public void initBinder(WebDataBinder binder) {
		binder.setAllowedFields("bookId","name","unitPrice","author","description","publisher","category","unitsInStock","totalPages","releaseDate","condition","bookImage");
	}
}

BookController 컨트롤러에 submitAddNewBook()과 initBinder() 메소드를 수정해줍니다.

 

커맨드 객체의 매개변수 중 도서 이미지를 MultipartFile 객체의 bookImage 변수로 전달받습니다.

MultipartFile 타입으로 전송받은 이미지 파일 이름을 얻어서

upload 폴더로 업로드 합니다.


addBook.jsp

<%@ page contentType="text/html; charset=utf-8" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<html>
<head>
<link href="<c:url value="/resources/css/bootstrap.min.css"/>" rel="stylesheet">
<title>도서 등록</title>
</head>
<body>
	<nav class="navbar navbar-expand navbar-dark bg-dark">
		<div class="container">
			<div class="navbar-header">
				<a class="navbar-brand" href="./home">Home</a>
			</div>
		</div>
	</nav>
	<div class="jumbotron">
		<div class="container">
			<h1 class="display-3">도서 등록</h1>
		</div>
	</div>
	<div class="container">
		<div class="float-right">
			<form:form action="${pageContext.request.contextPath }/logout" method="POST">
				<input type="submit" class="btn btn-sm btn-success" value="Logout" />
			</form:form>
		</div>
		<br><br>
		<form:form modelAttribute="NewBook" 
					action="./add?${_csrf.parameterName }=${_csrf.token }"
					class="form-horizontal"
					enctype="multipart/form-data">
		<fieldset>
		<legend>${addTitle }</legend>
		<div class="form-group row">
			<label class="col-sm-2 control-label">도서ID</label>
			<div class="col-sm-3">
				<form:input path="bookId" class="form-control"/>
			</div>
		</div>
		<div class="form-group row">
			<label class="col-sm-2 control-label">도서명</label>
			<div class="col-sm-3">
				<form:input path="name" class="form-control"/>
			</div>
		</div>
		<div class="form-group row">
			<label class="col-sm-2 control-label">가격</label>
			<div class="col-sm-3">
				<form:input path="unitPrice" class="form-control"/>
			</div>
		</div>
		<div class="form-group row">
			<label class="col-sm-2 control-label">저자</label>
			<div class="col-sm-3">
				<form:input path="author" class="form-control"/>
			</div>
		</div>
		<div class="form-group row">
			<label class="col-sm-2 control-label">상세정보</label>
			<div class="col-sm-5">
				<form:textarea path="description" cols="50" rows="2" class="form-control"/>
			</div>
		</div>
		<div class="form-group row">
			<label class="col-sm-2 control-label">출판사</label>
			<div class="col-sm-3">
				<form:input path="publisher" class="form-control"/>
			</div>
		</div>
		<div class="form-group row">
			<label class="col-sm-2 control-label">분야</label>
			<div class="col-sm-3">
				<form:input path="category" class="form-control"/>
			</div>
		</div>
		<div class="form-group row">
			<label class="col-sm-2 control-label">재고수</label>
			<div class="col-sm-3">
				<form:input path="unitsInStock" class="form-control"/>
			</div>
		</div>
		<div class="form-group row">
			<label class="col-sm-2 control-label">출판일</label>
			<div class="col-sm-3">
				<form:input path="releaseDate" class="form-control"/>
			</div>
		</div>
		<div class="form-group row">
			<label class="col-sm-2 control-label">상태</label>
			<div class="col-sm-3">
				<form:radiobutton path="condition" value="New"/>New
				<form:radiobutton path="condition" value="Old"/>Old
				<form:radiobutton path="condition" value="E-Book"/>E-Book
			</div>
		</div>
		<div class="form-group row">
			<label class="col-sm-2 control-label">도서이미지</label>
			<div class="col-sm-7">
				<form:input path="bookImage" type="file" class="form-control"/>
			</div>
		</div>
		<div class="form-group row">
			<div class="col-sm-offset-2 col-sm-10">
			<input type="submit" class="btn btn-primary" value="등록"/>
			</div>
		</div>
		</fieldset>
		</form:form>
		<hr>
	<footer>
		<p>&Copy; BookMarket</p>
	</footer>
	</div>
</body>
</html>

도서 등록 페이지에 이미지 파일을 업로드 시키기위한 코드를 추가해줍니다.

멀티파트 요청으로 인코딩 속성인 enctype="multipart/form-data"를 설정해줍니다.


books.jsp

<%@ page contentType="text/html; charset=utf-8" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
<html>
<head>
<link href="<c:url value="/resources/css/bootstrap.min.css"/>" rel="stylesheet">
<title>도서 목록</title>
</head>
<body>
	<nav class="navbar navbar-expand navbar-dark bg-dark">
		<div class="container">
			<div class="navbar-header">
				<a class="navbar-brand" href="./home">Home</a>
			</div>
		</div>
	</nav>
	<div class="jumbotron">
		<div class="container">
			<h1 class="display-3">도서 목록</h1>
		</div>
	</div>
	<div class="container">
		<div class="row" align="center">
			<c:forEach items="${bookList }" var="book">
				<div class="col-md-4">
					<c:choose>
						<c:when test="${book.getBookImage()==null }">
							<img src="<c:url value="C:\\upload\\${book.getBookId() }.png"/>" style="width:60%"/>
						</c:when>
						<c:otherwise>
							<img src="<c:url value="C:\\upload\\${book.getBookImage().getOriginalFilename() }"/>" style="width:60%"/>
						</c:otherwise>
					</c:choose>
					<h3>${book.name }</h3>
					<p>${book.author }
					<br>${book.publisher } | ${book.releaseDate }
					<p align="left">${fn:substring(book.description,0,100) }...
					<p>${book.unitPrice }원
					<p><a href="<c:url value="/books/book?id=${book.bookId }"/>" class="btn btn-Secondary" role="button">상세정보 &raquo;</a>
				</div>
			</c:forEach>
		</div>
		<hr>
		<footer>
			<p>&copy; BookMarket</p>
		</footer>
	</div>
</body>
</html>

업로드한 도서 이미지의 파일을 출력하기 위해 <c:choose> 문 내용을 추가해줍니다.


book.jsp

<%@ page contentType="text/html; charset=utf-8" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<link href="<c:url value="/resources/css/bootstrap.min.css"/>" rel="stylesheet">
<title>도서 상세 정보</title>
</head>
<body>
	<nav class="navbar navbar-expand navbar-dark bg-dark">
		<div class="container">
			<div class="navbar-header">
				<a class="navbar-brand" href="./home">Home</a>
			</div>
		</div>
	</nav>
	<div class="jumbotron">
		<div class="container">
			<h1 class="display-3">도서 정보</h1>
		</div>
	</div>
	<div class="container">
		<div class="row">
			<c:choose>
				<c:when test="${book.getBookImage()==null }">
					<img src="<c:url value="C:\\upload\\${book.getBookId() }.png"/>" style="width:100%"/>
				</c:when>
				<c:otherwise>
					<img src="<c:url value="C:\\upload\\${book.getBookImage().getOriginalFilename() }"/>" style="width:100%"/>
				</c:otherwise>
			</c:choose>
			<div class="col-md-8">
				<h3>${book.name }</h3>
				<p>${book.description }</p>
				<br/>
				<p><b>도서코드 : </b><span class="badge badge-info">${book.bookId }</span>
				<p><b>저자</b> : ${book.author }
				<p><b>출판사</b> : ${book.publisher }
				<p><b>출판일</b> : ${book.releaseDate }
				<p><b>분류</b> : ${book.category }
				<p><b>재고수</b> : ${book.unitsInStock }
				<h4>${book.unitPrice }원</h4>
				<br>
				<p><a href="#" class="btn btn-primary">도서주문 &raquo;</a>
				<a href="<c:url value="/books"/>" class="btn btn-secondary">도서 목록 &raquo;</a>
			</div>
		</div>
		<hr>
		<footer>
			<p>&copy; BookMarket
		</footer>
	</div>
</body>
</html>

books.jsp 페이지와 마찬가지로 내용을 추가해줍니다.


실행 결과

/books/add 경로로 들어가서 로그인 후 도서를 등록해봅니다.

다음과 같이 도서가 이미지와 함께 잘 추가된 것을 확인하였습니다.

반응형

'SPRING' 카테고리의 다른 글

[SPRING]#33 도서 쇼핑몰 구현 (예외 처리2)  (0) 2024.01.15
[SPRING]#32 도서 쇼핑몰 구현 (예외 처리1)  (0) 2024.01.15
[SPRING]#30 도서 쇼핑몰 구현 (파일 업로드4)  (0) 2024.01.11
[SPRING]#29 도서 쇼핑몰 구현 (파일 업로드3)  (0) 2024.01.11
[SPRING]#28 도서 쇼핑몰 구현 (파일 업로드2)  (0) 2024.01.11
'SPRING' 카테고리의 다른 글
  • [SPRING]#33 도서 쇼핑몰 구현 (예외 처리2)
  • [SPRING]#32 도서 쇼핑몰 구현 (예외 처리1)
  • [SPRING]#30 도서 쇼핑몰 구현 (파일 업로드4)
  • [SPRING]#29 도서 쇼핑몰 구현 (파일 업로드3)
아모사
아모사
혼자서 공부, 정리 하는 공간
  • 아모사
    아무것도 몰라요
    아모사
  • 전체
    오늘
    어제
    • 분류 전체보기 (211)
      • DJANGO (10)
        • Django REST (10)
      • 알고리즘 (36)
      • JAVA (16)
      • JSP (2)
      • SPRING (98)
      • GIT (14)
      • CS_운영체제 (8)
      • CS_네트워크 (6)
      • 취업관련 (0)
      • CS_데이터베이스 (6)
      • CS_디자인 패턴 (6)
      • 면접 대비 (7)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
아모사
[SPRING]#31 도서 쇼핑몰 구현 (파일 업로드5)
상단으로

티스토리툴바