[SpringBoot] TIL 082 - 23.11.22

유진·2023년 11월 21일
0

SpringBoot : 게시글 수정, 댓글

게시글 수정

BoardController2.java

package edu.kh.project.board.controller;

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

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.SessionAttribute;
import org.springframework.web.bind.annotation.SessionAttributes;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import edu.kh.project.board.model.dto.Board;
import edu.kh.project.board.model.service.BoardService;
import edu.kh.project.board.model.service.BoardService2;
import edu.kh.project.member.model.dto.Member;
import jakarta.servlet.http.HttpSession;

@Controller
@RequestMapping("/board2")
@SessionAttributes({"loginMember"})
public class BoardController2 {
	
	@Autowired
	private BoardService2 service; // 삽입,수정,삭제
	
	@Autowired
	private BoardService boardService; // 목록, 상세 조회
	
	
	// 게시글 작성 화면 전환
	@GetMapping("/{boardCode:[0-9]+}/insert")
	public String boardInsert(@PathVariable("boardCode") int boardCode) {
		// @PathVariable : 주소 값 가져오기 + request scope에 값 올리기
		
		return "board/boardWrite";
	}
	
	// 게시글 작성
	@PostMapping("/{boardCode:[0-9]+}/insert")
	public String boardInsert(
			@PathVariable("boardCode") int boardCode
			, Board board // 커맨드 객체 (필드에 파라미터 담겨있음!)
			, @RequestParam(value="images", required = false) List<MultipartFile> images
			, @SessionAttribute("loginMember") Member loginMember
			, RedirectAttributes ra
			) throws IllegalStateException, IOException {
	
		// 파라미터 : 제목, 내용, 파일(0~5개)
		// 파일 저장 경로 : HttpSession
		// 세션 : 로그인한 회원의 번호
		// 리다이렉트 시 데이터 전달 : RedirectAttributes ra (message)
		
		/* List<MultipartFile>
		 * - 업로드된 이미지가 없어도 List에 MultipartFile 요소는 존재함.
		 * 
		 * - 단, 업로드된 이미지가 없는 MultipartFile 요소는
		 * 	 파일 크기(size)가 0 또는 파일명(getOriginalFileName()) "" 빈칸
		 * 
		 * */
		
		// 1. 로그인한 회원 번호를 얻어와 board에 세팅
		board.setMemberNo(loginMember.getMemberNo());
		
		// 2. boardCode도 board에 세팅
		board.setBoardCode(boardCode);
		
		
		
		// 게시글 삽입 서비스 호출 후 삽입된 게시글 번호 반환 받기
		int boardNo = service.boardInsert(board, images);
		
		
		// 게시글 삽입 성공 시
		// -> 방금 삽입한 게시글의 상세 조회 페이지 리다이렉트
		// -> /board/{boardCode}/{boardNo}
		
		String message = null;
		String path = "redirect:";
		
		if(boardNo > 0) {
			message = "게시글이 등록 되었습니다";
			path += "/board/" + boardCode + "/" + boardNo;
		} else {
			message = "게시글 등록 실패................";
			path += "insert";
		}
		
		ra.addFlashAttribute("message", message);
		
		return path;
		
	}
	
	// 게시글 수정 화면 전환
	@GetMapping("/{boardCode}/{boardNo}/update")   // /board2/2/2006/update?cp=1
	public String boardUpdate(
			@PathVariable("boardCode") int boardCode,
			@PathVariable("boardNo") int boardNo,
			Model model
			// Model : 데이터 전달용 객체 (기본 scope: request)
			) {
		
		Map<String, Object> map = new HashMap<String, Object>();
		map.put("boardCode", boardCode);
		map.put("boardNo", boardNo);
		
		Board board = boardService.selectBoard(map);
		
		model.addAttribute("board", board);
		
		return "board/boardUpdate";
		
	}
	
