[세미프로젝트] 9월 23~28일 구현

hanahana·2022년 10월 2일
0
post-thumbnail

일주일동안 구현 과정을 올릴 시간이 없었다, 심지어 주말에도 구현과정을 올릴 시간이 나지 않을정도로 바빴다.

그래도 그 전주에는 30분정도 짬을 내서 지금까지 한 구현을 정리할수있었는데….

어쨌든 세미 프로젝트 기간은 종료했고 결과적으로는 원하던 기능과 반응형 구현에 성공해서 매우 만족스럽다.

구현하려던 기능

내가 맡은 기능은 다음과 같다

  1. 레시피 등록
  2. 레시피 수정
  3. 레시피 삭제
  4. 레시피 추천
  5. 레시피 열람
  6. 레시피 댓글
  7. Q&A 작성
  8. Q&A 수정,삭제
  9. Q&A 댓글
  10. Q&A 목록
  11. Q&A 열람
  12. 맡은 기능의 반응형

이었다. 일단 내가 맡은 기능은 전부 이상없이 정상작동했고 그동안 블로그에 갱신하지 않았던 기능들만 간단하게 작성해둘까 한다.

23일 구현

  1. 상세 레시피 창에서 관련 카테고리 추천 레시피 출력하기
  2. 상세 레시피 클릭하면 조횟수 올라가게 하기
  3. 레시피 추천하기
  4. 레시피 추천 취소하기
  5. 댓글 페이징하기
  6. 이미지 저장이 다른 폴더로 되는것 수정
  7. 작성자에 닉네임이 나올수있도록 수정

24일 구현

  1. 모든 기능에 로그인 체크하기
  2. 모든 jsp파일에 세션체크해서 로그인하지 않으면 사용할수 없는 기능 막기

25일 구현

없음!! HTML CSS 과제하다가 밤샘!

이건 따로 정리할예정

26일 구현

  1. 팀원들과 깃허브 합치기
  2. 헤더 푸터 적용하기

27일 구현

  1. 팀원들이 만든 기능 jsp에 링크 추가하기
  2. 시퀀스 다이어그램 작업

28일 구현

  1. 레시피 작성할때마다 포인트 추가하기
  2. 시퀀스 다이어그램 작업하기

구현 작업했던 작업내역

상세 레시피

상세 레시피 jsp

