Spring & Springboot/올인원 스프링 프레임워크

전자 도서관 프로젝트 - 신규 도서 등록 기능 구현

YJ_ma 2023. 11. 29. 17:20

패키지와 클래스 생성하기

관리자는 신규 도서를 등록할 수 있다. 관리자 로그인 후 '도서등록' 메뉴를 이용해서 신규 도서를 등록할 수 있다.

'도서등록' 메뉴는 nav.jsp에 다음과 같이 코딩되어 있다.

<li><a href="<c:url value='/book/admin/registerBookForm' />">도서등록</a></li>

 

도서 등록 메뉴에 대한 링크는 /book/admin/registerBookForm으로 관련 패키지와 클래스를 다음과 같이 만든다.

com.office.library.book 패키지
도서 정보 저장 Vo 클래스 BookVo.java
com.office.library.book.admin 패키지
컨트롤러 클래스 BookController.java
DAO 클래스 BookDao.java
서비스 클래스 BookService.java
com.office.library.book.admin.util 패키지
파일 업로드 서비스 클래스 UploadFileService.java

 

BookVo는 관리자뿐만 아니라 일반 사용자도 사용할 수 있는 클래스로, 일반 사용자가 도서 검색하거나 대출할 때 사용될 수 있다. 따라서 BookVo를 com.office.library.book.admin 패키지에 만들지 않고 com.office.library.book에 만들어서 관리자와 사용자가 공동으로 사용할 수 있게 구별해준다.

 

도서 테이블 생성하기

도서를 등록하기 위한 테이블을 데이터베이스에 만들어본다. SQL문을 이용해서 도서 테이블(tbl_book)을 만든다.

※ 한글 지원을 위해 마지막에 default character set uft8 collate uft8_general_ci;를 설정해준다!

CREATE TABLE tbl_book(
	b_no			INT	AUTO_INCREMENT,
	b_thumbnail		VARCHAR(100),
	b_name			VARCHAR(30)	NOT NULL, 	
	b_author		VARCHAR(20)	NOT NULL, 	
	b_publisher		VARCHAR(20)	NOT NULL,
	b_publish_year		CHAR(4)		NOT NULL, 	
	b_isbn			VARCHAR(30)	NOT NULL, 
	b_call_number		VARCHAR(30)	NOT NULL, 
	b_rantal_able		TINYINT	NOT NULL DEFAULT 1, 
	b_reg_date		DATETIME,
	b_mod_date		DATETIME,
	PRIMARY KEY(b_no)
) default character set utf8 collate utf8_general_ci;

 

tbl_book 테이블이 정상적으로 생성되었는지 확인한다.

SELECT * FROM tbl_book;

 

 

VO 구현하기

BookVo.java 파일을 열어서 다음과 같이 코딩한다.

· getter, setter 메서드는 source > Generate Getters and Setters를 이용하면 자동으로 생성

package com.office.library.book;

public class BookVo {

	int b_no;
	String b_thumbnail;
	String b_name;
	String b_author;	
	String b_publisher;
	String b_publish_year;
	String b_isbn;
	String b_call_number;
	int b_rantal_able;
	String b_reg_date;
	String b_mod_date;
	
	public int getB_no() {
		return b_no;
	}
	public void setB_no(int b_no) {
		this.b_no = b_no;
	}
	public String getB_thumbnail() {
		return b_thumbnail;
	}
	public void setB_thumbnail(String b_thumbnail) {
		this.b_thumbnail = b_thumbnail;
	}
	public String getB_name() {
		return b_name;
	}
	public void setB_name(String b_name) {
		this.b_name = b_name;
	}
	public String getB_author() {
		return b_author;
	}
	public void setB_author(String b_author) {
		this.b_author = b_author;
	}
	public String getB_publisher() {
		return b_publisher;
	}
	public void setB_publisher(String b_publisher) {
		this.b_publisher = b_publisher;
	}
	public String getB_publish_year() {
		return b_publish_year;
	}
	public void setB_publish_year(String b_publish_year) {
		this.b_publish_year = b_publish_year;
	}
	public String getB_isbn() {
		return b_isbn;
	}
	public void setB_isbn(String b_isbn) {
		this.b_isbn = b_isbn;
	}
	public String getB_call_number() {
		return b_call_number;
	}
	public void setB_call_number(String b_call_number) {
		this.b_call_number = b_call_number;
	}
	public int getB_rantal_able() {
		return b_rantal_able;
	}
	public void setB_rantal_able(int b_rantal_able) {
		this.b_rantal_able = b_rantal_able;
	}
	public String getB_reg_date() {
		return b_reg_date;
	}
	public void setB_reg_date(String b_reg_date) {
		this.b_reg_date = b_reg_date;
	}
	public String getB_mod_date() {
		return b_mod_date;
	}
	public void setB_mod_date(String b_mod_date) {
		this.b_mod_date = b_mod_date;
	}
	
}

 

