[세미프로젝트] 9월 20일 레시피 수정 완성, 상세 레시피 프론트 거의 완성

hanahana·2022년 9월 20일
0
post-thumbnail
  • 오늘 목표는 수정창과 댓글 이었다.
  • 수정은 완성했지만 아쉽게도 댓글까지 구현할 시간이 없었다
  • 수정부분이 굉장히 어려워서 많이 해맸다.
  • 댓글창은 완성하지 못했지만 상세 레시피의 프론트는 거의 완성했다. 이제 댓글기능과 검색기능 추천, 신고 기능을 넣으면 된다.

수정 기능

jsp

<body>

	<form action="/recipe/modify.do" method="post"
		enctype="multipart/form-data">
		<input type="hidden" name="recipeNo" value="${recipe.recipeNo }">
		<div class="container-lg align-items-center">
			<div class="container-lg col-sm-12 row align-items-center p-0">

				<!-- 여기는 대표 이미지 박스 -->
				<div class="col-md-5 col-sm-12 container-lg align-items-center">

					<div class="row col-md-4 m-2 col-sm-12  align-items-center">

						<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"
							fill="currentColor" class="bi bi-x-circle-fill float-end"
							onclick="mainPicDel()">
						<path
								d="M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0zM5.354 4.646a.5.5 0 1 0-.708.708L7.293 8l-2.647 2.646a.5.5 0 0 0 .708.708L8 8.707l2.646 2.647a.5.5 0 0 0 .708-.708L8.707 8l2.647-2.646a.5.5 0 0 0-.708-.708L8 7.293 5.354 4.646z" />
					  </svg>
						<label class="input-file-button float-start" for="input-file">
							<img id="output" class="mx-auto " width="400px" height="270px"
							src="/resources/recipeImg/${recipe.mainPicRename }"
							style="background-color: gray; border-radius: 10px;">
						</label> <input type="file" id="input-file" style="display: none"
							accept="image/jpeg, image/png, image/jpg" name="mainPicture"
							class="isFile" onchange="loadFile(event)" />
							<!-- 수정 전 이미지이름 전송 -->
							<input type="hidden" name="mainPicRename" value="${recipe.mainPicRename }">
							<input type="hidden" name="mainPic" value="${recipe.mainPic }">

					</div>

				</div>

				<div class="col-md-7 container-lg col-sm-12">

					<div class="form-floating col-sm-12 ">
						<input type="text" class="form-control" id="" name="recipeName"
							value="${recipe.recipeName }"> <label for="floatingInput">레시피
							제목</label>
					</div>
					<br>
					<div class="form-floating col-sm-12 ">
						<input type="text" class="form-control" id="" name="recipeVideo"
							value="${recipe.recipeVideo }" onblur="isYoutube()"> <label
							for="floatingInput">유튜브 링크</label>
					</div>

					<div class="mt-5 col-12">
						<label for="validationCustom04" class="form-label"><h5>카테고리</h5></label>
						<select class="form-select" id="" name="recipeCategory" required>
							<option selected disabled value="">카테고리 선택</option>
							<option value="mael"
								<c:if test="${recipeCategory == mael}"> selected</c:if>>식사</option>
							<option value="relish"
								<c:if test="${recipeCategory == relish}"> selected</c:if>>술안주</option>
							<option value="dessert"
								<c:if test="${recipeCategory == dessert}"> selected</c:if>>간식</option>
							<option value="drink"
								<c:if test="${recipeCategory == drink}"> selected</c:if>>술/음료</option>
						</select>
						<div class="invalid-feedback">카테고리를 선택하세요</div>
						<br>

						<div class="form-floating align-items-center">
							<input type="text" class="form-control mb-2" id=""
								value="${recipe.recipeTime }" name="recipeTime"> <label
								for="floatingInput">소요시간</label>
						</div>

						<div class="col-md-12 col-sm-12">
							<h5>해시태그</h5>
							<div class="overflow-hidden">
								<label class="w-25 float-start"> <input
									class="form-check-input" type="checkbox" name="jmt"
									<c:if test="${rTag.jmt==true }">checked</c:if> value="true">
									JMT
								</label> <label class="w-25 float-start"> <input
									class="form-check-input" type="checkbox" name="healthy"
									<c:if test="${rTag.healthy==true }">checked</c:if> value="true">
									건강한
								</label> <label class="w-25 float-start"><input
									class="form-check-input" type="checkbox" name="goodSpicy"
									<c:if test="${rTag.goodSpicy==true }">checked</c:if>
									value="true"> 맛있게 매운</label> <label class="w-25 float-start"><input
									class="form-check-input" type="checkbox" name="soSpicy"
									<c:if test="${rTag.soSpicy==true }">checked</c:if> value="true">
									아주매운</label> <label class="w-25 float-start"><input
									class="form-check-input" type="checkbox" name="sweet"
									<c:if test="${rTag.sweet==true }">checked</c:if> value="true">
									달콤한</label> <label class="w-25 float-start"><input
									class="form-check-input" type="checkbox" name="easy"
									<c:if test="${rTag.easy==true }">checked</c:if> value="true">
									간편한</label> <label class="w-25 float-start"><input
									class="form-check-input" type="checkbox" name="full"
									<c:if test="${rTag.full==true }">checked</c:if> value="true">
									든든한</label> <label class="w-25 float-start"><input
									class="form-check-input" type="checkbox" name="party"
									<c:if test="${rTag.party==true }">checked</c:if> value="true">
									파티용</label>
							</div>
						</div>

					</div>

				</div>

				<br>

				<div class=" row m-0 mt-3 mb-3  p-0 ">
					<div class="form-floating">
						<input type="text" class="form-control" id="" maxlength="30"
							name="recipeInfo" value="${recipe.recipeInfo}"
							required="required"> <label for="floatingInput">
							간단한소개 (30자 미만)</label>
					</div>
				</div>

				<!-- 재료 입력-->
				<div class="container align-items-center">

					<div class=" col-md-12 m-0 p-0">

						<div class="row col-md-6 col-12 float-start p-3 me-1">
							<div class="form-floating col-md-6">
								<input type="text" class="form-control" id="" maxlength="10"
									<c:if test="${rmListSize >=1  }"> value="${rmList.get(0).material }"</c:if>
									name="material"> <label for="floatingInput">재료명</label>
							</div>
							<div class="form-floating col-md-6">
								<input type="text" class="form-control" id="" maxlength="10"
									<c:if  test="${rmListSize >=1  }"> value="${rmList.get(0).material }"</c:if>
									name="amount"> <label for="floatingInput">재료수량</label>
							</div>
						</div>

						<div class="row col-md-6 col-12 float-start p-3 ms-1">
							<div class="form-floating col-md-6">
								<input type="text" class="form-control" id="" maxlength="10"
									<c:if  test="${rmListSize >=2  }"> value="${rmList.get(1).material }"</c:if>
									name="material"> <label for="floatingInput">재료명</label>
							</div>

							<div class="form-floating col-md-6">
								<input type="text" class="form-control" id="" maxlength="10"
									<c:if  test="${rmListSize >=2  }"> value="${rmList.get(1).amount }"</c:if>
									name="amount"> <label for="floatingInput">재료수량</label>
							</div>
						</div>

						<div class=" col-md-12">

							<div class="row col-md-6 col-12 float-start p-3 me-1">
								<div class="form-floating col-md-6">
									<input type="text" class="form-control" id="" maxlength="10"
										<c:if  test="${rmListSize >=3  }"> value="${rmList.get(2).material }"</c:if>
										name="material"> <label for="floatingInput">재료명</label>
								</div>
								<div class="form-floating col-md-6">
									<input type="text" class="form-control" id="" maxlength="10"
										<c:if  test="${rmListSize >=3  }"> value="${rmList.get(2).amount }"</c:if>
										name="amount"> <label for="floatingInput">재료수량</label>
								</div>
							</div>

							<div class="row col-md-6 col-12 float-start p-3 ms-1">
								<div class="form-floating col-md-6">
									<input type="text" class="form-control" id="" maxlength="10"
										<c:if  test="${rmListSize >=4  }"> value="${rmList.get(3).material }"</c:if>
										name="material"> <label for="floatingInput">재료명</label>
								</div>

								<div class="form-floating col-md-6">
									<input type="text" class="form-control" id="" maxlength="10"
										<c:if  test="${rmListSize >=4  }"> value="${rmList.get(3).amount }"</c:if>
										name="amount"> <label for="floatingInput">재료수량</label>
								</div>
							</div>

							<div class=" col-md-12 border-bottom-1">

								<div class="row col-md-6 col-12 float-start p-3 me-1">
									<div class="form-floating col-md-6">
										<input type="text" class="form-control" id="" maxlength="10"
											<c:if  test="${rmListSize >=5  }"> value="${rmList.get(4).material }"</c:if>
											name="material"> <label for="floatingInput">재료명</label>
									</div>
									<div class="form-floating col-md-6">
										<input type="text" class="form-control" id="" maxlength="10"
											<c:if  test="${rmListSize >=5  }"> value="${rmList.get(4).amount }"</c:if>
											name="amount"> <label for="floatingInput">재료수량</label>
									</div>
								</div>

								<div class="row col-md-6 col-12 float-start p-3 ms-1">
									<div class="form-floating col-md-6">
										<input type="text" class="form-control" id="" maxlength="10"
											<c:if  test="${rmListSize >=6  }"> value="${rmList.get(5).amount }"</c:if>
											name="material"> <label for="floatingInput">재료명</label>
									</div>

									<div class="form-floating col-md-6">
										<input type="text" class="form-control" id="" maxlength="10"
											<c:if  test="${rmListSize >=6  }"> value="${rmList.get(5).amount }"</c:if>
											name="amount"> <label for="floatingInput">재료수량</label>

									</div>

								</div>

							</div>

						</div>

					</div>

				</div>
			</div>

			<div class="recipeDetail container row">
				<!-- 여기서부터 레시피 설명-->
				<!-- 레시피step forEach문시작 -->
						<hr>
				<c:forEach items="${rsList }" var="rStep">
					<div class="REdetailC" id="REdetail">
						<div class="row container p-3 float-start col-md-6 p-2 " id="">

							<div class="form-floating col-md-12 p-0 pt-3">
								<textarea class="form-control" name="recipeDescription"
									placeholder="" id="floatingTextarea2" style="height: 250px">${rStep.recipeDescription }</textarea>
								<label for="floatingTextarea2" class="mt-3">설명을 입력하세요</label>
							</div>

							<!-- 					설명에 쉼표를 넣었을때 배열로 만들지 않기위한 더미 value -->
							<input type="text" name="recipeDescription" value="ab22bb"
								style="display: none">

						</div>

						<!-- 이미지 미리보기 이미지 파일 -->
						<div class="row col-md-6 float-start p-2">
							<div
								class="col-md-5 col-sm-12 container-lg align-items-center m-0">
								<div class="row col-md-4 col-sm-12  align-items-center">
						<!-- 이미지 삭제 아이콘 -->
									<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"
										fill="currentColor" class="bi bi-x-circle-fill float-end"
										onclick="PicDel(this, '${rStep.recipePicRename }', ${recipe.recipeNo })">
							<path
											d="M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0zM5.354 4.646a.5.5 0 1 0-.708.708L7.293 8l-2.647 2.646a.5.5 0 0 0 .708.708L8 8.707l2.646 2.647a.5.5 0 0 0 .708-.708L8.707 8l2.647-2.646a.5.5 0 0 0-.708-.708L8 7.293 5.354 4.646z" />
						  </svg>

									<label class="input-file-button float-start"> <img
										class="detailImg mx-auto" width="400px" height="270px"
										<c:if test="${rStep.recipePicRename  ne null }">
									src="/resources/recipeImg/${rStep.recipePicRename }"</c:if>
										style="background-color: gray; border-radius: 10px;"> <input
										type="file" name="recipePicModify" class="isFile"
										style="display: none"
										accept="image/jpeg, image/png, image/jpg"
										onchange="imgView(this);">
									</label>

								</div>

							</div>
						</div>
					</div>
				<input type="text" name="recipePicRename" value="${rStep.recipePicRename}" style="display:none">
				<input type="text" name="recipePic" value="${rStep.recipePic}" style="display:none">
				</c:forEach>
				<!-- 레시피step foreach문 종료 -->
				<!-- 레시피 한블럭 설명종료 -->
				<span id="addplace"></span>

			</div>
			<!-- 레시피 종료 -->

			<!-- 설명추가 -->
			<svg class="m-2" xmlns="http://www.w3.org/2000/svg" width="30"
				height="30" fill="currentColor" class="bi bi-plus-circle-fill"
				viewBox="0 0 16 16" onclick="addDe()">
  <path
					d="M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0zM8.5 4.5a.5.5 0 0 0-1 0v3h-3a.5.5 0 0 0 0 1h3v3a.5.5 0 0 0 1 0v-3h3a.5.5 0 0 0 0-1h-3v-3z" />