<section style="margin: 0 auto;">
		<span id="list-icon-area"> <svg onclick="list();"
				id="list-icon" xmlns="http://www.w3.org/2000/svg" width="50"
				height="50" fill="currentColor" class="bi bi-arrow-left-circle-fill"
				viewBox="0 0 16 16">
  <path
					d="M8 0a8 8 0 1 0 0 16A8 8 0 0 0 8 0zm3.5 7.5a.5.5 0 0 1 0 1H5.707l2.147 2.146a.5.5 0 0 1-.708.708l-3-3a.5.5 0 0 1 0-.708l3-3a.5.5 0 1 1 .708.708L5.707 7.5H11.5z" />
	</svg>
		</span>

		<div class=" container-lg">

			<div id="imgDiv" class="" style="">
				<img id="mainImg"
					src="/resources/recipeImg/${recipe.mainPicRename }"
					class="img-fluid" alt="...">

			</div>
			<div id="title" class="py-2 row">
				<h1>${recipe.recipeName }</h1>
				<!--  해쉬태그 영역 -->
				<div id="hashtag" class="ps-5 col-md-10">
					<h5>
						<c:if test="${rTag.jmt }">
									#jmt   
									</c:if>
						<c:if test="${rTag.healthy }">
									#건강한 
										</c:if>
						<c:if test="${rTag.goodSpicy }">
									#맛있게 매운 
										</c:if>
						<c:if test="${rTag.full }">
									#든든한 
										</c:if>
						<c:if test="${rTag.soSpicy }">
									#아주 매운 
										</c:if>
						<c:if test="${rTag.sweet }">
									#달콤한 
										</c:if>
						<c:if test="${rTag.easy }">
									#간편한
										</c:if>
						<c:if test="${rTag.party }">
									#파티용 
										</c:if>
					</h5>

				</div>
				<!-- 해쉬태그 영역종료 -->

				<div id="button-area" class="col-md-2">
					<c:if test="${loginUser.memberEmail==recipe.memberEmail || loginUser.adminCheck==true }">
					<!-- 버튼영역 -->
					<button class="btn btn-primary"
						onclick="location.href='/recipe/modifyForm.do?recipeNo=${recipe.recipeNo }';">수정</button>
					<button class="btn btn-primary"
						onclick="removeRecipe(${recipe.recipeNo });">삭제</button>
					</c:if>
				</div>
				<div id="info-area">${recipe.recipeInfo }</div>

			</div>
			<!-- 타이틀 영역 -->
			<hr>

			<div class="col-md-12 m-0 row">
				<!--  아티클 전체 들어감-->
				
				
				
					<!-- 레시피 왼쪽 영역 (반응형을 위한영역 pc에선 안보임) -->
				<div class="col-md-4 m-0 d-sm-none d-block" id="article4">
					<article>
						<div id="material-area" class="m-3">
							<h4 style="text-align: center">레시피 재료</h4>
							<ul>
								<c:forEach items="${rmList}" var="rmList">
									<li>재료: ${rmList.material}, 수량 : ${rmList.amount}
								</c:forEach>
							</ul>
							<hr>
						</div>
						<div id="recipe-time-area" class="m-3" style="text-align: center">
							<h4>조리 시간</h4>
							${recipe.recipeTime }
							<hr>
						</div>
						<div id="other-recipe-area">
							<h4 style="text-align: center">추천 레시피</h4>
							<!-- 추천레시피 출력영역 -->
							<div id="recommand-area">
								<c:forEach items="${recoList}" var="recoList" varStatus="i" begin="1" end="3">

									<div class="card col-md-3 m-3" style="width: 80%;">
										<div class="img-area" id="normal-img-area">
											<img src="/resources/recipeImg/${recoList.mainPicRename }"
												class="card-img-top" alt="">
										</div>
										<div class="card-body">
											<p class="card-text">
												<a href="/recipe/detail.do?recipeNo=${recoList.recipeNo }">${recoList.recipeName }</a>
											</p>
											
										</div>
									</div>

								</c:forEach>

							</div>
							<!-- 추천 레시피 영역 종료 -->
						</div>

					</article>
				</div><!-- 오른쪽 영역 종료 -->
				
				
				
				
				
				
				
				
				
				<div class="col-md-8" id="article1">
					<article>

						<!-- 작성자 영역 -->
						<div id="wirter-area" class="col-md-12">
							<h5>
								작성자 : ${name }
								
							<c:if test="${loginUser !=null }"> <!-- 로그인시에만 보임 -->
								<button class="btn btn-danger" onclick="location.href='/report/add?recipeNo=${recipe.recipeNo }'">신고</button>
								</c:if>
								

							</h5>
						</div>
						<!-- 작성자 영역종료 -->

						<!-- 비디오 영역 -->
						<div id="youtube-area" class="col-md-12 p-3">
							<!-- 비디오 주소를 입력했을때만-->
							<c:if test="${recipe.recipeVideo ne null }">
								<iframe width="100%" height="400em" src="${recipe.recipeVideo}"
									title="YouTube video player" frameborder="0"
									allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
									allowfullscreen></iframe>
							</c:if>
						</div>

						<!--레시피 순서영역 -->
						<div id="step-area" class="col-md-12 row">
						<c:forEach items="${rsList }" var="rsList">
						<div class="row m-2" id="step-one-area">
						<div class="col-md-6"> 
								<c:if test="${rsList.recipePicRename ne null }">
									<img id="step-img"
										src="/resources/recipeImg/${rsList.recipePicRename }">
									<br>
								</c:if>
						   </div>
						   <div class="col-md-6" id="step-img-area">
								<p>${rsList.recipeDescription }</p>
						   </div>
						   
						</div>
						<c:if test="${rsList.recipePicRename ne null || rsList.recipeDescription eq ''}">
						   <hr>
						   </c:if>
							

							</c:forEach>
						</div>
						<!-- 순서영역 종료 -->

						<!-- 추천, 나만의 레시피 이이콘 영역 -->
						<div id="recom-bookm-area" class="my-2 row">
						<!-- 추천을 하지 않았을때는 검은색 추천을 했다면 빨간 아이콘 -->
						
						
						
						
						<!-- 추천 아이콘 -->
						<c:if test="${loginUser != null }">
						
						
						<c:if test="${recodCheck == false }">
							<div id="Black-heart" class="p-3 p3 col-6">
	
							<form action="/recipe/recommand.do" method="get">
							<input type="hidden" name="memberEmail" value="${loginUser.memberEmail }">
							<input type="hidden" name="recipeNo" value="${recipe.recipeNo}">
							<label for="recommandButton">
								<svg xmlns="http://www.w3.org/2000/svg" width="60" height="60"
									fill="black" class="bi bi-chat-heart" viewBox="0 0 16 16">
						  <path fill-rule="evenodd"
										d="M2.965 12.695a1 1 0 0 0-.287-.801C1.618 10.83 1 9.468 1 8c0-3.192 3.004-6 7-6s7 2.808 7 6c0 3.193-3.004 6-7 6a8.06 8.06 0 0 1-2.088-.272 1 1 0 0 0-.711.074c-.387.196-1.24.57-2.634.893a10.97 10.97 0 0 0 .398-2Zm-.8 3.108.02-.004c1.83-.363 2.948-.842 3.468-1.105A9.06 9.06 0 0 0 8 15c4.418 0 8-3.134 8-7s-3.582-7-8-7-8 3.134-8 7c0 1.76.743 3.37 1.97 4.6a10.437 10.437 0 0 1-.524 2.318l-.003.011a10.722 10.722 0 0 1-.244.637c-.079.186.074.394.273.362a21.673 21.673 0 0 0 .693-.125ZM8 5.993c1.664-1.711 5.825 1.283 0 5.132-5.825-3.85-1.664-6.843 0-5.132Z" />				
						</svg></label>
						<input type="submit" style="display:none" id="recommandButton">
						</form>
						
				
								<br>추천<br> ${recipe.recommandCount }
							</div>
						</c:if>
							
							<!-- 추천아이콘 종료 -->
							
							<!-- 추천 취소 아이콘 -->
							
						<c:if test="${recodCheck == true }">
							<div id="heart" class="p-3 p3 col-6">
	
							<form action="/recipe/recoRemove.do" method="get">
							<input type="hidden" name="memberEmail" value="${loginUser.memberEmail }">
							<input type="hidden" name="recipeNo" value="${recipe.recipeNo}">
							<label for="recoRomoveButton">
								<svg xmlns="http://www.w3.org/2000/svg" width="60" height="60"
									fill="red" class="bi bi-chat-heart" viewBox="0 0 16 16">
						  <path fill-rule="evenodd"
										d="M2.965 12.695a1 1 0 0 0-.287-.801C1.618 10.83 1 9.468 1 8c0-3.192 3.004-6 7-6s7 2.808 7 6c0 3.193-3.004 6-7 6a8.06 8.06 0 0 1-2.088-.272 1 1 0 0 0-.711.074c-.387.196-1.24.57-2.634.893a10.97 10.97 0 0 0 .398-2Zm-.8 3.108.02-.004c1.83-.363 2.948-.842 3.468-1.105A9.06 9.06 0 0 0 8 15c4.418 0 8-3.134 8-7s-3.582-7-8-7-8 3.134-8 7c0 1.76.743 3.37 1.97 4.6a10.437 10.437 0 0 1-.524 2.318l-.003.011a10.722 10.722 0 0 1-.244.637c-.079.186.074.394.273.362a21.673 21.673 0 0 0 .693-.125ZM8 5.993c1.664-1.711 5.825 1.283 0 5.132-5.825-3.85-1.664-6.843 0-5.132Z" />				
						</svg></label>
						<input type="submit" style="display:none" id="recoRomoveButton">
						</form>
						
				
								<br>추천 취소<br> ${recipe.recommandCount }
							</div>
							</c:if>
							
							</c:if>
							<!-- 추천취소 아이콘 종료 -->
							
							<!-- //로그인 안했을때 보이는 추천 아이콘 -->
							<c:if test="${loginUser == null }">
							<div id="non-login-icon-heart" class="p-3 p3 col-6">
							<label for="recoRomoveButton">
								<svg xmlns="http://www.w3.org/2000/svg" width="60" height="60"
									fill="red" class="bi bi-chat-heart" viewBox="0 0 16 16">
						  <path fill-rule="evenodd"
										d="M2.965 12.695a1 1 0 0 0-.287-.801C1.618 10.83 1 9.468 1 8c0-3.192 3.004-6 7-6s7 2.808 7 6c0 3.193-3.004 6-7 6a8.06 8.06 0 0 1-2.088-.272 1 1 0 0 0-.711.074c-.387.196-1.24.57-2.634.893a10.97 10.97 0 0 0 .398-2Zm-.8 3.108.02-.004c1.83-.363 2.948-.842 3.468-1.105A9.06 9.06 0 0 0 8 15c4.418 0 8-3.134 8-7s-3.582-7-8-7-8 3.134-8 7c0 1.76.743 3.37 1.97 4.6a10.437 10.437 0 0 1-.524 2.318l-.003.011a10.722 10.722 0 0 1-.244.637c-.079.186.074.394.273.362a21.673 21.673 0 0 0 .693-.125ZM8 5.993c1.664-1.711 5.825 1.283 0 5.132-5.825-3.85-1.664-6.843 0-5.132Z" />				
						</svg></label>
							<br>추천<br> ${recipe.recommandCount }
							</div>
							</c:if>
							
							
							
							<!-- 나만의 레시피 아이콘 -->
							<!-- 로그인시 -->
							<c:if test="${loginUser != null }">
							
							
							<c:if test="${checkMyrecipe == false}" >
							<div id="star" class="p-3 p3 col-6">

							<label for=""><a href="/myRecipe/add?recipeNo=${recipe.recipeNo}&recipeName=${recipe.recipeName } ">

								<svg xmlns="http://www.w3.org/2000/svg" width="60" height="60"
									fill="orange" class="bi bi-star" viewBox="0 0 16 16">
						  <path
										d="M2.866 14.85c-.078.444.36.791.746.593l4.39-2.256 4.389 2.256c.386.198.824-.149.746-.592l-.83-4.73 3.522-3.356c.33-.314.16-.888-.282-.95l-4.898-.696L8.465.792a.513.513 0 0 0-.927 0L5.354 5.12l-4.898.696c-.441.062-.612.636-.283.95l3.523 3.356-.83 4.73zm4.905-2.767-3.686 1.894.694-3.957a.565.565 0 0 0-.163-.505L1.71 6.745l4.052-.576a.525.525 0 0 0 .393-.288L8 2.223l1.847 3.658a.525.525 0 0 0 .393.288l4.052.575-2.906 2.77a.565.565 0 0 0-.163.506l.694 3.957-3.686-1.894a.503.503 0 0 0-.461 0z" />					
						</svg></a></label>
								<br>나만의 레시피
							</div>
							</c:if>
						<!-- 나만의 레시피 아이콘 종료 -->
						
							<!-- 나만의 레시피취소 아이콘 -->
							<c:if test="${checkMyrecipe}" >
							<div id="star" class="p-3 p3 col-6">
							<label for=""><a href="/myRecipe/remove?recipeNo=${recipe.recipeNo} ">
								<svg xmlns="http://www.w3.org/2000/svg" width="60" height="60"
									fill="orange" class="bi bi-star" viewBox="0 0 16 16">
						    <path d="M3.612 15.443c-.386.198-.824-.149-.746-.592l.83-4.73L.173 6.765c-.329-.314-.158-.888.283-.95l4.898-.696L7.538.792c.197-.39.73-.39.927 0l2.184 4.327 4.898.696c.441.062.612.636.282.95l-3.522 3.356.83 4.73c.078.443-.36.79-.746.592L8 13.187l-4.389 2.256z"/>
						</svg></a></label>
								<br>나만의 레시피 취소
							</div>
							</c:if>
						<!-- 나만의 레시피 아이콘 취소 종료 -->
						</c:if>
						<!-- 로그인시 종료 -->
						
						
						<!-- 로그인 안했을시 나만의 레시피 아이콘 -->
						<c:if test="${loginUser == null }">
							<div id="star" class="p-3 p3 col-6">
							<label for="">
								<svg xmlns="http://www.w3.org/2000/svg" width="60" height="60"
									fill="orange" class="bi bi-star" viewBox="0 0 16 16">
						    <path d="M3.612 15.443c-.386.198-.824-.149-.746-.592l.83-4.73L.173 6.765c-.329-.314-.158-.888.283-.95l4.898-.696L7.538.792c.197-.39.73-.39.927 0l2.184 4.327 4.898.696c.441.062.612.636.282.95l-3.522 3.356.83 4.73c.078.443-.36.79-.746.592L8 13.187l-4.389 2.256z"/>
						</svg></label>
								<br>나만의 레시피
							</div>
						
						
						</c:if>
						
						
						
						
						</div>
						<!-- 추천, 나만의 레시피 이이콘 영역 종료 -->

					</article>
				</div>
				<!-- 아티클1 영역 종료 -->

				<!-- 레시피 오른쪽 영역 -->
				<div class="col-md-4 m-0 d-sm-block d-none" id="article2">
					<article>
						<div id="material-area" class="m-3">
							<h4 style="text-align: center">레시피 재료</h4>
							<ul>
								<c:forEach items="${rmList}" var="rmList">
									<li>재료: ${rmList.material}, 수량 : ${rmList.amount}
								</c:forEach>
							</ul>
							<hr>
						</div>
						<div id="recipe-time-area" class="m-3" style="text-align: center">
							<h4>조리 시간</h4>
							${recipe.recipeTime }
							<hr>
						</div>
						<div id="other-recipe-area">
							<h4 style="text-align: center">추천 레시피</h4>
