[세미프로젝트] 0917구현

hanahana·2022년 9월 17일
0
post-thumbnail
  • 오늘 목표인 레시피 사진까지 전부 등록하기에 성공했다.

레시피 등록 jsp 파일 유표성 체크하기

<%@ 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>

<head>

<title>레시피 등록</title>
<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>

</head>

<body>

	<form action="/recipe/regist.do" method="post"
		enctype="multipart/form-data">

		<div class="row row-cols-lg-auto container align-items-center">

			<div class="form-floating col-lg-4">
				<input type="text" class="form-control" id="" name="recipeName">
				<label for="floatingInput">레시피 제목</label>
			</div>
			<br>
			<div class="form-floating col-lg-4">
				<input type="text" class="form-control" id="" name="recipeVideo">
				<label for="floatingInput">유튜브 링크</label>
			</div>

			<div class="col-md-3">
				<label for="validationCustom04" class="form-label">카테고리</label> <select
					class="form-select" id="" name="recipeCategory" required>
					<option selected disabled value="">카테고리 선택</option>
					<option value="mael">식사</option>
					<option value="relish">술안주</option>
					<option value="dessert">간식</option>
					<option value="drink">술/음료</option>
				</select>
				<div class="invalid-feedback">카테고리를 선택하세요</div>
				<br>
				<div class="col-md-8 col-lg-8">
					해시태그<br> <label><input class="form-check-input"
						type="checkbox" name="jmt" value="true"> JMT</label> <label><input
						class="form-check-input" type="checkbox" name="healthy"
						value="true"> 건강한</label> <label><input
						class="form-check-input" type="checkbox" name="goodSpicy"
						value="true"> 맛있게 매운</label> <label><input
						class="form-check-input" type="checkbox" name="soSpicy"
						value="true"> 아주매운</label> <label><input
						class="form-check-input" type="checkbox" name="sweet" value="true">
						달콤한</label> <label><input class="form-check-input" type="checkbox"
						name="easy" value="true"> 간편한</label> <label><input
						class="form-check-input" type="checkbox" name="party" value="true">
						파티용</label> <label><input class="form-check-input" type="checkbox"
						name="full" value="true"> 든든한</label>
				</div>

			</div>
			<br>
			<div class="form-floating col-lg-2 align-items-center">
				<input type="text" class="form-control" id="" name="recipeTime">
				<label for="floatingInput">소요시간</label>
			</div>

			<div class="row col-lg-4">

				<label class="input-file-button" for="input-file"> 대표이미지추가 <img
					id="output">

				</label> <input type="file" id="input-file" style="display: none"
					accept="image/jpeg, image/png, image/jpg" name="mainPicture"
					class="isFile" onchange="loadFile(event)" required="required" />
			</div>

			<div class=" row row-cols-lg-auto col-lg-8">
				<div class="form-floating col-lg-8">
					<input type="text" class="form-control" id="" maxlength="30"
						name="recipeInfo" required="required"> <label
						for="floatingInput"> 간단한소개 (30자 미만)</label>
				</div>
			</div>

			<div class="row row-cols-lg-auto col-lg-12">
				<div class="form-floating col-lg-3">
					<input type="text" class="form-control" id="" maxlength="10"
						name="material"> <label for="floatingInput">재료명</label>
				</div>
				<div class="form-floating col-lg-3">
					<input type="text" class="form-control" id="" maxlength="10"
						name="amount"> <label for="floatingInput">재료수량</label>
				</div>

				<div class="form-floating col-lg-3">
					<input type="text" class="form-control" id="" maxlength="10"
						name="material"> <label for="floatingInput">재료명</label>
				</div>

				<div class="form-floating col-lg-3">
					<input type="text" class="form-control" id="" maxlength="10"
						name="amount"> <label for="floatingInput">재료수량</label>
				</div>
			</div>

			<div class="row row-cols-lg-auto col-lg-12 ">
				<div class="form-floating col-lg-3">
					<input type="text" class="form-control" id="" maxlength="10"
						name="material"> <label for="floatingInput">재료명</label>
				</div>

				<div class="form-floating col-lg-3">
					<input type="text" class="form-control" id="" maxlength="10"
						name="amount"> <label for="floatingInput">재료수량</label>
				</div>

				<div class="form-floating col-lg-3">
					<input type="text" class="form-control" id="" maxlength="10"
						name="material"> <label for="floatingInput">재료명</label>
				</div>

				<div class="form-floating col-lg-3">
					<input type="text" class="form-control" id="" maxlength="10"
						name="amount"> <label for="floatingInput">재료수량</label>
				</div>
			</div>

			<div class="row row-cols-lg-auto col-lg-12 ">
				<div class="form-floating col-lg-3">
					<input type="text" class="form-control" id="" maxlength="10"
						name="material"> <label for="floatingInput">재료명</label>
				</div>

				<div class="form-floating col-lg-3">
					<input type="text" class="form-control" id="" maxlength="10"
						name="amount"> <label for="floatingInput">재료수량</label>
				</div>

				<div class="form-floating col-lg-3">
					<input type="text" class="form-control" id="" maxlength="10"
						name="material"> <label for="floatingInput">재료명…</label>
				</div>

				<div class="form-floating col-lg-3">
					<input type="text" class="form-control" id="" maxlength="10"
						name="amount"> <label for="floatingInput">재료수량</label>
				</div>
			</div>

		</div>

		<hr>

		<div class="row container">
			<div class="form-floating col-lg-6">
				<input type="text" class="form-control" id="" maxlength="10"
					name="recipeDescription" required="required"> <label
					for="floatingInput">레시피 설명</label>
			</div>
			<div class="row col-lg-6">
				<input type="file" name="recipePicture" class="isFile"
					accept="image/jpeg, image/png, image/jpg" onchange="imgCheck();">
			</div>
			<div class="form-floating col-lg-6">
				<input type="text" class="form-control" id="" maxlength="10"
					name="recipeDescription"> <label for="floatingInput">레시피
					설명</label>
			</div>
			<div class="row col-lg-6">
				<input type="file" name="recipePicture" class="isFile"
					accept="image/jpeg, image/png, image/jpg" onchange="imgCheck();">
			</div>
			<div class="form-floating col-lg-6">
				<input type="text" class="form-control" id="" maxlength="10"
					name="recipeDescription"> <label for="floatingInput">레시피
					설명</label>
			</div>
			<div class="row col-lg-6">
				<input type="file" name="recipePicture" class="isFile"
					accept="image/jpeg, image/png, image/jpg" onchange="imgCheck();">
			</div>

			<input type="submit" value="등록" onclick="checkMainPic();">
		</div>

	</form>

	</p>
	<script>
		var loadFile = function(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 = "";

					}
				}
			}
		};
		/////이미지 확장자 체크 종료///
	</script>

