빅데이터 Java 개발자 교육 - 50일차[JSP 실습 2(물품 이미지 조회, 삭제, 수정 및 고객 회원가입)]

Jun_Gyu·2023년 4월 11일
0
post-thumbnail

typescript 프론트에 관심있는사람들은 필수!

나중에 한번 공부해보도록 하자.

물품 이미지 조회

package jejuWebController;

import java.io.IOException;
import java.util.List;

import config.MyBatisContext;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import webmapper.ItemImageMapper;


@WebServlet(urlPatterns = { "/item/selectimagelist" })
public class ItemImageSelectList extends HttpServlet {
	private static final long serialVersionUID = 1L;

	protected void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		ItemImageMapper mapper = MyBatisContext.getSqlSession().getMapper(ItemImageMapper.class);

		long ino = Long.parseLong(request.getParameter("ino"));
    //  <a href="selectimagelist.do?itemno=${obj.no}"><button>등록된이미지보기</button></a>

		List<Long> no = mapper.selectItemImageList(ino);

		// mapper로 itemno를 전달해서 해당하는 이미지번호만 리턴
		
		
		request.setAttribute("no", no );
		request.getRequestDispatcher("/WEB-INF/item_img_write.jsp").forward(request, response);


	}
}

물품 이미지 삭제

package jejuWebController;

import java.io.IOException;

import config.MyBatisContext;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import webmapper.ItemImageMapper;

// 컨트롤러 역활 X, DB에 있는 이미지를 URL 형태로 변경해서 반환하는 용도
@WebServlet(urlPatterns = { "/item/imagedelete.do" })
public class ItemImageDelete extends HttpServlet {
	private static final long serialVersionUID = 1L;

// ex) http://127.0.0.1:8080/web01/item/image?no=물품번호
	protected void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		// 삭제를 위해 필요한 값 (물품번호, 이미지번호)
		long imageNo = Long.parseLong(request.getParameter("no"));
		long itemNo = Long.parseLong(request.getParameter("ino"));
		// Mapper를 통한 삭제
		int ret = MyBatisContext.getSqlSession()
				.getMapper(ItemImageMapper.class)
				.deleteItemImageListOne(imageNo, itemNo);

		// 삭제 후 보내는 페이지
		if (ret == 1) {
			response.sendRedirect(request.getContextPath() + "/item" + "/imagewrite.do?ino=" + itemNo);
		} else {
			response.sendRedirect("imagewrite.do?ino=" + itemNo);
		}
	}
}

물품 이미지 수정

package jejuWebController;

import java.io.IOException;

import config.MyBatisContext;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.MultipartConfig;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.Part;
import webdto.ItemImage;
import webmapper.ItemImageMapper;

// 컨트롤러 역활 X, DB에 있는 이미지를 URL 형태로 변경해서 반환하는 용도
@WebServlet(urlPatterns = { "/item/imageupdate.do" })
@MultipartConfig()
public class ItemImageUpdate extends HttpServlet {
	private static final long serialVersionUID = 1L;

// ex) http://127.0.0.1:8080/web01/item/image?no=물품번호
	protected void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		
		System.out.println(request.getParameter("imageNo")); 
		
		long imageNo = Long.parseLong(request.getParameter("imageNo"));
		long itemNo = Long.parseLong(request.getParameter("ino"));
		Part file = request.getPart("file"); // 첨부된 이미지 파일

		if (file.getSize() > 0) {
			ItemImage itemimage = new ItemImage();
			itemimage.setNo(imageNo);
			itemimage.setItemno(itemNo);
			itemimage.setFilename(file.getSubmittedFileName());
			itemimage.setFilesize(file.getSize());
			itemimage.setFiledata(file.getInputStream().readAllBytes());
			itemimage.setFiletype(file.getContentType());

			int ret = MyBatisContext.getSqlSession().getMapper(ItemImageMapper.class).updateItemImageOne(itemimage);
			if (ret == 1) { // 변경 완료한 경우
//				request.setAttribute("message", "변경 완료되었습니다.");
				request.setAttribute("icon", "success");
				request.setAttribute("title", "변경완료");
				request.setAttribute("text", "화끈하시네요!");
				request.setAttribute("url", "imagewrite.do?ino=" + itemNo);
				request.getRequestDispatcher("/WEB-INF/alert.jsp").forward(request, response);
			} else { // 변경 실패한 경우
//				request.setAttribute("message", "변경 실패");
				request.setAttribute("icon", "warning");
				request.setAttribute("title", "변경실패");
				request.setAttribute("text", "변경에 실패했어요..");
				request.setAttribute("url", "imagewrite.do?ino=" + itemNo);
				request.getRequestDispatcher("/WEB-INF/alert.jsp").forward(request, response);
			}
		} else { // 변경사항 없는 경우
//			request.setAttribute("message", "변경사항 없음");
			request.setAttribute("icon", "question");
			request.setAttribute("title", "파일없음");
			request.setAttribute("text", "파일이.. 없네요?");
			request.setAttribute("url", "imagewrite.do?ino=" + itemNo);
			request.getRequestDispatcher("/WEB-INF/alert.jsp").forward(request, response);
		}

	}
}