<!-- 추천레시피 출력영역 -->
							<div id="recommand-area">
								<c:forEach items="${recoList}" var="recoList" varStatus="i" begin="1" end="3">

									<div class="card col-md-3 m-3" style="width: 80%;">
										<div class="img-area" id="normal-img-area">
											<img src="/resources/recipeImg/${recoList.mainPicRename }"
												class="card-img-top" alt="">
										</div>
										<div class="card-body">
											<p class="card-text">
												<a href="/recipe/detail.do?recipeNo=${recoList.recipeNo }">${recoList.recipeName }</a>
											</p>
											
										</div>
									</div>

								</c:forEach>

							</div>
							<!-- 추천 레시피 영역 종료 -->
						</div>

					</article>
				</div><!-- 오른쪽 영역 종료 -->
			</div>

			<article id="reply-area">
				<div id="article3-area">
					<hr>

					<!-- 코멘트 출력영역 시작 -->
					<c:forEach items="${rcList}" var="rcList">
						<!-- 코멘트 한개 출력 -->
						<div id="oneComment">
							<div id="comment" class="row my-2">
								<div id="comment-picture" class="col-md-2 d-none d-md-inline">
									<!-- 코맨트 사진영역 -->

									<svg xmlns="http://www.w3.org/2000/svg" width="80%" height="80%" fill="currentColor"
										class="bi bi-person-bounding-box" viewBox="0 0 16 16">
				  					<path
											d="M1.5 1a.5.5 0 0 0-.5.5v3a.5.5 0 0 1-1 0v-3A1.5 1.5 0 0 1 1.5 0h3a.5.5 0 0 1 0 1h-3zM11 .5a.5.5 0 0 1 .5-.5h3A1.5 1.5 0 0 1 16 1.5v3a.5.5 0 0 1-1 0v-3a.5.5 0 0 0-.5-.5h-3a.5.5 0 0 1-.5-.5zM.5 11a.5.5 0 0 1 .5.5v3a.5.5 0 0 0 .5.5h3a.5.5 0 0 1 0 1h-3A1.5 1.5 0 0 1 0 14.5v-3a.5.5 0 0 1 .5-.5zm15 0a.5.5 0 0 1 .5.5v3a1.5 1.5 0 0 1-1.5 1.5h-3a.5.5 0 0 1 0-1h3a.5.5 0 0 0 .5-.5v-3a.5.5 0 0 1 .5-.5z" />
				  					<path
											d="M3 14s-1 0-1-1 1-4 6-4 6 3 6 4-1 1-1 1H3zm8-9a3 3 0 1 1-6 0 3 3 0 0 1 6 0z" />
									</svg>

								</div>
								<!-- 코멘트 사진 영역 종료 -->

								<div id="commnet-contens" class="col-md-10">
									<!-- 코멘트 내용 영역 -->
									<div
										class="shadow-lg p-3 mb-5 bg-body rounded mt-4 text-justify">
										<div id="comment-row" class="row">
											<div id="comment-writer" class="col-md-10">
												<h4>${rcList.memberName }</h4>
											</div>
											<div id="comment-button" class="col-md-2" style="text-align: right">
												 
												 <!--  신고 로그인시에만 보임 -->
												 <c:if test= "${loginUser != null }"> 
												 <a href="/report/addComment?commentNo=${rcList.commentNo}">
												신고
												 </a>
												 </c:if> 
												
												</div>

										</div>
										<div id="comment-text-area">
											<span>${rcList.commentDate }</span> <br>
											<p>${rcList.commentContents }</p>
										</div>
										<div id="comment-delmodi-buttom-area"
											style="text-align: right">
											
											<!-- 관리자 작성자만 보임 -->
											<c:if test= "${loginUser != null }">
											<c:if test="${(loginUser.memberEmail == rcList.memberEmail)&& loginUser.adminCheck==false}">
											<button type="button" onclick="modifyViewOn(this);"
												class="btn btn-outline-primary">수정</button>
											<button
												onclick="removeComment(${rcList.commentNo},${rcList.recipeNo} );"
												class="btn btn-outline-primary">삭제</button>
											
											
											</c:if>
											 <c:if test="${loginUser.adminCheck}"> 
										
											<button type="button" onclick="modifyViewOn(this);"
												class="btn btn-outline-primary">수정</button>
											<button
												onclick="removeComment(${rcList.commentNo},${rcList.recipeNo});"
												class="btn btn-outline-primary">삭제</button>
												
												 </c:if>
												 </c:if>

										</div>
									</div>
								</div>
							</div>
							<!-- 코멘트 내용영역종료 -->
						</div>
						<!-- 코멘트 수정영역 시작 -->
						<div class="modifyView">
							<form action="/recipe/commentModify.do" method="post">
								<div id="comment-modify-area" class="row my-2">
									<input type="hidden" value="${rcList.memberEmail }"
										name="memberEmail"> <input type="hidden"
										value="${rcList.recipeNo }" name="recipeNo"> <input
										type="hidden" value="${rcList.commentNo }" name="commentNo">
									<div id="comment-textarea" class="col-md-11">
										<!-- 세션에서 사용자 id가지고 올것 -->
										<div class="form-floating">
											<textarea name="commentContents" class="form-control"
												placeholder="Leave a comment here" id="floatingTextarea2"
												style="height: 100px">${rcList.commentContents }</textarea>
											<label for="floatingTextarea2">댓글을 등록해주세요</label>
										</div>
									</div>

									<div id="comment-button-area" class="col-md-1">
										<input type="submit" value="수정" style="height: 50%;"
											class="btn btn-outline-primary">
										<button type="button" style="height: 50%;"
											onclick="modifyViewOff(this)"
											class="btn btn-outline-danger my-1">취소</button>
									</div>
								</div>
							</form>
						</div>
						<!-- 코멘트 수정영역 종료 -->

						<!-- 코멘트 출력 영역종료 -->
					</c:forEach>
					<hr>

					<!-- 코멘트 작성영역 -->

				<!-- 로그인 시에만 보임 -->
				 <c:if test="${loginUser != null}"> 
				
					<form action="/recipe/commentWrite.do" method="post">
						<div id="comment-write-area" class="row">
							<input type="hidden" value="${loginUser.memberEmail }" name="memberEmail"> <input
								type="hidden" value="${recipe.recipeNo }" name="recipeNo">
							<div id="comment-textarea" class="col-md-11">
								<!-- 세션에서 사용자 id가지고 올것 -->
								<div class="form-floating">
									<textarea name="commentContents" class="form-control"
										placeholder="Leave a comment here" id="floatingTextarea2"
										style="height: 100px" required="required"></textarea>
									<label for="floatingTextarea2">댓글을 등록해주세요</label>
								</div>
							</div>

							<div id="comment-button-area" class="col-md-1">
								<input type="submit" value="등록" style="height: 100%;"
									class="btn btn-outline-primary">
							</div>

						</div>
						</form>
					 	</c:if> 
						
						<!-- 코멘트 작성영역 종료 -->
						
						
						
						<!-- 코멘트 페이지 영역 -->
							<div id="page-area" style="text-align:center">
							
							
							<div id="app" class="container">
							<ul class="page">
								<!-- 1페이지 아닐때만 -->
								<c:if test="${startNavi ne 1 && startNavi > 0}">
									<li class="page__btn">
									<a href="/recipe/detail.do?recipeNo=${recipe.recipeNo }&page=${startNavi-1 }#reply-area"> < </a>
									</li>
								</c:if>
								
								<c:forEach var="p" begin="${startNavi }" end="${endNavi }">
								
									<c:if test="${currentPage == p}">
										<li class="page__numbers active">${p }</li>
									</c:if>
									<c:if test="${currentPage ne p}">
										<li class="page__numbers"><a
											href="/recipe/detail.do?recipeNo=${recipe.recipeNo }&page=${p }#reply-area">${p }</a></li>
									</c:if>
								</c:forEach>

								<!-- 마지막페이지 아닐때만 -->
								<c:if test="${endNavi < maxPage }">
									<li class="page__btn">
										<a href="/recipe/detail.do?recipeNo=${recipe.recipeNo }&page=${endNavi+1 }#reply-area"> > </a>
										</li>
								</c:if>
							</ul>
						</div>
							
							
							
							
							
							
							</div>
						
						<!-- 코멘트 페이지 영역 종료 -->
					</form>

				</div>
				<!-- 아트클3 에어리어 div종료 -->
			</article>
			<!-- 아티클3 종료 -->

		</div>
		</article>
		<!-- 아티클 전체 들어감 -->

		</div>
		<!-- 메인 내용 폼 전체 들어감 -->
	</section>
  • 레시피 오른쪽영역에 레시피 추천영역에 추천 레시피가 나타날수 있도록 c:forEach 태그를 사용하였다.
    	<div id="other-recipe-area">
    							<h4 style="text-align: center">추천 레시피</h4>
    <!-- 추천레시피 출력영역 -->
    							<div id="recommand-area">
    								<c:forEach items="${recoList}" var="recoList" varStatus="i" begin="1" end="3">
    
    									<div class="card col-md-3 m-3" style="width: 80%;">
    										<div class="img-area" id="normal-img-area">
    											<img src="/resources/recipeImg/${recoList.mainPicRename }"
    												class="card-img-top" alt="">
    										</div>
    										<div class="card-body">
    											<p class="card-text">
    												<a href="/recipe/detail.do?recipeNo=${recoList.recipeNo }">${recoList.recipeName }</a>
    											</p>
    											
    										</div>
    									</div>
    
    								</c:forEach>
    
    							</div>
    							<!-- 추천 레시피 영역 종료 -->
    						</div>
  • 원래는 데이터 베이스에서 조횟수가 높은 3개만 불러들이려고했지만 rownum을 활용한 쿼리문을 정상 인식하지 못했기때문에 begin 과 end를 통해 3개만 출력되도록 하였다.
    • 만약 실제 사이트를 만든다면 이건 모든 데이터베이스를 긁어오기 때문에 적절하지 못한 부분이 있다. 데이터베이스에서 원하는 양만큼 출력하는 적절한 쿼리문을 생각해보는것이 좋을것 같다.