</svg>
			<!--  설명 삭제 -->
			<svg class="m-2" xmlns="http://www.w3.org/2000/svg" width="30"
				height="30" fill="currentColor" class="bi bi-dash-circle-fill"
				viewBox="0 0 16 16" onclick="removeDe()">
  <path
					d="M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0zM4.5 7.5a.5.5 0 0 0 0 1h7a.5.5 0 0 0 0-1h-7z" />
</svg>

			<div class="col-md-12">
				<input type="submit" value="수정" onclick="checkMainPic();">
			</div>
		</div>
	</form>

	</div>

	<script>
		//유튜브 링크 유효성체크//

		var youUrl = /(http:|https:)?(\/\/)?(www\.)?(youtube.com|youtu.be)\/(watch|embed)?(\?v=|\/)?(\S+)?/g;
		function isYoutube() {
			var youtube = document.querySelector('[name="recipeVideo"]');
			if (!youUrl.test(youtube.value)) {
				alert("유튜브 주소는 embed이 포함된 고유주소로 입력해주세요")
				youtube.value = "";

			}

		}

		///설명 추가/삭제////
		var detailForm = document.querySelector('#REdetail');
		var addplace = document.querySelector('#addplace');
		var count = document.querySelectorAll('.REdetailC').length+1;
		var firstCount = document.querySelectorAll('.REdetailC').length+1;
		function addDe() {
			if (count <= 10) {
				count++;
				addplace.appendChild(detailForm.cloneNode(true));
				document.querySelectorAll('.REdetailC')[document
						.querySelectorAll('.REdetailC').length - 1].childNodes[1].childNodes[1].childNodes[1].value = "";
				document.querySelectorAll('.REdetailC')[document
					.querySelectorAll('.REdetailC').length - 1].childNodes[5].childNodes[1].childNodes[1].childNodes[5].childNodes[1].src = "";

			}

		}

		function removeDe() {
			var detailFormClass = document.querySelectorAll('.REdetailC');
			if (count > firstCount) {
				detailFormClass[detailFormClass.length - 1].remove();
				count--;
			}

		}

		function loadFile(event) {
			var output = document.getElementById('output');
			output.src = URL.createObjectURL(event.target.files[0]);
			output.onload = function() {
				URL.revokeObjectURL(output.src) // free memory
			};
			imgCheck()
		};

		///// 이미지파일 체크 시작 ////
		var imgFile = document.querySelectorAll('.isFile');
		var fileForm = /(.*?)\.(jpg|jpeg|png|gif|bmp)$/i;
		var fileSize;
		function checkMainPic() {
			if (imgFile[0].value == "") {
				alert("대표 이미지를 새로 설정하지 않으면 이미지가 그대로 출력됩니다");

			}
		};

		function imgCheck() {
			for (var i = 0; i < imgFile.length; i++) {
				if (imgFile[i].value != "") {

					if (!imgFile[i].value.match(fileForm)) {
						alert("이미지 파일만 업로드 가능");
						imgFile[i].value = "";

					}
				}
			}

		};

		/////이미지 확장자 체크 종료///

		function imgView(obj) {

			var imgid = obj.previousElementSibling;

			imgid.src = URL.createObjectURL(event.target.files[0]);
			imgid.onload = function() {
				URL.revokeObjectURL(imgid.src); // free memory

			}
			imgCheck()

		};

		function mainPicDel() {
			imgFile[0].value = "";
			output.removeAttribute('src');
		}

		function PicDel(obj,picName,recipeNo) {
			var imgfiles = obj.nextElementSibling.childNodes[1];
			var imgfilesinput = obj.nextElementSibling.childNodes[3];
			if(imgfiles.src == null || imgfiles.src ==''){
				alert("삭제할 이미지가 없습니다")
			}else{
				if(confirm("이미지를 삭제하시겠습니까? 삭제하면 복구할수 없고 현재페이지가 새로고침됩니다")){
					event.preventDefault()
				imgfilesinput.value = "";
				imgfiles.removeAttribute('src');
				location.href = "/recipe/imgRemove.do?picName="+picName+"&recipeNo="+recipeNo
				}
			}

		}
		
		//재료 유효성 검사//
		var check = /,/
		
		function materialCheck(obj){
			
				if(check.test(obj.value)){
					alert(",는 사용할수 없습니다.");
					obj.value="";
				
			}
			
		}
		
		
		
	</script>
  • 수정은 html부분에서 바뀐것은 별로 없다, 레시피 설명을 추가할때 사진이 복사되어 나오던 오류를 수정했고 재료 부분에 , 가 들어가지 않도록 유효성 검사를 추가했다.
    	
    		//재료 유효성 검사//
    		var check = /,/
    		
    		function materialCheck(obj){
    			
    				if(check.test(obj.value)){
    					alert(",는 사용할수 없습니다.");
    					obj.value="";
    				
    			}
    			
    		}