물품 이미지 수정 alert.jsp 설정

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<!-- sweetalert2 -->
	<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
	<script>
		Swal.fire({
			icon: '${icon}',
			title: '${title}',
			text: '${text}',
			showConfirmButton: false,
			timer: 2500
		});
		
		window.location.href = '${url}'; // 주소창을 바꾸고 enter키 (a 태그와 동일한 기능)

		/* alert('${message}'); // 알람을 표시 */
		
	</script>
</body>
</html>

조회, 삭제, 수정 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>
<html lang="ko">
<head>
<meta charset='utf-8'>
<meta http-equiv='X-UA-Compatible' content='IE=edge'>
<title>물품이미지 등록하기</title>
<meta name='viewport' content='width=device-width, initial-scale=1'>
<!-- Include stylesheet -->
<link href="https://cdn.quilljs.com/1.3.6/quill.snow.css"
	rel="stylesheet">
<!-- Bootstrap -->
<link
	href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha3/dist/css/bootstrap.min.css"
	rel="stylesheet"
	integrity="sha384-KK94CHFLLe+nY2dmCWGMq91rCGa5gtU4mk92HdvYe+M/SXH301p5ILy+dN9+nJOZ"
	crossorigin="anonymous">
</head>
<body style="color: rgba(123, 123, 102, 0.5);">
	<div id="layoutAuthentication">
		<div id="layoutAuthentication_content">
			<main>
				<div class="container">
					<div class="row justify-content-center">
						<div class="col-lg ">
							<div class="card shadow-lg border-0 rounded-lg mt-5">
								<div class="card-header">
									<h3 class="text-left font-weight-light my-4">🖼️ 물품이미지 등록</h3>
								</div>
								<form id="form"
									action="${pageContext.request.contextPath}/item/imagewrite.do"
									method="post" enctype="multipart/form-data">
									<div class="card-body">
										<div class="form-floating mt-3 mb-3">
											<input type="text" name="ino" class="form-control" id="ino"
												for="floatingInput" value="${ino}" readonly> <label
												for="ino" class="form-label">물품번호</label>
										</div>
										<c:forEach var='tmp' items="${no}">
											<img
												src="${pageContext.request.contextPath}/item/image?no=${tmp}"
												style="width: 70px; height: 70px">
										</c:forEach>
										<hr />
										<div class="form-floating mt-3 mb-3">
											<img
												src="${pageContext.request.contextPath}/resources/images.png"
												id="img"
												style="width: 250px; height: 200px; cursor: pointer;"
												onclick="clickImage()"> <input type="file" name="file"
												id="file" class="form-control" style="display: none"
												onchange="imageChange(this)" />
										</div>

										<input type="button" value="등록" id="commit" name="commit"
											class="btn btn-success btn-right" onclick="insertItemImage()"></input>
										<a class="btn btn-secondary" href="select.do">목록으로</a>
									</div>
								</form>
								<form id="form1" action="imagewritebatch.do?ino=${ino}"
									method="post" enctype="multipart/form-data">
									<div class="card-body">
										<hr />
										<div class="form-floating mt-3 mb-3">
											<c:forEach var="idx" begin="1" end="3" step="1">
												<img
													src="${pageContext.request.contextPath}/resources/images.png"
													class="imgs"
													style="width: 50px; height: 50px; cursor: pointer;">
												<input type="file" name="file[]"
													onchange="imageChangeBatch(this, '${idx-1}')" />
												<br />
											</c:forEach>
										</div>
										<input type="button" value="일괄등록"
											class="btn btn-success btn-right"
											onclick="insertImageBatch()"></input> <a
											class="btn btn-secondary" href="select.do">목록으로</a>
									</div>

								</form>
								<hr />
								<div class="card-body">
									<c:forEach var="no" items="${imageNo}">
									${no} :
										<img
											src="${pageContext.request.contextPath}/item/image?no=${no}"
											style="width: 70px; height: 70px">
										<button onclick="itemImageUpdateModal('${no}', '${ino}')"
											class="btn btn-warning">수정</button>
										<button onclick="itemImageDelete('${no}', '${ino}')"
											class="btn btn-danger">삭제</button>
										<br />
									</c:forEach>
								</div>

								<!-- Modal -->
								<div class="modal fade" id="exampleModal" tabindex="-1"
									aria-labelledby="exampleModalLabel" aria-hidden="true">
									<form action="imageupdate.do" method="post"
										enctype="multipart/form-data">
										<div class="modal-dialog">
											<div class="modal-content">
												<div class="modal-header">
													<h5 class="modal-title" id="exampleModalLabel">이미지 수정</h5>
													<button type="button" class="btn-close"
														data-bs-dismiss="modal" aria-label="Close"></button>
												</div>
												<div class="modal-body">
													이미지 번호 : <input type="text" name="imageNo"
														id="modal_image_no" readonly /><br /> 현재 적용된 이미지 : <img
														src="" style="width: 90px; height: 90px"
														id="modal_image_src"><br /> <input type="hidden"
														name="ino" value="${ino}"> 이미지변경 : <input
														name="file" type="file" id="modal_image_file"
														onchange="imageUpdateChange(this)" /><br />
												</div>
												<div class="modal-footer">
													<input type="submit" class="btn btn-success" value="변경하기" />
													<button type="button" class="btn btn-secondary"
														data-bs-dismiss="modal">취소</button>
												</div>
											</div>
										</div>
									</form>
								</div>
							</div>
						</div>
					</div>
				</div>
			</main>
		</div>
	</div>
	<!-- sweetalert2 -->
	<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
	<!-- jQuery -->
	<script
		src="${pageContext.request.contextPath}/resources/js/jquery-3.6.4.min.js"></script>
	<script
		src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js"
		integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM"
		crossorigin="anonymous"></script>



	<script>
		function itemImageUpdateModal(no, ino) {
			const imageNo = document.getElementById("modal_image_no"); // 이미지 넘버
			const imageSrc = document.getElementById("modal_image_src"); // 이미지 주소
			const imageFile = document.getElementById("modal_image_file");// 이미지 파일
			
			imageNo.value = no;
			imageSrc.src = "${pageContext.request.contextPath}/item/image?no=" + no; // 받은 이미지 넘버를 토대로 주소완성
			
			const modal = new bootstrap.Modal(document.getElementById("exampleModal"),{});
			modal.show();
		}
	
		function itemImageDelete(no, ino) {
			Swal.fire({
				  title: '정말로 지우실건가요?',
				  text: "지워진 이미지는 복구할 수 없어요!",
				  icon: 'warning',
				  showCancelButton: true,
				  confirmButtonColor: '#3085d6',
				  cancelButtonColor: '#d33',
				  confirmButtonText: '좋아요, 지워봅시다!'
				}).then((result) => {
			if (result.isConfirmed) {
				// <form action="imagedelete.do" method="post" style="display:none;">
				var form = document.createElement("form");
				form.setAttribute("action", "imagedelete.do");
				form.setAttribute("method", "post");
				form.style.display = "none";

				// <input type="hidden" name="imageno" value="삭제할 이미지번호">
				var input = document.createElement("input");
				input.setAttribute("type", "hidden");
				input.setAttribute("name", "no");
				input.setAttribute("value", no);
				console.log(no);

				// <input type="hidden" name="ino" value="삭제할 물품번호">
				var input1 = document.createElement("input");
				input1.setAttribute("type", "hidden");
				input1.setAttribute("name", "ino");
				input1.setAttribute("value", Number(ino));
				console.log( Number(ino));
				// form 태그에 추가
				form.appendChild(input);
				form.appendChild(input1);

				Swal.fire({
	 					icon: 'success',
	  					title: '삭제 완료!',
	  					showConfirmButton: false,
	  					timer: 3000
					})
				
				// body에 추가
				document.body.appendChild(form);
				// form 전송
				 form.submit(); 
			}
		  })
		};

		// document.getElementById("아이디"); id가 일치하는 1개 찾기
		// document.getElementsByName("name값"); name값이 일치하는 n개 찾기
		// document.getElementsByClassName("class값"); class값이 일치하는 n개 찾기
		// document.getElementsByTagName("img"); 태그가 img인 n개 찾기

		const imgs = document.getElementsByClassName("imgs");
		const files = document.getElementsByName("file[]")
		function imageChangeBatch(e, idx) {
			if (e.files.length > 0) {
				imgs[Number(idx)].src = URL.createObjectURL(e.files[0]); // 가상의 url 정보를 생성해 추가. 
			} else {
				imgs[Number(idx)].src = "${pageContext.request.contextPath}/resources/images.png";
			}
		}

		function insertImageBatch() { // no image 이미지를 클릭하면 "file"이라는 id의 기능을 실행시킨다. (이미지 추가하기 기능. 현재 감춰둔 상태)
			console.log(imgs);
			console.log(imgs.length);
			console.log(e.files);
			console.log(idx);
		}

		function clickImage() {
			document.getElementById("file").click();
		}

		function clickImages() {
			document.getElementById("file[]").click();
		}

		function imageChange(e) {
			console.log(e.files);
			if (e.files.length > 0) { // 첨부
				// 파일을 첨부하면 크롬에서 "blob:http://127.0.0.1:8080/...."라고 콘솔창에 띄운다.
				console.log(URL.createObjectURL(e.files[0])); // 확인용

				img.src = URL.createObjectURL(e.files[0]); // 가상의 url 정보를 생성해서 추가함. 
			} else { // 취소
				img.src = "${pageContext.request.contextPath}/resources/images.png";
			}
		}
		
		function imageUpdateChange(e) {
			console.log(e.files);
			if (e.files.length > 0) { // 첨부
				// 파일을 첨부하면 크롬에서 "blob:http://127.0.0.1:8080/...."라고 콘솔창에 띄운다.
				console.log(URL.createObjectURL(e.files[0])); // 확인용

				modal_image_src.src = URL.createObjectURL(e.files[0]); // 가상의 url 정보를 생성해서 추가함. 
			} else { // 취소
				modal_image_src.src = "${pageContext.request.contextPath}/resources/images.png";
			}
		}

		function insertItemImage() {
			// 유효성 검사 한 후 
			const file = document.getElementById("file");
			if (file.value.length <= 0) {
				Swal.fire('첨부된 파일이 없어요!', '이미지가 없으면 등록할 수 없어요.', 'error')
				return false;
			}
			// form 태그 전송
			document.getElementById("form").submit();

			Swal.fire({
				icon : 'success',
				title : '이미지등록 완료!',
				showConfirmButton : false,
				timer : 2000
			})
		}

		function insertImageBatch() {
			// 유효성 검사		
			var chk = 0;
			for (let i = 0; i < imgs.length; i++) { // 반복문으로 files 전체 유효성 검사
				if (files[i].value.length <= 0) {
					Swal.fire('첨부된 파일이 없어요!', '이미지가 없으면 등록할 수 없어요.', 'error')
					chk = 1;
					break; // 반복문 종료
				}
			}
			if (chk === 0) { // if문을 한번도 수행하지 않았다면,
				//form 전송
				document.getElementById("form1").submit();

				Swal.fire({
					icon : 'success',
					title : '이미지등록 완료!',
					showConfirmButton : false,
					timer : 2000
				})
			}
		}
	</script>