로그인시, 작성자시에만 보이는 버튼

	<div id="button-area" class="col-md-2">
					<c:if test="${loginUser.memberEmail==recipe.memberEmail || loginUser.adminCheck==true }">
					<!-- 버튼영역 -->
					<button class="btn btn-primary"
						onclick="location.href='/recipe/modifyForm.do?recipeNo=${recipe.recipeNo }';">수정</button>
					<button class="btn btn-primary"
						onclick="removeRecipe(${recipe.recipeNo });">삭제</button>
					</c:if>
				</div>
				<div id="info-area">${recipe.recipeInfo }</div>
  • 거의 모든 버튼이 c:if문에 반응하기때문에 대표적인 것 하나만 설명하려고 한다.
  • 수정 삭제 버튼은 loginUser라는 controller에서 저장한 현재 로그인한 유저의 세션이 있을때(이것은 로그인 기능에서 담당하였고 내 담당은 아니기에 손대지 않았다.) 그 로그인한 유저의 memberEmail값이 recipe를쓴 유저의 meberEmail값과 동일할때와 로그인한 유저의 adminCheck값이 true로 현재 로그인한 유저가 관리자인것이 확인될때만 보인다.
    • 이것은 프론트단에서 하는 기능이고 get방식이기때문에 주소로 들어가 수정/삭제하는것을 방지하기 위해 controller의 영역에서 해당기능을 작동시키면 현재 로그인한 사람의 세션이 loginUser의 값을 한번 더 체크하여 로그인한 유저와 레시피를 작성한 유저의 값이 같지 않을때는 오류페이지로 이동하도록 구성되어있다.

