도서 이미지 파일 업로드
커맨드 객체를 사용해서 도서 페이지에서 이미지 사진을 업로드하고 처리하는 것을
구현해보도록 하겠습니다.
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">상세정보 »</a>
</div>
</c:forEach>
</div>
<hr>
<footer>
<p>© 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">도서주문 »</a>
<a href="<c:url value="/books"/>" class="btn btn-secondary">도서 목록 »</a>
</div>
</div>
<hr>
<footer>
<p>© 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 |