학원/SPRING

12/14 64-2 [SPRING] 게시판(댓글처리)-수정해야함

도원결의 2022. 12. 14. 22:09

댓글기능이 이렇게 어렵고 까다롭고 힘든 기능인지 이제 알았다....
애초에 게시판 글 용이랑 댓글 용이랑 DTO 를 따로만들어 놔서 (내가 만든거아님... 이거 쓰면서 지금 이해함 ..)
DAO 랑 컨트롤러도 댓글용은 따로 만들 거얌!!
(comment ~~~)
그치만 로직은 똑같아!
뷰(views) -> 컨트롤러(.web) -> 서비스(impl) -> DAO (.mapper : 쿼리문작성하는 .xml)
우선 댓글을 달려면 글이 있어야겠지
댓글은 상세보기view 에서부터 시작 하겠다....

[Write] --이건 댓글용 !!!!

1.뷰(views)
기존 View 밑에 코드 추가
이건 폼도 중요함
<c:if >,<c:forEach> 도 잘 봐야하고
${ }이거도 잘 봐야 해!!!

	<!-- 수정/삭제/목록 컨트롤 버튼 -->
	<div class="text-center">
		<a href="<c:url value="/onememo/bbs/Edit.do?no=${record.no}"/>"
			class="btn btn-success">수정</a> <a
			href="javascript:isDelete(${record.no})" class="btn btn-success">삭제</a>
		<a
			href="<c:url value="/onememo/bbs/List.do?nowPage=${param.nowPage}"/>"
			class="btn btn-success">목록</a>
	</div>
	<!-- 한줄 코멘트 입력 폼 -->
	<form id="form" 
		class="form-inline col-sm-12 d-flex justify-content-center mt-3">
		<input type="hidden" name="${_csrf.parameterName}"
			value="${_csrf.token}" /> <input type="hidden" name="no"
			value="${record.no}" />
		<!-- 댓글 수정용 -->
		<input type="hidden" name="lno" /> <input type="text" id="linecomment"
			name="linecomment" class="form-control mx-2 w-50"
			placeholder="한줄 댓글을 입력하세요" /> <input type="button"
			class="btn btn-danger mx-2" value="등록" id="submit" />
	</form>
	<!-- 한줄 코멘트 목록 -->
	<div class="row d-flex justify-content-center mt-3">
    <div class="col-sm-8">
    <table class="table table-hover text-center">
    <thead>
        <tr>
            <th class="col-2">작성자</th>
            <th>코멘트</th>
            <th class="col-2">작성일</th>
            <th class="col-2">삭제</th>
        </tr>
    </thead>
    <tbody class="table-sm down-file-body" id="comments-list">
        <c:if test="${empty record.comments }" var="isEmpty">
            <tr id="empty-comment">
                <td colspan="4">등록된 한줄 댓글이 없습니다.</td>
            </tr>
        </c:if>
        <c:if test="${not isEmpty}">
            <c:forEach var="comment" items="${record.comments}">
                <tr>
                    <td>${comment.name }</td>
                    <td class="text-left line-comment" title="${comment.lno}">${comment.lineComment}</td>
                    <td>${comment.lpostDate}</td>
                    <td>
                    <c:if test="${sessionScope.id==comment.id}" var="isSame">
                        <button class="btn btn-info btn-sm my-delete">삭제</button>
                    </c:if>
                    <c:if test="${not isSame }">
                        삭제불가
                    </c:if>
                    </td>
                </tr>
            </c:forEach>
        </c:if>
    </tbody>
   </table>
 </div>


2.컨트롤러 -- 댓글용 !!!
CommentController.java
서비스 주입받음 근데 신기한거 ! 부모도 주입 받을 수 있음!!
LineCommentServiceImpl를 서비스로 주입 받는 대신
부모인 OneMemoService<LineCommentDTO>를 서비스로 주입 받으면 확장성이 좋음
(단 사용가능한 메소드가 다를 수 있으니 주의)

 

@SessionAttributes("id")
@RestController
@RequestMapping("/onememo/comments")
public class CommentController {

    @Autowired 
    private LineCommentServiceImpl commentService;

	1. String으로 반환(DB입력시는 문제 없으나 클라이언트로 전송 시 한글 깨짐: p)	
	public String write(@ModelAttribute("id") String id, @RequestParam Map map){
             map.put("id",id);
            //서비스 호출
            int newLno = commentService.insert(map); // 입력한 행의 키 값(lni)-수정/삭제시 사용
            map.put("lno", newLno);
            String name=commentService.findNameByNo(map);
            map.put("name",name);
            //데이터반환(뷰정보x)
            ObjectMapper mapper = new ObjectMapper(); //잭슨 라이브러리에 있는 클래스 사용함 !
                String returnValue =null;
                try {
                    returnValue = mapper.writeValueAsString(map);
                } 
                catch (JsonProcessingException e) {e.printStackTrace();}
                return returnValue ;
        }

      
      2.map으로 반환 시
      public Map write(@ModelAttribute("id") String id, @RequestParam Map map){
        //한줄 댓글 작성자의  아이디 설정
        map.put("id",id);
        //서비스 호출
        int newLno = commentService.insert(map); // 입력한 행의 키 값(lni)-수정/삭제시 사용
        map.put("lno", newLno);
        String name=commentService.findNameByNo(map);
        map.put("name",name);
        //데이터반환
        return map;
      }
      
}