레시피 추천, 마이레시피 기능 관련

		<!-- 추천, 나만의 레시피 이이콘 영역 -->
						<div id="recom-bookm-area" class="my-2 row">
						<!-- 추천을 하지 않았을때는 검은색 추천을 했다면 빨간 아이콘 -->
						
						
						
						
						<!-- 추천 아이콘 -->
						<c:if test="${loginUser != null }">
						
						
						<c:if test="${recodCheck == false }">
							<div id="Black-heart" class="p-3 p3 col-6">
	
							<form action="/recipe/recommand.do" method="get">
							<input type="hidden" name="memberEmail" value="${loginUser.memberEmail }">
							<input type="hidden" name="recipeNo" value="${recipe.recipeNo}">
							<label for="recommandButton">
								<svg xmlns="http://www.w3.org/2000/svg" width="60" height="60"
									fill="black" class="bi bi-chat-heart" viewBox="0 0 16 16">
						  <path fill-rule="evenodd"
										d="M2.965 12.695a1 1 0 0 0-.287-.801C1.618 10.83 1 9.468 1 8c0-3.192 3.004-6 7-6s7 2.808 7 6c0 3.193-3.004 6-7 6a8.06 8.06 0 0 1-2.088-.272 1 1 0 0 0-.711.074c-.387.196-1.24.57-2.634.893a10.97 10.97 0 0 0 .398-2Zm-.8 3.108.02-.004c1.83-.363 2.948-.842 3.468-1.105A9.06 9.06 0 0 0 8 15c4.418 0 8-3.134 8-7s-3.582-7-8-7-8 3.134-8 7c0 1.76.743 3.37 1.97 4.6a10.437 10.437 0 0 1-.524 2.318l-.003.011a10.722 10.722 0 0 1-.244.637c-.079.186.074.394.273.362a21.673 21.673 0 0 0 .693-.125ZM8 5.993c1.664-1.711 5.825 1.283 0 5.132-5.825-3.85-1.664-6.843 0-5.132Z" />				
						</svg></label>
						<input type="submit" style="display:none" id="recommandButton">
						</form>
						
				
								<br>추천<br> ${recipe.recommandCount }
							</div>
						</c:if>
							
							<!-- 추천아이콘 종료 -->
							
							<!-- 추천 취소 아이콘 -->
							
						<c:if test="${recodCheck == true }">
							<div id="heart" class="p-3 p3 col-6">
	
							<form action="/recipe/recoRemove.do" method="get">
							<input type="hidden" name="memberEmail" value="${loginUser.memberEmail }">
							<input type="hidden" name="recipeNo" value="${recipe.recipeNo}">
							<label for="recoRomoveButton">
								<svg xmlns="http://www.w3.org/2000/svg" width="60" height="60"
									fill="red" class="bi bi-chat-heart" viewBox="0 0 16 16">
						  <path fill-rule="evenodd"
										d="M2.965 12.695a1 1 0 0 0-.287-.801C1.618 10.83 1 9.468 1 8c0-3.192 3.004-6 7-6s7 2.808 7 6c0 3.193-3.004 6-7 6a8.06 8.06 0 0 1-2.088-.272 1 1 0 0 0-.711.074c-.387.196-1.24.57-2.634.893a10.97 10.97 0 0 0 .398-2Zm-.8 3.108.02-.004c1.83-.363 2.948-.842 3.468-1.105A9.06 9.06 0 0 0 8 15c4.418 0 8-3.134 8-7s-3.582-7-8-7-8 3.134-8 7c0 1.76.743 3.37 1.97 4.6a10.437 10.437 0 0 1-.524 2.318l-.003.011a10.722 10.722 0 0 1-.244.637c-.079.186.074.394.273.362a21.673 21.673 0 0 0 .693-.125ZM8 5.993c1.664-1.711 5.825 1.283 0 5.132-5.825-3.85-1.664-6.843 0-5.132Z" />				
						</svg></label>
						<input type="submit" style="display:none" id="recoRomoveButton">
						</form>
						
				
								<br>추천 취소<br> ${recipe.recommandCount }
							</div>
							</c:if>
							
							</c:if>
							<!-- 추천취소 아이콘 종료 -->
							
							<!-- //로그인 안했을때 보이는 추천 아이콘 -->
							<c:if test="${loginUser == null }">
							<div id="non-login-icon-heart" class="p-3 p3 col-6">
							<label for="recoRomoveButton">
								<svg xmlns="http://www.w3.org/2000/svg" width="60" height="60"
									fill="red" class="bi bi-chat-heart" viewBox="0 0 16 16">
						  <path fill-rule="evenodd"
										d="M2.965 12.695a1 1 0 0 0-.287-.801C1.618 10.83 1 9.468 1 8c0-3.192 3.004-6 7-6s7 2.808 7 6c0 3.193-3.004 6-7 6a8.06 8.06 0 0 1-2.088-.272 1 1 0 0 0-.711.074c-.387.196-1.24.57-2.634.893a10.97 10.97 0 0 0 .398-2Zm-.8 3.108.02-.004c1.83-.363 2.948-.842 3.468-1.105A9.06 9.06 0 0 0 8 15c4.418 0 8-3.134 8-7s-3.582-7-8-7-8 3.134-8 7c0 1.76.743 3.37 1.97 4.6a10.437 10.437 0 0 1-.524 2.318l-.003.011a10.722 10.722 0 0 1-.244.637c-.079.186.074.394.273.362a21.673 21.673 0 0 0 .693-.125ZM8 5.993c1.664-1.711 5.825 1.283 0 5.132-5.825-3.85-1.664-6.843 0-5.132Z" />				
						</svg></label>
							<br>추천<br> ${recipe.recommandCount }
							</div>
							</c:if>
							
							
							
							<!-- 나만의 레시피 아이콘 -->
							<!-- 로그인시 -->
							<c:if test="${loginUser != null }">
							
							
							<c:if test="${checkMyrecipe == false}" >
							<div id="star" class="p-3 p3 col-6">

							<label for=""><a href="/myRecipe/add?recipeNo=${recipe.recipeNo}&recipeName=${recipe.recipeName } ">

								<svg xmlns="http://www.w3.org/2000/svg" width="60" height="60"
									fill="orange" class="bi bi-star" viewBox="0 0 16 16">
						  <path
										d="M2.866 14.85c-.078.444.36.791.746.593l4.39-2.256 4.389 2.256c.386.198.824-.149.746-.592l-.83-4.73 3.522-3.356c.33-.314.16-.888-.282-.95l-4.898-.696L8.465.792a.513.513 0 0 0-.927 0L5.354 5.12l-4.898.696c-.441.062-.612.636-.283.95l3.523 3.356-.83 4.73zm4.905-2.767-3.686 1.894.694-3.957a.565.565 0 0 0-.163-.505L1.71 6.745l4.052-.576a.525.525 0 0 0 .393-.288L8 2.223l1.847 3.658a.525.525 0 0 0 .393.288l4.052.575-2.906 2.77a.565.565 0 0 0-.163.506l.694 3.957-3.686-1.894a.503.503 0 0 0-.461 0z" />					
						</svg></a></label>
								<br>나만의 레시피
							</div>
							</c:if>
						<!-- 나만의 레시피 아이콘 종료 -->
						
							<!-- 나만의 레시피취소 아이콘 -->
							<c:if test="${checkMyrecipe}" >
							<div id="star" class="p-3 p3 col-6">
							<label for=""><a href="/myRecipe/remove?recipeNo=${recipe.recipeNo} ">
								<svg xmlns="http://www.w3.org/2000/svg" width="60" height="60"
									fill="orange" class="bi bi-star" viewBox="0 0 16 16">
						    <path d="M3.612 15.443c-.386.198-.824-.149-.746-.592l.83-4.73L.173 6.765c-.329-.314-.158-.888.283-.95l4.898-.696L7.538.792c.197-.39.73-.39.927 0l2.184 4.327 4.898.696c.441.062.612.636.282.95l-3.522 3.356.83 4.73c.078.443-.36.79-.746.592L8 13.187l-4.389 2.256z"/>
						</svg></a></label>
								<br>나만의 레시피 취소
							</div>
							</c:if>
						<!-- 나만의 레시피 아이콘 취소 종료 -->
						</c:if>
						<!-- 로그인시 종료 -->
						
						
						<!-- 로그인 안했을시 나만의 레시피 아이콘 -->
						<c:if test="${loginUser == null }">
							<div id="star" class="p-3 p3 col-6">
							<label for="">
								<svg xmlns="http://www.w3.org/2000/svg" width="60" height="60"
									fill="orange" class="bi bi-star" viewBox="0 0 16 16">
						    <path d="M3.612 15.443c-.386.198-.824-.149-.746-.592l.83-4.73L.173 6.765c-.329-.314-.158-.888.283-.95l4.898-.696L7.538.792c.197-.39.73-.39.927 0l2.184 4.327 4.898.696c.441.062.612.636.282.95l-3.522 3.356.83 4.73c.078.443-.36.79-.746.592L8 13.187l-4.389 2.256z"/>
						</svg></label>
								<br>나만의 레시피
							</div>
						
						
						</c:if>
						
						
						
						
						</div>
						<!-- 추천, 나만의 레시피 이이콘 영역 종료 -->
  • 추천/나만의 레시피 아이콘은 3가지로 나누어져 출력되도록 되어있다.
    1. 로그인을 하지 않았을때
      • 이때는 추천/나만의 레시피 아이콘은 빨간하트, 색칠된 별로 출력되며 기능으로 연결되지 않는다.
    2. 로그인을 했는데 추천/나만의 레시피 추가를 하지 않았을때
      • 아이콘의 링크는 추천/ 나만의 레시피 추가 링크로 연결되며 아이콘은 까만하트 색칠되지 않은 별이다
    3. 로그인을 했는데 추천/나만의 레시피 추가를 했을대
      • 아이콘의 링크는 추천취소/나만의 레시피 삭제로 연결되며 아이콘은 빨간하테 색칠된 별이 된다

상레 레시피 출력 컨트롤러

/**
		 * 디테일 레시피 보기
		 * 
		 * @param recipeNo
		 * @param session
		 * @param mv
		 * @return
		 */
		@RequestMapping(value = "/recipe/detail.do", method = RequestMethod.GET)
		public ModelAndView viewRecipeStep(int recipeNo, HttpSession session, ModelAndView mv,
				@RequestParam(value = "page", required = false) Integer page) {

			try {
				Recipe recipe = rService.printOneRecipe(recipeNo);
				List<RecipeMaterial> rmList = rService.printOneRecipeMaterial(recipeNo);
				List<RecipeStep> rsList = rService.printOneRecipeStep(recipeNo);
				RecipeTag rTag = rService.printOneRecipeTag(recipeNo);
// 추천레시피 목록
				List<Recipe> recomnandList = rService.recomadRecipe(recipe.getRecipeCategory());

				/// 레시피 댓글 가지고 오기///
				// 페이징중//
				int currentPage = (page != null) ? page : 1;
				// 현재 페이지
				// 만약 page값이 없으면 기본형 1로 출력할것, 아니면 받아온 page의 값을 준다.
				// 삼항연상자 사용

				int totalCount = rService.getTotalCount(recipeNo);
				int boardLimit = 10; // 한 화면에 출력할 게시물 수
				int naviLimit = 10; // 한 화면에 출력할 게시판 페이지 수
				int maxPage; // 게시판의 총 페이지 수
				int startNavi; // 한 화면에 출력되는 게시판 페이지의 처음 수
				int endNavi;// 한 화면에 출력되는 게시판 페이지의 마지막 수

				maxPage = (int) ((double) totalCount / boardLimit + 0.9);
				startNavi = ((int) ((double) currentPage / naviLimit + 0.9) - 1) * naviLimit + 1;
				endNavi = startNavi + naviLimit - 1;

				// endNavi가 maxNavi보다 커지는 오류방지
				if (maxPage < endNavi) {
					endNavi = maxPage;
				}
				mv.addObject("startNavi", startNavi);
				mv.addObject("endNavi", endNavi);
				mv.addObject("maxPage", maxPage);
				mv.addObject("currentPage", currentPage);

				/// 페이징 종료////

				List<RecipeComment> rcList = rService.printRecipeCommentList(recipeNo,currentPage,boardLimit);

				//멤버 닉네임 가지고 오기
				String name = rService.printMemberName(recipe.getMemberEmail());
				
				//코멘트 닉네임 가지고 오기
				String cName[] = new String[rcList.size()];
				
				for(int i=0; i<cName.length;i++) {
					
					cName[i] = rService.printMemberName(rcList.get(i).getMemberEmail());
					rcList.get(i).setMemberName(cName[i]);
					
					
				}
				
				
				//추천 체크 영역 비로그인시에는 체크하지 않음
				boolean recodCheck = false;
				if(session.getAttribute("loginUser")!=null) {
				Member loginUser = (Member)session.getAttribute("loginUser");
				int recommandCount = rService.checkRecommand(recipeNo, loginUser.getMemberEmail());
				if(recommandCount>0) {
					recodCheck = true;
				}
				}
				
				//마이레시피 체크 영역
				boolean checkMyrecipe = false;
				if(session.getAttribute("loginUser")!=null) {
				Member loginUser = (Member)session.getAttribute("loginUser");
				int MyRCount = rService.checkMyRecipe(recipeNo, loginUser.getMemberEmail());
					if(MyRCount>0) {
						checkMyrecipe = true;
					}
				}
				
				mv.addObject("name", name);
				mv.addObject("recipe", recipe);
				mv.addObject("rmList", rmList);
				mv.addObject("rsList", rsList);
				mv.addObject("rTag", rTag);
				mv.addObject("rcList", rcList);
				mv.addObject("recoList", recomnandList);
				mv.addObject("recodCheck", recodCheck);
				mv.addObject("checkMyrecipe", checkMyrecipe);
				mv.setViewName("/recipe/recipeDetail");

			} catch (Exception e) {
				mv.addObject("msg", e.getMessage());
				mv.setViewName("common/error");
			}
			return mv;
		}
  • 추천레시피는 상세 페이지에 출력되기때문에 디테일 레시피 컨트롤러에서 작동한다.
    • 가장 많은 3개만 데이터베이스에서 가져오려고했는데 rownum이 먹히질 않았다.
    • 그래서 모든 레시피를 가져오고 3개만 출력하는 방식을 사용했다.
    • 만약 데이터가 많았다면 이 방식은 매우 서버에 부담을주기때문에 실행할수 없다.
      • 나중에 이걸로 피드백을 받았는데 Rank 를 이용해여 쿼리문을 사용하면 실행이 될것이라고했다. 이 방식으로 쿼리문을 고쳐서 깃허브에 올려두어야 할것같다.
  • 이 컨트롤러에서 댓글의 페이징작업을 했다.
    • 페이징 작업은 레시피 Q&A페이징 작업과 다를것이 없고 원래 정해진 페이징의 공식을 사용하여 페이지를 지정했다. 댓글이기에 목록으로 돌아갔다가 페이지로 돌아갈 필요는 없어서 그 부분은 신경쓰지 않았다,

