[싱글이의 영수증] 상세 조회
업데이트:
싱글이의 영수증 상세 조회
- 출력화면
상세조회 이동 script
게시글 클릭 시 목록의 숨겨진 게시글 번호를 통해서 해당 번호와 일치하는 게시글의 상세조회 페이지로 이동한다.
<script>
$(".viewdetail").on("click", function() {
var boardNo = $(this).children("span#boardNo").text();
var boardViewURL = "${contextPath}/review/" + boardNo;
location.href = boardViewURL;
});
</script>
controller
해당 게시글 번호에 맞는 게시글 정보들을 조회해오고, 조회에 성공하면 조회수를 증가시킨다.
게시글 정보가 성공적으로 출력이 되면 조회수 상위 3개의 게시글 목록을 조회해오고,
그것에 해당하는 썸네일도 불러온다.
@RequestMapping("{boardNo}")
public String reviewView(@PathVariable("boardNo") int boardNo, Model model, @RequestHeader(value="referer",required=false) String referer,
RedirectAttributes ra, @ModelAttribute(name="loginMember", binding=false) Member loginMember) {
Review review = service.selectReview(boardNo);
String url = null;
if(review!=null) { // 상세조회 성공시
// 조회수 상위3 게시글 출력
List<Review> reviewList = service.reviewListTop3();
// 조회수 상위3 썸네일
if(reviewList!=null && !reviewList.isEmpty()) {
/* 썸네일 출력 */
List<ReviewAttachment> thumbnailList = service.selectThumbnailList(reviewList);
if(thumbnailList!=null) {
model.addAttribute("thList", thumbnailList);
}
}
// 좋아요 정보 출력
int memberNo = loginMember.getMemberNo();
List<ReviewLike> likeInfo = service.selectLike(memberNo);
Map<String, Integer> map = new HashMap<String, Integer>();
map.put("memberNo", memberNo);
map.put("boardNo", boardNo);
int like = service.selectLikePushed(map);
model.addAttribute("review",review);
model.addAttribute("reviewList",reviewList);
model.addAttribute("likeInfo",likeInfo);
model.addAttribute("like", like);
url = "review/reviewView";
}else {
if(referer == null) { //이전 요청주소가 없는 경우
url = "redirect:../list";
}else {
url="redirect:"+referer;
}
ra.addFlashAttribute("swalicon","error");
ra.addFlashAttribute("swalTitle","존재하지 않는 게시글입니다.");
}
return url;
}
- 게시글 상세 조회
Service
Review selectReview(int boardNo);
ServiceImpl
@Transactional(rollbackFor = Exception.class)
@Override
public Review selectReview(int boardNo) {
Review review = dao.selectReview(boardNo);
if (review != null) {
int result = dao.increaseReadCount(boardNo);
if (result > 0) {
review.setReadCount(review.getReadCount() + 1);
}
}
return review;
}
DAO
public Review selectReview(int boardNo) {
return sqlSession.selectOne("reviewMapper.selectReview",boardNo);
}
Mapper
<select id="selectReview" parameterType="_int" resultMap="review_rm">
SELECT * FROM V_BOARD
WHERE STATUS = 'N'
AND BOARD_NO = #{boardNo}
AND BOARD_CD = '2'
</select>
- 조회 수 증가
DAO
public int increaseReadCount(int boardNo) {
return sqlSession.update("reviewMapper.increaseReadCount", boardNo);
}
Mapper
<select id="increaseReadCount" parameterType="_int">
UPDATE BOARD SET
READ_COUNT = READ_COUNT + 1
WHERE BOARD_NO = #{boardNo}
</select>
- 조회수 TOP3 게시글 조회
Service
List<Review> reviewListTop3();
ServiceImpl
@Override
public List<Review> reviewListTop3() {
return dao.reviewListTop3();
}
DAO
public List<Review> reviewListTop3() {
return sqlSession.selectList("reviewMapper.reviewListTop3");
}
Mapper
<select id="reviewListTop3" resultMap="review_rm">
SELECT * FROM
(SELECT ROWNUM RNUM, R.* FROM
(SELECT * FROM V_BOARD
WHERE STATUS='N'
AND BOARD_CD = '2'
ORDER BY READ_COUNT DESC) R)
WHERE RNUM BETWEEN 1 AND 3
ORDER BY READ_COUNT DESC
</select>
- 조회 수 TOP3 썸네일 조회
Service
List<ReviewAttachment> selectThumbnailList(List<Review> rList);
ServiceImpl
@Override
public List<ReviewAttachment> selectThumbnailList(List<Review> rList) {
return dao.selectThumbnailList(rList);
}
DAO
public List<ReviewAttachment> selectThumbnailList(List<Review> rList) {
return sqlSession.selectList("reviewMapper.selectThumbnailList",rList);
}
Mapper
<select id="selectThumbnailList" parameterType="list" resultMap="attachment_rm">
SELECT * FROM BOARD_FILE
WHERE FILE_LEVEL = 1
AND PARENT_BOARD_NO IN
<foreach collection="list" item="review" open="(" close=")" separator=",">
#{review.boardNo}
</foreach>
</select>
- 좋아요 정보 조회
Service
List<ReviewLike> selectLike(int memberNo);
ServiceImpl
@Override
public List<ReviewLike> selectLike(int memberNo) {
return dao.selectLike(memberNo);
}
DAO
public List<ReviewLike> selectLike(int memberNo) {
return sqlSession.selectList("reviewMapper.selectLike",memberNo);
}
Mapper
<select id="selectLike" parameterType="_int" resultMap="like_rm">
SELECT
BOARD_NO, MEM_NO
FROM BOARD_LIKE
WHERE MEM_NO = #{memberNo}
</select>
- 좋아요 여부 조회
Service
int selectLikePushed(Map<String, Integer> map);
ServiceImpl
@Override
public int selectLikePushed(Map<String, Integer> map) {
return dao.selectLikePushed(map);
}
DAO
public int selectLikePushed(Map<String, Integer> map) {
return sqlSession.selectOne("reviewMapper.selectLikePushed",map);
}
Mapper
<select id="selectLikePushed" parameterType="map" resultType="_int">
SELECT COUNT(*) FROM BOARD_LIKE
WHERE MEM_NO = #{memberNo}
AND BOARD_NO = #{boardNo}
</select>
- 데이터 화면에 뿌려주기
CSS
<style>
.boardInfo {
display: inline-block;
margin-right: 15px;
}
.image {
width: 30px;
height: 30px;
}
/* 좋아요/댓글 */
.viewArea, .replyArea {
display: inline-block;
font-size: 11px;
margin-right: 5px;
}
#likeBtn {
border: 0px solid #ddd;
background-color: rgba(255, 255, 255, 0);
}
.likeCnt {
color: #6c757d;
}
.like {
background-image: url('${contextPath}/resources/img/like2.png');
background-repeat: no-repeat;
}
.like2 {
background-size : 15px;
background-image: url('${contextPath}/resources/images/like2.png');
background-repeat: no-repeat;
}
.like3 {
background-size : 11px;
background-image: url('${contextPath}/resources/images/like2.png');
background-repeat: no-repeat;
}
/* TOP3 출력 */
body {
background: #f4f4f4;
}
.boardName {
margin-right: 40px;
}
.card-img-top {
height: 15rem;
}
.categoryArea, .arrayArea {
display: inline-block;
}
.category, .array {
text-decoration: none;
color: black;
line-height: 54px;
margin-right: 5px;
}
/* 제목 */
.text-dark {
display: block;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-weight: bold;
}
/* 좋아요/댓글 */
.viewArea, .replyArea {
display: inline-block;
font-size: 11px;
margin-right: 5px;
}
.nickNameArea {
clear: both;
}
.icon {
width: 13px;
}
/* 인기게시글 */
.viewdetail:hover {
cursor: pointer;
}
/******* 페이징 *******/
.flex {
-webkit-box-flex: 1;
-ms-flex: 1 1 auto;
flex: 1 1 auto
}
#page-content {
margin-top: 20px;
}
.pagination, .jsgrid .jsgrid-pager {
display: flex;
padding-left: 0;
list-style: none;
border-radius: 0.25rem
}
.page-item>a, .page-item>a:hover {
color: black;
}
.pagination.pagination-rounded-flat .page-item {
margin: 0 .25rem
}
.pagination-success .page-item.active .page-link {
background: #00c689;
border-color: #00c689
}
.pagination.pagination-rounded-flat .page-item .page-link {
border: none;
border-radius: 50px;
}
</style>
JSP
- 목록으로 주소 조합
<c:set var="referer" value="${header.referer}" />
<c:set var="a" value="${fn:indexOf(referer,'/')}" />
<c:set var="l" value="${fn:length(referer)}" />
<c:set var="referer" value="${fn:substring(referer, a+2, l)}" />
<c:set var="a" value="${fn:indexOf(referer,'/')}" />
<c:set var="l" value="${fn:length(referer)}" />
<c:set var="referer" value="${fn:substring(referer, a, l-1)}" />
<c:if test="${referer == contextPath}">
<c:set var="returnListURL" value="list" />
</c:if>
- 목록 버튼, 본인의 게시글이 아닐 경우 신고 버튼
<span class="bn" style="visibility: hidden">${review.boardNo}</span>
<a type="button" class="btn btn-primary ml-2 returnBtn maincolor" href="${returnListURL }" >목록</a>
<c:if test="${loginMember.memberNo != review.memberNo }">
<button type="button" class="btn btn-primary ml-2 report maincolor">
신고
</button>
</c:if>
- 카테고리, 제목
<h2 style="margin-top: 5px;">
<div class='badge badge-danger px-3 rounded-pill font-weight-normal' style='
<c:if test="${review.categoryCode == '21'}">background-color: burlywood;</c:if>
<c:if test="${review.categoryCode == '22'}">background-color: #8dbe88;</c:if>
<c:if test="${review.categoryCode == '23'}">background-color: #5d8eb6d5;</c:if>
<c:if test="${review.categoryCode == '24'}">background-color: #d48a9a;</c:if> '>${review.categoryName }</div>
${review.boardTitle }
</h2>
- 아이콘, 닉네임
<div class="boardInfo" id="writer" >
<c:if test="${review.memeberGrade=='F' }">
<img class="image" src="${contextPath}/resources/images/grade1.png"/>
</c:if>
<c:if test="${review.memeberGrade=='S' }">
<img class="image" src="${contextPath}/resources/images/grade2.png" />
</c:if>
<c:if test="${review.memeberGrade=='T' }">
<img class="image" src="${contextPath}/resources/images/grade3.png" />
</c:if>
${review.nickName }
</div>
- 작성일 (오늘이면 시간, 오늘이 아니면 날짜)
<div class="boardInfo" id="createDt" style="color: gray">
<jsp:useBean id="now" class="java.util.Date" />
<fmt:formatDate var="createDate" value="${review.createDate }" pattern="yyyy-MM-dd" />
<fmt:formatDate var="today" value="${now }" pattern="yyyy-MM-dd" />
<c:choose>
<c:when test="${createDate != today }">
${createDate }
</c:when>
<c:otherwise>
<fmt:formatDate value="${review.createDate}" pattern="HH:mm" />
</c:otherwise>
</c:choose>
</div>
- 조회 수, 좋아요 수
좋아요 버튼의 이미지는 좋아요 여부의 반환값이 1인 경우 class에 like2를 추가해준다.
<div class="infoArea float-right">
<i class="far fa-eye"></i> ${review.readCount }
<!-- 좋아요 -->
<span>
<button type="button" id="likeBtn" class="likeBtns" >
<img src="${contextPath}/resources/images/like1.png"
width="15" height="15" id="heart" class='likeImgs
<c:if test="${like == 1}">like2</c:if>'>
<span class="likeCnt">${review.likeCount}</span>
</button> </span>
</div>
- 좋아요 클릭 시 상태에 따라 증가,감소 AJAX
좋아요 버튼을 클릭 할 경우 AJAX를 통해 비동기적으로 좋아요 상태를 변경해준다.
만약 크래스 배열 중 1번째 인덱스의 값이 like2라면 (좋아요가 눌러져 있는 경우) like1로 지정되어 있던 클래스 이름을 like2로 대입한다
만약 클래스가 like2가 아닌 경우 클릭시 좋아요 증가 메서드를 실행
만약 클래스가 like2인 경우 클릭 시 좋아요 감소 메서드를 실행
<script>
$(".likeBtns").on("click", function(){
var boardNo = Number($(this).parents('.no').prev().find("span.bn").text());
var likeClassArray = $(this).children().attr('class').split(" ");
var likeClass = "like1";
var likeImg = $(this).children(".likeImgs");
var likeCnt = $(this).children(".likeCnt");
if(likeClassArray[1] == "like2") {
likeClass = "like2";
}
if(!$(this).children("img").hasClass("like2")) {
$.ajax({
url : "increaseLike",
type : "post",
data : {"boardNo" : boardNo},
success : function(result){
if(result > 0) {
likeCnt.text(Number(likeCnt.text()) + 1);
likeImg.toggleClass("like2");
}
},
error : function(result){
console.log("ajax 통신 오류 발생");
}
});
} else{
$.ajax({
url : "decreaseLike",
type : "post",
data : {"boardNo" : boardNo},
success : function(result){
if(result > 0){ // 삭제 성공
likeCnt.text(Number(likeCnt.text()) - 1);
likeImg.removeClass("like2");
}
},
error : function(result){
console.log("ajax 통신 오류 발생");
}
});
}
});
</script>
- 좋아요 증가 AJAX
Controller
@ResponseBody
@RequestMapping("increaseLike")
public int increaseLike(@RequestParam("boardNo") int boardNo, @ModelAttribute(name="loginMember", binding=false) Member loginMember) {
int memberNo = loginMember.getMemberNo();
Map<String, Object> map = new HashMap<String,Object>();
map.put("memberNo", memberNo);
map.put("boardNo", boardNo);
int result = service.increaseLike(map);
return result;
}
Service
int increaseLike(Map<String, Object> map);
ServiceImpl
@Transactional(rollbackFor = Exception.class)
@Override
public int increaseLike(Map<String, Object> map) {
return dao.increaseLike(map);
}
DAO
public int increaseLike(Map<String, Object> map) {
return sqlSession.insert("reviewMapper.increaseLike", map);
}
Mapper
<insert id="increaseLike" parameterType="map">
INSERT INTO BOARD_LIKE
VALUES (#{memberNo},#{boardNo})
</insert>
- 좋아요 감소 AJAX
Controller
@ResponseBody
@RequestMapping("decreaseLike")
public int decreaseLike(@RequestParam("boardNo") int boardNo,
@ModelAttribute("loginMember") Member loginMember) {
Map<String, Object> map = new HashMap<String, Object>();
map.put("memberNo", loginMember.getMemberNo());
map.put("boardNo", boardNo);
int result = service.decreaseLike(map);
return result;
}
Service
int decreaseLike(Map<String, Object> map);
ServiceImpl
@Transactional(rollbackFor = Exception.class)
@Override
public int decreaseLike(Map<String, Object>map) {
return dao.decreaseLike(map);
}
DAO
public int decreaseLike(Map<String, Object> map) {
return sqlSession.delete("reviewMapper.decreaseLike", map);
}
Mapper
<delete id="decreaseLike" parameterType="map">
DELETE FROM BOARD_LIKE
WHERE MEM_NO = #{memberNo}
AND BOARD_NO = #{boardNo}
</delete>
- 게시글 내용
<div class="row">
<div class="col-md-12 contentArea">${review.boardContent }</div>
</div>
- 댓글 JSP 연결
<jsp:include page="reviewReply.jsp"/>
- 수정,삭제 버튼
<c:if test="${loginMember.memberNo == review.memberNo }">
<div class="row float-right mt-3">
<div class="col-md-12">
<div class="row">
<div class="col-md-12">
<button type="button" id="updateBtn" class="btn btn-success maincolor-re">수정</a>
<button type="button" id="deleteBtn" class="btn btn-danger maincolor-re">삭제</button>
</div>
</div>
</div>
</div>
</c:if>
<>
$("#deleteBtn").on("click", function(){
if(confirm("삭제 하시겠습니까?")){
location.href = "${contextPath}/review/${review.boardNo}/delete";
}
});
$("#updateBtn").on("click",function(){
location.href= "${contextPath}/review/${review.boardNo}/update";
});
</>
- 목록으로 버튼
<div class="row py-3" style="clear: both;">
<div class="col-md-12 text-center ">
<c:if test="${empty sessionScope.returnListURL }">
<c:set var="returnListURL" value="../" scope="session" />
</c:if>
<a type="button" class="btn btn-success returnBtn maincolor" href="${returnListURL }" style="width: 100px; height: 40px;" >목록으로</a>
</div>
</div>
<script>
$(".returnBtn").on("click", function(){
location.href = "${sessionScope.returnListURL}"
});
<script>
- TOP3 게시글
<h7 style="font-weight:bold;">싱글이의 영수증 인기 게시글</h7>
<hr>
<div class="row" style="margin-bottom: 25px;">
<c:if test="${!empty reviewList }">
<c:forEach var="review" items="${reviewList}" varStatus="vs">
<!-- Gallery item -->
<div class="col-xl-4 col-lg-4 col-md-6 mb-4">
<div class="bg-white rounded shadow-sm viewdetail">
<!-- 썸네일 영역 -->
<div class="embed-responsive embed-responsive-4by3">
<c:set var="flag" value="true" />
<c:forEach var="thumbnail" items="${thList}">
<c:if test="${review.boardNo == thumbnail.parentBoardNo }">
<img src="${contextPath}${thumbnail.filePath}/${thumbnail.fileName}" class="img-fluid card-img-top embed-responsive-item">
<c:set var="flag" value="false" />
</c:if>
</c:forEach>
<c:if test="${flag=='true'}">
<img src="${contextPath}/resources/images/ReviewNonImages.png" class="img-fluid card-img-top embed-responsive-item">
</c:if>
</div>
<div class="p-4">
<h5>
<a class="text-dark">${review.boardTitle }</a>
</h5>
<div class="infoArea">
<div class="viewArea float-left">
<jsp:useBean id="now2" class="java.util.Date" />
<fmt:formatDate var="createDate" value="${review.createDate }" pattern="yyyy-MM-dd" />
<fmt:formatDate var="today" value="${now2 }" pattern="yyyy-MM-dd" />
<c:choose>
<c:when test="${createDate != today }">
${createDate }
</c:when>
<c:otherwise>
<fmt:formatDate value="${review.createDate}" pattern="HH:mm" />
</c:otherwise>
</c:choose>
</div>
<div class="viewArea mb-2 float-right">
<img class="icon" src="${contextPath}/resources/images/view.png" /> ${review.readCount }
<span>
<img src="${contextPath}/resources/images/like1.png"
width="11" height="11" id="heart" class='likeImgs
<c:forEach var="like" items="${likeInfo}">
<c:if test="${like.boardNo == review.boardNo}">like3</c:if>
</c:forEach>'>
<span class="likeCnt" style="font-size:12px;">${review.likeCount}</span>
</button>
</span>
</div>
</div>
<div class="nickNameArea d-flex align-items-center justify-content-between rounded-pill bg-light px-3 py-2 mt-4">
<p class="small mb-0">
<span class="font-weight-bold price">${review.nickName }</span>
</p>
<div class='badge badge-danger px-3 rounded-pill font-weight-normal' style='
<c:if test="${review.categoryCode == '21'}">
background-color: burlywood;
</c:if>
<c:if test="${review.categoryCode == '22'}">
background-color: #8dbe88;
</c:if>
<c:if test="${review.categoryCode == '23'}">
background-color: #5d8eb6d5;
</c:if>
<c:if test="${review.categoryCode == '24'}">
background-color: #d48a9a;
</c:if>
'>${review.categoryName }
</div>
</div>
</div>
<span id="boardNo" style="visibility: hidden">
${review.boardNo }
</span>
</div>
</div>
</c:forEach>
</c:if>
</div>
<>
$(".viewdetail").on("click",function(){
var boardNo = $(this).children("span#boardNo").text();
var boardViewURL = "${contextPath}/review/"+boardNo;
location.href = boardViewURL;
});
</>
공유하기
Twitter Google+ LinkedIn
댓글남기기