Controller

/**
	 * 레시피 수정
	 * 
	 * @param recipe
	 * @param rStep
	 * @param rMaterial
	 * @param rTag
	 * @param mv
	 * @param mainPicture
	 * @param recipePicture
	 * @param session
	 * @param request
	 * @return
	 */
	@RequestMapping(value = "/recipe/modify.do", method = RequestMethod.POST)
	public ModelAndView modifyRecipe(@ModelAttribute Recipe recipe, @ModelAttribute RecipeStep rStep,
			@ModelAttribute RecipeMaterial rMaterial, @ModelAttribute RecipeTag rTag, ModelAndView mv,
			@RequestParam(value = "mainPicture", required = false) MultipartFile mainPicture,
			@RequestParam(value = "recipePicModify", required = false) List<MultipartFile> recipePicture,
			@RequestParam("recipeNo") Integer recipeNo, HttpSession session, HttpServletRequest request) {

		try {
			
			// 대표 이미지 교체
			String mainPic = mainPicture.getOriginalFilename();
			if (mainPicture != null && !mainPic.equals(""))// 새로 파일을 올렸을때, 이름이 없는 파일이 있을 경우를 생각해 null체크 2번함
			{// 수정 할경우 대체/ 삭제 후 등록/ 대체는 어려워서 삭제후 등록으로 한다
				String root = request.getSession().getServletContext().getRealPath("resources");// 저장된 파일의 경로를 가져온다.
				String savedPath = root + "\\recipeImg"; // 가져온 경로에 업로드 파일이 들어있는 폴더의 경로까지 더해줌
				File file = new File(savedPath + "\\" + recipe.getMainPicRename()); // 이미 저장한 파일의 이름을 가져와야 한다.

				if (file.exists()) { // 지정한 파일이 있는지 없는지 체크
					file.delete(); // 있으면 삭제
				}

				////////// 여기부터 파일 재 업로드/////////////////////
				// 파일 이름으로 업로드하면 파일이름이 겹치면 파일이 겹쳐서 사라진다.
				// 고유한 rename으로 변경해주어야 한다.
				SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
				String mainPicRename = sdf.format(new Date(System.currentTimeMillis())) + "."
						+ mainPic.substring(mainPic.lastIndexOf(".") + 1);

				mainPicture.transferTo(new File(savedPath + "\\" + mainPicRename));
				recipe.setMainPic(mainPic);
				recipe.setMainPicRename(mainPicRename);
				recipe.setRecipeNo(recipeNo);

			}
			// 대표 이미지 교체 끝

			int result = rService.modifyOneRecipe(recipe); // 레시피 메인테이블

			// 레시피 재료 리스트 만들어서 전달하기
			ArrayList<RecipeMaterial> rmList = new ArrayList<RecipeMaterial>();
			String amount[] = rMaterial.getAmount().split(",");
			String material[] = rMaterial.getMaterial().split(",");
			for (int i = 0; i < material.length; i++) {
				if (!amount[i].equals("") && !material[i].equals("")) {
					// 재료나 수량이 비어있지 않을때만 List에 저장
					RecipeMaterial rMaterialOne = new RecipeMaterial();
					rMaterialOne.setAmount(amount[i]);
					rMaterialOne.setMaterial(material[i]);
					rMaterialOne.setMaterialOrder(i + 1);
					rMaterialOne.setRecipeNo(recipeNo);
					rmList.add(rMaterialOne);
				}

			}
			int result1 = rService.modifyOneRecipeMaterial(rmList);// 레시피 재료 테이블

			// 레시피 태그 true false로 받음
			int result3 = rService.modifyOneRecipeTag(rTag);

			// 레시피 순서 리스트 만들어서 전달하기
			ArrayList<RecipeStep> rsList = new ArrayList<RecipeStep>();
			rStep.getRecipeDescription();
			String arrDescription[] = rStep.getRecipeDescription().split(",ab22bb,");
			// 더미 value까지 배열을 나누는것으로 인식해서 사용자가 ,를 입력했을때 정상적으로 table에 저장되게 한다
			arrDescription[arrDescription.length - 1] = arrDescription[arrDescription.length - 1].replace(",ab22bb",
					"");
			// 배열의 마지막은 ,가 안들어가기때문에 더미vlaue 배열값으로 인식한다, ,가 없는 더미value를 삭제 해주는 코드

			// 레시피 이미지 교체
			
			String root = request.getSession().getServletContext().getRealPath("resources");
			String savedPath = root + "\\recipeImg";
			String recipeRe[] = rStep.getRecipePicRename().split(",");
			// 반복문으로 삭제/저장
			for (int i = 0; i <arrDescription.length; i++) {
				String recipePic = recipePicture.get(i).getOriginalFilename();
				
				System.out.println(recipePic+","+i);
				if (recipePicture.get(i) != null && !recipePic.equals("")) {

					File file = new File(savedPath + "\\" + recipeRe); // 이미 저장한 파일의 이름을 가져와야 한다.
					
					if (file.exists()) { // 지정한 파일이 있는지 없는지 체크
						file.delete(); // 있으면 삭제
					}

					////////// 여기부터 파일 재 업로드/////////////////////
					// 파일 이름으로 업로드하면 파일이름이 겹치면 파일이 겹쳐서 사라진다.
					// 고유한 rename으로 변경해주어야 한다.
					SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
					String recipePicRename = sdf.format(new Date(System.currentTimeMillis())) + "rstep" + i + "."
							+ recipePic.substring(recipePic.lastIndexOf(".") + 1);

					recipePicture.get(i).transferTo(new File(savedPath + "\\" + recipePicRename));

					// 여기서부터 레시피 step 테이블에 저장할 값 List화 시키는 코드
					RecipeStep rStepOne = new RecipeStep();
					if (i < arrDescription.length) {
						if (!arrDescription[i].equals("")) {
							rStepOne.setRecipeDescription(arrDescription[i]);
						}
					}
					rStepOne.setRecipePic(recipePic);
					rStepOne.setRecipePicRename(recipePicRename);
					rStepOne.setRecipeOrder(i + 1);
					rStepOne.setRecipeNo(recipeNo);

					rsList.add(rStepOne);
					

				}
			} // 레시지 저장 반복문 종료

			int result2 = rService.modifyOneRecipeStep(rsList); // 레시피 순서저장 코드 종료

			mv.setViewName("redirect:/recipe/recipeList.do");

		} catch (Exception e) {
			e.printStackTrace();
			mv.addObject("msg", e.getMessage());
			mv.setViewName("common/error");
		}

		return mv;

	}
  • 레시피 수정에서 굉장히 오류가 많이나서 강사님 도움을 많이 받았다.
  • 가장 문제는 레시피의 재료를 받아올때는 레시피 재료폼의 순서대로 레시피 재료안의 번호가 1~6까지 각각 인식하는데 수정에서는 전혀 다르다는 것이었다.
    • 레시피 재료는 첫번째칸에 쓴건 번호1 3번째 칸에 쓴건 번호3으로 인식하여 등록되지만 수정에서는 쓰지 않은 나머지 번호는 불러오지 않고 1,2 칸만 채우는 것이다.

    • 그렇게 되면 재료1,3외에 다른 것은 쿼리문 update로는 수정할수 없는 문제가 있었다 (왜냐하면 2는 등록되어있지 않으니 2재료를 입력해도 update문은 되지 않는다)
      - 이 문제는 레시피 입력창에서 재료 순서를 for문 i로 설정하는것이 가장 큰문제였는데, 그 문제를 해결하기 위해 재료 순서는 i가 아니라 입력된 입력된 그 숫자와 순서만큼으로 인식하게 하여 해결했다
      - 다음 문제인 순서를 지나면 update를 할수 없는 문제는 다른 방식으로 해결했는데..
      - 이번에는 service는 별로 중요하지 않으니 store만 공개할까 한다.

      ### Store
      
      ```java
      /** 레시피 재료 수정 */
      	@Override
      	public int updateOneRecipeMaterial(SqlSessionTemplate session, List<RecipeMaterial> rmList) {
      		int result = 0;
      	
      
      			for (int i = 0; i < rmList.size(); i++) {
      
      				result += session.update("RecipeMapper.updateOneMaterial", rmList.get(i));
      
      			}
      		if(result<rmList.size()) {
      			//null방지코드
      			for(int i=result; i<rmList.size(); i++) {
      				if(rmList.get(i).getAmount() == null) {
      					rmList.get(i).setAmount("");
      				}
      				if(rmList.get(i).getMaterial() == null) {
      					rmList.get(i).setMaterial("");
      				}
      			session.insert("RecipeMapper.insertRecipeMaterialPlus", rmList.get(i));
      			}
      		}
      		
      		int count =session.selectOne("RecipeMapper.countMaterial",rmList.get(0).getRecipeNo());
      		
      		
      		if(count>rmList.size()) {
      			for(int i =rmList.size(); i<count; i++) {
      				HashMap<String, Integer> paraMap = new HashMap<String, Integer>();
      				paraMap.put("recipeNo", rmList.get(0).getRecipeNo());
      				paraMap.put("materialOrder", i);
      				result = session.delete("RecipeMapper.deleteOneMaterial",paraMap);
      			}
      		}
      
      		return result;
      	}
      ```
      
      - if문을 활용해서 내가 가져온 재료의 순서만큼은 일반적으로 update하고 그 외에 다른값은 가져온 재료의 순서 size와 비교하여 size보다 많으면 insert문을 사용하여 새롭게 등록하였다
      - 만약 내가 가지고온 재료 순서가 원래 등록된 재료 순서보다 적다면 나머지 재료 순서는 삭제해야 하기 때문에  count쿼리문을 이용하여 나머지 재료 순서는 삭제하도록 코드를 구성했다.

      Mapper

      <insert id="insertRecipeMaterialPlus">
      	insert into recipe_material
      		values(#{materialOrder},#{recipeNo},#{material},#{amount})
      	</insert>
      
      <update id = "updateOneMaterial">
      	update recipe_material set MATERIAL = #{material}, AMOUNT = #{amount}
      	where RECIPE_NO = #{recipeNo} and MATERIAL_ORDER = #{materialOrder}
      </update>
      
      <select id="countMaterial" resultType="_int">
      		select count(*) from recipe_material where RECIPE_NO = #{recipeNo}
      	</select>
      
      <delete id="deleteOneMaterial">
      	delete recipe_material  where RECIPE_NO = #{recipeNo} and MATERIAL_ORDER = #{materialOrder}
      	
      </delete>
    • countMaterial의 경우 resultType을 잘못써서 한참 오류가 났다. 잘 틀리는 부분이니 신경써야 할것 같다.

그외 수정

  • 똑같이 List로 들어가는 레시피 순서는 재료 순서와 같은 방식으로 처리했고 나머지는 어려울것이 없었다.
  • 간단하게 코드만 공개한다.

Store

/** 레시피수정 */
	@Override
	public int updateOneRecipe(SqlSessionTemplate session, Recipe recipe) {
		int result = session.update("RecipeMapper.updateOneRecipe", recipe);
		return result;
	}

	/** 레시피 순서수정 */
	@Override
	public int updateOneRecipeStep(SqlSessionTemplate session, List<RecipeStep> rsList) {
		int result = 0;
		for (int i = 0; i < rsList.size(); i++) {
			result += session.update("RecipeMapper.updateOneStep", rsList.get(i));
		}
		
		
		if(result<rsList.size()) {
			for(int i=result; i<rsList.size();i++) {
			result+= session.insert("RecipeMapper.insertRstepPlus",rsList.get(i));
			}
		}
		
		return result;
	}

/** 레시피 태그 수정 */
	@Override
	public int updateOneRecipeTag(SqlSessionTemplate session, RecipeTag rTag) {
		int result = session.update("RecipeMapper.updateOneTag", rTag);
		return result;
	}
  • 레시피 순서는 비어있으면 비어있는대로 null값을 인식해 테이블에 등록하기때문에 재료보다는 간편하게 할수있었다.
  • 똑같이 원래 등록된 부분은 update 그 이상이면 insert사용 만약 원래부분을 지운다고해도 update로 null처리 된다.

mapper

<update id = "updateOneRecipe">
	update recipe_tbl set RECIPE_NAME = #{recipeName}, RECIPE_INFO = #{recipeInfo}, MAIN_PICTURE = #{mainPic}, RECIPE_CATEGORY= #{recipeCategory},
	RECIPE_VIDEO = #{recipeVideo}, MAIN_PIC_RENAME = #{mainPicRename}, RECIPE_TIME = #{recipeTime}, UPDATE_DATE = default
	where RECIPE_NO = #{recipeNo}
</update>

<update id = "updateOneStep">
	update recipe_step set recipe_Description = #{recipeDescription}, RECIPE_PICTURE = #{recipePic}, RECIPE_PIC_RENAME= #{recipePicRename}
	where RECIPE_NO = #{recipeNo} and RECIPE_ORDER = #{recipeOrder}
</update>

<update id = "updateOneMaterial">
	update recipe_material set MATERIAL = #{material}, AMOUNT = #{amount}
	where RECIPE_NO = #{recipeNo} and MATERIAL_ORDER = #{materialOrder}
</update>

<update id = "updateOneTag">
	update recipe_tag set jmt = #{jmt}, healthy = #{healthy}, goodSpicy = #{goodSpicy}, full = #{full},soSpicy = #{soSpicy}, sweet = #{sweet},easy = #{easy},party = #{party}
	where RECIPE_NO = #{recipeNo}
</update>

<insert id="insertRstepPlus">
	insert into recipe_step values(#{recipeOrder},#{recipeNo},#{recipeDescription},#{recipePic},#{recipePicRename})
	
	</insert>

레시피 상세창 프론트 단 완성

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>${recipe.recipeName }</title>
</head>
<body>

	<style>
#imgDiv {
	width: 100%;
	height: 500px;
	overflow: hidden;
}

#mainImg {
	width: 100%;
	height: auto;
	position:  relative;
	top: 10;
}