</body>
</html>

주의해야 할 내용


javascript 명칭 확인할 것!

이미지 수정 모달창


버튼누를때 이미지 넘버와 물품넘버를 넘기도록 onclick에 저장


form 태그에서 반응하기 위해서는 button이 아닌 input의 submit 형태로 바꿔주어야 함.



또한 form의 enctype을 multipart/form-data로 지정해주었으니 @MultipartConfig로 지정해주어야 한다.

<!-- Modal -->
		<div class="modal fade" id="exampleModal" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true">
			<form action="imageupdate.do" method="post"	enctype="multipart/form-data">
				<div class="modal-dialog">
					<div class="modal-content">
						<div class="modal-header">
							<h5 class="modal-title" id="exampleModalLabel">이미지 수정</h5>
							<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
						</div>
						<div class="modal-body">
								이미지 번호 : <input type="text" name="imageNo"
												    id="modal_image_no" readonly /><br /> 
                                현재 적용된 이미지 : <img style="width: 90px; height: 90px"
													   id="modal_image_src"><br /> <input type="hidden"
													   name="ino" value="${ino}"> 
                                이미지변경 : <input name="file" type="file" id="modal_image_file"
												  onchange="imageUpdateChange(this)" /><br />
						</div>
						<div class="modal-footer">
							<input type="submit" class="btn btn-success" value="변경하기" />
							<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">취소</button>
						</div>
					</div>
				</div>
		    </form>
		 </div>



