[Springboot] 댓글 게시판 #3 (ajax사용한 댓글 crud)

728x90

🔔 TODO :  Ajax를 사용한 , 댓글 등록 , 댓글 수정, 삭제

📘 project : 인텔리제이 - SpringBootMybatisMini

 

form : content.jsp
dto : MbAnswerDto

controller : MbanswerController.java
Mapper : mbanswersql.xml
service : MbanswerMapperInter.java

 

 

스프링부트 동작관정 간단

  1. 클라이언트가 JSP 페이지에 데이터를 입력하고 제출합니다.
  2. JSP 페이지에서 컨트롤러에게 요청을 보냅니다.
  3. 컨트롤러는 요청을 받고 필요한 작업을 수행합니다.
  4. 컨트롤러는 서비스로 데이터 처리를 위임합니다.
  5. 서비스는 필요한 비즈니스 로직을 실행하고 데이터베이스에서 데이터를 가져옵니다.
  6. 서비스가 데이터 처리를 완료하면, 결과를 컨트롤러로 반환합니다.
  7. 컨트롤러는 JSP 페이지로 데이터를 전달합니다.
  8. JSP 페이지는 데이터를 이용하여 동적 웹 페이지를 생성하고 클라이언트에게 반환합니다.

결론 : 데이터 처리 후 반환되는 곳은  컨트롤러이다.


스프링부트가 동작하는  과정 대로 설명을 해보겠습니다. 

 

form

 <div style="margin : 50px 150px;">
    <table class="table table-bordered" style="width:800px;">
        <tr>
          <td>
            <h4><b>${dto.subject}</b>
              <span style="font-size:0.7em; color:gray; float: right">
                  🔔 조회수 : ${dto.readcount}&nbsp;&nbsp;
                  🕰 작성일 : <fmt:formatDate value="${dto.writeday}" pattern="yyyy-MM-dd HH:mm:ss"/>
              </span>
            </h4>
              <span><b id="myid" myid="${sessionScope.myid}">작성자 : ${dto.name} (${dto.myid})</b></span>

              <c:if test="${dto.uploadfile!= 'no'}">
                <span style="float:right">
                  <a href="download?clip=${dto.uploadfile}">
                    <i class="bi bi-arrow-down-circle">&nbsp;</i><b>${dto.uploadfile}</b>
                  </a>
                </span>
              </c:if>
          </td>
        </tr>
      <tr>
        <td>
          <c:if test="${bupload ==true}">
          <img src="../savefile/${dto.uploadfile}" style="width:350px; height:400px;">
          </c:if>
          <br><br>
          <pre>
            ${dto.content}
          </pre>
            <br>
            <b>조회 수 : ${dto.readcount}</b> &nbsp;&nbsp;&nbsp;
            <b>댓글 수 : <span class="acount"></span></b>
        </td>
      </tr>

        <%--댓글--%>
        <tr>
            <td>
                <input type="hidden" id="num" value="${dto.num}">
                <div class="alist"></div>
                <c:if test="${sessionScope.loginok != null}">
                    <div class="aform">
                        <div>
                            <input type="text" class="form-control" style="width:500px; display: inline-flex" placeholder="댓글 입력" id="content" >
                            <button type="button" class="btn btn-outline-danger" id="btnansweradd" num="${dto.num}">등록</button>
                        </div>
                    </div>
                </c:if>
            </td>
        </tr>

      <c:if test="${sessionScope.loginok!=null}">
      <tr>
        <td>
          <button type="button" class="btn btn-outline-dark" onclick="location.href='form?currnePage=${currentPage}'" style="width:100px;">글작성</button>
          <button type="button" class="btn btn-outline-dark" onclick="location.href='list?currnePage=${currentPage}'" style="width:100px;">목록</button>
          <c:if test="${sessionScope.loginok!=null and sessionScope.myid ==dto.myid}">
          <button type="button" class="btn btn-outline-dark" onclick="location.href='update?num=${dto.num}&currentPage=${currentPage}'" style="width:100px;">수정</button>
          <button type="button" class="btn btn-outline-dark" onclick="location.href='delete?num=${dto.num}&currentPage=${currentPage}'" style="width:100px;">삭제</button>
          </c:if>

        </td>
      </tr>
      </c:if>
    </table>
  </div>
</body>
  • 이 form에서는 client가 요청한 데이터를 list로 띄운 것이고, 그 list에서 댓글을 달기 위한 form입니다.
    • form안에 <div.alist> 여기 div에 댓글을 띄울 예정입니다. 이 div에 댓글을 띄우기 위해서 ajax비동기방식으로 처리를      합니다.

 