3.서비스 --댓글!!!
LineCommentServiceImpl
얘도 큰 로직 없이그냥 값만 넘겨주네

@Service
public class LineCommentServiceImpl implements OneMemoService<LineCommentDTO>{

	//LineCommentDAO주입
	@Autowired
	private LineCommentDAO dao;
	
    @Override
	public int insert(Map map) {
		영향받은 행의 수가 아니라 새로 입력 된 레코드의 키값(lno)를 반환 받음
		마이바티스의 insert는 무조건 영향받은 행의 수 반환
		int newLno = dao.insert(map);
		System.out.println("새로 추가된 코맨트 키번호:"+newLno);
		return newLno;
	}
    
  }


4.DAO --댓글용 !!!

@Repository
public class LineCommentDAO {
	//SqlSessionTemplate객체주입
	@Autowired
	private SqlSessionTemplate template;

	public int insert(Map map) {
		 마이바티스 insert는 무조건 영향 받은 행의 수 반환 
		
        template.insert("commentInsert",map);
		
        위 메소드 호출 시 commentInsert 를 가진 퀴리 실행 
           -> 입력된 행의 번호(키)를 인자로 전달한 맵에 담을것임
		인자로 전달하는 map에 새로 입력된 행의 키 를 담을 수 있따.

		return 	Integer.parseInt(map.get("lno").toString());
}


+++mapper
linecomments.xml
쿼리문 고 !
여기 좀 복잡함....이거도 우선 주석 받고.... 천천히 이해하자...ㅠ
insert태그에 직접 useGeneratedKeys="true" keyProperty="lno"추가하면
새롭게 입력된 행의 키값(keyProperty에 지정한 속성)이 반환된다
단,autoincrement를 지원하는 MySql이나 MS-SQL등만 가능
오라클은 selectkey태그 사용
keyProperty:인자로 전달된 맵에 저장할 키값 설정
resultType:키값의 타입
order:순서로 아래 INSERT문다 먼저 실행된다(BEFORE일때)
즉 쿼리(SELECT SEQ_LINECOMMENTS.NEXTVAL FROM DUAL)가 실행되서 파라미터로
전달된 Map의 "lno"라는 키로 SEQ_LINECOMMENTS.NEXTVAL로 설정된다

<insert id="commentInsert" parameterType="Map">
    <selectKey keyProperty="lno" resultType="int" order="BEFORE">
        SELECT SEQ_LINECOMMENTS.NEXTVAL FROM DUAL
    </selectKey>
    INSERT INTO linecomments VALUES(SEQ_LINECOMMENTS.CURRVAL,#{linecomment},SYSDATE,#{no},#{id})
</insert>

이거 보다가 갑자기
이거 발견했는데... 바로 전 올린 글에서 마지막에 resultmap 이랑 연결된 놈임..
이거.......... 나중에 동영상으로 확인 해봐야겠다.. 심오했던거 같은데 기억을 잃음

<!-- no에 따른 댓글 모든 목록 얻기 -->
<select id="commentListsByNo" parameterType="Map" resultType="commentDto">
    SELECT line.*,name
    FROM member m JOIN linecomments line ON m.id=line.id
    WHERE no=#{no}
    ORDER BY lno DESC		
</select>

우선 패스


[Edit] / [Delete] -- 댓글용

묶쟈.... 안그럼 나 집 못간다...
1.뷰
여긴 뷰가 관건.... 왜냐면
ajax를쓸 거라서...
이거...... 는 내일의 나와 주말의 나에게맡겨본다....
폼은 위에꺼랑 같이 쓰고 여기는 스크립트.....

[ajax로 서버에 데이터를 요청하는 함수]

※AJAX에서의 요청방식
-GET, POST요청 :
data:key1=value1&key2=value2&...
혹은 data:{key1:value1,key2:value2,...}
contentType:"application/x-www-form-urlencoded"(디폴트)
스프링에서는 @RequestParam으로 데이타를 받는다
-POST,PUT, DELETE요청
data:JSON.stringify({key1:value1,key2:value2,...})
contentType:"application/json"
스프링에서는 @RequestBody 로 데이터를 받는다.

 

$.ajax({ }).done(ffunction( ){ }}.fail(function( ){ })   형태 공부 !!

<script>
	//코멘트 등록 및 수정처리
	$('#submit').click(function(){
		console.log($(this).val());
		console.log($('#form').serialize());
		var action;
		if($(this).val()==='등록')
			action="<c:url value="/onememo/comments/Write.do"/>"		
		else
			action="<c:url value="/onememo/comments/Edit.do"/>";
		
		//ajax로 요청
		$.ajax({
			url:action,
			data:$('#form').serialize(),
			dataType:'json',
			type:'post'})
			.done(function(data){
				console.log('서버로부터 받은 데이타:',data);
				if($('#submit').val()==='등록'){//등록처리
					var tr="<tr><td>"+data.name+"</td><td class='text-left line-comment' title='"+data.lno+"'>"+data.linecomment+"</td><td>"+getToday()+"</td><td><span class='btn btn-info btn-sm my-delete'>삭제</span></td></tr>";					
					$('#comments-list').prepend(tr);
					if($("#empty-comment").length !=0){//댓글이 없습니다 요소 삭제
						$("#empty-comment").remove();
					}
				}
				else{//수정처리
					$('#submit').val('등록');
					$('td[title="'+data.lno+'"]').html(data.linecomment);
					$('td[title="'+data.lno+'"]').css('color','red');
				}
				//입력값 클리어 및  포커스 주기
				$('#linecomment').val("");
				$('#linecomment').focus();
				
			})
			.fail(function(error){
				console.log('에러:',error);
			});			
	});
	
	//오늘날짜 얻는 함수
	function getToday(){
		var date = new Date();
		return date.getFullYear()+"-"+(date.getMonth()+1)+"-"+date.getDate();
	}
	
	//※댓글 목록의 제목 클릭시-click이벤트걸때 반드시  $(document).on('이벤트명','셀렉터',콜백함수)으로
	//그래야 동적으로 추가된 요소에도 이벤트가 발생한다
	$(document).on('click','.line-comment',function(){
		console.log($(this).html());
		//입력상자값을 클릭한 제목으로 변경
		$('#linecomment').val($(this).html());
		//버튼의 텍스트를 수정으로 변경
		$('#submit').val('수정');
		//폼의 hidden인 lno의 value를 클릭한 제목의 lno값으로 설정
		$('input[name=lno]').val($(this).attr('title'));
		console.log('히든값 설정 확인(lno):',$('input[name=lno]').val());
	});
	
	//댓글 삭제 처리
	$(document).on('click','.my-delete',function(){
		if(confirm("정말로 삭제하시겠습니까?")){
			console.log($(this).parent().prev().prev().attr('title')); //부모 이전에 이전으로 가서 얻어오기	
			var lno=$(this).parent().prev().prev().attr('title');
			var this_ = $(this);
			$.ajax({
				url:"<c:url value="/onememo/comments/Delete.do"/>",  //키 : 값
				type:"delete",
				data:JSON.stringify({"lno":lno}),
				dataType:'json',
				contentType:"application/json"
			})
			.done(function(data){
				console.log('삭제 성공:',data);
				//클릭한 tr삭제
				this_.parent().parent().remove();
			})
			.fail(function(error){
				console.log('삭제 실패:',error);
			});
		}
	});
</script>



2.컨트롤러

@SessionAttributes("id")
@RestController
@RequestMapping("/onememo/comments")
public class CommentController {
	@Autowired
	private LineCommentServiceImpl commentService;
    
    @PostMapping("/Edit.do")   //putMapping도 가능하나 viewdpsms post로되어있어서 그냥 post씀
	public Map edit(@ModelAttribute("id") String id, @RequestParam Map map){
        //서비스 호출
        commentService.update(map);			
        //map 반환
        return map;
	}
		
    @DeleteMapping("/Delete.do")
    public Map delete(@ModelAttribute("id") String id,@RequestBody Map map) {
        //서비스 호출
        commentService.delete(map);
        //데이타 반환
        return map;
	}


3.서비스

@Service
public class LineCommentServiceImpl implements OneMemoService<LineCommentDTO>{

	//LineCommentDAO주입
	@Autowired
	private LineCommentDAO dao;
        
	@Override
	public int update(Map map) {		
		return dao.update(map);
	}

	@Override
	public String findNameByNo(Map map) {
		return dao.findNameByLno(map);
	}
    
    @Override
	public int delete(Map map) {		
		return dao.delete(map);
	}
}


4.DAO+mapper

@Repository
public class LineCommentDAO {
	//SqlSessionTemplate객체주입
	@Autowired
	private SqlSessionTemplate template;
    
    public String findNameByLno(Map map) {		
    	return template.selectOne("commentFindNameByLno",map);
	}

	public int update(Map map) {
		return template.update("commentUpdate",map);
	}
	
	public int delete(Map map) {	
		System.out.println("삭제:"+map.get("lno"));
		return template.delete("commentDelete",map);
	}
}

+쿼리문 !!!!!

<select id="commentFindNameByLno" parameterType="Map" resultType="String">
    SELECT name FROM member m JOIN linecomments line ON m.id=line.id
    WHERE lno=#{lno}	
</select>
<update id="commentUpdate" parameterType="Map" >
    UPDATE linecomments SET linecomment = #{linecomment} WHERE lno=#{lno}
</update>
<delete id="commentDelete" parameterType="Map">
    DELETE FROM linecomments WHERE lno=#{lno}
</delete>

가자 집으로....