본문 바로가기
개발 공부 Today I Learned

[국비 60일차 TIL] spring 글쓰기, 디테일, 댓글 modal

by 개발자신입 2024. 2. 19.
반응형

20240219 spring 웹 표준 기술 modal RESTAPI RESTFULL

 

board.jsp

게시글 디테일 모달

	<!-- 글쓰기 모달 만들기 -->
	<div class="modal" id="write">
		<div class="modal-dialog modal-xl">
			<div class="modal-content">
				<div class="modal-header">
					<h3 class="modal-title">글쓰기 창입니다.</h3>
					<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
				</div>
				<div class="modal-body">
					<div class="mt-2">
						<form action="./write" method="post" onsubmit="return writeCheck()" name="frm">
							<input type="text" id="title" name="title" class="form-control mb-2" required="required" placeholder="제목을 입력하세요">
							<textarea id="content" name="content" class="form-control mb-2 vh-500" required="required"></textarea>
							<button type="submit" class="btn btn-info">글쓰기</button>
						</form>
					</div>
				</div>
				<div class="modal-footer">
					2024-02-19 웹표준 기술 / RESTAPI / RESTFULL
				</div>
			</div>
		</div>
	</div>


	<!-- 내용보기 detail 모달 만들기 -->
	<div class="modal" id="detail">
		<div class="modal-dialog modal-xl">
			<div class="modal-content">
				<div class="modal-header">
					<h3 class="modal-title">글 내용 보기</h3>
					<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
				</div>
				<div class="modal-body">
					<div class="mt-2">
						제목 <br> 본문 내용
					</div>
				</div>
				<div class="modal-footer">디테일 모달 닫기</div>
			</div>
		</div>
	</div>

 

td class에 onclick="detail()" 추가 -> detail() 펑션 만들어야 함
detail() 괄호 안에 ${row.board_no } = 몇 번째 글을 클릭했어

			<tbody>
				<c:forEach items="${list }" var="row">
					<tr>
						<td>${row.board_no }</td>
						<td class="title" onclick="detail(${row.board_no })">
						<%-- <a href="./detail?no=${row.board_no }"> </a>--%>
						${row.board_title }
						<c:if test="${row.comment gt 0}">
							<span class="badge">${row.comment }</span>
						</c:if>
						</td>
						<td>${row.board_write }</td>
						<td>${row.board_date }</td>
						<td>${row.board_count }</td>
					</tr>
				</c:forEach>
			</tbody>

SweetAlert 


https://sweetalert.js.org/

<script src="https://unpkg.com/sweetalert/dist/sweetalert.min.js"></script>

위의 코드를 입력하고 alert 대신에 swal 로 기입함.

 

SweetAlert

You've arrived! How lovely. Let me take your coat. Oops! Seems like something went wrong! Delete important stuff? That doesn't seem like a good idea. Are you sure you want to do that?

sweetalert.js.org

 

	function detail(){
		/* swal("Good job!", "상세보기 입니다.", "success"); // sweet alert 사용 : title, text, icon, button */
		swal({
		       title:"Good job!",
		       text:"상세보기입니다.",
		       icon:"success",
		       button:"좋아요"});
	}

 

 

modal 잘 뜹니다.

 

 

<td class="title" onclick="detail(${row.board_no })"> = 몇 번째 글을 클릭했어
no값이 들어오는지 alert 확인 (swal 지우고 기본 alert만)

	function detail(no){
		alert(no);
}

 

클릭하면 text에 글 번호가 나옴.

	function detail(no){
		swal({
		       title:"Good job!",
		       text:"번호는 " + no,
		       icon:"success",
		       button:"좋아요"}); 
		// alert(no);
	}

 

modal 확인

function detail(no){}에 추가 : 모달이 잘 뜨는지 확인용도

// 모달 보이게 하기		       
let detailModal = new bootstrap.Modal('#detail', {}); // {옵션}
detailModal.show();  // detail modal을 보여줘

detail.jsp

내용보기 모달 만들기

모달 타이틀에 id 추가

<h5 class="modal-title" id="modalTitle">글 내용 보기</h5>

 

