mjeongriver
article thumbnail
Published 2023. 2. 9. 17:34
day81-spring TIL/Spring

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에 모두 생성해줄 것!

 

2번째 사진: 5까지만 나오게 하려면 pagaVO 수정해야함!

더보기

- 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) 검색(제대로 이해할 것!)

 

검색을 누를 경우 리스트로 보내서 키와 제목에 대한 것을 조회해서 다시 가지고 나옴(키에 맞는 sql문 실행)

 

- 검색을 누르면 검색된 결과 중에서 페이지 네이션을 누를 때에도 그 검색 키워드가 유지가 되기 때문에 두번째는 페이지 네이션을 누를때도 고려를 해줘야함

- 검색 버튼을 누를때에도 검색 키워드, 검색값(단어), 페이지 번호, amount값 다 들어가 있어야 하고(form 형식), 페이지네이션 누를 때에도 검색 키워드, 검색값(단어), 페이지 번호, amount값 4개를 유지시켜줘야함! (a 링크) → 둘 다 컨트롤러로 들어갈 거임(4가지 값 던져주기)

- 4개로 sql 문 만들어서 다시 실어서 나가게끔만 해주면 됨

 

1] 첫번째 방법(검색)-form

- 값을 criteria 안에다가 넣어놓을 것!

searchType, searchName, 2번째 사진: notice_list에서 부분 수정

 

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

mjeongriver

@mjeongriver

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!

검색 태그