다음으로는 Ajax를 처리하려면 Controller , service ,mapper에서 미리 메소드를 만들고 sql작성을 끝내놔야지 바로바로 ajax처리를 할 수 있으니 미리 만들어 보겠습니다

 

#1) dto

import java.sql.Timestamp;
import org.apache.ibatis.type.Alias;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;

@Data
@Alias("mbdto")
public class MbAnswerDto {
	private String idx;
	private String num;
	private String name;
	private String myid;
	private String content;
	@JsonFormat(pattern = "yyyyMMdd")
	private Timestamp writeday;
}

 

  • DB에 생성해둔 column 들이랑 이름을 같게 생성을 해줘야 합니다 (datatype은 달라도 상관없습니다)
  • 여기서 중요한건 idx는 -> primary key이고
    • num은 Mbanswer말고 그전에 생성한 memboard num이랑 foreign key를 주어 참조를 시킨 것 입니다.
  • num은 댓글을 달기 전, 작성 된 글을 번호를 의미하는 것입니다
    • 즉 작성된 글은 num으로 구별이고, idx는 그 작성된 글num 에 댓글을 다는 것이기 때문에 차별화를 둬야함.

 

#2) service 생성

-중요한건 service를 직접적으로 생성하지는 않았지만, 서비스 역할을 할 수 있는 클래스 입니다

- 왜 일까?? 라고 생각해봤는데 그것에 대한 답변은 다시 공부하고 업로드 하겠습니다.

package boot.data.mapper;

import java.util.List;
import org.apache.ibatis.annotations.Mapper;
import boot.data.dto.MbAnswerDto;

@Mapper
public interface MbanswerMapperInter {

	public void insertMbanswer(MbAnswerDto dto);
	public List<MbAnswerDto> getAllAnswers(String num);  //num 값에 따른 정보 넘기기
	public MbAnswerDto getAnswer(String idx); //idx값에 따른 answer 값들 가져오기
	public void updateMbanswer(MbAnswerDto dto);
	public void deleteMbanswer(String idx);
}
  • @Mapper 어노테이션은 -> Marker이다.  즉 이게 mapper를 처리하는 곳이다 라는걸 알려주는 어노테이션
    • @Mapper을 상위 어노테이션은 @Repository 이다  -> @Repository는 bean에 등록을 시켜준다. 

 

#3) mapper 

