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

전자 도서관 프로젝트 - 희망 도서 요청 기능 구현

YJ_ma 2023. 12. 4. 15:20

도서관에 내가 원하는 도서가 없을 때 도서 입고를 요청하는 희망 도서 요청 기능을 구현한다.

구현해야 할 기능은 희망 도서 요청과 희망 도서 요청 목록 조회 그리고 관리자의 희망 도서 요청 처리(신규 도서 입고)이다.

 

희망 도서 요청 화면 구현하기

<희망 도서 요청>은 '나의책장'에서 이용할 수 있다. 희망 도서 요청은 bookshelf.jsp에 있다.

<a href="<c:url value='/book/user/requestHopeBookForm'/>">희망 도서 요청</a>

 

컨트롤러 기능 구현

requestHopeBookForm()은 서비스 또는 DAO를 사용하지 않고 희망 도서를 요청하는 화면으로 이동한다.

단, 로그인 인증을 위해서는 servlet-context.xml의 인터셉터에 등록해야 한다.

// 희망 도서 요청
@GetMapping("/requestHopeBookForm")
public String requestHopeBookForm() {
    System.out.println("[UserBookController] requestHopeBookForm()");

    String nextPage = "user/book/request_hope_book_form";

    return nextPage;
}
<interceptors>
    <interceptor>
        <mapping path="/book/user/rentalBookConfirm"/>
        <mapping path="/book/user/enterBookshelf"/>
        <mapping path="/book/user/listupRentalBookHistory"/>
        <mapping path="/book/user/requestHopeBookForm"/>
      	..생략..
    </interceptor>
</interceptors>

 

프로젝트를 실행하고 '나의책장'에서 <희망도서요청>버튼을 클릭하면 희망 도서 요청할 수 있는 화면으로 이동하는지 확인한다.

이때, 희망 도서 요청 화면의 form은 다음과 같다.

<form action="<c:url value='/book/user/requestHopeBookConfirm' />" name="request_hope_book_form" method="get">

    <input type="text"		name="hb_name" 			placeholder="* INPUT HOPE BOOK NAME."> <br>
    <input type="text"		name="hb_author" 		placeholder="* INPUT HOPE BOOK AUTHOR."> <br>
    <input type="text"		name="hb_publisher"		placeholder="INPUT HOPE BOOK PUBLISHER."> <br>
    <input type="text"		name="hb_publish_year" 	placeholder="INPUT HOPE BOOK PUBLISH YEAR."> <br>
    <input type="button"	value="request hope book" onclick="requestHopeBookForm();"> 
    <input type="reset"		value="reset">

</form>

'희망 도서 요청' 화면

 

희망 도서 요청 테이블 생성하기

희망 도서 요청 테이블 tbl_hope_book을 생성한다.

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

CREATE TABLE tbl_hope_book(
	hb_no 		     INT		AUTO_INCREMENT, 
	u_m_no		     INT, 
	hb_name		     VARCHAR(30)	NOT NULL, 	
	hb_author	     VARCHAR(20)	NOT NULL, 	
	hb_publisher	     VARCHAR(20),
	hb_publish_year	     CHAR(4), 
	hb_reg_date	     DATETIME, 
	hb_mod_date	     DATETIME, 
	hb_result	     TINYINT	        NOT NULL DEFAULT 0, 
	hb_result_last_date  DATETIME,
	PRIMARY KEY(hb_no)
) default character set utf8 collate utf8_general_ci;

 

VO 구현

tbl_hope_book 테이블에 대한 VO를 com.office.library.book 패키지에 HopeBookVo 이름으로 만든다.

package com.office.library.book;

import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
public class HopeBookVo {

	int hb_no;
	String hb_name;
	String hb_author;
	String hb_publisher;
	String hb_publish_year;
	String hb_reg_date;
	String hb_mod_date;
	int hb_result;
	String hb_result_last_date;

	int u_m_no;
	String u_m_id;
	String u_m_pw;
	String u_m_name;
	String u_m_gender;
	String u_m_mail;
	String u_m_phone;
	String u_m_reg_date;
	String u_m_mod_date;
}

 

희망 도서 요청 추가하기

희망 도서 요청을 데이터베이스에 등록하기 위해서 컨트롤러, 서비스, DAO 기능을 구현한다.

 

컨트롤러 기능 구현

