12/14 64-2 [SPRING] 게시판(댓글처리)-수정해야함
댓글기능이 이렇게 어렵고 까다롭고 힘든 기능인지 이제 알았다....
애초에 게시판 글 용이랑 댓글 용이랑 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>
가자 집으로....