	// 게시글 수정
	@PostMapping("/{boardCode}/{boardNo}/update")
	public String boardUpdate(
			Board board, // 커맨드 객체(name == 필드 경우 필드에 파라미터 세팅)
			@PathVariable("boardCode") int boardCode,
			@PathVariable("boardNo") int boardNo,
			@RequestParam(value="cp", required = false, defaultValue = "1") int cp, // 쿼리스트링 유지
			@RequestParam(value="images", required = false) List<MultipartFile> images, // 업로드된 파일 리스트
			@RequestParam(value="deleteList", required = false) String deleteList, // 삭제할 이미지 순서
			RedirectAttributes ra // 리다이렉트 시 값 전달용(message)
			) throws IllegalStateException, IOException {
		
		// 1) boardCode, boardNo를 커맨드 객체(board)에 세팅
		board.setBoardCode(boardCode);
		board.setBoardNo(boardNo);
		
		// 3) 게시글 수정 서비스 호출
		int rowCount = service.boardUpdate(board, images, deleteList);
		
		// 4) 결과에 따라 message, path 설정
		String message = null;
		String path = "redirect:";
		
		
		if(rowCount > 0) {
			message = "게시글이 수정되었습니다";
			path += "/board/" + boardCode + "/" + boardNo + "?cp=" + cp;
		} else {
			message = "게시글 수정 실패";
			path += "update";
		}
		
		ra.addFlashAttribute("message", message);
		
		return path;
	}
	
	
	// 게시글 삭제 = DELETE 하지 않고 UPDATE 하기!
	@GetMapping("/{boardCode}/{boardNo}/delete")
	public String boardDelete(
			@PathVariable("boardCode") int boardCode,
			@PathVariable("boardNo") int boardNo,
			RedirectAttributes ra
			) {
		
		// boardCode, boardNo 서비스로 넘겨야함
		// map 으로 담아서 보내는걸 추천
		Map<String, Object> map = new HashMap<String, Object>();
		map.put("boardCode", boardCode);
		map.put("boardNo", boardNo);
		
		int result = service.boardDelete(map);
		
		// 결과값이 > 0 라면
		// "삭제되었습니다" 
		// /board/{boardCode} = 게시글 목록으로 돌아감
		
		// else
		// "삭제 실패"
		// /board/{boardCode}/{boardNo}
		
		String message = null;
		String path = "redirect:";
		
		if(result > 0) {
			System.out.println("삭제되었습니다");
			
			message = "삭제되었습니다";
			path += "/board/" + boardCode;
			
		} else {
			System.out.println("삭제 실패");
			
			message = "삭제 실패";
			path += "/board/" + boardCode + boardNo;
			
		}
		
		ra.addFlashAttribute("message", message);
		
		return path;
	}
	
	
	

}

BoardService2.java

package edu.kh.project.board.model.service;

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

import org.springframework.web.multipart.MultipartFile;

import edu.kh.project.board.model.dto.Board;

public interface BoardService2 {

	/** 게시글 삽입
	 * @param board
	 * @param images
	 * @param webPath
	 * @param filePath
	 * @return boardNo
	 */
	int boardInsert(Board board, List<MultipartFile> images)
								throws IllegalStateException, IOException;

	/** 게시글 수정 서비스
	 * @param board
	 * @param images
	 * @param webPath
	 * @param filePath
	 * @param deleteList
	 * @return rowCount
	 */
	int boardUpdate(Board board, List<MultipartFile> images, String deleteList) throws IllegalStateException, IOException;

	/** 게시글 삭제 서비스
	 * @param map
	 * @return result
	 */
	int boardDelete(Map<String, Object> map);

}

BoardServiceImpl2.java

package edu.kh.project.board.model.service;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import edu.kh.project.board.model.exception.FileUploadException;
import edu.kh.project.board.model.exception.ImageDeleteException;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import edu.kh.project.board.model.dao.BoardMapper2;
import edu.kh.project.board.model.dto.Board;
import edu.kh.project.board.model.dto.BoardImage;
import edu.kh.project.common.utility.Util;

@Service
@PropertySource("classpath:/config.properties")
public class BoardServiceImpl2 implements BoardService2{
	
	@Autowired
	private BoardMapper2 mapper;
	
	@Value("${my.board.webpath}")
	private String webPath;
	
	@Value("${my.board.location}")
	private String filePath;
	