고객 웹 만들기

고객 회원가입
127.0.0.1:8080/web01/customer/join.do
ROLE CUSTOMER

판매자 회원가입
127.0.0.1:8080/web01/customer/join.do
ROLE SELLER

고객 회원가입

ID 중복검사 (RestMemberIdCheck.java)

id 값 입력마다 console창에 로그가 생성되도록 설정

ID 중복검사 Mapper SQL 추가

// 중복되는 id값의 개수를 받아옴
	@Select( value = {
			"	SELECT COUNT(*) cnt FROM memtb	",
			"	WHERE id = #{id}	"
	} )
	public int selectMemberIdCheck(@Param("id") String id);

join.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>
<html lang="ko">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>고객용 회원</title>
<!-- bootstrap -->
<link
	href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css"
	rel="stylesheet"
	integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC"
	crossorigin="anonymous">
</head>
<body>
	<div class="container">
		<div
			style="width: 600px; margin: 0 auto; padding: 50px; border: 1px solid #efefef;">
			<h3>회원가입</h3>
			<div class="row">
				<div class="col-sm">
					<div class="form-floating mb-2">
						<input type="text" id="id" class="form-control"	onkeyup="ajaxIDCheck(this)">
						<label for="id" id="lbl_check" class="form-label">사용할아이디</label>
					</div>

					<div class="form-floating mb-2">
						<input type="password" id="pw" class="form-control" required /> <label
							for="pw" id="lbl_pwCheck" class="form-label">암호</label>
					</div>
					<div class="form-floating mb-2">
						<input type="password" id="pw1" class="form-control" onkeyup="ajaxPWCheck(this)" required/>
						<label for="pw1" id="lbl_pwCheck" class="form-label" >암호재확인</label>
					</div>
					<div class="form-floating mb-2">
						<input type="text" id="name" class="form-control" required /> <label
							for="name" class="form-label">이름</label>
					</div>
					<div class="form-floating mb-2">
						<input type="text" id="age" class="form-control" /> <label
							for="age" class="form-label">나이</label>
					</div>
					<div>
						<input type="submit" value="회원가입" class="btn btn-success">
						<button type="button" class="btn btn-secondary">로그인하기</button>
					</div>
				</div>
			</div>
		</div>
	</div>

	<!-- sweetalert2 -->
	<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
	<!-- jQuery -->
	<script src="${pageContext.request.contextPath}/resources/js/jquery-3.6.4.min.js"></script>
	<!-- axios -->
	<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/1.3.5/axios.min.js"></script>	

	<script>
	
	function ajaxPWCheck(e) {
		console.log(e.value);
	      var pw = document.getElementById('pw').value;
	      var pw1 = document.getElementById('pw1').value;
	      
	      
	      if(pw.length < 6) { lbl_pwCheck
				document.getElementById("lbl_pwCheck").innerText = '비밀번호는 6글자 이상이어야 합니다.';
	          }
	
	          if( pw != pw1 ) {
					document.getElementById("lbl_pwCheck").innerText = '입력한 글자가 6글자 이상이어야 합니다.';
	            return false;
	          } else {
	        	  document.getElementById("lbl_pwCheck").innerText = '비밀번호가 일치합니다!';
				  document.getElementById("lbl_pwCheck").style.color = 'blue';
	            return true;
	          }
	    }
	
	
	async function ajaxIDCheck(e){
		console.log(e.value);
			document.getElementById("lbl_check").innerText = '아이디';
			document.getElementById("lbl_check").style.color = 'black';
			document.getElementById("id").className = 'form-control';
		if(e.value.length>0) {
			// rest api 호출
			const url 		= '${pageContext.request.contextPath}/api/member/idcheck.json?id=' + e.value;
			const headers 	= {"Content-Type":"application/json"};
			const {data} 	= await axios.get(url, {headers});
			console.log(data);
			
			if(data.ret === 1){
				document.getElementById("lbl_check").innerText = '이미 사용중인 ID입니다!';
				document.getElementById("lbl_check").style.color = 'red';
				document.getElementById("id").className = 'form-control is-invalid';
			}
			else if(data.ret === 0){
				document.getElementById("lbl_check").innerText = '사용가능!';
				document.getElementById("lbl_check").style.color = 'blue';
			}
		} 
	}
	</script>
</body>
</html>


중복되는 아이디일때는 빨간색,


사용가능한 아이디일때는 파란색으로 표시되도록 설정하였다.

profile
시작은 미약하지만, 그 끝은 창대하리라

0개의 댓글