상세레시피 서비스


/** 댓글 출력*/
	
	@Override
	public List<RecipeComment> printRecipeCommentList(int recipeNo, int currentPage, int limit) {
		List<RecipeComment> rcList = rStore.selectRecipeCommentList(recipeNo, session, currentPage,limit);
		return rcList;
	}

/** 레시피 추천했는지 체크하기*/
	@Override
	public int checkRecommand(int recipeNo, String memberEmail) {
		int result = rStore.selectRecommand(session, recipeNo, memberEmail);
		return result;
	}

/**
	 * 상세 레시피, 레시피
	 */
	@Override
	public Recipe printOneRecipe(int recipeNo) {
		Recipe recipe = rStore.selectOneRecipe(recipeNo, session);
		return recipe;
	}

	/**상세레시피 순서*/
	@Override
	public List<RecipeStep> printOneRecipeStep(int recipeNo) {
		List<RecipeStep>  rsList = rStore.selectOneRecipeDetail(recipeNo, session);
		return rsList;
	}
	
	/**
	 * 상세 레시피 레시피 재료
	 */
	@Override
	public List<RecipeMaterial> printOneRecipeMaterial(int recipeNo) {
		 List<RecipeMaterial> rmList = rStore.selectOneRecipeMaterial(recipeNo, session);
		return rmList;
	}

	/**상세 레시피 태그*/
	@Override
	public RecipeTag printOneRecipeTag(int recipeNo) {
		RecipeTag rTag = rStore.selectOneRecipeTag(recipeNo, session);
		return rTag;
	}

/**
 * 이미지 삭제
 */
	@Override
	public int removeOneImg(String picName) {
		int result = rStore.deleteOneImg(session, picName);
		return result;
	}

/***
 * 추천레시피 불러오기
 */
@Override
public List<Recipe> recomadRecipe(String recipeCategory) {
	List<Recipe> RecommandList = rStore.selectRecomandRecipe(session,recipeCategory);
	return RecommandList;
}

/**댓글 갯수 가져오기*/
@Override
public int getTotalCount(int recipeNo) {
	int count = rStore.selectTotalCount(session,recipeNo);
	return count;

}

/**멤버 이름 가져오기**/
public String printMemberName(String memberEmail) {
	String name = rStore.selectMemberName(memberEmail, session);
	return name;
}

/** 마이레시피 했는지 체크하기*/
@Override
public int checkMyRecipe(int recipeNo, String memberEmail) {
	int result = rStore.selectMyRecipe(session,recipeNo,memberEmail);
	return result;
}

/**회원이메일불러오기*/
@Override
public String getMemberEmial(int recipeNo) {
	String memberEmail= rStore.selectMemberEmail(session,recipeNo);
	return memberEmail;
}
  • 서비스 자체에 특별한건 없지만 상세 레시피 하나를 불러오기위해 서비스에 많은 메소드가 필요했다는건 확인할수있다.
  • 마이레시피, 레시피 추천을 확인하여 가져오고, 댓글작성자, 작성자의 이메일만 수집한 뒤 회원이 닉네임을 변경했을때 바로 적용할수 있도록 회원메일을 불러와 회원의 닉네임을 체크해 가지고 오고 레시피나 코멘트 작성자의 이메일을 현재 접속한 회원의 이메일과 비교한후 수정/삭제 가능하도록 하는등….상세 레시피 하나를 출력하기위해 어마어마한 정보가 필요했다.

상세레시피 sotre

/** 상세레시피 */
	@Override
	public Recipe selectOneRecipe(int recipeNo, SqlSessionTemplate session) {
		int result = session.update("RecipeMapper.countPlus", recipeNo);
		Recipe recipe = session.selectOne("RecipeMapper.selectOneRecipe", recipeNo);
		return recipe;
	}

	/** 상세 레시피 순서 */
	@Override
	public List<RecipeStep> selectOneRecipeDetail(int recipeNo, SqlSessionTemplate session) {
		List<RecipeStep> rsList = session.selectList("RecipeMapper.selectOneRStep", recipeNo);
		return rsList;
	}

	/** 상세재료 */
	@Override
	public List<RecipeMaterial> selectOneRecipeMaterial(int recipeNo, SqlSessionTemplate session) {
		List<RecipeMaterial> rmList = session.selectList("RecipeMapper.selectOneRMaterial", recipeNo);
		return rmList;
	}

	/** 상세 태그 */
	@Override
	public RecipeTag selectOneRecipeTag(int recipeNo, SqlSessionTemplate session) {
		RecipeTag rTag = session.selectOne("RecipeMapper.selectOneRTag", recipeNo);
		return rTag;
	}

	/**레시피 추천 수 가져오기*/
	@Override
	public int selectRecommand(SqlSessionTemplate session, int recipeNo, String memberEmail) {
		
		Recipe recipeOne = new Recipe();
		recipeOne.setRecipeNo(recipeNo);
		recipeOne.setMemberEmail(memberEmail);
		int result = session.selectOne("RecipeMapper.selectRecommandCount", recipeOne);
		return result;
	}

	/**레시피 코멘트 출력*/
	@Override
	public List<RecipeComment> selectRecipeCommentList(int recipeNo, SqlSessionTemplate session, int currentPage,int limit) {
		int offset = (currentPage - 1) * limit;
		RowBounds rowBounds = new RowBounds(offset, limit);
		List<RecipeComment> rcList = session.selectList("RecipeMapper.selectCommentList", recipeNo, rowBounds);
		
		return  rcList;
	}
/**레시피 추천*/
	@Override
	public int insertRecommand(Recommandation recommand, SqlSessionTemplate session) {
		int result=session.insert("RecipeMapper.insertRecommand", recommand);
		result +=session.insert("RecipeMapper.recomandPlus", recommand.getRecipeNo());
		
		return result;
	}
/**추천 삭제*/
	@Override
	public int deleteRecommand(Recommandation recommand, SqlSessionTemplate session) {
		int result= session.delete("RecipeMapper.deleteRecommand", recommand);
		result+= session.delete("RecipeMapper.recomandMinus", recommand);
		return result;
	}