모달 보이게 하는 let 부분에 적용함.
모달 title에 글 번호가 뜸. title안의 text를 no로 보이도록.

		       let detailModal = new bootstrap.Modal('#detail', {}); // {옵션}
		       $("#modalTitle").text(no);
		       detailModal.show();

 

모달 제목, 내용에도 id 추가 

 

글 내용보기 : id="modalTitle"
제목, 본문내용 : id="modalContent"

	<!-- detail 모달 -->
	<div class="modal" id="detail">
		<div class="modal-dialog modal-xl">
			<div class="modal-content">
				<div class="modal-header">
					<h5 class="modal-title" id="modalTitle">글 내용 보기</h5>
					<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
				</div>
				<div class="modal-body">
					<div class="mt-2" id="modalContent">
						제목<br>
						본문내용
					</div>
				</div>
				<div class="modal-footer">
					Detail 모달 닫기
				</div>
			</div>
		</div>
	</div>
let detailModal = new bootstrap.Modal('#detail', {}); // {옵션}
		       $("#modalTitle").text(no);
		       $("#modalContent").text("변경된 내용입니다.");
		       detailModal.show();

 

-> title, content의 id를 변경한 후, function detail(no)에서 모달 보이게 하기

let detailModal = new bootstrap.Modal('#detail', {}); // {옵션}
       $("#modalTitle").text(no);
       $("#modalContent").text("변경된 내용입니다.");
       detailModal.show();

jQuery

ajax를 쓰기 위해 jQuery 추가

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js" 
integrity="sha512-v2CJ7UaYy4JwqLDIrZUI/4hqeoQieOmAZNXBeQyjo21dadnwR+8ZaIJVT8EE2iyI61OV8e6M8PP2/4hpQINQ/g==" 
crossorigin="anonymous" referrerpolicy="no-referrer">
</script>

 

 		$.ajax({
			url 	 : "restDetail",
			type 	 : "post",
			dataType : "text",
			data 	 : {'no' : no}, // 날라갈 데이터(no) text -> json
			success  : function(data){
				alert(data);
			},
			error 	 : function(error){
				alert(error);
			}
		}); 
	}
</script>

RestController.java

먼저 출력문으로 값이 오는지 확인함.

@Controller
public class RestController {
	
	@Autowired
	private BoardService boardService;
	
	@PostMapping("/restDetail")
	public BoardDTO restDetail(@Param("no") int no) { 
//		System.out.println("restDetail : " + no);
		BoardDTO detail = boardService.detail(no); // detail에 담겨서 옵니다.
		System.out.println(detail.getBoard_title());
//		System.out.println(detail.getBoard_content());
		
		return detail;
	}

}

 

@ResponseBody 어노테이션 추가

@Controller
public class RestController {
	
	@Autowired
	private BoardService boardService;
	
	@PostMapping("/restDetail")
	public @ResponseBody BoardDTO restDetail(@Param("no") int no) { // 결과는 body에 출력해 (view를 안 보여주게)
		BoardDTO detail = boardService.detail(no); // detail에 담겨서 옵니다.
		return detail;
	}

}

board.jsp

$("#modalTitle").text(data.board_title);

$("#modalContent").html(data.board_content);

detailModal.show();

	function detail(no){		       
	       // 모달 보이게 하기
	       let detailModal = new bootstrap.Modal('#detail', {}); // {옵션}
		       
			$.ajax({
				url      : "/restDetail",
				type     : "post",
				dataType : "json",
				data     : {'no' : no},
				success  : function(data){  //text -> json
					//alert(data.board_title);
					$("#modalTitle").text(data.board_title);
					$("#modalContent").html(data.board_content);
					detailModal.show();
				},
				error    : function(error){
					alert(error);
				}
			});
		}
		
	</script>

 

a링크와 onclick 동시에 사용하기.

					<tbody>
						<c:forEach items="${list }" var="row">
							<tr>
								<td onclick="detail(${row.board_no })">${row.board_no }</td>
								<td class="title">
									<a href="./detail?no=${row.board_no }"> 
										${row.board_title }
										<c:if test="${row.comment gt 0}">
											<span class="badge">${row.comment }</span>
										</c:if>
									</a>
								</td>
								<td>${row.board_write }</td>
								<td>${row.board_date }</td>
								<td>${row.board_count }</td>
							</tr>
						</c:forEach>
					</tbody>