// 희망 도서 요청 확인
@GetMapping("/requestHopeBookConfirm")
public String requestHopeBookConfirm(HopeBookVo hopeBookVo, HttpSession session) {
    System.out.println("[UserBookController] requestHopeBookConfirm()");

    String nextPage = "user/book/request_hope_book_ok";

    UserMemberVo loginedUserMemberVo = (UserMemberVo) session.getAttribute("loginedUserMemberVo");
    hopeBookVo.setU_m_no(loginedUserMemberVo.getU_m_no());

    int result = bookService.requestHopeBookConfirm(hopeBookVo);

    if (result <= 0)
        nextPage = "user/book/request_hope_book_ng";

    return nextPage;
}

 

서비스 기능 구현

public int requestHopeBookConfirm(HopeBookVo hopeBookVo) {
    System.out.println("[BookService] requestHopeBookConfirm()");

    return bookDao.insertHopeBook(hopeBookVo);
}

 

DAO 기능 구현

public int insertHopeBook(HopeBookVo hopeBookVo) {
    System.out.println("[BookDao] insertHopeBook()");

    String sql = "INSERT INTO tbl_hope_book(u_m_no, hb_name, hb_author, hb_publisher, "
            + "hb_publish_year, hb_reg_date, hb_mod_date, hb_result_last_date) "
            + "VALUES(?, ?, ?, ?, ?, NOW(), NOW(), NOW())";

    int result = -1;

    try {
        result = jdbcTemplate.update(sql, hopeBookVo.getU_m_no(),
                hopeBookVo.getHb_name(),
                hopeBookVo.getHb_author(),
                hopeBookVo.getHb_publisher(),
                hopeBookVo.getHb_publish_year());
    } catch (Exception e) {
        e.printStackTrace();
    }
    return result;
}

 

이제 프로젝트를 실행하고 5권의 희망 도서를 요청한다.

 

희망 도서 요청 목록 확인하기

희망 도서 요청 목록 확인도 '나의책장(bookshelf.jsp)'에 있다.

<a href="<c:url value='/book/user/listupRequestHopeBook'/>">희망 도서 요청 목록 </a>

 

컨트롤러 기능 구현

// 희망 도서 요청 목록
@GetMapping("/listupRequestHopeBook")
public String listupRequestHopeBook(HttpSession session, Model model) {
    System.out.println("[UserBookController] listupRequestHopeBook()");

    String nextPage = "user/book/list_hope_book";

    UserMemberVo loginedUserMemberVo = (UserMemberVo) session.getAttribute("loginedUserMemberVo");

    List<HopeBookVo> hopeBookVos = bookService.listupRequestHopeBook(loginedUserMemberVo.getU_m_no());

    model.addAttribute("hopeBookVos", hopeBookVos);

    return nextPage;
}

 

서비스 기능 구현

public List<HopeBookVo> listupRequestHopeBook(int u_m_no) {
    System.out.println("[BookService] listupRequestHopeBook()");

    return bookDao.selectRequestHopeBooks(u_m_no);

}

 

DAO 기능 구현

public List<HopeBookVo> selectRequestHopeBooks(int u_m_no){
    System.out.println("[BookDao] insertHopeBook()");

    String sql = "SELECT * FROM tbl_hope_book WHERE u_m_no = ?";

    List<HopeBookVo> hopeBookVos = null;

    try {
        hopeBookVos = jdbcTemplate.query(sql, new RowMapper<HopeBookVo>() {

            @Override
            public HopeBookVo mapRow(ResultSet rs, int rowNum) throws SQLException{

                HopeBookVo hopeBookVo = new HopeBookVo();

                hopeBookVo.setHb_no(rs.getInt("hb_no"));
                hopeBookVo.setU_m_no(rs.getInt("u_m_no"));
                hopeBookVo.setHb_name(rs.getString("hb_name"));
                hopeBookVo.setHb_author(rs.getString("hb_author"));
                hopeBookVo.setHb_publisher(rs.getString("hb_publisher"));
                hopeBookVo.setHb_publish_year(rs.getString("hb_publish_year"));
                hopeBookVo.setHb_reg_date(rs.getString("hb_reg_date"));
                hopeBookVo.setHb_mod_date(rs.getString("hb_mod_date"));
                hopeBookVo.setHb_result(rs.getInt("hb_result"));
                hopeBookVo.setHb_result_last_date(rs.getString("hb_result_last_date"));

                return hopeBookVo;	
            }
        }, u_m_no);
    } catch (Exception e) {
        e.printStackTrace();
    }
    return hopeBookVos;
}

 