/** 추천 레시피 불러오기*/
	@Override
	public List<Recipe> selectRecomandRecipe(SqlSessionTemplate session, String recipeCategory) {
		List<Recipe> recommandList = session.selectList("RecipeMapper.selectRecommandRecipe",recipeCategory);
		return recommandList;
	}

	/**댓글 갯수 가져오기*/
	@Override
	public int selectTotalCount(SqlSessionTemplate session, int recipeNo) {
		int count = session.selectOne("RecipeMapper.selectCommentCount",recipeNo);
		return count;
		
	}

	/**멤버 닉네임 가져오기*/
	@Override
	public String selectMemberName(String memberEmail,SqlSessionTemplate session) {
		String name = session.selectOne("RecipeMapper.selectOneName", memberEmail);
		return name;
	}

	
	/**마이레시피 등록여부 확인하기*/
	@Override
	public int selectMyRecipe(SqlSessionTemplate session, int recipeNo, String memberEmail) {
		Recipe oneRecipe = new Recipe();
		oneRecipe.setMemberEmail(memberEmail);
		oneRecipe.setRecipeNo(recipeNo);
		int result = session.selectOne("RecipeMapper.selectMyrecipe", oneRecipe);
		return result;
	}

	/**회원이메일 가져오기*/
	@Override
	public String selectMemberEmail(SqlSessionTemplate session, int recipeNo) {
		String memberEmail=session.selectOne("RecipeMapper.selectMember", recipeNo);
		return memberEmail;
	}
  • 스토어 자체에도 여러가지 메소드를 많이 사용해야했다.
  • 그 외에 특별한 부분은 없지만 레시피 디테일에 접속했을때 조횟수가 올라가도록 추가된부분이 있다.

조횟수 추가하기

/** 상세레시피 */
	@Override
	public Recipe selectOneRecipe(int recipeNo, SqlSessionTemplate session) {
		int result = session.update("RecipeMapper.countPlus", recipeNo);
		Recipe recipe = session.selectOne("RecipeMapper.selectOneRecipe", recipeNo);
		return recipe;
	}
  • 상세레시피에 접속함으로서 컨트롤러가 데이터베이스로 상세 레시피를 가지고 오는 store메소드에 조횟수가 올라가는 코드를 추가하였다.
  • 이 메소드에는 2가지의 매퍼가 실행되도록 되어있는데 사실 이 경우 result값이 다른 메소드로 전송되지 않기에 오류가 생기면 파악하기 힘들수도 있다. 다만 전달하는 쿼리문이 복잡한것은 아니기에 간단히 추가하는것으로 레시피의 조횟수를 추가할수있었다.

상세레시피 Mapper

<resultMap type="Recipe" id="recipeResultMap">
		<id property="recipeNo" 			column="RECIPE_NO" />
		<result property="recipeName" 		column="RECIPE_NAME" />
		<result property="recipeInfo" 		column="RECIPE_INFO" />
		<result property="mainPic" 			column="MAIN_PICTURE" />
		<result property="insertDate" 		column="INCERT_DATE" />
		<result property="recipeCategory" 	column="RECIPE_CATEGORY" />
		<result property="recipeVideo" 		column="RECIPE_VIDEO" />
		<result property="viewCount" 		column="VIEW_COUNT" />
		<result property="memberEmail" 		column="MEMBER_EMAIL" />
		<result property="updateDate" 		column="UPDATE_DATE" />
		<result property="recipeStatus"		column="RECIPE_STATUS" />
		<result property="recommandCount" 	column="RECOMMAND_COUNT" />
		<result property="mainPicRename" 	column="MAIN_PIC_RENAME" />
		<result property="recipeTime" 		column="RECIPE_TIME" />
	</resultMap>

	<select id="selectAllRecipe" resultMap="recipeResultMap">
		select * from recipe_tbl where RECIPE_STATUS = 'Y'
	</select>

	<select id="selectOneRecipe" resultMap="recipeResultMap">
		select * from recipe_tbl where RECIPE_NO = #{recipeNo} and RECIPE_STATUS = 'Y'
	</select>
	
	<select id="selectRecommandRecipe" resultMap="recipeResultMap">
	 select * from recipe_tbl where RECIPE_CATEGORY = #{recipeCategory} and RECIPE_STATUS = 'Y'
	</select>
	
	<select id="selectMember" resultType="string">
	select MEMBER_EMAIL from recipe_tbl where RECIPE_NO = #{recipeNo}
	</select>
	

	
	
	

	<resultMap type="RecipeMaterial" id="RecipeMaterialResultMap">
		<id property="recipeNo"				column="RECIPE_NO" />
		<result property="materialOrder" 	column="MATERIAL_ORDER" />
		<result property="material" 		column="MATERIAL" />
		<result property="amount" 			column="AMOUNT" />
	</resultMap>

	<select id="selectOneRMaterial" resultMap="RecipeMaterialResultMap">
		select * from recipe_material where RECIPE_NO = #{recipeNo}order by MATERIAL_ORDER
	</select>
	
	<select id="countMaterial" resultType="_int">
		select count(*) from recipe_material where RECIPE_NO = #{recipeNo}
	</select>

	<resultMap type="RecipeTag" id="RecipeTagResultMap">
		<id property="recipeNo" 		column="recipeNo" />
		<result property="jmt" 			column="JMT" />
		<result property="healthy" 		column="HEALTHY" />
		<result property="goodSpicy" 	column="GOODSPICY" />
		<result property="full" 		column="FULL" />
		<result property="soSpicy" 		column="SOSPICY" />
		<result property="sweet" 		column="SWEET" />
		<result property="easy" 		column="EASY" />
		<result property="party"		column="PARTY" />
	</resultMap>

	<select id="selectOneRTag" resultMap="RecipeTagResultMap">
		select * from recipe_tag where RECIPE_NO = #{recipeNo}
	</select>

	<resultMap type="RecipeStep" id="RecipeStepResultMap">
		<id property="recipeNo" 				column="recipe_No" />
		<result property="recipeOrder" 			column="RECiPE_ORDER" />
		<result property="recipeDescription"	column="RECIPE_DESCRIPTION" />
		<result property="recipePic" 			column="RECIPE_PICTURE" />
		<result property="recipePicRename"		column="RECIPE_PIC_RENAME" />
	</resultMap>
	
	<select id="selectOneRStep" resultMap="RecipeStepResultMap">
		select * from recipe_Step where recipe_no = #{recipeNo} order by RECIPE_ORDER

<resultMap type="Recommandation" id="RecommandResultMap">
	<id property="recipeNo" 				column="RECIPE_NO" />
	<result property="memberEmail"			column="MEMBER_EMAIL" />

	</resultMap>

	<select id="selectRecommandCount" resultType="_int">
	
	select count(*) from RECOMMANDATION where RECIPE_NO= #{recipeNo} and MEMBER_EMAIL = #{memberEmail}
	
	</select>
	
	<select id="selectMyrecipe" resultType="_int">
	
	select count(*) from myrecipe_tbl where RECIPE_NO= #{recipeNo} and MEMBER_EMAIL = #{memberEmail}
	</select>

<!--  레시피 코멘트 영역-->

<resultMap type="RecipeComment" id="RecipeCommentResultMap">
		<id property="commentNo" 				column="COMMENT_NO" />
		<result property="commentDate"			column="COMMENT_DATE" />
		<result property="commentContents" 		column="COMMNET_CONTENTS" />
		<result property="recipeNo" 			column="RECIPE_NO" />
		<result property="memberEmail"			column="MEMBER_EMAIL" />
	</resultMap>

<select id="selectCommentList" resultMap="RecipeCommentResultMap">
select * from recipe_comment where RECIPE_NO = #{recipeNo} order by COMMENT_NO
</select>

<select id="selectCommentCount" resultType="_int">

select count(*) from recipe_comment where RECIPE_NO = #{recipeNo}

</select>

<select id="selectCommentMember" resultType="string">
select MEMBER_EMAIL from recipe_comment where COMMENT_NO = #{commentNo}
</select>

<!-- 멤버 불러오기 영역 -->

<select id="selectOneName" resultType="string">
select MEMBER_NICKNAME from Member_tbl where MEMBER_EMAIL =#{memberEmail}
</select>
  • 상세레시피이기에 대부분의 레시피 테이블의 모든 select태그를 사용했으며 멤버 이름을 불러오는 select나 레시피 추천이 몇개나 됐는지 세어주는 select 태그 그리고 조횟수를 추가하는 update등이 사용됐다.
  • 나중이 이 매퍼에서 문제가 발생했는데 다른 팀원이 이 매퍼에 다른 기능 관련된 쿼리문을 추가했다가 깃허브를 합쳤을때 그 팀원이 추가 기재한 태그가 전부 사라져 기능이 작동을 하지 않은것이다
    • 깃허브에서는 이런 자잘한 문제가 많이 일어났다.
    • 그래서 합칠때는 잘 살펴봐야 하고 가능하면 자신의 기능이 다른 사람이 작성하는 기능 페이지와 섞이지 않도록 하는것이 좋을것같다.