	// 게시글 삽입
	@Transactional(rollbackFor = Exception.class)
	@Override
	public int boardInsert(Board board, List<MultipartFile> images) 
			throws IllegalStateException, IOException {
		
		/* XSS 방지 처리 더이상 하지 않아도 됨.
		 * 
		 * th:text ------> <h1>안녕하세요</h1> 태그 그대로 나와서 따로 처리하지 않아도 됨
		 * 
		 * 태그 그대로 해석하고 싶을때? th:utext  [(${text})]
		 * 
		 * */
		
		
		// 1. BOARD 테이블 INSERT 하기 (제목, 내용, 작성자, 게시판 코드)
		// -> boardNo (시퀀스로 생성한 번호) 반환 받기
		int result = mapper.boardInsert(board);
		
		// 실패 시 서비스 종료
		if(result == 0) return 0;
		
		// mapper.xml에서 selectKey 태그로 인해 세팅된 값 얻어오기
		int boardNo = board.getBoardNo();
		
		
		
		// 2. 게시글 삽입 성공 시
		// 업로드된 이미지가 있다면 BOARD_IMG 테이블에 삽입하는 DAO 호출
		if(boardNo > 0) { // 게시글 삽입 성공 시
			
			// List<MultipartFile> images
			// -> 업로드된 파일이 담긴 객체 MultipartFile이 5개 존재
			// -> 단, 업로드된 파일이 없어도 MultipartFile 객체는 존재
			
			// 실제 업로드된 파일의 정보를 기록할 List
			List<BoardImage> uploadList = new ArrayList<BoardImage>();
			
			// images에 담겨있는 파일 중 실제 업로드된 파일만 분류
			for(int i = 0; i < images.size(); i++) {
				
				// i번째 요소에 업로드된 파일이 있다면
				if(images.get(i).getSize() > 0) {
					
					BoardImage img = new BoardImage();
					
					// img 에 파일 정보를 담아서 uploadList 에 추가
					img.setImagePath(webPath); // 웹 접근 경로
					img.setBoardNo(boardNo); // 게시글 번호
					img.setImageOrder(i); // 이미지 순서

					// 파일 원본명
					String fileName = images.get(i).getOriginalFilename();
					
					img.setImageOriginal(fileName); // 원본명
					img.setImageReName( Util.fileRename(fileName) ); // 변경명
					
					
					uploadList.add(img);
					
				}
				
			} // 분류 for 문 종료
			
			
			// 분류 작업 후 uploadList가 비어 있지 않은 경우
			// == 업로드한 파일이 있다
			if( !uploadList.isEmpty() ) {
				
				// BOARD_IMG 테이블에 insert 하는 dao 호출
				result = mapper.insertImageList(uploadList);
				// result == 삽입된 행의 개수
				
				// 전체 insert 성공 여부 확인
				// 삽입된 행의 개수와 uploadList 의 개수가 같다면
				// == 전체 insert 성공
				if(result == uploadList.size()) {
					
					// 서버에 파일을 저장 (transferTo)
					
					for(int i = 0; i < uploadList.size(); i++) {
						
						int index = uploadList.get(i).getImageOrder();
						
						String rename = uploadList.get(i).getImageReName();
						
						images.get(index).transferTo( new File(filePath + rename) );
						
					}
					
					
					
				} else { // 일부 또는 전체 insert 실패
					
					// rollback 필요
					
					// @Transactional(rollbackFor = Exception.class)
					// -> 예외가 발생 해야지만 롤백
					
					// [결론]
					// 예외를 강제 발생 시켜서 rollback 해야된다
					// 사용자 정의 예외 만들어 발생시키자!
					
					
					throw new FileUploadException();
				}
				
			}
			
		}
		
		
		return boardNo;
	}