</body>
</html>
  • 자바스크립트를 이용해 이미지 파일만 등록 가능하게 하였다.
    ///// 이미지파일 체크 시작 ////
    		var imgFile = document.querySelectorAll('.isFile'); //모든 파일의 클래스를 imgFile로 지정했다.
    		var fileForm = /(.*?)\.(jpg|jpeg|png|gif|bmp)$/i; //그림파일 확장자만 체크한다
    
    			function checkMainPic() {
    			if (imgFile[0].value == "") {
    				alert("대표사진은 필수입니다!");
    			}
    		}; //메인사진이 없을때는 오류메세지를 출력한다.
    
    //onchange 이벤트를 사용해 파일이 그림파일인지 체크하고 그림파일 아니면 받은 파일의 value를 지워버린다.
    		function imgCheck() {
    			for (var i = 0; i < imgFile.length; i++) {
    				if (imgFile[i].value != "") {
    
    					if (!imgFile[i].value.match(fileForm)) {
    						alert("이미지 파일만 업로드 가능");
    						imgFile[i].value = "";
    
    					}
    				}
    			}
    		};
    		/////이미지 확장자 체크 종료///

Controller

  • 오늘은 서비스클래스나 스토어, 매퍼에 손대지 않고 controller만 수정했다.
/**
	 * 레시피 등록 컨트롤러
	 * @param recipe
	 * @param rStep
	 * @param rMaterial
	 * @param rTag
	 * @param mv
	 * @param mainPicture
	 * @param recipePicture
	 * @param session
	 * @param request
	 * @return
	 */
	@RequestMapping(value = "/recipe/regist.do", method = RequestMethod.POST)
	public ModelAndView registRecipe(@ModelAttribute Recipe recipe, @ModelAttribute RecipeStep rStep,
			@ModelAttribute RecipeMaterial rMaterial, @ModelAttribute RecipeTag rTag, ModelAndView mv,
			@RequestParam(value = "mainPicture", required = false) MultipartFile mainPicture,
			@RequestParam(value = "recipePicture", required = false) List<MultipartFile> recipePicture,
			HttpSession session, HttpServletRequest request) {
		try {
			// 레시피 전달

			// 사진 저장코드
			String mainPic = mainPicture.getOriginalFilename();
			if (!mainPic.equals("")) {

				String root = request.getSession().getServletContext().getRealPath("resources");
				String savePath = root + "\\recipeImg"; // 내가 저장할 폴더
				File file = new File(savePath); // 파일 객체 만들기

				SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
				String mainPicRename = sdf.format(new Date(System.currentTimeMillis())) + "."
						+ mainPic.substring(mainPic.lastIndexOf(".") + 1);

				if (!file.exists()) { // 경로에 savePath가 없을땐
					file.mkdir(); // 경로 만들기
				}

				mainPicture.transferTo(new File(savePath + "\\" + mainPicRename));// 파일을 buploadFile경로에 저장
				recipe.setMainPic(mainPic);
				recipe.setMainPicRename(mainPicRename);

			}
			// 사진 저장 코드 종료

			int result = rService.registRecipe(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++) {

				// 재료나 수량이 비어있지 않을때만 List에 저장
				if (!amount[i].equals("") && !material[i].equals("")) {
					RecipeMaterial rMaterialOne = new RecipeMaterial();
					rMaterialOne.setAmount(amount[i]);
					rMaterialOne.setMaterial(material[i]);
					rMaterialOne.setMaterialOrder(i + 1);
					rmList.add(rMaterialOne);
				}

			}
			int result1 = rService.registMaterial(rmList);

			// 레시피 순서 리스트 만들어서 전달하기
			ArrayList<RecipeStep> rsList = new ArrayList<RecipeStep>();
			String arrDescription[] = rStep.getRecipeDescription().split(",");

			///// 레시피 순서 사진 저장코드

			for (int i = 0; i < recipePicture.size(); i++) {
				String recipePic = recipePicture.get(i).getOriginalFilename();
				String recipePicRename = "";
				if (!recipePic.equals("")) {

					String root = request.getSession().getServletContext().getRealPath("resources");
					String savePath = root + "\\recipeImg"; // 내가 저장할 폴더
					File file = new File(savePath); // 파일 객체 만들기

					SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
					recipePicRename = sdf.format(new Date(System.currentTimeMillis())) + "stepImg" + i + "."
							+ recipePic.substring(recipePic.lastIndexOf(".") + 1);// 동시에여러사진이올라가기에 이름에 순서추가해줌

					if (!file.exists()) { // 경로에 savePath가 없을땐
						file.mkdir(); // 경로 만들기
					}
					recipePicture.get(i).transferTo(new File(savePath + "\\" + recipePicRename));// 파일을 buploadFile경로에 저장
					///// 여기까지 사진 저장코드/////

				}
				// 여기서부터 레시피 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);
					rsList.add(rStepOne);
			}

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

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

		} catch (

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

기억할만 것

  • 오류가 굉장히 많이나서 하루를 통째로 사용했다.
  • 일단, 서버가 실행이 안되는 오류가 났다.. 이건 메이븐의 오류인거 같은데 이 오류에 관해서는 https://velog.io/@hana78786/오류-메이븐을-업데이트-했을때-서버오류 여기에 작성했다.
  • 메인 사진을 저장하는건 서버 오류를 해결하니 별 문제가 아니었지만 문제는 레시피 사진 저장 코드였다.
    • 레시피 사진은 총 10개까지 등록가능하기때문에 controller에서 사진을 10개 가져와야 한다.
    • 10개를 일일히 코드를 넣는것은 번거로우니 requestparm으로 가지고온 파일을 배열로 만들어 실행하는 코드를 짰다.
      MultipartFile[] rePic = { recipePicture1, recipePicture2, recipePicture3, recipePicture4, recipePicture5,
      					recipePicture6, recipePicture7, recipePicture8, recipePicture9, recipePicture10 };
      
      			for (int i = 0; i < rePic.length; i++) {
      				String recipePic = rePic[i].getOriginalFilename();
      				String recipePicRename = "";
      				if (!recipePic.equals("")) {
      
      					String root = request.getSession().getServletContext().getRealPath("resources");
      					String savePath = root + "\\recipeImg"; // 내가 저장할 폴더
      					File file = new File(savePath); // 파일 객체 만들기
      
      					SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
      					recipePicRename = sdf.format(new Date(System.currentTimeMillis())) + "stepImg" + i + "."
      							+ recipePic.substring(recipePic.lastIndexOf(".") + 1);// 동시에여러사진이올라가기에 이름에 순서추가해줌
      
      					if (!file.exists()) { // 경로에 savePath가 없을땐
      						file.mkdir(); // 경로 만들기
      					}
      					rePic[i].transferTo(new File(savePath + "\\" + recipePicRename));// 파일을 buploadFile경로에 저장
      					///// 여기까지 사진 저장코드/////
      
      				}
      				// 여기서부터 레시피 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);
      				
      				if(!(rStepOne.getRecipeDescription()==null && rStepOne.getRecipePic().equals(""))) {
      				rsList.add(rStepOne);
      				}
      			}
      
      			
      			
      			int result2 = rService.registStep(rsList); // 레시피 순서저장 코드 종료
      • 하지만 사용자가 원하지 않으면 input file은 3개밖에 존재하지 않는다 requestParam값이 없이 빈 변수명만 존재하게 된다.
      • 여기서 오류가 발생했다 MultipartFile[] rePic은 10개로 구성되어있는데 실제로는 3개밖에 값이 들어오지 않은것이다 for문은 10개를 돌리려고 하는데 배열에는 3개밖에 들어오지 않는상황… for문은 딱 3번 돌아가고 값이 들어오기를 무한히 기다리다 오류를 냈다……….
      • 다행이 보낸 이미지는 정상적으로 폴더에 업로드되어 원인을 찾을수 있었다.
      • 원인을 찾아서 그나마 다행이다. 강사님께 주말이지만 헬프를 쳤는데 defaultValue를 넣어보라고 조언해주셨다.
      • 하지만.. 그 defaultValue를 못찾았다.. 대신 다른걸 찾았다 input의 name을 같게 하면 file을 List로 인식해 들어온다는 것이다.
      • 배열을 빼고 List를 활용했다! List.size()로 for문을 만드니 오류없이 해결!
  • 거의 하루 종일을 사용했지만 나름 모든 오류를 해결하고 오늘 목표를 완성해서 만족스럽다
  • 내일은 할수있다면 레시피 폼의 디자인을 원래 의도했던 방향으로 최대한 수정해보고 시간이 된다면 레시피를 출력하는 창도 만들어 볼까 한다.
profile
hello world

0개의 댓글