그림이 원하지 않는 다른 폴더로 저장되는 문제

  • 이것은 문제라는걸 깨닫지도 못했다. 다른 팀원들이 내가 올린 사진을 보지 못해서 체크하면서 알게된것인데 이건 간단하게 해결되었다.
  • server- overview- server Option - server modules with out publishing 체크
  • 이렇게 해줘야 사진이 main밑에 있는 resuorces폴더로 저장된다.

모든 기능에서 로그인, 작성자 체크하기

  • 이건 컨트롤러에서 해결했다. 전부 표현하면 길어자기에 간단한것 몇개만 작성해둘까 한다.
@RequestMapping(value = "/recipe/writeView.do", method = RequestMethod.GET)
		public ModelAndView showRecipeWrite(ModelAndView mv, HttpSession session) {
			
//			로그인 유저용
			if(session.getAttribute("loginUser")==null) {
				mv.addObject("msg", "로그인한 유저만 작성가능합니다");
			mv.setViewName("common/error");
				return mv;
				
			}
			
			
			
			mv.setViewName("/recipe/recipeWirteForm");
			return mv;

		}

/**
		 * 레시피 수정창 연결
		 * 
		 * @param mv
		 * @param recipeNo
		 * @param session
		 * @return
		 */
		@RequestMapping(value = "/recipe/modifyForm.do", method = RequestMethod.GET)
		public ModelAndView recipeModifyView(ModelAndView mv, @RequestParam("recipeNo") Integer recipeNo,
				HttpSession session) {
			
			

			try {
				Recipe recipe = rService.printOneRecipe(recipeNo);
				RecipeTag rTag = rService.printOneRecipeTag(recipeNo);
				List<RecipeMaterial> rmList = rService.printOneRecipeMaterial(recipeNo);
				List<RecipeStep> rsList = rService.printOneRecipeStep(recipeNo);

				//작성자 아니면 수정금지
				Member loginUser= (Member)session.getAttribute("loginUser");
				if(!loginUser.getMemberEmail().equals(recipe.getMemberEmail())&&loginUser.getAdminCheck()==false) {
					
					mv.addObject("msg", "작성자만 수정할 수 있습니다");
					mv.setViewName("common/error");
					return mv;
				}
				
				
				
				
				mv.addObject("recipe", recipe);
				mv.addObject("rTag", rTag);
				mv.addObject("rmList", rmList);
				mv.addObject("rmListSize", rmList.size());
				mv.addObject("rsList", rsList);
				mv.setViewName("/recipe/recipeModifyForm");
			} catch (Exception e) {
				mv.addObject("msg", e.getMessage());
				mv.setViewName("common/error");
			}
			return mv;
		}
  • 크게 2가지를 확인했는데, 로그인을 해야 작성할수있는 레시피, 댓글과 작성자만이 할수있는 수정/삭제 부분이었다.
  • 대부분 겟방식으로 전달됐고 로그인을 안했다면 작성되어야할 memberEmail부분이 null이 되어 오류가 떴겠지만, 애초에 그것을 막아야 사이트가 원할하게 작동한다고 할수있을것이다
  • 그래서 세션을 활용하여 전부 체크해주었다.
    	if(session.getAttribute("loginUser")==null) {
    				mv.addObject("msg", "로그인한 유저만 작성가능합니다");
    			mv.setViewName("common/error");
    				return mv;
    				
    			}
    • 세션이 없을때는 로그인한 유저만 작성가능하다는 메세지가 뜨는 오류페이지로 가게된다.

      	//작성자 아니면 수정금지
      				Member loginUser= (Member)session.getAttribute("loginUser");
      				if(!loginUser.getMemberEmail().equals(recipe.getMemberEmail())&&loginUser.getAdminCheck()==false) {
      					
      					mv.addObject("msg", "작성자만 수정할 수 있습니다");
      					mv.setViewName("common/error");
      					return mv;
      				}
    • 세션 안에있는 user의 Email과 작성자의 Email을 비교하여 그것이 같거나 admin이 true일때만 작동할수있도록 만들었다.

    • 작성자 email은 jsp영역에도 존재하는 부분이라 처음에는 이것 프론트단에서 가져와 비교할생각이었지만 그럴경우 주소로 조작하기가 매우 쉬워진다는 문제가 있어서 좀 귀찮지만 레시피나 댓글 번호를 데이터베이스로 넘겨 해당하는 email을 가져와 비교하는 방법을 써서 더 안전하도록 구성했다

    • 하지만 이경우 모든 유저가 자신의 권한밖의 행동을 하면 오류페이지를 보게된다, 이 시도자체를 막는것도 중요하다고 생각했다.

JSP에서 사용자의 차단

<div id="button-area" class="col-md-2">
					<c:if test="${loginUser.memberEmail==recipe.memberEmail || loginUser.adminCheck==true }">
					<!-- 버튼영역 -->
					<button class="btn btn-primary"
						onclick="location.href='/recipe/modifyForm.do?recipeNo=${recipe.recipeNo }';">수정</button>
					<button class="btn btn-primary"
						onclick="removeRecipe(${recipe.recipeNo });">삭제</button>
					</c:if>
				</div>
  • c:if태그를 활용해 세션을 체크하여 사용자와 작성자가 같을때만 버튼이 보일수있도록 모든 jsp를 수정해주었다, 댓글쓰기나 레시피 쓰기 같은경우는 loginUser가 ≠ null일때만 해당 버튼이 보이도록 만들었다.

해더푸터 적용하기

<jsp:include page="../header.jsp"/>
<section class="container">
</section>	

<jsp:include page="../footer.jsp"/>
  • 해더푸터는 담당하는 다른 팀원이 만들었기때문에 나는 해당 해더푸터를 내가 만든 페이지에 적용하였다.
  • 하지만 일일이 추가했다가 해더푸터를 수정했을때 다시 모든 페이지를 수정해야하는 귀찮음이 생긴다.
  • 그래서 이런식으로 섹션 영역 위 아래에 inluce태그를 이용해 해더푸터 파일을 연결해주었다. 덕분에 간단하게 해더푸터의 수정이 가능했다.
  • 단점은 해더푸터의 스타일과 겹쳐서 아이콘의 크기가 변했다는건데.. 변한것도 나름 괜찮아서 굳이 수정하지는 않았다.

레시피 작성시 포인트 추가하기

  • 이건 따로 기능을 추가하지는 않고 store부분의 mapper연결만 시켜줬다.
/**
	 * 레시피 등록
	 */
	@Override
	public int insertRecipe(Recipe recipe, SqlSessionTemplate session) {
		int result = session.insert("RecipeMapper.insertRecipe", recipe);
		result += session.insert("RecipeMapper.insertPoint",recipe.getMemberEmail());
		result+= session.update("RecipeMapper.updatePiont",recipe.getMemberEmail());
		return result;
	}
  • insertPoint태그를 통해 point10이되었다는 내역을 표시하고 updatePoint를 통해 현재 point에서 +10을 해 멤버 테이블에서 해당 멤버의 포인트를 늘려주었다.
<!-- 포인트추가 -->
	<insert id="insertPoint">
		insert into point values(#{memberEmail},'레시피 등록 적립',10,sysdate)
	</insert>
	
	<update id="updatePiont">
	update member_tbl set TOTAL_POINT = TOTAL_POINT+10 where MEMBER_EMAIL = #{memberEmail}
	</update>

마치며..

이렇게 내가 맡은 기능들의 구현은 끝이 났다.

사실 내 경우 대단한 오류는 없었고 팀원들과 깃허브를 합칠때마다 기능이 사라지거나 오류가 나거나 서버에 접속이 되지 않았던 문제가 가장 힘들었던것 같다

그래도 하나씩 오류를 찾아서 수정하고 사라졌던 기능을 복구하고 그걸 다시 합치고 수정하면서 많은걸 배운것 같다, 깃허브가 생각보다 어렵다는건 확실하게 알았다.. 혼자 사용할때와는 많이 다르다는것도

반응형 웹도 성공했기때문에 나는 굉장히 만족스러운 프로젝트였다!

profile
hello world

0개의 댓글