detail.jsp

댓글쓰기 창과 버튼 css

			<!-- 2024-02-19 -->
			<hr>
			<div class="container">
				<form action="./commentWrite" method="post">
					<div class="row">
						<div class="col-xs-8 col-sm-8 col-md-11 col-xl-11">
							<textarea class="form-control" style="height: 100%;"></textarea>
						</div>
						<div class="col-xs-4 col-sm-4 col-md-1 col-xl-1">
							<button class="btn btn-success" style="width: 100px; height: 100%;">댓글쓰기</button>
						</div>
					</div>
				</form>
			</div>

BoardController.java

댓글은 컨트롤러를 따로 만들지 않고, board에 포함시켜서 작업함.

	// 2024-02-19 댓글쓰기 psd = 글 번호 no, 댓글 내용 comment, 글쓴이 필요함.
		@PostMapping("/commentWrite")
		public String commentWrite() {
			return "redirect:/detail"; 
		}

detail.jsp

글 번호 가져오기 
댓글 버튼 아래에 코드 추가

 

<input type="hidden" name="no" value="${detail.board_no }">

textarea에 name 붙여줌.
<textarea class="form-control" name="comment" style="height: 100%;"></textarea>

			<div class="container">
				<form action="./commentWrite" method="post">
					<div class="row">
						<div class="col-xs-8 col-sm-8 col-md-11 col-xl-11">
							<textarea class="form-control" name="comment" style="height: 100%;"></textarea>
						</div>
						<div class="col-xs-4 col-sm-4 col-md-1 col-xl-1">
							<button class="btn btn-success" style="width: 100px; height: 100%;">댓글쓰기</button>
						</div>
					</div>
				<input type="hidden" name="no" value="${detail.board_no }">
				</form>
			</div>

 

detail.jsp 에 글 번호 no, 댓글 내용 comment 추가 -> CommentDTO 생성해서 불러오기

	// 2024-02-19 댓글쓰기 psd = 글 번호(no), 댓글 내용(comment), 글쓴이 필요함.
		@PostMapping("/commentWrite")
		public String commentWrite(CommentDTO comment) {
			System.out.println("접근?"); // 확인용도
			return "redirect:/detail"; 
		}

CommentDTO.java

import lombok.Data;

@Data
public class CommentDTO { // 필요한거 : 글 번호, 댓글 내용, 작성자 (mid)
	private int no;
	private String comment, mid;
}

 

CommentDTO 생성 후에 BoardController에서 값이 오는지 확인하기


System.out.println(comment.getNo());
System.out.println(comment.getComment());
System.out.println(comment.getMid());


BoardController.java

	// 2024-02-19 댓글쓰기 psd = 글 번호 no, 댓글 내용 comment, 글쓴이 필요함.
		@PostMapping("/commentWrite")
		public String commentWrite(CommentDTO comment) {
			int result = boardService.commetWrite(comment); // boardService 실행 시 dto를 가지고 날아감
			System.out.println("댓글쓰기 결과 : " + result); // 1이면 정상, 0이면 에러
			return "redirect:/detail"; 
			
		}

 

-> boardService.commetWrite(comment);의 commentWrite가 없기 때문에 boardService에 생성해주기.

	public int commetWrite(CommentDTO comment) {
		comment.setMid("test2"); // mid에 있는 아이디 하나 불러오기
		return boardDAO.commentWrite(comment); // DAO에게 일 시키기
	}


-> commentWrite를 BoardDAO에 생성해주기

	public int commentWrite(CommentDTO comment) {
		return sqlSession.insert("board.commentWrite", comment);
	}

 


