공지사항 리스트 조회 및 검색
공지사항 파트이다.
먼저 리스트뷰 컨트롤러이다.
// 리스트내보내기
@RequestMapping(value="nlist.do", method= RequestMethod.GET)
public String noticeListMethod(@RequestParam(name = "page", required = false) String page,
@RequestParam(name = "limit", required = false) String slimit, Model model) {
int currentPage = 1;
if (page != null && page.length()>0) {
currentPage = Integer.parseInt(page);
}
// 한 페이지에 게시글 10개씩 출력되게 한다면
int limit = 10;
if (slimit != null) {
limit = Integer.parseInt(slimit);
}
// 총 페이지수 계산을 위해 게시글 전체 갯수 조회해 옴
int listCount = noticeService.selectListCount(); // 페이징 계산 처리 실행
Paging paging = new Paging(listCount, currentPage, limit, "nlist.do");
paging.calculate();
// 출력할 페이지에 대한 목록 조회
ArrayList<Notice> list = noticeService.selectList(paging);
logger.info("리스트카운트 : " + listCount);
// 받은 결과로 성공/실패 페이지 내보냄
model.addAttribute("list", list);
model.addAttribute("paging", paging);
model.addAttribute("currentPage", currentPage);
model.addAttribute("limit", limit);
return "notice/noticeListView";
}
nlist.do 요청을 받으면 맨처음 현재 페이지 값을 1로 설정하고 만약 요청에 page값까지 넘어왔다면 currentPage값을 넘어온 값으로 바꾼 후 계산한다. 페이지 수 계산을 위한 Paging 객체에게 limit값을 보내야 하지만 우리는 디자인을 위해 따로 고객이 한 번에 볼 수 있는 게시글 수를 설정해놓지 않았고 10개로 통일했기에 Default 값으로 10을 주었다.
그리고 공지사항 전체 수를 조회해오고 그거로 페이지 수를 계산한다. 그리고 그 공지사항 객체들을 ArrayList에 넣고 그거를 모델에 담아서 view페이지로 보낸다.
<table>
<tr id="titlerow">
<th>번호</th>
<th>제목</th>
<th>작성한관리자</th>
<th>날짜</th>
<th>조회수</th>
</tr>
<c:forEach items="${ requestScope.list }" var="n">
<c:url var="ndetail" value="ndetail.do">
<c:param name="nno" value="${ n.noticeNo }" />
<c:param name="page" value="${ nowpage }" />
</c:url>
<tr onclick="location.href='${ndetail}';">
<td>${n.noticeNo}</td>
<td>${n.noticeTitle }</td>
<td>${n.writer }</td>
<td>${n.writeDate }</td>
<td>${n.readCount }</td>
</tr>
</c:forEach>
</table>
리스트뷰 코드이다. jstl을 사용해 현재 페이지에 있는 리스트를 받고. 그 리스트를 반복문으로 테이블에 출력한다.
다음은 검색이다.
<div class="searchdiv">
<form action="nsearch.do" method="get">
<select style="height: 35px; width: 80px;" name="action"
id="searchselect">
<option value="title">제목</option>
<option value="writer">작성자</option>
<option id="date" value="date">날짜</option>
</select> <input type="date" name="begin"> <input type="date"
name="end"> <input style="height: 30px; width: 325px;"
type="text" id="searchtext" name="keyword" placeholder="검색어 입력">
<input type="submit" class="searchbtn" value="검색"> <br>
</form>
<c:if test="${ !empty loginUser && loginUser.adminOk eq 'Y'}">
<button class="writerB" onclick="showWriteForm();">글쓰기</button>
</c:if>
</div>
뷰쪽에서의 검색이다. 지금보니 각각의 태그에 따로 스타일을 준게 보인다. 프로젝트 마지막에 가서는 어느정도 디자인을 컨트롤 할 수 있게되어 스타일태그 안에 정리해서 넣어놨지만 제일 처음했던 작업이었던 만큼 조금씩 수적하며 했던것같다.
form태그로 만들어 검색 종류를 action에 검색 내용을 keyword에 담아 컨트롤러로 get요청을 한다.
글쓰기도 같이있는데 아마 디자인을 위해 여기에 껴있나보다.
아래는 날짜를 선택했을 때 검색창이 사라지고 날짜 선택창이 등장하는 자바스크립트이다.
날짜 사이에 ~도 넣으려고 했던거같은데 없는걸 보니 하다가 포기한듯 싶다. 아마 내가 프로젝트 시작하고 제일먼저 한게 공지사항이었으니 그럴수도 있으려나. 지금보면 저걸 왜못했지 싶은데, 그만큼 실력이 늘었다는 뜻으로 생각하자.
<script type="text/javascript">
function showWriteForm() {
//게시글 원글 쓰기 페이지로 이동 요청
location.href = "${ pageContext.servletContext.contextPath}/${nwf}";
}
$(document).ready(function() {
// 셀렉트 요소에서 옵션을 선택했을 때 이벤트 핸들러
$("input[type='date']").hide();
$('#searchselect').change(function() {
// 선택된 옵션 값 확인
var selectedValue = $(this).val();
// 만약 선택된 값이 '날짜'일 경우 달력 표시
if (selectedValue === 'date') {
$("#searchtext").hide()
$("input[type='date']").show(); // 달력 보이기
} else {
$("#searchtext").show()
$("input[type='date']").hide(); // 다른 경우 달력 숨기기
}
});
});
</script>
대충 코드를보면 페이지가 로드되면 type이 date인 input 태그를 숨긴다. 그리고 id=searchselect 즉, 셀렉트 창의 값이 바뀔때 그 값을 검사해서 date일경우 숨겼던 input태그를 보여지게한다.
다음은 검색 컨트롤러이다.
@RequestMapping("nsearch.do")
public String noticeSearch(@RequestParam("action") String action, Search search,
@RequestParam(name = "page", required = false) String page, Model model) {
int currentPage = 1;
if (page != null&& page.length()>0) {
currentPage = Integer.parseInt(page);
}
int listCount = 0;
Paging paging = new Paging(0,currentPage, 10, "nsearch.do");
ArrayList<Notice> list =null;
switch (action) {
case "title":
listCount = noticeService.selectSearchTitleCount(search.getKeyword());
paging.setListCount(listCount);
paging.calculate();
search.setStartRow(paging.getStartRow());
search.setEndRow(paging.getEndRow());
list = noticeService.selectSearchTitle(search);
break;
case "writer":
listCount = noticeService.selectSearchWriterCount(search.getKeyword());
paging.setListCount(listCount);
paging.calculate();
search.setStartRow(paging.getStartRow());
search.setEndRow(paging.getEndRow());
list = noticeService.selectSearchWriter(search);
break;
case "date":
SearchDate searchDate = new SearchDate(search.getBegin(),search.getEnd());
listCount = noticeService.selectSearchDateCount(searchDate);
paging.setListCount(listCount);
paging.calculate();
search.setStartRow(paging.getStartRow());
search.setEndRow(paging.getEndRow());
list = noticeService.selectSearchDate(search);
break;
}
model.addAttribute("list", list);
model.addAttribute("paging", paging);
model.addAttribute("currentPage", currentPage);
model.addAttribute("search", search);
model.addAttribute("limit", 10);
model.addAttribute("action", action);
model.addAttribute("keyword", search.getKeyword());
return "notice/noticeListView";
}
뭔가 코드가 참 더러운거같다. 리스트 조회와 동작방식은 같지만 게시글 갯수를 셀때 search객체를 같이보내서 검색값에 해당하는 공지사항 객체를 가져오고 그 리스트를 페이지에 맞게 반환한다. 저당시에는 깔끔하게 하려고 한거같지만 지금 다시한다면 저 중간 겹치는 코드들은 모아서 어떻게 하지 않았을까 싶다.
다음은 마이바티스 매퍼이다. 여기서 조금 고생을 했던 기억이있다. selectCount들은 별거 없으니 넘어가고 검색 부분만 복기해보려 한다.
<select id="selectSearchWriterCount" parameterType="string" resultType="_int">
select count(*) from tb_notice left join TB_user on (Writer=id) where user_id like '%${writer}%'
</select>
<select id="selectSearchDateCount" parameterType="SearchDate" resultType="_int">
select count(*) from tb_notice where write_date between #{begin} and #{end}
</select>
<select id="selectSearchTitle" parameterType ="Search" resultMap="resultList">
select * from (select rownum rnum, NOTICE_NO, WRITER, NOTICE_TITLE, NOTICE_CONTENT, WRITE_DATE, MODIFY_DATE, READ_COUNT, IMPORTANCY, user_id
from(select * from tb_notice left join TB_USER ON (Writer = id)
where notice_title like '%${keyword}%'
order by write_date desc) )
where rnum between #{startRow} and #{endRow}
</select>
먼저 #{} 과 ${}는 결과가 다르다. 저 writer 에 문자열 'han'이 들어간다고 해보자. #{}로 실행한다면 실제로 실행되는 sql문에 where user_id like 'han' 이런식으로 들어간다. 하지만 ${}로 할경우 where user_id like han 이런식으로 따옴표가 벗겨진채로 들어간다. 나는 이걸 알려고 안게 아니라 수업시간에 실수로 #{}를 ${}로 했었는데 그때 오류를 찾다가 알게되었다. 다른 사람들은 ${}의 존재를 몰라서 #{}로 like문에 %때문에 애를 먹던데, 나는 ${}의 존재를 알아서 위처럼 어렵지 않게 진행했다.
쿼리문은 title로 검색을 하고 그거를 글쓴 날짜순으로 정리한다. 그리고 그 중에서 Search객체에 담겨온 startRow와 endRow사이의 값들을 리턴한다. 이부분은 페이징 처리때문이다. ex)검색을 한 상태에서 1페이지를 누르면 우리는 default limit값이 10이니까 startRow = 10, endRow = 20 => 2페이지를 누르면 20, 40 ....