도서 등록에 필요한 기능과 화면 구현하기

도서 등록 화면으로 이동하는 기능 구현하기

BookController.java 파일에서 컨트롤러의 역할을 하도록 코딩한다.

BookController에 도서 등록 화면으로 이동하기 위한 registerBookForm()을 선언한다.

package com.office.library.book.admin;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@RequestMapping("/book/admin")
public class BookController {
	// 도서 등록
	@GetMapping("/registerBookForm")
	public String registerBookForm() {
		System.out.println("[BookController] registerBookForm()");

		String nextPage = "admin/book/register_book_form";

		return nextPage;
	}
}

 

도서 등록 양식 화면 구현하기

register_book_form.jsp : 신규 도서를 등록하는 화면

· <form>에서 action은 도서 등록 요청에 대한 서버 URI(/book/admin/registerBookConfirm)을 의미

· enctype : 이미지(도서표지) 파일을 업로드하기 위한 설정

· 도서를 등록할 때는 테스트 데이터뿐만 아니라 도서의 표지도 이미지 파일로 서버에 전송해야 한다.

· 파일을 서버에 전송하기 위해서는 <form>의 enctype 속성을 multipart/form-data로 설정해야 한다.

· 도서 이미지 파일을 '내 컴퓨터'에서 선택하기 위한 <input>이며 type은 file이다.

<form action="<c:url value='/book/admin/registerBookConfirm' />" name="register_book_form" method="post" enctype="multipart/form-data">

    <input type="text" name="b_name" placeholder="INPUT BOOK NAME."> <br>
    <input type="text" name="b_author" placeholder="INPUT BOOK AUTHOR."> <br>
    <input type="text" name="b_publisher" placeholder="INPUT BOOK PUBLISHER."> <br>
    <input type="text" name="b_publish_year" placeholder="INPUT BOOK PUBLISH YEAR."> <br>
    <input type="text" name="b_isbn" placeholder="INPUT BOOK ISBN."> <br>
    <input type="text" name="b_call_number" placeholder="INPUT BOOK CALL NUMBER."> <br>
    <select name="b_rantal_able">
        <option value="">SELECT BOOK RANTAL ABLE.</option>
        <option value="0">UNABLE.</option>
        <option value="1">ABLE.</option>
    </select><br>
    <input type="file" name="file"><br>
    <input type="button" value="register book" onclick="registerBookForm();"> 
    <input type="reset"	value="reset">

</form>

 

파일 업로드에 필요한 모듈 추가하기

스프링에서 파일을 업로드하기 위해서는 commons-fileupload 모듈을 이용해야 한다.

pom.xml 파일에서 <dependencies>에 다음 코드를 추가해준다.

<!-- File upload -->
<!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload -->
<dependency>
    <groupId>commons-fileupload</groupId>
    <artifactId>commons-fileupload</artifactId>
    <version>1.5</version>
</dependency>

 

register_book_form.jsp에서 사용된 multipart를 사용하기 위해서 스프링에서 제공하는 CommonsMutipartResolver를 빈으로 등록해야 한다. CommonsMultipartResolver를 빈으로 등록하기 위해서 [spring]폴더에 file-context.xml 파일을 만들고 다음과 같이 코딩한다.

· CommonsMultipartResolver를 빈으로 등록한다.

아이디 : multipartResolver

· 파일 업로드 시 최대 파일 사이즈는 10,240,000 바이트(byte)로 설정한다.(약 10MB)

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">
		
	<!-- mariaDB connection 객체 -->
	<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
		<property name="maxUploadSize" value="10240000" />
		<property name="defaultEncoding" value="utf-8" />
	</bean>
	
</beans>

 

file-context.xmlㅇ르 web.xml의 <context-param>에 추가한다.

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>
    /WEB-INF/spring/root-context.xml
    /WEB-INF/spring/jdbc-context.xml
    /WEB-INF/spring/security-context.xml
    /WEB-INF/spring/mail-context.xml
    /WEB-INF/spring/file-context.xml
    </param-value>
</context-param>

 

도서 등록 처리하기

컨트롤러 구현

BookController에 /book/admin/registerBookConfirm 요청을 처리하는 registerBookConfirm()을 선언하고 매핑한다.

@Autowired
BookService bookService;

@Autowired
UploadFileService uploadFileService;