	// 게시글 수정 서비스
	@Transactional(rollbackFor = Exception.class)
	@Override
	public int boardUpdate(Board board, List<MultipartFile> images,
			String deleteList) throws IllegalStateException, IOException {
		
		// 2) DAO 호출
		int rowCount = mapper.boardUpdate(board);
		
		
		// 2. 게시글 부분이 수정 성공 했을 때
		if(rowCount > 0) {
			
			if(!deleteList.equals("")) { // 삭제할 이미지가 있다면
				
				// 3. deleteList에 작성된 이미지 모두 삭제
				Map<String, Object> deleteMap = new HashMap<String, Object>();
				deleteMap.put("boardNo", board.getBoardNo());
				deleteMap.put("deleteList", deleteList);
				
				rowCount = mapper.imageDelete(deleteMap);
				
				if(rowCount == 0) { // 이미지 삭제 실패 시 전체 롤백
									// -> 예외 강제로 발생
					
					throw new ImageDeleteException();
				}
		
			}
			
			
			// 4. 새로 업로드된 이미지 분류 작업
			// images : 실제 파일이 담긴 List
			//         -> input type="file" 개수만큼 요소가 존재
			//         -> 제출된 파일이 없어도 MultipartFile 객체가 존재
			
			List<BoardImage> uploadList = new ArrayList<>();
			
			for(int i=0 ; i<images.size(); i++) {
				
				if(images.get(i).getSize() > 0) { // 업로드된 파일이 있을 경우
					
					// BoardImage 객체를 만들어 값 세팅 후 
					// uploadList에 추가
					BoardImage img = new BoardImage();
					
					// img에 파일 정보를 담아서 uploadList에 추가
					img.setImagePath(webPath); // 웹 접근 경로
					img.setBoardNo(board.getBoardNo()); // 게시글 번호
					img.setImageOrder(i); // 이미지 순서
					
					// 파일 원본명
					String fileName = images.get(i).getOriginalFilename();
					
					img.setImageOriginal(fileName); // 원본명
					img.setImageReName( Util.fileRename(fileName) ); // 변경명    
					
					uploadList.add(img);
					
					// 오라클은 '다중 UPDATE를 지원하지 않기 때문에'
					// 하나씩 UPDATE 수행
					
					rowCount = mapper.imageUpdate(img);
					
					if(rowCount == 0) {
						// 수정 실패 == DB에 이미지가 없었다 
						// -> 이미지를 삽입
						rowCount = mapper.imageInsert(img);
					}
				}
			}
			
			
			// 5. uploadList에 있는 이미지들만 서버에 저장(transferTo())
			if(!uploadList.isEmpty()) {
				for(int i=0 ; i< uploadList.size(); i++) {
					
					int index = uploadList.get(i).getImageOrder();
					
					// 파일로 변환
					String rename = uploadList.get(i).getImageReName();
					
					images.get(index).transferTo( new File(filePath + rename)  );                    
				}
			}
		}
		
		
		return rowCount;
	}

	// 게시글 삭제 서비스
	@Override
	public int boardDelete(Map<String, Object> map) {
		return mapper.boardDelete(map);
	}
}

boardUpdate.html

<!DOCTYPE html>
<html lang="ko" xmlns:th="http://thymeleaf.org">
<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 th:text="${boardName}">게시판 이름</title>

    <link rel="stylesheet" th:href="@{/css/board/boardWrite-style.css}">
