작가 관리 페이지(authorManage.jsp)에 작가 목록을 출력을 구현할 것입니다.
먼저 정해진 갯수와 페이지의 작가 정보를 출력을 구현한 뒤, 사용자가 마우스를 통해 페이지 이동을 할 수 있도록 '페이지 이동 인터페이스'를 구현하겠습니다. 또 '검색 기능'을 구현하겠습니다.
admin폴더에서 중복이자 공통적으로 적용되는 코드를 <include>태그를 적용을 합니다. 각 jsp파일마다 변경될 코드에 집중할 수 있도록 하기 위함입니다. 공통되는 코드들을 하나의 파일로 관리하는 것이기 때문에 유지보수에도 용이합니다.
"../WEB-INF/views"경로에 "includes/admin"폴더를 생성 후 'header.jsp', 'footer.jsp'파일을 생성합니다. 각 파일에 아래의 코드만 남기고 모든 태그 코드를 삭제하고 기존의 jsp파일에서 footer부분, header부분을 가져오고 삭제합니다.
footer.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<div class="clearfix"></div>
</div>
<!-- Footer 영역 -->
<div class="footer_nav">
<div class="footer_nav_container">
<ul>
<li>회사소개</li>
<span class="line">|</span>
<li>이용약관</li>
<span class="line">|</span>
<li>고객센터</li>
<span class="line">|</span>
<li>광고문의</li>
<span class="line">|</span>
<li>채용정보</li>
<span class="line">|</span>
</ul>
</div>
</div> <!-- class="footer_nav" -->
<div class="footer">
<div class="footer_container">
<div class="footer_left">
<img src="../resources/img/mtbook.png">
</div>
<div class="footer_right">
(주) TBook 대표이사 : OOO
<br>
사업자등록번호 : ooo-oo-ooooo
<br>
대표전화 : oooo-oooo(발신자 부담전화)
<br>
<br>
COPYRIGHT(C) <strong>velog.io</strong> ALL RIGHTS RESERVED.
</div>
<div class="clearfix"></div>
</div>
</div> <!-- class="footer" -->
</div> <!-- class="wrap" -->
</div> <!-- class="wrapper" -->
header.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<div class="wrapper">
<div class="wrap">
<!-- gnv_area -->
<div class="top_gnb_area">
<ul class="list">
<li><a href="/main">메인 페이지</a></li>
<li><a href="/member/logout.do">로그아웃</a></li>
<li>고객센터</li>
</ul>
</div>
<!-- top_subject_area -->
<div class="admin_top_wrap">
<span>관리자 페이지</span>
</div>
<!-- contents-area -->
<div class="admin_wrap">
<!-- 네비영역 -->
<div class="admin_navi_wrap">
<ul>
<li >
<a class="admin_list_01" href="/admin/goodsEnroll">상품 등록</a>
</li>
<li>
<a class="admin_list_02" href="/admin/goodsManage">상품 관리</a>
</li>
<lI>
<a class="admin_list_03" href="/admin/authorEnroll">작가 등록</a>
</lI>
<lI>
<a class="admin_list_04" href="/admin/authorManage">작가 관리</a>
</lI>
<lI>
<a class="admin_list_05">회원 관리</a>
</lI>
</ul>
</div>
기존에 jsp파일에서 삭제한 footer부분과 header부분을 아래의 코드를 작성합니다.
<%@include file="../includes/admin/header.jsp" %>
<%@include file="../includes/admin/footer.jsp" %>
com.test.model패키지에 Criteria.java클래스를 생성 후 limit을 활용하여 아래의 코드를 작성합니다. 해당 클래스는 지정한 개수와 검색 조건에 따라서 작가 데이터를 출력하는 쿼리를 실행하는데 필요로 한 데이터들의 모임입니다. 참고로 Criteria는 기준이라는 의미입니다.
/* 현재 페이지 번호 */
private int pageNum;
/* 페이지 표시 개수 */
private int amount;
/* 페이지 skip */
private int skip;
/* 검색 타입 */
private String type;
/* 검색 키워드 */
private String keyword;
/* Criteria 생성자 */
public Criteria(int pageNum, int amount) {
this.pageNum = pageNum;
this.amount = amount;
this.skip = (pageNum -1) * amount;
}
/* Criteria 기본 생성자 */
public Criteria(){
this(1,10);
}
/* 검색 타입 데이터 배열 변환 */
public String[] getTypeArr() {
return type == null? new String[] {}:type.split("");
}
getter/setter, toString메서드를 추가해줍니다. 그리고 amount와 pageNum 변수의 값이 변경될 때 skip변수의 값도 변경되도록 setAmount(), setPageNum()메서드를 일부 수정해줍니다. Criteria클래스의 데이터를 사용할 때 매번 새로운 생성자를 호출하여 사용하기 때문에 해당 과정이 필요 없지만 혹시 모를 경우를 위해 작업하였습니다.
public void setPageNum(int pageNum) {
this.pageNum = pageNum;
this.skip = (pageNum - 1) * this.amount;
}
public void setAmount(int amount) {
this.amount = amount;
this.skip = (this.pageNum - 1) * amount;
}
작가 데이터 목록 쿼리를 실행하는 메서드를 선언합니다. 여러 작가의 데이터를 반환받아야 하기 때문에 리턴 타입으로 List 자료 구조를 지정하였습니다. List에 저장될 데이터가 AuthorVO(작가 정보) 임을 명시하기 위해 AuthorVO 제네릭을 선언하였습니다.
/* 작가 목록 */
public List<AuthorVO> authorGetList(Criteria cri);
AuthorMapper.java 인터페이스에서 선언한 메서드가 실행할 쿼리 코드를 작성합니다. <select>태그의 resultType속성 값은 'com.test.model.AuthorVO'을 부여합니다. resultType을 클래스로 지정하였지만 메서드의 리턴 타입을 List로 선언하였기 때문에 MyBatis가 지정된 클래스 인스턴스 요소를 가지는 List로 자동으로 변환해줍니다.
<!-- 작가 목록 -->
<select id="authorGetList" resultType="com.test.model.AuthorVO">
select authorid, authorname, nationid, regdate, updatedate
from test_author
<if test="keyword != null">
where authorname like concat('%', #{keyword}, '%')
</if>
order by authorid desc
limit #{skip}, #{amount}
</select>
앞으로의 페이징 테스트를 위하여 MySQL에 있는 test_author테이블의 데이터를 늘려줍니다.
-- 재귀 복사
insert into test_author(authorname, nationid)(select authorname, nationid from test_author);
Mapper메서드를 호출하는 Service단계의 메서드를 AuthorService.java인터페이스 아래에 선언합니다.
/* 작가 목록 */
public List<AuthorVO> authorGetList(Criteria cri) throws Exception;
Service인터페이스에서 선언한 메서드를 오버라이딩하여 구현합니다. 해당 메서드는 Mapper의 authorGetList()메서드를 호출하고 List를 반환받아야 하기 때문에 return에 Mapper의 메서드를 호출합니다. 구현부에는 해당 메서드가 사용되는 것을 확인할 수 있도록 콘솔(console)에 메시지를 log.info()메서드를 작성하였습니다.
log.info()메서드를 사용하기 위해 클래스 삿ㅇ단에 아래의 변수를 선언 및 초기화하였습니다.
private static final Logger log = LoggerFactory.getLogger(AuthorServiceImpl.class);
/* 작가 목록 */
@Override
public List<AuthorVO> authorGetList(Criteria cri) throws Exception {
log.info("(service)authorGetList()......." + cri);
return authorMapper.authorGetList(cri);
}
작가 관리 페이지(authorManage.jsp)에서 작가 목록을 출력할 수 있도록 서버에서 작가 목록 데이터를 넘겨주는 작업을 해주어야 합니다.
"authorManage"url매핑 메서드인 authorManageGET()에 파라미터로 Criteria, Model클래스를 부여해줍니다. Criteria는 사용자가 요청하는 몇 페이지(pageNum), 몇개의 작가 정보를 출력(amount)을 원하는지에 대한 데이터를 전달 받기 위한 수단입니다. 전달받은 Criteria데이터를 활용하여 '작가 목록'데이터를 반환하는 쿼리를 실행하게 됩니다.
Model은 쿼리의 실행 결과 반환받은 '작가 목록'데이터를 authorManage.jsp에 넘겨주기 위해 파라미터로 부여했습니다. 구현부에는 AuthorService의 authorGetList()메서드를 호출하여 반환받은 결과를 "list" 속성명에 저장하여 전달해주는 코드를 작성합니다.
쿼리 반환 결과 데이터에는 AuthorVO에 정의되어 있는 '소속 국가 이름(nationName)'은 반환되지 않습니다. 반환받도록 쿼리문을 작성할 수 있지만 다른 표(test_nation)에서 데이터를 가져와야 하기 때문에 자원을 좀 더 많이 소모하게 됩니다. 이러한 소모를 줄이기 위해서 쿼리 문의 반환받은 결과 데이터 중 nationId를 전달받을 때 nationName의 값이 초기화될 수 있도록 AuthorVO 클래스 코드를 수정해줄 것입니다. (더불어 처리해야 할 데이터가 '01(국내)', '02(국외)' 밖에 없기 때문에 Java단계에서 처리해주도록 하였습니다.
setNationId()메서드를 따로 만들어 구현부에 아래의 코드를 추가합니다.
public void setNationId(String nationId) {
this.nationId = nationId;
if (nationId.equals("01")) {
this.nationName = "국내";
} else {
this.nationName = "국외";
}
}
JSTL c, JSTL fmt를 사용할 것이기 때문에 페이지 상단에 태그 라이브러리를 추가해줍니다.
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>
전달받은 '작가 목록'데이터("list")를 활용하여 게시판 표의 형태로 출력시키고자 합니다. class 속성명이 'admin_content_subject'인 div태그 다음 순서에 아래의 코드를 추가해줍니다.
서버로부터 전달받은 "list"에 담긴 데이터들을 collection데이터를 반복해서 처리해주는 <c:foreach>태그를 활용하여 출력시켰습니다. 날짜는 원하는 형식을 출력시키기 위해서 <fmt:formDate>태그를 활용하였습니다.
<div class="author_table_wrap">
<table class="author_table">
<thead>
<tr>
<td class="th_column_1">작가 번호</td>
<td class="th_column_2">작가 이름</td>
<td class="th_column_3">작가 국가</td>
<td class="th_column_4">등록 날짜</td>
<td class="th_column_5">수정 날짜</td>
</tr>
</thead>
<c:forEach items="${list}" var="list">
<tr>
<td><c:out value="${list.authorId}"></c:out> </td>
<td><c:out value="${list.authorName}"></c:out></td>
<td><c:out value="${list.nationName}"></c:out> </td>
<td><fmt:formatDate value="${list.regDate}" pattern="yyyy-MM-dd"/></td>
<td><fmt:formatDate value="${list.updateDate}" pattern="yyyy-MM-dd"/></td>
</tr>
</c:forEach>
</table>
</div>
아래의 코드를 authorManage.css파일에 추가해주었습니다.
/* 작가 목록 영역 */
.author_table_wrap{
padding: 20px 35px
}
.author_table{
width: 100%;
border: 1px solid #d3d8e1;
text-align: center;
border-collapse: collapse;
}
.author_table td{
padding: 10px 5px;
border : 1px solid #e9ebf0;
}
.author_table thead{
background-color: #f8f9fd;
font-weight: 600;
}
.th_column_1{
width:120px;
}
.th_column_3{
width:110px;
}
.th_column_4{
width:140px;
}
.th_column_5{
width:140px;
}
아직 '페이지 이동 인터페이스'를 추가해주지 않았기 때문에 마우스를 통한 이동은 불가능합니다. 대신 url의 쿼리 스트링을 통해 페이지 이동이 정상적으로 이동하는 테스트합니다.
com.test.model패키지에 PageDTO클래스를 생성 후 아래의 변수, 생성자를 작성합니다. 그리고 선언된 변수들에 대한 getter()/setter(), toString()메서드를 추가해줍니다. pageDTO 클래스의 데이터들은 '페이지 이동 인터페이스'를 출력시키는데 필요로 한 데이터들의 모임입니다.
/* 페이지 시작 번호 */
private int pageStart;
/* 페이지 끝 번호 */
private int pageEnd;
/* 이전, 다음 버튼 존재 유무 */
private boolean next, prev;
/* 행 전체 개수 */
private int total;
/* 현재페이지 번호(pageNum), 행 표시 수(amount), 검색 키워드(keyword), 검색 종류(type) */
private Criteria cri;
/* 생성자(클래스 호출 시 각 변수 값 초기화) */
public PageDTO(Criteria cri, int total) {
/* cri, total 초기화 */
this.cri = cri;
this.total = total;
/* 페이지 끝 번호 */
this.pageEnd = (int)(Math.ceil(cri.getPageNum()/10.0))*10;
/* 페이지 시작 번호 */
this.pageStart = this.pageEnd - 9;
/* 전체 마지막 페이지 번호 */
int realEnd = (int)(Math.ceil(total*1.0/cri.getAmount()));
/* 페이지 끝 번호 유효성 체크 */
if(realEnd < pageEnd) {
this.pageEnd = realEnd;
}
/* 이전 버튼 값 초기화 */
this.prev = this.pageStart > 1;
/* 다음 버튼 값 초기화 */
this.next = this.pageEnd < realEnd;
}
pageDTO클래스를 정의하였는데 해당 클래스를 인스턴스화 시키기 위해서는 Criteria클래스의 데이터와 전체 데이터 개수(total) 값이 필요로 합니다. 왜냐하면 두 개의 데이터를 pageDTO클래스 생성자 파라미터로 부여했기 때문입니다.
Criteria클래스는 이미 정의되어 있기도 하고 PageDTO클래스를 사용할 url매핑 메서드인 authorManageGET() 뷰로부터 Criteria클래스 데이터를 받아오기 때문에 전체 데이터 개수(total)에 대한 값만 구해주면 됩니다.
total의 값은 test_author테이블의 총 행의 개수입니다. 따라서 test_author테이블의 행의 총개수를 구해주는 쿼리를 작성하고, 해당 쿼리를 실행을 하는 메서드(Mapper, Service단계)를 작성하는 작업을 합니다.
test_author테이블의 총 행의 개수를 구하는 쿼리를 호출하는 메서드를 선언합니다. 총 개수 값을 반환받아야 하기 때문에 메서드 선언부의 리턴 타입은 int입니다. 그리고 조건문에 사용할 'keyword' 데이터를 전달받기 위해 파라미터로 Criteria클래스를 부여하였습니다.
/* 작가 총 수 */
public int authorGetTotal(Criteria cri);
Mapper 인터페이스에서 선언한 메서드가 실행할 쿼리를 작성합니다.
총개수를 구하는 것이기 때문에 count(*)를 사용하였습니다. 더불어 authorGetList() 쿼리에서 적용되는 조건문(where문)을 같이 작성해주어야 합니다. 왜냐하면 검색조건에 따라 페이지 개수가 변해야 하는데 조건문을 적용해주지 않는다면 뷰(view)에 출력되는 '페이지 이동 인터페이스'에 실제 존재해야 할 페이지 개수보다 더 많은 페이지 번호가 출력되기 때문입니다.
<!-- 작가 총 수 -->
<select id="authorGetTotal" resultType="int">
select count(*) from test_author
<if test="keyword != null">
where authorname like concat('%', #{keyword}, '%');
</if>
</select>
AuthorService.java에 앞서 작성한 Mapper메서드를 호출한 메서드를 선언합니다.
/* 작가 총 수 */
public int authorGetTotal(Criteria cri) throws Exception;
AuthorServiceImpl.java에 오버라이딩하여 인터페이스에서 선언한 메서드의 구현부를 작성합니다.
/* 작가 총 수 */
@Override
public int authorGetTotal(Criteria cri) throws Exception {
log.info("(service)authorGetTotal()......." + cri);
return authorMapper.authorGetTotal(cri);
}
total의 값을 얻기 위해 AuthorService클래스의 authorGetTotal()을 호출한 후 해당 값과 Criteria클래스 데이터를 인자 값으로 부여하여 PageDTO를 인스턴스화 시킵니다. addAttribute()을 사용하여 "pageMaker"속성명에 인스턴스화한 PageDTO데이터를 저장시킵니다.
/* 페이지 이동 인터페이스 데이터 */
int total = authorService.authorGetTotal(cri);
PageDTO pageMaker = new PageDTO(cri, total);
model.addAttribute("pageMaker", pageMaker);
서버로부터 전달받은 "pageMaker" 데이터를 활용하여 '페이지 이동 인터페이스'를 구현합니다. class속성 값이 "author_table_wrap"인 <div>태그 바로 다음 순서에 아래의 코드를 추가해줍니다.
<li>태그 class 속성 값에 '${pageMaker.cir.pageNum == num?"active":""}'을 작성한 이유는 현재 페이지일 경우 class속성 값이 "pageMaker_btn active"되는데 해당 버튼에 현재 페이지임을 알 수 있도록 css 설정을 해주기 위함입니다.
<!-- 페이지 이동 인터페이스 영역 -->
<div class="pageMaker_wrap" >
<ul class="pageMaker">
<!-- 이전 버튼 -->
<c:if test="${pageMaker.prev}">
<li class="pageMaker_btn prev">
<a href="${pageMaker.pageStart - 1}">이전</a>
</li>
</c:if>
<!-- 페이지 번호 -->
<c:forEach begin="${pageMaker.pageStart}" end="${pageMaker.pageEnd}" var="num">
<li class="pageMaker_btn ${pageMaker.cri.pageNum == num ? "active":""}">
<a href="${num}">${num}</a>
</li>
</c:forEach>
<!-- 다음 버튼 -->
<c:if test="${pageMaker.next}">
<li class="pageMaker_btn next">
<a href="${pageMaker.pageEnd + 1 }">다음</a>
</li>
</c:if>
</ul>
</div>
<a>태그의 href 속성 값으로 url 경로를 작성하지 않았습니다. href속성 값에 url경로를 삽입할 경우 "/admin/authorManage? pageNum=${num}&amount=10"와 같이 쿼리스트링을 통해서 필요 데이터 값을 직접 작성해주면 됩니다. 하지만 좀 더 다양한 상황에서 유연하게 명령을 처리할 수 있도록 <form>태그 내부 <input>태그에 필요데이터를 저장하고 Javascript코드를 통해서 버튼의 동작과 <form>태그 안의 데이터를 서버에 전송할 수 있도록 하고자합니다.
<div> 태그 바로 다음칸에 아래의 <form> 태그 코드를 추가해줍니다.
<form id="moveForm" action="/admin/authorManage" method="get">
<input type="hidden" name="pageNum" value="${pageMaker.cri.pageNum}">
<input type="hidden" name="amount" value="${pageMaker.cri.amount}">
<input type="hidden" name="keyword" value="${pageMaker.cri.keyword}">
</form>
페이지 이동 버튼이 동작하도록 <script>태그 내에 아래의 js코드를 추가합니다.
let moveForm = $('#moveForm');
/* 페이지 이동 버튼 */
$(".pageMaker_btn a").on("click", function(e){
e.preventDefault();
moveForm.find("input[name='pageNum']").val($(this).attr("href"));
moveForm.submit();
});
뷰(view)에 출력되는 '페이지 이동 인터페이스'를 꾸며주기 위해 아래의 css코드를 authorManage.css파일에 추가하였습니다.
/* 페이지 버튼 인터페이스 */
.pageMaker_wrap{
text-align: center;
margin-top: 30px;
margin-bottom: 40px;
}
.pageMaker_wrap a{
color : black;
}
.pageMaker{
list-style: none;
display: inline-block;
}
.pageMaker_btn {
float: left;
width: 40px;
height: 40px;
line-height: 40px;
margin-left: 20px;
}
.next, .prev {
border: 1px solid #ccc;
padding: 0 10px;
}
.next a, .prev a {
color: #ccc;
}
.active{ /* 현재 페이지 버튼 */
border : 2px solid black;
font-weight:400;
}
기존 <form>태그가 있지만 검색 기능에 사용될 <form>태그를 새로 추가하여 구현할 것입니다. js코드를 통해서 기존 <form>태그를 활용하여 검색 기능을 구현해도 상관없지만 보통 사용자가 <input>태그에 검색어를 입력 후 enter를 누르면 검색이 되는데 javascript를 통해 기존 <form>태그를 활용하는 방식은 enter를 눌렀을 때 동작하지 않는 단점이 있습니다. 따라서 사용자가 입력할 <input>태그와 검색을 실행하는 <button>태그를 새로운 <form>태그안에 작성하고자 합니다.
검색 키워드에 대한 정보뿐만 아니라 pageNum과 amount에 대한 데이터도 같이 넘겨야 하기 때문에 type속성 값이 hidden인 <input>태그를 추가해주었습니다. 해당 <input>태그는 페이지가 로딩될 때 기본적으로 서버에서 전달받은 pageNum과 amount, keyword값이 저장되도록 설정하였습니다.
<!-- 검색 영역 -->
<div class="search_wrap">
<form id="searchForm" action="/admin/authorManage" method="get">
<div class="search_input">
<input type="text" name="keyword" value='<c:out value="${pageMaker.cri.keyword}"></c:out>'>
<input type="hidden" name="pageNum" value='<c:out value="${pageMaker.cri.pageNum }"></c:out>'>
<input type="hidden" name="amount" value='${pageMaker.cri.amount}'>
<button class='btn search_btn'>검 색</button>
</div>
</form>
</div>
지금 작성된 상태만으로도 검색 기능 동작이 가능합니다. 하지만 키워드 입력 없이 사용자가 검색 버튼을 누르지 못하도록 유효성 체크 기능과 pageNum의 값을 1로 대입해주는 처리를 하기 위해서 아래의 js코드를 작성합니다.
let searchForm = $('#searchForm');
/* 작거 검색 버튼 동작 */
$("#searchForm button").on("click", function(e){
e.preventDefault();
/* 검색 키워드 유효성 검사 */
if(!searchForm.find("input[name='keyword']").val()){
alert("키워드를 입력하십시오");
return false;
}
searchForm.find("input[name='pageNum']").val("1");
searchForm.submit();
});
검색 인터페이스를 꾸며주기 위해서 authorManage.css에 아래의 코드를 추가해주었습니다.
/* 검색 영역 */
.search_wrap{
margin-top:15px;
}
.search_input{
position: relative;
text-align:center;
}
.search_input input[name='keyword']{
padding: 4px 10px;
font-size: 15px;
height: 20px;
line-height: 20px;
}
.search_btn{
height: 32px;
width: 80px;
font-weight: 600;
font-size: 18px;
line-height: 20px;
position: absolute;
margin-left: 15px;
background-color: #c3daf7;
}
서버 단계에서 검색 결과가 없다는 것을 알게 해주는 데이터를 뷰(view)에 전송을 하고 뷰(view)에서는 전달 받은 데이터를 활용하여 <c:if>태그를 활용하여 '작가 목록'을 출력하거나 '검색 결과가 없다는 문구'를 출력되도록 할 것입니다.
서버 단계에서 검색 결과 존재 유무를 판단해야합니다. 검색결과들은 authorGetList()의 List타입으로 반환이 되는데 List타입이 가지고 있는 empty()메서드를 활용하여 검색결과 존재 유므를 판단할 것입니다. List클래스의 empty()메서드는 List타입의 데이터가 요소 값을 가지고 있지 않은 경우에 true을 반환하고, 요소를 하나 이상 가지고 있는 경우 false를 반환합니다.
AdminController.java의 authorMagnageGET()메서드에 작성한 기존 아래의 코드를 삭제합니다. 삭제한 코드 대신 아래의 코드를 작성해줍니다. 검색 결과가 존재하는 경우 검색결과들을 "list" 속성명에 저장하여 뷰에 전송합니다. 검색결과가 존재하지 않는 경우에 'empty'문구를 "listCheck"속성명에 저장하여 뷰에 전송합니다.
if (!list.isEmpty()) {
model.addAttribute("list", list); // 작가 존재 경우
} else {
model.addAttribute("listCheck", "empty"); // 작가 존재하지 않을 경우
}
authorManage.jsp에 class속성 값이 "author_table"인 <div>태그 코드를 아래의 <c:if>태그로 감싸줍니다. "listCheck"속성의 값이 'empty'가 아닌 경우 <div>태그가 출력되게 됩니다. 그리고 작성한 <c:if>태그 바로 다음 공간 아래에 <c:if>태그 코드를 추가해줍니다. 검색 결과가 없을 경우 출력되게 될 문구입니다.
<!-- 게시물 O -->
<c:if test="${listCheck != 'empty' }">
</c:if>
<!-- 게시물 X -->
<c:if test="${listCheck == 'empty'}">
<div class="table_empty">
등록된 작가가 없습니다.
</div>
</c:if>
검색 결과가 없을 경우 출력될 <div>태그에 css설정을 해주기 위해 AuthorManage.css에 아래의 코드를 추가해주었습니다.
.table_empty{
height: 50px;
text-align: center;
margin: 200px 0 215px 0px;
font-size: 25px;
}
- 페이지 이동
- 존재할 경우 검색
- 존재하지 않을 경우 검색