#article1 {
	border-right: 1px solid lightgray;
	margin: 0 auto;
	text-align : center;
}

#article2 {

	margin: 0 auto;
}

#title{
  text-align : center;
  }
  
 #hashtag{
  
  text-align : left;
  }
  
  #wirter-area{
  text-align : right;
  }
  
  #other-recipe-area{
  height:80%;
  }
  
  #list-icon{
    position: fixed;
    top: 6%;
    left:6%;
    z-index: 99;
  }
  
  #list-icon:hover, .p3:hover{
  cursor:pointer
  }
  
  #step-img{
  width:80%;
  height:auto;
  }
  
</style>

	<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"><!-- 버튼영역 -->
								<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>
							</div>
							
					</div><!-- 타이틀 영역 -->
					<hr>

				<div class="col-md-12 m-0 row" >
					<!--  아티클 전체 들어감-->
					<div class="col-md-8" id="article1"
						><article>

							<!-- 작성자 영역 -->
							<div id="wirter-area" class="col-md-12" > 
							<h5>작성자 : ${recipe.memberEmail } ${recipe.recipeInfo } <button class="btn btn-danger">신고</button></h5> 
							</div><!-- 작성자 영역종료 -->
							
							<!-- 비디오 영역 -->
							<div id="youtube-area" class="col-md-12 p-3">
							<!-- 비디오 주소를 입력했을때만-->
							<c:if test="${recipe.recipeVideo ne null }">
								<iframe width="560" height="315" 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">
							<c:forEach items="${rsList }" var="rsList">
								<c:if test="${rsList.recipePicRename ne null }">
									<img id="step-img" src="/resources/recipeImg/${rsList.recipePicRename }">
									<br>
								</c:if>
		
								<p>	${rsList.recipeDescription }</p>
		
							</c:forEach>
							</div><!-- 순서영역 종료 -->

						<!-- 추천, 나만의 레시피 이이콘 영역 -->
						<div id="recom-bookm-area" class="my-2">
						<span id="heart" class="p-3 p3">
						<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> </span>
						<span id="star" class="p-3 p3">
						<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>
						</span>
						</div>
						<!-- 추천, 나만의 레시피 이이콘 영역 종료 -->
	
						</article>
					</div> <!-- 아티클1 영역 종료 -->
					
					
					
					
					<div class="col-md-4 m-0" 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>
							
						
						
						</article>
					</div>
				</div>
				
				<article id="reply-area">
				<div id="article3-area">
				<hr>
				
				<div id="comment" class="row">
				<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>작성자</h4></div>  
				<div id="comment-button" class="col-md-2" style="text-align:right"> 신고</div>
				</div>
				<div id="comment-text-area">
                    <span>- 20 October, 2018</span>
                    <br>
                    <p>Lorem ipsum dolor sit, amet consectetur adipisicing elit. Accusamus numquam assumenda hic aliquam vero sequi velit molestias doloremque molestiae dicta?</p>
				</div>
				<div id="comment-delmodi-buttom-area"style="text-align:right">
				<button class="btn btn-outline-primary">수정</button> <button class="btn btn-outline-primary">삭제</button>
				
				</div>		
						
				</div>
				</div><!-- 코멘트 내용영역종료 -->
				
				  </div><!-- 코멘트 내용 영역종료 -->
                    
                    <div id="comment-write-area" class="row">
                    
                    <div id="comment-textarea" class="col-md-11">
                    <div class="form-floating">
					  <textarea class="form-control" placeholder="Leave a comment here" id="floatingTextarea2" style="height: 100px"></textarea>
					  <label for="floatingTextarea2">Comments</label>
					</div>
                    </div>
                    
                    <div id="comment-button-area" class="col-md-1">
                    <button style="height:100%; width=100%;" class="btn btn-outline-primary">등록</button>
                    </div>
                    
                    
                    </div>
              
            
                </div>
                </article><!-- 아티클3 종료 -->
                
				</div>
				</article>
				<!-- 아티클 전체 들어감 -->

			
		</div>
		<!-- 메인 내용 폼 전체 들어감 -->
	</section>

	<link
		href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css"
		rel="stylesheet"
		integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3"
		crossorigin="anonymous">
	<script
		src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"
		integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p"
		crossorigin="anonymous"></script>
</body>
<script>
function removeRecipe(recipeNo){
	if(confirm("삭제 하시겠습니까? 삭제하면 복구할수 없습니다")){
		location.href='/recipe/remove.do?recipeNo='+recipeNo;
	}
}

function list(){
	location.href='/recipe/recipeList.do';
	
}

</script>
</html>
  • 아직 자바스크립트로 추가하고 로그인 세션이나 이벤트를 연결해야하지만 페이지 자체는 완성되었다.
  • 여기에 댓글만 추가하면 나머지는 이벤트 연결만 하면된다!!
  • 반응형은 계속 안되고있지만 약간 부트스트랩을 이해한거 같다.. 근데 왜 난 반응형이 안되지?
profile
hello world

0개의 댓글