</head>
<body>
    <main>
        <th:block th:replace="~{common/header}"></th:block>

        <form th:action="@{update}" method="POST" 
            class="board-write" id="boardUpdateFrm" enctype="multipart/form-data">

            <h1 class="board-name" th:text="${boardName}">게시판 이름</h1>

            <!-- 제목 -->
            <h1 class="board-title">
                <input type="text" name="boardTitle" placeholder="제목" th:value="${board.boardTitle}">   
            </h1>

            <!-- 썸네일 영역 -->
            <h5>썸네일</h5>
            <div class="img-box">
                <div class="boardImg thumbnail">
                    <label for="img0">
                        <img class="preview">
                    </label>
                    <input type="file" name="images" class="inputImage" id="img0" accept="image/*">
                    <span class="delete-image">&times;</span>
                </div>
            </div>


            <!-- 업로드 이미지 영역 -->
            <h5>업로드 이미지</h5>
            <div class="img-box">

                <div class="boardImg">
                    <label for="img1">
                        <img class="preview">
                    </label>
                    <input type="file" name="images" class="inputImage" id="img1" accept="image/*">
                    <span class="delete-image">&times;</span>
                </div>

                <div class="boardImg">
                    <label for="img2">
                        <img class="preview">
                    </label>
                    <input type="file" name="images" class="inputImage" id="img2" accept="image/*">
                    <span class="delete-image">&times;</span>
                </div>

                <div class="boardImg">
                    <label for="img3">
                        <img class="preview">
                    </label>
                    <input type="file" name="images" class="inputImage" id="img3" accept="image/*">
                    <span class="delete-image">&times;</span>
                </div>

                <div class="boardImg">
                    <label for="img4">
                        <img class="preview">
                    </label>
                    <input type="file" name="images" class="inputImage" id="img4" accept="image/*">
                    <span class="delete-image">&times;</span>
                </div>
            </div>

            <!-- 내용 -->
            <div class="board-content">
                <textarea name="boardContent" th:text="${board.boardContent}">내용</textarea>
            </div>


            <!-- 버튼 영역 -->
            <div class="board-btn-area">
                <button type="submit" id="writebtn">등록</button>
            </div>

            
            <!-- 기존 이미지가 있다가 삭제된 이미지의 순서를 기록-->
            <input type="hidden" name="deleteList" value="">

            <!-- 수정 성공 시 주소(쿼리스트링) 유지용도 -->
            <input type="hidden" name="cp" th:value="${param.cp}">
        </form>

    </main>

    <th:block th:replace="~{common/footer}"></th:block>

    <script th:src="@{/js/board/boardUpdate.js}"></script>

    <script th:inline="javascript">
        // 타임리프로 얻어온 자바의 자료형을 JS 자료형으로 변환

        const imageList = /*[[${board.imageList}]]*/ [];

        const previewList = document.querySelectorAll("img.preview");
                            // img 태그 중 preview라는 클래스 모든 것!

        for(let img of imageList) {
            previewList[img.imageOrder].src = img.imagePath + img.imageReName;
        }                    

    </script>

</body>
</html>


댓글

CommentController.java

package edu.kh.project.board.controller;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import edu.kh.project.board.model.dto.Comment;
import edu.kh.project.board.model.service.CommentService;

// @Controller + @ResponseBody

@RestController // 요청/응답 처리(단, 모든 요청 응답은 비동기)
				// -> REST API를 구축하기 위한 Controller
public class CommentController {

	@Autowired
	private CommentService service;
	
	// 댓글 목록 조회					// json 통신 시 한글깨짐 방지
	@GetMapping(value="/comment", produces="application/json; charset=UTF-8")
	public List<Comment> select(int boardNo) {
		
		return service.select(boardNo);
		// 동기 시 return : forward / redirect
		// 비동기 시 return : 값 자체
	}
	
	// 댓글 삽입
	@PostMapping("/comment")
	public int insert(@RequestBody Comment comment) {
		// 요청 데이터(JSON)
		// HttpMessageConverter가 해석 -> Java 객체(comment)에 대입
		
		return service.insert(comment);
		
	}
	

	// 댓글 삭제
	@GetMapping("/comment/delete")
	public int delete(int commentNo) {
		return service.delete(commentNo);
	}
	
	// 댓글 수정
	@PostMapping("/comment/update")
	public int update(@RequestBody Comment comment) {
		return service.update(comment);
	}
	
}

CommentService.java

package edu.kh.project.board.model.service;

import java.util.List;
import java.util.Map;

import edu.kh.project.board.model.dto.Comment;

public interface CommentService {

	/** 댓글 목록 조회
	 * @param boardNo
	 * @return List
	 */
	List<Comment> select(int boardNo);

	/** 댓글 삽입
	 * @param comment
	 * @return result
	 */
	int insert(Comment comment);

	/** 댓글 삭제
	 * @param commentNo
	 * @return result
	 */
	int delete(int commentNo);

	/** 댓글 수정
	 * @param comment
	 * @return result
	 */
	int update(Comment comment);

}

CommentServiceImpl.java

package edu.kh.project.board.model.service;

import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import edu.kh.project.board.model.dao.CommentMapper;
import edu.kh.project.board.model.dto.Comment;
import edu.kh.project.common.utility.Util;

@Service
public class CommentServiceImpl implements CommentService{

	@Autowired
	private CommentMapper dao;
	
	// 댓글 목록 조회
	@Override
	public List<Comment> select(int boardNo) {
		
		return dao.select(boardNo);
	}

	// 댓글 삽입
	@Transactional(rollbackFor = Exception.class)
	@Override
	public int insert(Comment comment) {
		// XSS 방지 처리
		comment.setCommentContent( Util.XSSHandling(comment.getCommentContent()) );
		return dao.insert(comment);
	}