인터셉터 추가

<희망 도서 요청 목록>은 로그인 상태에서 이용할 수 있다. 따라서 인터셉터에 추가한다.

<mapping path="/book/user/listupRequestHopeBook"/>

 

프로젝트를 실행하여 '나의 책장' 에서 <희망 도서 요청 목록> 버튼을 클릭해서 목록이 출력되는 것을 확인한다.

희망 도서 요청 목록의 처리 상태는 '검토중'이다. 이는 사용자가 요청한 희망 도서를 관리자가 아직 신규 도서로 등록하지 않은 상태이기 때문이다.

 

희망 도서 요청 처리하기

희망 도서를 신규 도서로 등록하는 업무는 관리자의 몫이다. 따라서 관리자 화면으로 이동한 후 로그인한다.

'희망 도서(입고처리)' 메뉴는 nav.jsp에 있다. 서버에 요청하는 URI를 /book/admin/getHopeBooks로 설정한다.

<li><a href="<c:url value='/book/admin/getHopeBooks' />">희망도서(입고처리)</a></li>

 

희망 도서를 입고처리 하기 위해서는 우선 희망 도서 목록을 조회하고, 조회된 도서를 신규 도서로 등록(입고 처리)하는 절차가 필요하다. 따라서 도서 목록 조회를 구현하고, 신규 도서 등록을 구현한다.

 

컨트롤러 기능 구현(도서 목록 조회)

book.admin 패키지의 BookController.java에 선언한다.

// 희망 도서 목록
@GetMapping("/getHopeBooks")
public String getHopeBooks(Model model) {
    System.out.println("[BookController] getHopeBooks()");

    String nextPage = "admin/book/hope_books";

    List<HopeBookVo> hopeBookVos = bookService.getHopeBooks();

    model.addAttribute("hopeBookVos", hopeBookVos);

    return nextPage;
}

 

서비스 기능 구현(도서 목록 조회)

public List<HopeBookVo> getHopeBooks(){
    System.out.println("[BookService] getHopeBooks()");

    return bookDao.selectHopeBooks();
}

 

DAO 기능 구현(도서 목록 조회)

public List<HopeBookVo> selectHopeBooks(){
    System.out.println("[BookDao] selectHopeBooks()");

    String sql = "SELECT * FROM tbl_hope_book hb "
            + "JOIN tbl_user_member um "
            + "ON hb.u_m_no = um.u_m_no "
            + "ORDER BY hb.hb_no DESC";

    List<HopeBookVo> hopeBookVos = new ArrayList<HopeBookVo>();

    try {
        hopeBookVos = jdbcTemplate.query(sql, new RowMapper<HopeBookVo>() {

            @Override
            public HopeBookVo mapRow(ResultSet rs, int rowNum) throws SQLException{

                HopeBookVo hopeBookVo = new HopeBookVo();

                hopeBookVo.setHb_no(rs.getInt("hb_no"));
                hopeBookVo.setHb_name(rs.getString("hb_name"));
                hopeBookVo.setHb_author(rs.getString("hb_author"));
                hopeBookVo.setHb_publisher(rs.getString("hb_publisher"));
                hopeBookVo.setHb_publish_year(rs.getString("hb_publish_year"));
                hopeBookVo.setHb_reg_date(rs.getString("hb_reg_date"));
                hopeBookVo.setHb_mod_date(rs.getString("hb_mod_date"));
                hopeBookVo.setHb_result(rs.getInt("hb_result"));
                hopeBookVo.setHb_result_last_date(rs.getString("hb_result_last_date"));

                hopeBookVo.setU_m_no(rs.getInt("u_m_no"));
                hopeBookVo.setU_m_id(rs.getString("u_m_id"));
                hopeBookVo.setU_m_pw(rs.getString("u_m_pw"));
                hopeBookVo.setU_m_name(rs.getString("u_m_name"));
                hopeBookVo.setU_m_gender(rs.getString("u_m_gender"));
                hopeBookVo.setU_m_mail(rs.getString("u_m_mail"));
                hopeBookVo.setU_m_phone(rs.getString("u_m_phone"));
                hopeBookVo.setU_m_reg_date(rs.getString("u_m_reg_date"));
                hopeBookVo.setU_m_reg_date(rs.getString("u_m_mod_date"));

                return hopeBookVo;
            }
        });
    } catch (Exception e) {
        e.printStackTrace();
    }
    return hopeBookVos;
}

 