..생략..
// 도서 등록 확인
@PostMapping("/registerBookConfirm")
public String registerBookConfirm(BookVo bookVo, @RequestParam("file") MultipartFile file) {
    System.out.println("[BookController] registerBookConfirm()");

    String nextPage = "admin/book/register_book_ok";

    // 파일 저장
    String savedFileName = uploadFileService.upload(file);

    if (savedFileName != null) {
        bookVo.setB_thumbnail(savedFileName);
        int result = bookService.registerBookConfirm(bookVo);

        if (result <= 0)
            nextPage = "admin/book/register_book_ng";
    } else {
        nextPage = "admin/book/register_book_ng";
    }
    return nextPage;
}

 

파일 업로드 기능 구현

파일 업로드 역할을 담당하는 클래스 UploadFileService.java를 코딩한다.

package com.office.library.book.admin.util;

import java.io.File;
import java.util.UUID;

import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

@Service
public class UploadFileService {

	public String upload(MultipartFile file) {

		boolean result = false;

		// 파일 저장
		String fileOriName = file.getOriginalFilename();
		String fileExtension = 
				fileOriName.substring(fileOriName.lastIndexOf("."), fileOriName.length());
		String uploadDir = "C:\\library\\upload\\";

		UUID uuid = UUID.randomUUID();
		String uniqueName = uuid.toString().replaceAll("-", "");

		File saveFile = new File(uploadDir + "\\" + uniqueName + fileExtension);

		if (!saveFile.exists())
			saveFile.mkdirs();

		try {
			file.transferTo(saveFile);
			result = true;		
		} catch (Exception e) {
			e.printStackTrace();

		}

		if (result) {
			System.out.println("[UploadFileService] FILE UPLOAD SUCCESS!!");
			return uniqueName + fileExtension;	
		} else {
			System.out.println("[UploadFileService] FILE UPLOAD FAIL!!");
			return null;
		}

	}	

}

 

서비스 기능 구현

BookService 클래스를 서비스 빈으로 등록하기 위해서 @Service를 명시하고 registerBookConfirm()을 선언한다.

package com.office.library.book.admin;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.office.library.book.BookVo;

@Service
public class BookService {

	final static public int BOOK_ISBN_ALREADY_EXIST = 0;	// 이미 등록된 도서
	final static public int BOOK_REGISTER_SUCCESS = 1;	// 신규 도서 등록 성공
	final static public int BOOK_REGISTER_FAIL = -1;	// 신규 도서 등록 실패

	@Autowired
	BookDao bookDao;

	public int registerBookConfirm(BookVo bookVo) {
		System.out.println("[BookService] registerBookConfirm()");

		boolean isISBN = bookDao.isISBN(bookVo.getB_isbn());

		if (!isISBN) {
			int result = bookDao.insertBook(bookVo);

			if (result > 0)
				return BOOK_REGISTER_SUCCESS;
			else
				return BOOK_REGISTER_FAIL;
		} else {
			return BOOK_ISBN_ALREADY_EXIST;
		}

	}

}

 

DAO 기능 구현

신규 도서를 tbl_book 테이블에 추가하기 위한 BookDao를 코딩한다.

package com.office.library.book.admin;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;

import com.office.library.book.BookVo;

@Component
public class BookDao {

	@Autowired
	JdbcTemplate jdbcTemplate;

	public boolean isISBN(String b_isbn) {
		System.out.println("[BookDao] isISBN()");

		String sql = "SELECT COUNT(*) FROM tbl_book " + "WHERE b_isbn = ?";

		int result = jdbcTemplate.queryForObject(sql, Integer.class, b_isbn);

		return result > 0 ? true : false;
	}

	public int insertBook(BookVo bookVo) {
		System.out.println("[BookDao] insertBook()");

		String sql = "INSERT INTO tbl_book(b_thumbnail, "
				+ "b_name, " + "b_author, " + "b_publisher, "
				+ "b_publish_year, " + "b_isbn, " + "b_call_number, "
				+ "b_rantal_able, " + "b_reg_date, " + "b_mod_date) "
				+ "VALUES(?, ?, ?, ?, ?, ?, ?, ?, NOW(), NOW())";

		int result = -1;

		try {
			result = jdbcTemplate.update(sql,
					bookVo.getB_thumbnail(), bookVo.getB_name(),
					bookVo.getB_author(), bookVo.getB_publisher(),
					bookVo.getB_publish_year(), bookVo.getB_isbn(),
					bookVo.getB_call_number(), bookVo.getB_rantal_able());
		} catch (Exception e) {
			e.printStackTrace();
		}
		return result;
	}
}

 

 

신규 도서 등록하기

프로젝트를 실행하고 5권의 도서를 등록해본다. 관리자로 로그인한 후 메뉴에서 '도서등록'을 클릭한다.