- 오늘 목표인 레시피 사진까지 전부 등록하기에 성공했다.
레시피 등록 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)
};
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>
Controller
- 오늘은 서비스클래스나 스토어, 매퍼에 손대지 않고 controller만 수정했다.
@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()) {
file.mkdir();
}
mainPicture.transferTo(new File(savePath + "\\" + mainPicRename));
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++) {
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()) {
file.mkdir();
}
recipePicture.get(i).transferTo(new File(savePath + "\\" + recipePicRename));
}
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);
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()) {
file.mkdir();
}
rePic[i].transferTo(new File(savePath + "\\" + recipePicRename));
}
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문을 만드니 오류없이 해결!
- 거의 하루 종일을 사용했지만 나름 모든 오류를 해결하고 오늘 목표를 완성해서 만족스럽다
- 내일은 할수있다면 레시피 폼의 디자인을 원래 의도했던 방향으로 최대한 수정해보고 시간이 된다면 레시피를 출력하는 창도 만들어 볼까 한다.