<?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="boot.data.mapper.MbanswerMapperInter">
    <insert id="insertMbanswer" parameterType="mbdto">
        insert into mbanswer(num,name,myid,content,writeday) values (#{num},#{name},#{myid},#{content},now())
    </insert>
    <select id="getAllAnswers" resultType="mbdto" parameterType="String">
        select * from mbanswer where num=#{num} order by idx desc;
    </select>

    <select id="getAnswer" resultType="mbdto" parameterType="String">
        select * from mbanswer where idx=#{idx}
    </select>

    <update id="updateMbanswer" parameterType="mbdto">
        update mbanswer set content=#{content} where idx=#{idx}
    </update>

    <delete id="deleteMbanswer" parameterType="String">
        delete from mbanswer where idx=#{idx}
    </delete>
</mapper>
  • mapper에 들어가는 id들은 service에서 생성한 메소드 이름이랑 꼭 같게 해주어야 한다. 4

 

#4) controller

package boot.data.controller;

import java.util.List;

import javax.servlet.http.HttpSession;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
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.RestController;

import boot.data.dto.MbAnswerDto;
import boot.data.mapper.MbanswerMapperInter;
import boot.data.service.MemberService;

@RestController
@RequestMapping("/mbanswer")
public class MbanswerController {

	@Autowired
	MbanswerMapperInter mapper;
	@Autowired
	MemberService memberService;

	@PostMapping("/ainsert")
	public void insert(@ModelAttribute MbAnswerDto dto, HttpSession httpSession) {
		//세션에서 저장한 아이디를 dto에 저장시킨다.
		String myid = (String)httpSession.getAttribute("myid");
		dto.setMyid(myid);
		//세션에서 저장된 이름을 dto에 저장시킨다.
		String name =memberService.getName(myid);
		dto.setName(name);

		mapper.insertMbanswer(dto);
	}

	@GetMapping("/alist")
	public List<MbAnswerDto> alist(@RequestParam String num)
	{
		return mapper.getAllAnswers(num);
	}

	@GetMapping("/mbdelete")
	public void adelete(@RequestParam String idx) {
		mapper.deleteMbanswer(idx);
	}


}
  • Ajax로 데이터를 처리할 떄는 @Responsebody || @RestController 를 꼭 선언하고 해주어야 한다 아니면 컴파일에러

 

  • insert할때는 @Modelattribute를 통해 MbanswerDto 값을 다 보내준다. 
    • 그리고 httpsession을 사용해서 , 세션에서 저장한 아이디를 보내줄 dto에 담아서 보내준다.
    • 다른방식으로 미리 만들어둔 메서드를 통해서 name값을 같이 dto에 담아서 보내준다. 

 

  • List로 출력할 때는 간단하게, 반환하는 값은 당연히 dto값들이고, 이 dto값들을 list에 담아서 반환해준다
    • 그리고 num값에 맞는 list를 출력해야 하기 때문에 num값 또한 매개변수 값으로 같이 보내주고 service에서 미리 작성해둔 메소드에 num을 담아서 return 해준다

 

  • delete는 간단하게 댓글에 primary key인 idx에 따라서 삭제해준다.

 

#5) 마지막으로 form에서 위 모든 데이터들을 가지고 ajax 처리하는 코드를 보여드리겠습니다. 

    <script>
        $(function(){

            list();

            $("#btnansweradd").click(function (){

                var num = $(this).attr("num")
                var content = $("#content").val();
                var myid  = $("#myid").attr("myid");
                loginok = "${sessionScope.loginok}";
                //alert(num+"_"+content+"_"+myid+"_"+loginok);

                if(content.length==0) {
                    alert("댓글을 입력해주세요");
                    return;
                }

                $.ajax({
                    type:"post",
                    url:"/mbanswer/ainsert",
                    dataType:"html",
                    data : {"num":num,"content":content},
                    success:function (data){
                        alert("등록되었습니다.")


                        //댓글 수정창 띄우기
                        list();
                        //입력값 초기화
                        $("#content").val("");
                    }
                })

            })

             //댓글 삭제
             $(document).on("click","#del",function(){
                 var idx= $(this).attr("idx");
                 var a = confirm("삭제하시겠습니까?");
                 //alert(idx);

                 if(a) {

                 $.ajax({
                     type:"get",
                     dataType :"json",
                     url : "/mbanswer/mbdelete",
                     data : {"idx":idx},
                     success:function(){
                            location.reload();

                        }
                    })
                 }
             })



            // $("i.update").click(function(){
            //
            // })





        })
        function list() {
            var num = $("#num").val();
            //alert(num);
            var loginok = "${sessionScope.loginok}";
            var myid = "${sessionScope.myid}";
            //alert(loginok + myid);

            $.ajax({
                type:"get",
                dataType :"json",
                url : "/mbanswer/alist",
                data : {"num":num},
                success:function(res){

                    $("span.acount").text(res.length);

                    var s = "";
                    $.each(res, function (i, dto) {
                        s += "<br>";
                        s += "<table class='table table-striped' style='width:800px; height:100px;'>"
                        s += "<input type='hidden' id='idx' value='idx'>";
                        s += "<tr>";
                        s += "<td><b> 🖐 작성자 : " + dto.name + "</b>" + "<span class='day' style='float:right'> 작성날짜 : "+dto.writeday+"&nbsp;&nbsp;";
                        if(loginok!=null || myid ==dto.myid) {
                        s += "<i class='bi bi-trash3-fill' id='del' idx='"+dto.idx+"' style='cursor: pointer'></i> &nbsp; <i class='bi bi-clipboard-check update' style='cursor: pointer'></i></span></td>";
                        }
                        s += "</tr>";
                        s += "<tr>";
                        s += "<td> 📋 댓글 : " +dto.content + "</td>";
                        s += "</tr>"
                        s += "</table>"
                    });

                    $("div.alist").html(s);

                }
            })
            //댓글 수정창 띄우기
        }
    </script>

 

  • 댓글 등록 버튼을 누르면, 이벤트가 발생하고 댓글을 클릭해서 서버로 전송될 때는 list로 출력 될 값을 미리 설정해두고 ajax 처리를 해줘야합니다.  ex) var content = $("#content").val();
    • 댓글 창이 null값 즉 댓글창에 아무것도 없이 서버로 전송하려하면 댓글 입력하라는 알림이 뜬다
  • 그리고 위 과정이 잘 되었다면 ajax를 통해서 데이터를 처리해준다.

 

다음으로는 ajax처리된 데이터들을 list로 띄웁니다.

  • 이것 또한 ajax로 처리 했기 때문에 기존에는 댓글들이 다 보이고, 내가 댓글을 등록하면은 바로 맨위에 올라오게한다.
    • $("span.acount").text(res.length); 이 코드는 댓글의 수를 출력하기 위한 코드이다.

 

다음은 삭제 입니다.

  • 삭제하는 버튼에 미리 idx값을 심어놓습니다. 그리고 그 버튼이 클릭되면은 idx값을 가져오는게 중요합니다
    • var idx= $(this).attr("idx");
  • 그리고 무난하게 ajax처리를해서 삭제 하면 끝입니다

 

다음은 수정 입니다.

728x90