브라우저에서 로그인한 후 '희망 도서(입고 처리)' 메뉴를 클릭하여 정상적으로 수행되는지 확인한다.

 

목록에서 <입고> 버튼을 클릭하면 희망 도서를 입고 처리(신규 도서 등록)할 수 있다. <입고> 버튼은 hope_books.jsp에 있다.

<td>
    <c:choose>
        <c:when test="${item.hb_result eq 0}">
            <c:url value="/book/admin/registerHopeBookForm" var="hope_book_url">
                <c:param name="hb_no" value="${item.hb_no}"/>
                <c:param name="hb_name" value="${item.hb_name}"/>
                <c:param name="hb_author" value="${item.hb_author}"/>
                <c:param name="hb_publisher" value="${item.hb_publisher}"/>
                <c:param name="hb_publish_year" value="${item.hb_publish_year}"/>
            </c:url>
            <a href="${hope_book_url}">입고</a>
        </c:when>
        <c:when test="${item.hb_result eq 1}">
            완료
        </c:when>
    </c:choose>
</td>

 

컨트롤러 기능 구현(도서 등록 화면)

// 희망 도서 등록(입고 처리)
@GetMapping("/registerHopeBookForm")
public String registerHopeBookForm(Model model, HopeBookVo hopeBookVo) {
    System.out.println("[BookController] registerHopeBookForm()");

    String nextPage = "admin/book/register_hope_book_form";

    model.addAttribute("hopeBookVo", hopeBookVo);

    return nextPage;
}

 

<입고> 버튼을 클릭하면 신규 도서 등록 화면으로 이동한다. 이때, 사용자가 입력한 정보(도서명, 저자 등)이 자동으로 입력되어 있는 것을 확인할 수 있다.

 

다음은 register_hope_book_form.jsp의 <form>이다.

<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>

 

컨트롤러 기능 구현(도서 등록)

// 희망 도서 등록(입고 처리) 확인
@PostMapping("/registerHopeBookConfirm")
public String registerHopeBookConfirm(BookVo bookVo,
        @RequestParam("hb_no") int hb_no,
        @RequestParam("file") MultipartFile file) {
    System.out.println("[BookController] registerHopeBookConfirm()");

    System.out.println("hb_no: " + hb_no);

    String nextPage = "admin/book/register_book_ok";

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

    if (savedFileName != null) {
        bookVo.setB_thumbnail(savedFileName);
        int result = bookService.registerHopeBookConfirm(bookVo, hb_no);

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

 

서비스 기능 구현(도서 등록)

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

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

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

        if (result > 0) {
            bookDao.updateHopeBookResult(hb_no);

            return BOOK_REGISTER_SUCCESS;
        } else {
            return BOOK_REGISTER_FAIL;
        }
    } else {
        return BOOK_ISBN_ALREADY_EXIST;
    }
}

 

DAO 기능 구현(희망 도서 업데이트)

public void updateHopeBookResult(int hb_no) {
    System.out.println("[BookDao] updateHopeBookResult()");

    String sql = "UPDATE tbl_hope_book "
            + "SET hb_result = 1, hb_result_last_date = NOW() "
            + "WHERE hb_no = ?";

    try {
        jdbcTemplate.update(sql, hb_no);
    } catch (Exception e) {
        e.printStackTrace();
    }
}

 

이제 도서 정보를 참고하여 희망 도서를 모두 입고 처리(신규 도서 등록)한다.

 

희망 도서 목록의 입고가 '완료'로 변경된 것을 확인할 수 있다.

또한 사용자 화면에서도 '희망 도서 요청 목록'을 보면 처리상태가 '완료'로 변경된 것을 확인할 수 있다.

 

다음은 데이터베이스의 희망도서(tbl_hope_book)과 도서(tbl_bok)테이블 이다.

tbl_hope_table의 hb_result가 '1'로 업데이트됨
tbl_book에 신규 도서 5권이 등록됨