board-mapper.xml

	<!-- 2024-02-19 -->
   <insert id="commentWrite" parameterType="commentDTO">
      INSERT INTO comment (board_no, ccomment, mno) 
      VALUES (#{no}, #{comment}, (SELECT mno FROM member WHERE mid=#{mid}))
   </insert>

 

mybatis-config.xml

<typeAlias type="org.-----.dto.CommentDTO" alias="commentDTO"/>

 


BoardController.java

public detail 부분 파라미터 값 변경

@Param("no) -> @RequestParam(value = "no", defaultValue = "0", required = true) 으로 수정

축약한다면 @RequestParam(value = "no")

		@GetMapping("/detail")
		public String detail(@RequestParam(value = "no", defaultValue = "0", required = true) String no, Model model) { // @Param : spring이 알아서 처리함
			// @RequestParam : http 요청을 컨트롤러에 전달할 때 사용. url에서 오는 거
			// no가 없으면 기본값은 "" 이걸로 가져감. (몇 번글로 넘어감)
			// defaultValue를 0으로 세팅하면 바로 error로 넘어감.   (0번 글이 없으니까)
			// required 반드시 있어야 하는 경우 (없어도 가능함. 기본은 true로 되어있음 / 필요없는 경우는 false로 적음)
			
			int reNo = util.str2Int(no);
			if(reNo != 0) { 
				// 0이 아니라면 (정상: DB에 물어보기, 값 가져오기, 붙이기(model 객체), 이동하기)
				BoardDTO detail = boardService.detail(reNo);
				model.addAttribute("detail", detail);
				return "detail"; 	// 주소창이 detail?no= 이렇게 detail이 들어감.
				
			} else { // 0이라면 (비정상: 에러 페이지로 이동하기)
				return "redirect:/error"; 	// controller에 있는 error매핑을 실행해 (http://localhost/error)
			}

 

-> 글 번호를 받아서 글 번호로 페이지 이동하도록 return 코드 수정

	// 2024-02-19 댓글쓰기 psd = 글 번호 no, 댓글 내용 comment, 글쓴이 필요함.
		@PostMapping("/commentWrite")
		public String commentWrite(CommentDTO comment) {
			int result = boardService.commetWrite(comment); // boardService 실행 시 dto를 가지고 날아감
			System.out.println("댓글쓰기 결과 : " + result); // 1이면 정상, 0이면 에러
			return "redirect:/detail?no="+comment.getNo(); // 글 번호를 받아서 글 번호로 페이지 이동 	
		}
}

 


board-mapper.xml

detail 부분 SQL 수정:

 게시글의 상세 정보를 가져오는 데 사용되며, comment 서브쿼리를 사용하여 해당 게시글의 댓글 개수도 함께 조회

<select id="detail" resultType="boardDTO" parameterType="Integer">
	SELECT b.board_no, b.board_title, b.board_content, m.mname as board_write, b.board_date, b.board_ip, 
	(SELECT COUNT(*) FROM comment WHERE board_no=b.board_no) AS comment 
	FROM board b JOIN member m ON b.mno=m.mno WHERE board_no=#{no} AND board_del ='1' <!-- mybatis 변수명 # -->
</select>

 


BoardController.java

sql 수정 후 콘솔에 출력되나 확인

boardcontroller의 detail if문에서  System.out.println("댓글 수 : "+ detail.getComment()); 출력문 추가해서 확인해보기.

		@GetMapping("/detail")
		public String detail(@RequestParam(value = "no", defaultValue = "0") String no, Model model) { // @Param : spring이 알아서 처리함

			int reNo = util.str2Int(no);
			if(reNo != 0) { 
				BoardDTO detail = boardService.detail(reNo);
				model.addAttribute("detail", detail);
				
				// 2024-02-19 psd 댓글 출력

				System.out.println("댓글 수 : "+ detail.getComment());
								
				return "detail"; 	// 주소창이 detail?no= 이렇게 detail이 들어감.
				
			} else { // 0이라면 (비정상: 에러 페이지로 이동하기)
				return "redirect:/error"; 	// controller에 있는 error매핑을 실행해 (http://localhost/error)
			}
		}

 

			int reNo = util.str2Int(no);
			if(reNo != 0) { 
				BoardDTO detail = boardService.detail(reNo);
				model.addAttribute("detail", detail);
				
				if(detail.getComment() > 0) { // 댓글이 1개 이상이면
					List<CommentDTO> commentsList = boardService.commentsList(reNo);
					model.addAttribute("commentsList", commentsList); 
				}				
				return "detail";

 

-> 위에서 만들어진 commentsList를 BoardService에 추가하기

	public List<CommentDTO> commentsList(int no) {
	      return boardDAO.commentsList(no);
	   }

BoardDAO

	public List<CommentDTO> commentsList(int no) {
		return sqlSession.selectList("board.commentsList", no);
	}

 

board-mapper.xml

   	<select id="commentsList" resultType="commentDTO" parameterType="Integer">
		SELECT cno, ccomment AS comment, cdate, clike, mname, cip
		FROM commentview 
		WHERE board_no=#{no}
	</select>

CommentDTO

DTO에 cno, mname, cdate, clike, cip 추가하기

import lombok.Data;

@Data
public class CommentDTO {
	private int no, cno, board_no, clike, mno;
	private String comment, mid, mname, cdate, cip;
}

board-mapper.xml

  	<resultMap type="commentDTO" id="commentDTOmap">
  		<result column="cno" property="no"/>
  		<result column="board_no" property="board_no"/>
  		<result column="ccomment" property="comment"/>
  		<result column="cdate" property="cdate"/>
  		<result column="clike" property="clike"/>
  		<result column="mno" property="mno"/>
  		<result column="mid" property="mid"/>
  		<result column="mname" property="mname"/>
  		<result column="cip" property="cip"/>
  	</resultMap>

 

-> 생성한 resultMap(id = commentDTOmap)을 resultType -> resultMap으로 변경 후 resultMap에 적용하기

   	<select id="commentsList" parameterType="Integer" resultMap="commentDTOmap" >
		SELECT cno, ccomment, cdate, clike, mid, mname, cip
		FROM commentview 
		WHERE board_no=#{no}
	</select>

detail.jsp

-> detail.jsp의 댓글출력창 입력

		<!-- 댓글 출력창 20240219 -->
		<c:forEach items="${commentsList }" var="c">
			${c.no } / ${c.comment } / ${c.cdate } / ${c.clike } / ${c.mno } / ${c.mid } / ${c.mname } / ${c.cip } <br>
		</c:forEach>

 

 

-> 댓글 출력창 css 만들기 (bootstrap)

 

		<!-- 댓글 출력창 20240219 -->
	
		<div class="mt-2">
  		<c:forEach items="${commentsList}" var="c">
   			 <div class="card mb-3">
      			<div class="card-header bg-success text-white">
       				 ${c.no} / ${c.cdate} / ${c.clike} / ${c.mno} / ${c.mid} / ${c.mname}
     			 </div>
     		 <div class="card-body">
      	  <p class="card-text">${c.comment}</p>
     	 </div>
  	 </div>
 		 </c:forEach>
</div>

 

-> 게시글 디테일 부분에 아이콘 추가하기

다운받은 이미지 img 폴더에 넣기.
${detail.board_write } 뒤에 아이콘 추가하기
아이콘을 누르면 넘어가도록 onclick 기능도 추가하기. onclick="deletePost(${detail.board_no})"

 

	<!-- 게시판 -->
	<br>
	<br>
	<section class="page-section" id="detail">
		<div class="container">
			<div class="text-center">
				<h2 class="section-heading text-uppercase">게시글 디테일</h2>
			</div>
			<div class="card mb-4" style="min-height: 500px;">
				<div class="card-body">
					<div class="h2">${detail.board_title }</div>
					<div class="row p-2 bg-secondary">
						<div class="col align-middle text-start">${detail.board_write }
							<img alt="edit" src="./assets/img/pencil.png">
							<img alt="delete" src="./assets/img/deletey.png" title="글 삭제" onclick="deletePost(${detail.board_no})">
							</div>
						<div class="col align-middle text-end">${detail.board_date }</div>
					</div>
					<div class="mt-4 vh -75">${detail.board_content }</div>
				</div>
			</div>
			<button class="btn btn-warning" onclick="history.back()">게시판으로</button>
			<button class="btn btn-warning" onclick="history.go(-1)">게시판으로</button>

 

-> function deletePost() 생성
swal.fire 사용해서 alert창 뜨도록 만들기

<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
<script type="text/javascript">
function deletePost(){
   Swal.fire({
        title: "글을 삭제합니다",
        //text: "post를 삭제합니다.",
        icon: "warning",
        showCancelButton: true,
        confirmButtonText: "Yes",
        cancelButtonText: "No",
      }).then(result => {
        if (result.isConfirmed) {
          Swal.fire("삭제했습니다.","", "success");
        }
      });
}
</script>

 

반응형

댓글