1. 게시판 구현 이어서
1) notice_write에서 글 쓰고 notice_list로 쓴 글 보여주기
2) notice_list에서 글 선택하면 선택한 글 보여주기, 수정하기(수정하고 글을 보여주거나, list로 넘어가게 redirect), 삭제하기 기능 추가
3) 상세 글 화면에서 이전글, 다음글 보는 기능
4) 페이징 처리
- pageTest(TripVO가 안 읽힐 때 tripVO에서 import lombok.AllArgsConstructor; 꼭 선언해줄 것!)
package com.coding404.myweb;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import com.coding404.myweb.command.TripVO;
import com.coding404.myweb.trip.service.TripMapper;
@RunWith(SpringJUnit4ClassRunner.class) //junit으로 테스트환경을 구성
@ContextConfiguration("file:src/main/webapp/WEB-INF/config/root-context.xml") //동작시킬 스프링 설정파일
public class PageTest {
@Autowired
TripMapper tripMapper;
// @Test
// public void testCode01() {
//
// for(int i = 1; i <= 300; i++) {
// TripVO vo = new TripVO(0, "2023-02-08", "admin" + i, "test" + i, "example" + i, 0, null);
// tripMapper.noticeRegist(vo);
// }
//
//
// }
//
//
//}
* notice_list, notice_modify, notice_view, notice_write
더보기
- 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">
<a href="javascript:;" class="firstpage pbtn"><img src="${pageContext.request.contextPath }/resources/img/btn_firstpage.png" alt="첫 페이지로 이동"></a>
<a href="javascript:;" class="prevpage pbtn"><img src="${pageContext.request.contextPath }/resources/img/btn_prevpage.png" alt="이전 페이지로 이동"></a>
<a href="javascript:;"><span class="pagenum currentpage">1</span></a>
<a href="javascript:;"><span class="pagenum">2</span></a>
<a href="javascript:;"><span class="pagenum">3</span></a>
<a href="javascript:;"><span class="pagenum">4</span></a>
<a href="javascript:;"><span class="pagenum">5</span></a>
<a href="javascript:;" class="nextpage pbtn"><img src="${pageContext.request.contextPath }/resources/img/btn_nextpage.png" alt="다음 페이지로 이동"></a>
<a href="javascript:;" 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>
- notice_modify
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!-- 데이트피커 -->
<link rel="stylesheet" href="https://code.jquery.com/ui/1.13.2/themes/base/jquery-ui.css">
<script src="https://code.jquery.com/ui/1.13.2/jquery-ui.js"></script>
<script>
$( function() {
$( "#datepicker_a" ).datepicker({
dateFormat: 'yy-mm-dd',
editable: true
});
});
</script>
<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>
<div class="bodytext_area box_inner">
<!-- appForm -->
<form action="modifyForm" method="post" class="appForm">
<fieldset>
<legend>상담문의 수정양식</legend>
<p class="info_pilsoo pilsoo_item">필수입력</p>
<ul class="app_list">
<li class="clear">
<label for="email_lbl" class="tit_lbl pilsoo_item">등록일 (수정 일자)</label>
<div class="app_content email_area">
<!-- required, pattern속성을 사용할 떄는 form태그를 반드시 submit버튼으로 전송해야 동작됩니다. -->
<input type="text" name="tripdate" value="${vo.tripdate }" id="datepicker_a" placeholder="날짜를 선택하세요" required="required" pattern="[0-9]{4}-[0-9]{2}-[0-9]{2}" >
</div>
</li>
<li class="clear">
<label for="email_lbl" class="tit_lbl pilsoo_item">작성자 (수정 불가)</label>
<div class="app_content email_area">
<input type="hidden" name="tno" value="${vo.tno }"/>
<input type="text" name="writer" value="${vo.writer }" readonly="readonly"/>
</div>
</li>
<li class="clear">
<label for="name_lbl" class="tit_lbl pilsoo_item">제목</label>
<div class="app_content">
<input type="text" name="title" value="${vo.title }" class="w100p" id="name_lbl" placeholder="제목을 입력하세요" required="required"/>
</div>
</li>
<li class="clear">
<label for="content_lbl" class="tit_lbl">문의내용</label>
<div class="app_content">
<textarea name="content" id="content_lbl" class="w100p">${vo.content }</textarea>
</div>
</li>
</ul>
<p class="btn_line">
<input type="submit" class="btn_baseColor" value="글 수정">
<input type="button" class="btn_baseColor" value="목록">
</p>
</fieldset>
</form>
</div>
</div>
<!-- //container -->
- notice_view
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<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 -->
<!--
삭제 시는 post로 동작하는데
hidden 이용해서 삭제에 필요한 키값을 전달해줍니다.
js를 이용해서 form을 전송
-->
<form action="deleteForm" method="post" name="actionForm">
<input type="hidden" name="tno" value="${vo.tno }">
<div class="bodytext_area box_inner">
<ul class="bbsview_list">
<li class="bbs_title">${vo.title }</li>
<li class="bbs_hit">작성일 : <span><fmt:formatDate value="${vo.regdate }" pattern="yyyy-MM-dd"/></span></li>
<li class="bbs_date">작성자 : <span>${vo.writer }</span></li>
<li class="bbs_date">조회수 : <span>${vo.hit }</span></li>
<li class="bbs_content">
<div class="editer_content">
${vo.content }
</div>
</li>
</ul>
<p class="btn_line txt_right">
<a href="notice_modify?tno=${vo.tno }" class="btn_bbs">글수정</a>
<a href="javascript:;" onclick="noticeDelete()" class="btn_bbs">글삭제</a>
<a href="notice_list" class="btn_bbs">목록</a>
</p>
<ul class="near_list mt20">
<!--
1. 글이 2개인 경우 - 이전글 < 현재글 인 경우 이전글
2. 글이 1개인 경우 - 리스트 길이가 1이고, 이전글 < 현재글인 경우
-->
<c:forEach var="data" items="${list }" >
<c:if test="${fn:length(list) == 1 and data.tno < vo.tno }">
<li><h4 class="prev">다음글</h4>은 없습니다</li>
</c:if>
<c:if test="${ data.tno > vo.tno }">
<li><h4 class="prev">다음글</h4><a href="notice_view?tno=${data.tno }">#{data.title }</a></li>
</c:if>
<c:if test="${ data.tno < vo.tno }">
<li><h4 class="next">이전글</h4><a href="notice_view?tno=${data.tno }"> #{data.title }</a></li>
</c:if>
<c:if test="${fn:length(list) == 1 and data.tno > vo.tno }">
<li><h4 class="next">이전글</h4>은 없습니다</li>
</c:if>
</c:forEach>
<!--
<li><h4 class="prev">다음글</h4><a href="javascript:;">추석 연휴 티켓/투어 배송 및 직접 수령 안내</a></li>
<li><h4 class="next">이전글</h4><a href="javascript:;">이번 여름 휴가 제주 갈까? 미션 투어 (여행경비 50만원 지원)</a></li>
-->
</ul>
</div>
</form>
<!-- //bodytext_area -->
</div>
<!-- //container -->
<script>
function noticeDelete(){
//a링크 고유 이벤트 중지
event.preventDefault();
if(confirm("정말 지울 거에요?ㅠㅠ")) {
//폼 형식으로 삭제를 날려줌
document.actionForm.submit();
}
}
</script>
- notice_write
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!-- 데이트피커 -->
<link rel="stylesheet" href="https://code.jquery.com/ui/1.13.2/themes/base/jquery-ui.css">
<script src="https://code.jquery.com/ui/1.13.2/jquery-ui.js"></script>
<script>
$( function() {
$( "#datepicker_a" ).datepicker();
$( "#datepicker_a" ).datepicker( "option", "dateFormat", "yy-mm-dd");
});
</script>
<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">
<!-- appForm -->
<form action="registForm" method="post" class="appForm">
<fieldset>
<legend>상담문의 입력 양식</legend>
<p class="info_pilsoo pilsoo_item">필수입력</p>
<ul class="app_list">
<li class="clear">
<label for="email_lbl" class="tit_lbl pilsoo_item">등록일</label>
<div class="app_content email_area">
<input type="text" id="datepicker_a" name="tripdate" placeholder="날짜를 선택하세요" required="required"></p>
</div>
</li>
<li class="clear">
<label for="email_lbl" class="tit_lbl pilsoo_item">작성자</label>
<div class="app_content email_area">
<input type="hidden" />
<input type="text" placeholder="작성자" name="writer" required="required"/>
</div>
</li>
<li class="clear">
<label for="name_lbl" class="tit_lbl pilsoo_item">제목</label>
<div class="app_content"><input type="text" class="w100p" id="name_lbl" name="title" placeholder="제목을 입력하세요" required="required"/></div>
</li>
<li class="clear">
<label for="content_lbl" class="tit_lbl">문의내용</label>
<div class="app_content"><textarea id="content_lbl" class="w100p" name="content" placeholder="간단한 상담 요청 사항을 남겨주시면 보다 상세한 상담이 가능합니다.
전화 상담 희망시 기재 부탁드립니다."></textarea></div>
</li>
</ul>
<p class="btn_line">
<!--
<a href="javascript:;" class="btn_baseColor">글작성</a>
<a href="javascript:;" class="btn_baseColor">목록</a>
-->
<input type="submit" class="btn_baseColor" value="글작성">
<input type="button" class="btn_baseColor" value="목록" onclick="location.href='notice_list' ">
</p>
</fieldset>
</form>
<!-- //appForm -->
</div>
<!-- //bodytext_area -->
</div>
<!-- //container -->
* TripMapper.java, Tripmapper.xml, TripService, TripserviceImpl, NoticeController
더보기
- TripMapper.java
package com.coding404.myweb.trip.service;
import java.util.ArrayList;
import org.apache.ibatis.annotations.Mapper;
import com.coding404.myweb.command.TripVO;
@Mapper
public interface TripMapper {
public int noticeRegist(TripVO vo);
public ArrayList<TripVO> getList();
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); //이전글, 다음글
}
- Tripmapper.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">
<!-- mybatis-config에 TripVO 앨리어스 추가 -->
<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
</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>
<!-- parameterType은 생략이 가능함(넘어오는 값이 int) -->
<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이나 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>
- TripService
package com.coding404.myweb.trip.service;
import java.util.ArrayList;
import org.springframework.stereotype.Service;
import com.coding404.myweb.command.TripVO;
@Service("tripService")
public interface TripService {
//등록 메서드-성공 실패 결과를 정수로 받을 것!
public int noticeRegist(TripVO vo);
//조회 메서드
public ArrayList<TripVO> getList();
//한 행 상세 조회
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);
}
- TripserviceImpl
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;
@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() {
return tripMapper.getList();
}
@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);
}
}
- NoticeController
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.stereotype.Service;
import org.springframework.ui.Model;
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;
@Controller
@RequestMapping("trip")
public class NoticeController {
@Autowired
@Qualifier("tripService")
private TripService tripService;
@RequestMapping("/notice_list")
public String notice_list(Model model) {
/*
* service, mapper 영역에 getList 함수를 선언하고
* 등록번호 역순으로 데이터를 조회해서 가지고 나옵니다.
* model에 담아서 화면에서는 반복문으로 처리만 해주세요.
*/
//data 조회
ArrayList<TripVO> list = tripService.getList();
model.addAttribute("list", list);
return "trip/notice_list";
}
@RequestMapping("/notice_view")
//화면에 가지고 나가야 하니까 model 선언
public String notice_view(@RequestParam("tno") int tno,
Model model,
HttpServletResponse response,
HttpServletRequest request) {
//클릭한 글 번호에 대한 내용을 조회해줘야함! - sql문에 조건이 들어가야함.
TripVO vo = tripService.getContent(tno);
model.addAttribute("vo", vo);
//조회수 - Cookie or 세션 이용해서 조회수 중복 방지
tripService.upHit(tno);
// Cookie cookie = new Cookie("키", "값");
// Cookie cookie = new Cookie("key", "1");
// cookie.setMaxAge(30);
// response.addCookie(cookie);
//이전글과 다음글
ArrayList<TripVO> list = tripService.getPrevNext(tno);
model.addAttribute("list", list);
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("/notice_write")
public String notice_write() {
return "trip/notice_write";
}
//글 등록
@RequestMapping(value="/registForm", method=RequestMethod.POST)
public String registForm(TripVO vo, RedirectAttributes ra) {
// System.out.println(vo.toString());
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";
}
}
'TIL > Spring' 카테고리의 다른 글
빌드 관리 도구(maven, gradle의 차이) (0) | 2023.08.18 |
---|---|
day81-spring (0) | 2023.02.09 |
day79-spring (0) | 2023.02.07 |
day78-spring (0) | 2023.02.06 |
day77-spring (0) | 2023.02.03 |