	// 댓글 삭제
	@Transactional(rollbackFor = Exception.class)
	@Override
	public int delete(int commentNo) {
		
		return dao.delete(commentNo);
	}

	// 댓글 수정
	@Transactional(rollbackFor = Exception.class)
	@Override
	public int update(Comment comment) {
		// XSS 방지 처리
		comment.setCommentContent( Util.XSSHandling(comment.getCommentContent()) );
		return dao.update(comment);
	}

}

CommentMapper.java

package edu.kh.project.board.model.dao;

import java.util.List;
import java.util.Map;

import org.apache.ibatis.annotations.Mapper;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import edu.kh.project.board.model.dto.Comment;

@Mapper
public interface CommentMapper {

	/** 댓글 목록 조회
	 * @param boardNo
	 * @return List
	 */
	public List<Comment> select(int boardNo);

	/** 댓글 삽입
	 * @param comment
	 * @return result
	 */
	public int insert(Comment comment);

	/** 댓글 삭제
	 * @param commentNo
	 * @return result
	 */
	public int delete(int commentNo);

	/** 댓글 수정
	 * @param comment
	 * @return result
	 */
	public int update(Comment comment);
	
	
	

}

comment-mapper.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="edu.kh.project.board.model.dao.CommentMapper">
	
	<!-- Comment resultMap -->
	<resultMap type="Comment" id="comment_rm">
		<id property="commentNo" column="COMMENT_NO"/>
		<result property="commentContent" column="COMMENT_CONTENT"/>
		<result property="commentCreateDate" column="C_CREATE_DATE"/>
		<result property="boardNo" column="BOARD_NO"/>
		<result property="memberNo" column="MEMBER_NO"/>
		<result property="commentDeleteFlag" column="COMMENT_DEL_FL"/>
		<result property="parentNo" column="PARENT_NO"/>
		<result property="memberNickname" column="MEMBER_NICKNAME"/>
		<result property="profileImage" column="PROFILE_IMG"/>
	</resultMap>
	
	
	<!-- 특정 게시글 댓글 조회(바뀔 예정) -->
	<select id="select" resultMap="comment_rm">
		SELECT LEVEL, C.* FROM
			(SELECT COMMENT_NO, COMMENT_CONTENT,
			TO_CHAR(C_CREATE_DATE, 'YYYY"년" MM"월" DD"일" HH24"시" MI"분" SS"초"') C_CREATE_DATE,
			BOARD_NO, MEMBER_NO, MEMBER_NICKNAME, PROFILE_IMG, PARENT_NO, COMMENT_DEL_FL
			FROM "COMMENT"
			JOIN MEMBER USING(MEMBER_NO)
			WHERE BOARD_NO = #{boardNo}) C
		WHERE COMMENT_DEL_FL = 'N'
		START WITH PARENT_NO IS NULL
		CONNECT BY PRIOR COMMENT_NO = PARENT_NO
		ORDER SIBLINGS BY COMMENT_NO
	</select>
	
	
	<!-- 댓글 삽입 -->
	<insert id="insert">
		INSERT INTO "COMMENT"
		VALUES(SEQ_COMMENT_NO.NEXTVAL,
				#{commentContent},
				DEFAULT, DEFAULT,
				#{boardNo}, #{memberNo},
				
				<!-- 동적 sql : if문 -->
				<!-- 부모 댓글 -->
				<if test="parentNo == 0"> NULL </if>
				
				<!-- 자식 댓글 -->
				<if test="parentNo != 0"> #{parentNo} </if>
				
				)
	</insert>
	
	<!-- 댓글 삭제 -->
	<update id="delete">
		UPDATE "COMMENT" SET
		COMMENT_DEL_FL = 'Y'
		WHERE COMMENT_NO = #{commentNo}
	</update>
	
	
	<!-- 댓글 수정 -->
	<update id="update">
		UPDATE "COMMENT" SET
		COMMENT_CONTENT = #{commentContent}
		WHERE COMMENT_NO = #{commentNo}
	</update>
	
</mapper>

== 댓글, 답글 등록 / 수정 / 삭제 다 가능!

0개의 댓글