1. 게시판 구현 이어서
1) 페이징 Criteria 클래스: 페이징을 처리하는 기준
* Criteria
package com.coding404.myweb.util;
import lombok.Data;
//data 달면 getter, setter 자동 생성, 생성자만 필요에 따라 다시 만들었음
@Data
//sql문에 페이지 번호, 데이터 갯수를 전달해줄 클래스
public class Criteria {
private int page; //페이지 번호
private int amount; //데이터 갯수
//롬복 쓰면 생성자에 정의해줄 수가 없으니까 여기는 그냥 씀
public Criteria() {
this.page = 1;
this.amount = 10;
}
public Criteria(int page, int amount) {
this.page = page;
this.amount = amount;
}
//limit 함수의 페이지 시작 부분에 들어갈 getter
public int getPageStart() {
return (page - 1) * amount;
}
}
- TripMapper.java에 getList의 매개변수에 Criteria 객체 넣어줄 것
- TripMapper.xml 수정
- 그 다음에 Test 실행
* TripMapper.xml, Pagetest 추가 내용
<select id="getList" resultType="TripVO">
select * from trip order by tno desc
limit #{pageStart}, #{amount}
</select>
@Test
public void testCode02() {
// Criteria cri = new Criteria(); //1, 10
Criteria cri = new Criteria(2, 10);
ArrayList<TripVO> list = tripMapper.getList(cri);
list.stream().forEach( x -> System.out.println(x) );
}
* 컨트롤러-getlist, 서비스, 서비스 impl 모두 변경
@RequestMapping("/notice_list")
public String notice_list(Criteria cri, Model model) {
/*
* service, mapper 영역에 getList 함수를 선언하고
* 등록번호 역순으로 데이터를 조회해서 가지고 나옵니다.
* model에 담아서 화면에서는 반복문으로 처리만 해주세요.
*/
//data 조회
ArrayList<TripVO> list = tripService.getList(cri);
model.addAttribute("list", list);
return "trip/notice_list";
}
public ArrayList<TripVO> getList(Criteria cri);
@Override
public ArrayList<TripVO> getList(Criteria cri) {
return null;
}
2) 페이징 PageVO 클래스: 페이징 계산 처리 클래스
* pageVO, notice_controller, service, serviceImpl, mapper.xml, mapper.java
- getTotal 생성해주기!
- public int getTotal(); //전체 게시글 수
- get Total 컨트롤러, 서비스, 서비스 impl, mapper에 모두 생성해줄 것!
- pageVO
package com.coding404.myweb.util;
import lombok.Data;
//화면에 그려지는 페이지 네이션의 값을 계산하는 클래스
@Data
public class PageVO {
private int end; //페이지 네이션 끝번호
private int start; //페이지 네이션 시작 번호
private boolean next; //다음 버튼 활성화 여부
private boolean prev; //이전 버튼 활성화 여부
private int realEnd; //페이지 네이션 실제 끝 번호
private int page; //사용자가 조회하는 페이지 번호
private int amount; //화면 1페이지에 나타나는 데이터 개수
private int total; //전체 게시글 수
private Criteria cri; //페이지 기준
private int pageCnt = 5; //페이지 네이션 개수
//생성자 - pageVO가 만들어질 때 criteria, total을 받는다.
public PageVO(Criteria cri, int total) {
//계산에 필요한 값(페이지 번호, 데이터 갯수, 전체 게시글 수, cri)을 초기화
this.page = cri.getPage();
this.amount = cri.getAmount();
this.total = total;
this.cri = cri;
//1. 끝 페이지 계산
//page가 1~10 → 끝 페이지 10
//page가 11~20 → 끝 페이지 20
//(int)Math.ceil(조회하는 페이지 번호 / 페이지네이션 수) * 페이지네이션 수
// math.ceil은 올림
this.end = (int)Math.ceil(this.page / (double)pageCnt) * 10;
//2. 시작 페이지번호 계산
//end - 페이지 네이션 갯수 + 1
this.start = this.end - pageCnt + 1;
//3. 실제 끝번호 계산
//데이터가 60개라고 가정할 때, end = 6
//데이터가 112개라고 가정할 때, 11번 페이지 조회 시에는 end = 12
//데이터가 356개라고 가정할 때, 32번 페이지 조회 시에는 end = 36
//356 / 10하면 35.6 ceil은 그냥 올림이라서 36 end가 그래서 36이 됨
//(int)Math.ceil(전체 게시글 수 / 데이터 개수)
this.realEnd = (int)Math.ceil(this.total / (double) this.amount);
//4. 마지막 페이지 번호를 재계산(다시 계산)
//realEnd > end end를 따라간다.
//데이터가 112개라고 가정할 때
//5번 페이지 조회시 end=10, realEnd=12 → 10
//end > realEnd면 realEnd를 따라간다.
//데이터 112개라고 가정할 때,
//11번 페이지 조회시, end=20, realEnd=12 → 12
//즉, 끝번호 > 실제 끝번호라면 실제 끝번호를 따라감
this.end = this.end > this.realEnd ? this.realEnd : this.end;
//5. 이전 버튼
//start는 1, 11, 21, 31 ... 로 증가되는데 1보다 크면 true
//2번에 정의된 start 참고
this.prev = this.start > 1;
//6. 다음 버튼
//조건: 실제 끝 번호가(realEnd) end보다 크면 true
this.next = this.realEnd > this.end;
}
}
- notice_controller
package com.coding404.myweb.controller;
import java.util.ArrayList;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import com.coding404.myweb.command.TripVO;
import com.coding404.myweb.trip.service.TripService;
import com.coding404.myweb.util.Criteria;
import com.coding404.myweb.util.PageVO;
@Controller
@RequestMapping("/trip")
public class NoticeController {
@Autowired
@Qualifier("tripService")
private TripService tripService;
//등록화면
@RequestMapping("/notice_write")
public String notice_write() {
return "trip/notice_write";
}
@RequestMapping("/notice_list")
public String notice_list(Criteria cri, Model model) {
/*
* service, mapper영역에 getList 함수를 선언하고
* 등록번호 역순으로 데이터를 조회해서 가지고 나옵니다.
* model에 담아서
* 화면에서는 반복문으로 처리.
*
*/
//데이터
ArrayList<TripVO> list = tripService.getList(cri);
//페이지 네이션
int total = tripService.getTotal();
PageVO pageVO = new PageVO(cri, total);
// System.out.println(pageVO.toString());
model.addAttribute("list", list);
model.addAttribute("pageVO", pageVO);
return "trip/notice_list";
}
@RequestMapping("/notice_view")
public String notice_view(@RequestParam("tno") int tno,
Model model,
HttpServletResponse response,
HttpServletRequest request) {
//클릭한 글 번호에 대한 내용을 조회
TripVO vo = tripService.getContent(tno);
model.addAttribute("vo", vo);
//조회수 - Cookie or 세션 이용해서 조회수 중복 방지
tripService.upHit(tno);
//이전글 다음글
ArrayList<TripVO> list = tripService.getPrevNext(tno);
model.addAttribute("list", list);
// Cookie cookie = new Cookie("key", "1");
// cookie.setMaxAge(30);
// response.addCookie(cookie);
return "trip/notice_view";
}
//수정화면
@RequestMapping("/notice_modify")
public String notice_modify(@RequestParam("tno") int tno,
Model model) {
//클릭한 글 번호에 대한 내용을 조회
TripVO vo = tripService.getContent(tno);
model.addAttribute("vo", vo);
return "trip/notice_modify";
}
//수정, 상세 화면이 완전 동일하다면
// @RequestMapping({"notice_view", "notice_modify"})
// public void notice_view(@RequestParam("tno") int tno,
// Model model) {
//
// TripVO vo = tripService.getContent(tno);
// model.addAttribute("vo", vo);
// }
//글등록
@RequestMapping(value="/registForm", method = RequestMethod.POST)
public String registForm(TripVO vo, RedirectAttributes ra) {
int result = tripService.noticeRegist(vo);
String msg = result == 1 ? "문의사항이 정상 등록되었습니다" : "문의 등록에 실패했습니다";
ra.addFlashAttribute("msg", msg);
return "redirect:/trip/notice_list";
}
//글수정
@RequestMapping(value="/modifyForm", method = RequestMethod.POST)
public String modifyForm(TripVO vo,
RedirectAttributes ra) {
//업데이트작업-화면에서는 tno가 필요하기 때문에 hidden태그를 이용해서 넘겨주세요.
int result = tripService.noticeModify(vo);
String msg = result == 1 ? "문의사항이 수정되었습니다" : "수정에 실패했습니다";
ra.addFlashAttribute("msg", msg);
return "redirect:/trip/notice_list";
//return "redirect:/trip/notice_view?tno=" + vo.getTno();
}
//글삭제
@RequestMapping(value="/deleteForm", method = RequestMethod.POST)
public String deleteForm(@RequestParam("tno") int tno,
RedirectAttributes ra) {
/*
* service, mapper에는 noticeDelete 메서드로 삭제를 진행
* 삭제 이후에는 list화면으로 이동해주면 됩니다.
*/
int result = tripService.noticeDelete(tno);
String msg = result == 1 ? "삭제 되었습니다" : "삭제에 실패했습니다";
ra.addFlashAttribute("msg", msg);
return "redirect:/trip/notice_list";
}
}
- service
package com.coding404.myweb.trip.service;
import java.util.ArrayList;
import com.coding404.myweb.command.TripVO;
import com.coding404.myweb.util.Criteria;
public interface TripService {
public int noticeRegist(TripVO vo); //등록
//public ArrayList<TripVO> getList(); //조회
public ArrayList<TripVO> getList(Criteria cri); //페이지
public int getTotal(); //전체 게시글 수
public TripVO getContent(int tno); //상세조회
public int noticeModify(TripVO vo); //수정
public int noticeDelete(int tno); //삭제
public void upHit(int tno); //조회수
public ArrayList<TripVO> getPrevNext(int tno); //이전글,담글
}
- serviceImpl
package com.coding404.myweb.trip.service;
import java.util.ArrayList;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.coding404.myweb.command.TripVO;
import com.coding404.myweb.util.Criteria;
@Service("tripService")
public class TripServiceImpl implements TripService {
@Autowired
private TripMapper tripMapper;
@Override
public int noticeRegist(TripVO vo) {
return tripMapper.noticeRegist(vo);
}
@Override
public ArrayList<TripVO> getList(Criteria cri) {
return tripMapper.getList(cri);
}
@Override
public int getTotal() {
return tripMapper.getTotal();
}
@Override
public TripVO getContent(int tno) {
return tripMapper.getContent(tno);
}
@Override
public int noticeModify(TripVO vo) {
return tripMapper.noticeModify(vo);
}
@Override
public int noticeDelete(int tno) {
return tripMapper.noticeDelete(tno);
}
@Override
public void upHit(int tno) {
tripMapper.upHit(tno);
}
@Override
public ArrayList<TripVO> getPrevNext(int tno) {
return tripMapper.getPrevNext(tno);
}
}
- mapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.coding404.myweb.trip.service.TripMapper">
<insert id="noticeRegist" parameterType="TripVO">
insert into trip(tripdate, writer, title, content)
values(#{tripdate}, #{writer}, #{title}, #{content} )
</insert>
<select id="getList" resultType="TripVO">
select * from trip order by tno desc
limit #{pageStart}, #{amount}
</select>
<select id="getTotal" resultType="int">
select count(*) as total from trip
</select>
<select id="getContent" resultType="TripVO">
select * from trip where tno = #{tno}
</select>
<update id="noticeModify" parameterType="TripVO">
update trip
set tripdate = #{tripdate},
title = #{title},
content = #{content}
where tno = #{tno}
</update>
<delete id="noticeDelete" parameterType="int">
delete from trip where tno = #{tno}
</delete>
<update id="upHit" parameterType="int">
update trip
set hit = hit + 1
where tno = #{tno}
</update>
<!-- 이전글, 담글 -->
<!-- xml or html에서 부등호는 태그로 인식이 되는데, CDATA는 순수한 문자열 형태로 인식을 시킴 -->
<select id="getPrevNext" resultType="TripVO">
<![CDATA[
select * from trip
where tno in ( (select tno from trip where tno < #{tno} order by tno desc limit 1),
(select tno from trip where tno > #{tno} limit 1) )
order by tno desc
]]>
</select>
</mapper>
- mapper.java
package com.coding404.myweb.trip.service;
import java.util.ArrayList;
import org.apache.ibatis.annotations.Mapper;
import com.coding404.myweb.command.TripVO;
import com.coding404.myweb.util.Criteria;
@Mapper
public interface TripMapper {
public int noticeRegist(TripVO vo);
//public ArrayList<TripVO> getList(); //조회
public ArrayList<TripVO> getList(Criteria cri); //페이지
public int getTotal(); //전체 게시글 수
public TripVO getContent(int tno); //상세조회
public int noticeModify(TripVO vo); //수정
public int noticeDelete(int tno); //삭제
public void upHit(int tno); //조회수
public ArrayList<TripVO> getPrevNext(int tno); //이전글,담글
}
* notice_list 페이지 네이션 부분 수정
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>
<div id="container">
<!-- location_area -->
<div class="location_area customer">
<div class="box_inner">
<h2 class="tit_page">TOURIST <span class="in">in</span> TOUR</h2>
<p class="location">고객센터 <span class="path">/</span> 공지사항</p>
<ul class="page_menu clear">
<li><a href="#" class="on">공지사항</a></li>
<li><a href="#">문의하기</a></li>
</ul>
</div>
</div>
<!-- //location_area -->
<!-- bodytext_area -->
<div class="bodytext_area box_inner">
<form action="#" class="minisrch_form">
<fieldset>
<select name="###" style="height: 35px;">
<option value="#">제목</option>
<option value="#">내용</option>
<option value="#">작성자</option>
<option value="#">제목+내용</option>
</select>
<legend>검색</legend>
<input type="text" class="tbox" title="검색어를 입력해주세요" placeholder="검색어를 입력해주세요">
<a href="javascript:;" class="btn_srch">검색</a>
</fieldset>
</form>
<table class="bbsListTbl" summary="번호,제목,조회수,작성일 등을 제공하는 표">
<caption class="hdd">공지사항 목록</caption>
<thead>
<tr>
<th scope="col">번호</th>
<th scope="col">제목</th>
<th scope="col">조회수</th>
<th scope="col">작성일</th>
</tr>
</thead>
<tbody>
<c:forEach var="vo" items="${list }" varStatus="num">
<tr>
<td>${vo.tno }</td>
<td class="tit_notice"><a href="notice_view?tno=${vo.tno }">${vo.title }</a> </td>
<td>${vo.hit }</td>
<td><fmt:formatDate value="${vo.regdate }" pattern="yyyy-MM-dd"/></td>
</tr>
</c:forEach>
</tbody>
</table>
<!-- pagination -->
<div class="pagination">
<!-- 5. 맨 처음으로 -->
<a href="notice_list?page=1&amount=${pageVO.amount }" class="firstpage pbtn"><img src="${pageContext.request.contextPath }/resources/img/btn_firstpage.png" alt="첫 페이지로 이동"></a>
<!-- 3. 이전 페이지 네이션 -->
<c:if test="${pageVO.prev }">
<a href="notice_list?page=${pageVO.start-1 }&amount=${pageVO.amount}" class="prevpage pbtn"><img src="${pageContext.request.contextPath }/resources/img/btn_prevpage.png" alt="이전 페이지로 이동"></a>
</c:if>
<!-- 1.페이지네이션 -->
<c:forEach var="num" begin="${pageVO.start }" end="${pageVO.end }">
<a href="notice_list?page=${num }&amount=${pageVO.amount }"><span class="pagenum ${pageVO.page == num ? 'currentpage' : ''}">${num }</span></a>
</c:forEach>
<!-- 2. 다음 페이지 네이션 -->
<c:if test="${pageVO.next }">
<a href="notice_list?page=${pageVO.end+1 }&amount=${pageVO.amount}" class="nextpage pbtn"><img src="${pageContext.request.contextPath }/resources/img/btn_nextpage.png" alt="다음 페이지로 이동"></a>
</c:if>
<!-- 4. 맨 마지막으로 -->
<a href="notice_list?page=${pageVO.realEnd }&amount=${pageVO.amount}" class="lastpage pbtn"><img src="${pageContext.request.contextPath }/resources/img/btn_lastpage.png" alt="마지막 페이지로 이동"></a>
</div>
<!-- //pagination -->
</div>
<!-- //bodytext_area -->
</div>
<!-- //container -->
<script>
var msg = '${msg}';
if(msg !== '') {
alert(msg);
}
</script>
3) 검색(제대로 이해할 것!)
- 검색을 누르면 검색된 결과 중에서 페이지 네이션을 누를 때에도 그 검색 키워드가 유지가 되기 때문에 두번째는 페이지 네이션을 누를때도 고려를 해줘야함
- 검색 버튼을 누를때에도 검색 키워드, 검색값(단어), 페이지 번호, amount값 다 들어가 있어야 하고(form 형식), 페이지네이션 누를 때에도 검색 키워드, 검색값(단어), 페이지 번호, amount값 4개를 유지시켜줘야함! (a 링크) → 둘 다 컨트롤러로 들어갈 거임(4가지 값 던져주기)
- 4개로 sql 문 만들어서 다시 실어서 나가게끔만 해주면 됨
1] 첫번째 방법(검색)-form
- 값을 criteria 안에다가 넣어놓을 것!
* critetria, notice_list, notice_controller, mapper.xml
(검색 기능, 10~100개씩 보기)
- criteria
package com.coding404.myweb.util;
import lombok.Data;
//data 달면 getter, setter 자동 생성, 생성자만 필요에 따라 다시 만들었음
@Data
//sql문에 페이지 번호, 데이터 갯수를 전달해줄 클래스
public class Criteria {
private int page; //페이지 번호
private int amount; //데이터 갯수
private String searchType; //제목 눌렀을 때 나오는 내용들(검색 타입)
private String searchName; //검색 값
//롬복 쓰면 생성자에 정의해줄 수가 없으니까 여기는 그냥 씀
public Criteria() {
this.page = 1;
this.amount = 10;
}
public Criteria(int page, int amount) {
super();
this.page = page;
this.amount = amount;
}
//limit 함수의 페이지 시작 부분에 들어갈 getter
public int getPageStart() {
return (page - 1) * amount;
}
}
- notice_list(맨 뒤에 사진처럼 쓰면 검색했을때 2페이지 나오면 1페이지에서 페이지 넘어가도 1,2 페이지만 나옴)
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>
<div id="container">
<!-- location_area -->
<div class="location_area customer">
<div class="box_inner">
<h2 class="tit_page">TOURIST <span class="in">in</span> TOUR</h2>
<p class="location">고객센터 <span class="path">/</span> 공지사항</p>
<ul class="page_menu clear">
<li><a href="#" class="on">공지사항</a></li>
<li><a href="#">문의하기</a></li>
</ul>
</div>
</div>
<!-- //location_area -->
<!-- bodytext_area -->
<div class="bodytext_area box_inner">
<form action="notice_list" class="minisrch_form" name="actionForm">
<fieldset>
<select id="handleAmount" style="height: 35px;">
<option value="10" ${pageVO.amount == 10 ? 'selected' : '' }>10개씩 보기</option>
<option value="20" ${pageVO.amount == 20 ? 'selected' : '' }>20개씩 보기</option>
<option value="50" ${pageVO.amount == 50 ? 'selected' : '' }>50개씩 보기</option>
<option value="100"${pageVO.amount == 100 ? 'selected' : '' }>100개씩 보기</option>
</select>
<select name="searchType" style="height: 35px;">
<option value="title" ${pageVO.cri.searchType == 'title' ? 'selected' : '' }>제목</option>
<option value="content" ${pageVO.cri.searchType == 'content' ? 'selected' : '' }>내용</option>
<option value="writer" ${pageVO.cri.searchType == 'writer' ? 'selected' : '' }>작성자</option>
<option value="titcont" ${pageVO.cri.searchType == 'titcont' ? 'selected' : '' }>제목+내용</option>
</select>
<legend>검색</legend>
<input type="text" name="searchName" value="${pageVO.cri.searchName }" class="tbox" title="검색어를 입력해주세요" placeholder="검색어를 입력해주세요">
<input type="hidden" name="page" value="1">
<!-- 이렇게 해야 amount값이 유지됨 -->
<input type="hidden" name="amount" value="${pageVO.amount }">
<input type="submit" class="btn_srch" value="검색" style="line-height: 30px;" >
<!-- <a href="javascript:;" class="btn_srch">검색</a> -->
</fieldset>
</form>
<table class="bbsListTbl" summary="번호,제목,조회수,작성일 등을 제공하는 표">
<caption class="hdd">공지사항 목록</caption>
<thead>
<tr>
<th scope="col">번호</th>
<th scope="col">제목</th>
<th scope="col">조회수</th>
<th scope="col">작성일</th>
</tr>
</thead>
<tbody>
<c:forEach var="vo" items="${list }" varStatus="num">
<tr>
<td>${num.count }</td>
<td class="tit_notice"><a href="notice_view?tno=${vo.tno }">${vo.title }</a> </td>
<td>${vo.hit }</td>
<td><fmt:formatDate value="${vo.regdate }" pattern="yyyy-MM-dd"/></td>
</tr>
</c:forEach>
</tbody>
</table>
<!-- pagination -->
<%--
<div class="pagination">
<!-- 5.맨 처음으로 -->
<a href="notice_list?page=1&amount=${pageVO.amount }" class="firstpage pbtn"><img src="${pageContext.request.contextPath }/resources/img/btn_firstpage.png" alt="첫 페이지로 이동"></a>
<!-- 3.이전페이지네이션 -->
<c:if test="${pageVO.prev }">
<a href="notice_list?page=${pageVO.start-1 }&amount=${pageVO.amount}" class="prevpage pbtn"><img src="${pageContext.request.contextPath }/resources/img/btn_prevpage.png" alt="이전 페이지로 이동"></a>
</c:if>
<!-- 1.페이지네이션 -->
<c:forEach var="num" begin="${pageVO.start }" end="${pageVO.end }">
<a href="notice_list?page=${num }&amount=${pageVO.amount }"><span class="pagenum ${pageVO.page == num ? 'currentpage' : ''}">${num }</span></a>
</c:forEach>
<!-- 2.다음페이지네이션 -->
<c:if test="${pageVO.next }">
<a href="notice_list?page=${pageVO.end+1 }&amount=${pageVO.amount}" class="nextpage pbtn"><img src="${pageContext.request.contextPath }/resources/img/btn_nextpage.png" alt="다음 페이지로 이동"></a>
</c:if>
<!-- 4.맨 마지막으로 -->
<a href="notice_list?page=${pageVO.realEnd }&amount=${pageVO.amount}" class="lastpage pbtn"><img src="${pageContext.request.contextPath }/resources/img/btn_lastpage.png" alt="마지막 페이지로 이동"></a>
</div>
--%>
<%--
컨트롤러에서 사용자 클래스를 매개변수로 지정을 하면 이름이 클래스명 소문자로
지정되서 자동으로 다음화면으로 전달됩니다.
${criteria }
--%>
<div class="pagination">
<!-- 5.맨 처음으로 -->
<a href="notice_list?page=1&amount=${pageVO.amount }&searchType=${pageVO.cri.searchType}&searchName=${pageVO.cri.searchName}" class="firstpage pbtn"><img src="${pageContext.request.contextPath }/resources/img/btn_firstpage.png" alt="첫 페이지로 이동"></a>
<!-- 3.이전페이지네이션 -->
<c:if test="${pageVO.prev }">
<a href="notice_list?page=${pageVO.start-1 }&amount=${pageVO.amount}&searchType=${pageVO.cri.searchType}&searchName=${pageVO.cri.searchName}" class="prevpage pbtn"><img src="${pageContext.request.contextPath }/resources/img/btn_prevpage.png" alt="이전 페이지로 이동"></a>
</c:if>
<!-- 1.페이지네이션 -->
<c:forEach var="num" begin="${pageVO.start }" end="${pageVO.end }">
<a href="notice_list?page=${num }&amount=${pageVO.amount }&searchType=${pageVO.cri.searchType}&searchName=${pageVO.cri.searchName}"><span class="pagenum ${pageVO.page == num ? 'currentpage' : ''}">${num }</span></a>
</c:forEach>
<!-- 2.다음페이지네이션 -->
<c:if test="${pageVO.next }">
<a href="notice_list?page=${pageVO.end+1 }&amount=${pageVO.amount}&searchType=${pageVO.cri.searchType}&searchName=${pageVO.cri.searchName}" class="nextpage pbtn"><img src="${pageContext.request.contextPath }/resources/img/btn_nextpage.png" alt="다음 페이지로 이동"></a>
</c:if>
<!-- 4.맨 마지막으로 -->
<a href="notice_list?page=${pageVO.realEnd }&amount=${pageVO.amount}&searchType=${pageVO.cri.searchType}&searchName=${pageVO.cri.searchName}" class="lastpage pbtn"><img src="${pageContext.request.contextPath }/resources/img/btn_lastpage.png" alt="마지막 페이지로 이동"></a>
</div>
<!-- //pagination -->
</div>
<!-- //bodytext_area -->
</div>
<!-- //container -->
<script>
var msg = '${msg}';
if(msg !== '') {
alert(msg);
}
</script>
<script>
var handleAmount = document.getElementById("handleAmount");
handleAmount.onchange = function() {
//console.log( event.target.value );
document.actionForm.amount.value = event.target.value;
document.actionForm.submit();
}
</script>
- notice_controller
package com.coding404.myweb.controller;
import java.util.ArrayList;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import com.coding404.myweb.command.TripVO;
import com.coding404.myweb.trip.service.TripService;
import com.coding404.myweb.util.Criteria;
import com.coding404.myweb.util.PageVO;
@Controller
@RequestMapping("/trip")
public class NoticeController {
@Autowired
@Qualifier("tripService")
private TripService tripService;
//등록화면
@RequestMapping("/notice_write")
public String notice_write() {
return "trip/notice_write";
}
@RequestMapping("/notice_list")
public String notice_list(Criteria cri, Model model) {
/*
* service, mapper영역에 getList 함수를 선언하고
* 등록번호 역순으로 데이터를 조회해서 가지고 나옵니다.
* model에 담아서
* 화면에서는 반복문으로 처리.
*
*/
//데이터
// ArrayList<TripVO> list = tripService.getList(cri);
//페이지 네이션
// int total = tripService.getTotal();
// PageVO pageVO = new PageVO(cri, total);
// System.out.println(pageVO.toString());
//페이지 검색 처리
/*
* 1. 화면에서는 page, amount, searchType, searchName를 넘긴다.
* 2. criteria에서 검색 값을 받는다.
* 3. sql문을 바꾼다. (동적 쿼리)
* 4. totla sql을 바꾼다(동적 쿼리)
*
* */
System.out.println(cri.toString());
ArrayList<TripVO> list = tripService.getList(cri);
int total = tripService.getTotal();
PageVO pageVO = new PageVO(cri, total);
model.addAttribute("list", list);
model.addAttribute("pageVO", pageVO);
return "trip/notice_list";
}
@RequestMapping("/notice_view")
public String notice_view(@RequestParam("tno") int tno,
Model model,
HttpServletResponse response,
HttpServletRequest request) {
//클릭한 글 번호에 대한 내용을 조회
TripVO vo = tripService.getContent(tno);
model.addAttribute("vo", vo);
//조회수 - Cookie or 세션 이용해서 조회수 중복 방지
tripService.upHit(tno);
//이전글 다음글
ArrayList<TripVO> list = tripService.getPrevNext(tno);
model.addAttribute("list", list);
// Cookie cookie = new Cookie("key", "1");
// cookie.setMaxAge(30);
// response.addCookie(cookie);
return "trip/notice_view";
}
//수정화면
@RequestMapping("/notice_modify")
public String notice_modify(@RequestParam("tno") int tno,
Model model) {
//클릭한 글 번호에 대한 내용을 조회
TripVO vo = tripService.getContent(tno);
model.addAttribute("vo", vo);
return "trip/notice_modify";
}
//수정, 상세 화면이 완전 동일하다면
// @RequestMapping({"notice_view", "notice_modify"})
// public void notice_view(@RequestParam("tno") int tno,
// Model model) {
//
// TripVO vo = tripService.getContent(tno);
// model.addAttribute("vo", vo);
// }
//글등록
@RequestMapping(value="/registForm", method = RequestMethod.POST)
public String registForm(TripVO vo, RedirectAttributes ra) {
int result = tripService.noticeRegist(vo);
String msg = result == 1 ? "문의사항이 정상 등록되었습니다" : "문의 등록에 실패했습니다";
ra.addFlashAttribute("msg", msg);
return "redirect:/trip/notice_list";
}
//글수정
@RequestMapping(value="/modifyForm", method = RequestMethod.POST)
public String modifyForm(TripVO vo,
RedirectAttributes ra) {
//업데이트작업-화면에서는 tno가 필요하기 때문에 hidden태그를 이용해서 넘겨주세요.
int result = tripService.noticeModify(vo);
String msg = result == 1 ? "문의사항이 수정되었습니다" : "수정에 실패했습니다";
ra.addFlashAttribute("msg", msg);
return "redirect:/trip/notice_list";
//return "redirect:/trip/notice_view?tno=" + vo.getTno();
}
//글삭제
@RequestMapping(value="/deleteForm", method = RequestMethod.POST)
public String deleteForm(@RequestParam("tno") int tno,
RedirectAttributes ra) {
/*
* service, mapper에는 noticeDelete 메서드로 삭제를 진행
* 삭제 이후에는 list화면으로 이동해주면 됩니다.
*/
int result = tripService.noticeDelete(tno);
String msg = result == 1 ? "삭제 되었습니다" : "삭제에 실패했습니다";
ra.addFlashAttribute("msg", msg);
return "redirect:/trip/notice_list";
}
}
- mapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.coding404.myweb.trip.service.TripMapper">
<insert id="noticeRegist" parameterType="TripVO">
insert into trip(tripdate, writer, title, content)
values(#{tripdate}, #{writer}, #{title}, #{content} )
</insert>
<!--
<select id="getList" resultType="TripVO">
select * from trip order by tno desc
limit #{pageStart}, #{amount}
</select>
-->
<!-- 동적쿼리구문의 test에는 vo의 getter, map의 키값이 들어값니다 -->
<select id="getList" resultType="TripVO">
select * from trip
<if test="searchType == 'title' ">where title like concat( '%' , #{searchName} , '%')</if>
<if test="searchType == 'content' ">where content like concat( '%' , #{searchName} , '%')</if>
<if test="searchType == 'writer' ">where writer like concat( '%' , #{searchName} , '%')</if>
<if test="searchType == 'titcont' ">where title like concat( '%' , #{searchName} , '%')
or content like concat( '%' , #{searchName} , '%')</if>
<if test="searchType == null or searchType == '' ">where 1 = 1</if>
<!--
<choose>
<when test="searchType == 'title' ">where title like concat( '%' , #{searchName} , '%')</when>
<when test="searchType == 'content'">where content like concat( '%' , #{searchName} , '%')</when>
<when test="searchType == 'writer' ">where writer like concat( '%' , #{searchName} , '%')</when>
<when test="searchType == 'titcont'">where title like concat( '%' , #{searchName} , '%')
or content like concat( '%' , #{searchName} , '%')</when>
<otherwise>where 1 = 1</otherwise>
</choose>
-->
order by tno desc
limit #{pageStart}, #{amount}
</select>
<select id="getTotal" resultType="int">
select count(*) as total from trip
</select>
<select id="getContent" resultType="TripVO">
select * from trip where tno = #{tno}
</select>
<update id="noticeModify" parameterType="TripVO">
update trip
set tripdate = #{tripdate},
title = #{title},
content = #{content}
where tno = #{tno}
</update>
<delete id="noticeDelete" parameterType="int">
delete from trip where tno = #{tno}
</delete>
<update id="upHit" parameterType="int">
update trip
set hit = hit + 1
where tno = #{tno}
</update>
<!-- 이전글, 담글 -->
<!-- xml or html에서 부등호는 태그로 인식이 되는데, CDATA는 순수한 문자열 형태로 인식을 시킴 -->
<select id="getPrevNext" resultType="TripVO">
<![CDATA[
select * from trip
where tno in ( (select tno from trip where tno < #{tno} order by tno desc limit 1),
(select tno from trip where tno > #{tno} limit 1) )
order by tno desc
]]>
</select>
</mapper>
'TIL > Spring' 카테고리의 다른 글
consumes와 produces의 차이 (0) | 2024.01.22 |
---|---|
빌드 관리 도구(maven, gradle의 차이) (0) | 2023.08.18 |
day80-spring (0) | 2023.02.08 |
day79-spring (0) | 2023.02.07 |
day78-spring (0) | 2023.02.06 |