[댓글작성] Ajax로 댓글 작성 기능 구현

     

    * 세미 프로젝트에서 구현한 기능들을 복습 겸 정리해보려고 합니다.

    당연한 이야기이지만, 제 코드가 정답은 아니기 때문에 감안하고 읽어주시면 감사하겠습니다.


     

    레시피 상세 보기 페이지에서 댓글 기능을  AJAX를 이용해서 구현했습니다.

    대략적인 UI는 다음과 같습니다. 

     

     

    저는 SQL ->View->Controller ->Service-> DAO 순서로 작업하는 것을 좋아합니다.

    왜냐면.. 그게 좋으니까요.. 

     

    * 헉 DAO가 무슨 뜻이지? 궁금하다면 ?

    더보기

    DAO(Data Access Object)는 DB를 사용해 데이터를 조화하거나 조작하는 기능을 전담하도록 만든 오브젝트를 말한다

     


     

     

     

    1. SQL

    <entry key="insertReply">
    
    INSERT INTO REPLY
    (
    REPLY_NO
    ,USER_NO
    ,RECIPE_NO
    ,REPLY_CONTENT
    )
    VALUES
    (
    SEQ_CNO.NEXTVAL
    ,?
    ,?
    ,?
    )
    
    </entry>
    

     

    먼저 댓글 작성 시 필요한 정보는

    댓글 번호 / 댓글 작성자 / 레시피 번호 / 댓글 내용으로 정했습니다.

    필요한 데이터 타입은 DB에 따라 다를 수 있습니다.

    댓글 번호는 SEQ로 작성할 때마다 새롭게 생성되기 때문에,

    우리가 필요한 내용은 댓글 작성자 / 레시피 번호 / 댓글 내용 이렇게 총 3개입니다. 

     


     

    2. View

    <td style="width: 80%;">
    <div class="form-group">
    <label for="usr"></label>
    <input type="text" class="form-control" id="usr" placeholder="소중한 레시피에 쉐프님의 멋진 댓글을 남겨주세요 :) "  style="height: 30px;" name="<%=loginUser.getUserId()%>">
    </div>
    </td>
    
    <td><button class="btn btn-sm btn-success" onclick="insertReply();">등록</button></td>

    input type="text"의 id값을 usr로 지정했습니다. 지금 생각해보면 content가 더 적절했을 것 같은데, 그때는 그렇게 지정하고 싶었나 봅니다. 다른 사람도 제 코드를 쓸 수 있으니까 더 명시적으로 작성하는 게 좋을 것 같습니다. 

     

    등록하기 버튼을 실행하면 insertReply()라는 함수가 호출됩니다.

     

     

    먼저, Ajax를 사용하기 전에 조건문을 통해 login한 user에게만 댓글 작성 권한을 주었습니다.

    비회원이 댓글을 작성하려고 하면, 다음과 같은 문구가 출력되면서 등록 버튼이 disabled 됩니다.

     

    script안에 있는 isnertReply함수의 내용은 다음과 같습니다.

     

    <%if(loginUser!=null){%>   
    
      function insertReply(){
      $.ajax({
          url : "rinsert.recipe"
          ,data : {
            content : $("#usr").val()
            ,recipeNo : <%=rc.getRecipeNo()%>
            ,userNo : <%=loginUser.getUserNo()%>
          }
          ,type : "post"
          ,success : function(result){
    
            if(result>0){
              selectReplyList();
              $("#usr").val("");
            }
          }
    
          })
          }
      <%}%>

     

     

     

    url은 Servlet의 mapping값을 작성했습니다.

     

    data에는 전달할 3개의 값을 지정합니다. 댓글 작성자 / 레시피 번호 / 댓글 내용 입니다. 

     

    1) content는 id가 usr인 요소의 val을 가져왔습니다. 

    2) recipeNo은 레시피 상세보기 페이지에서 레시피를 조회할 때 가져온 레시피 번호를 담았습니다.

    3) userNo은 loginUser의 userNo을 담았습니다. 

     

     

    type은 한글이 담기기 때문에 post로 지정했습니다.

     

    success는 성공시 실행할 함수를 정의하는데 이때는 function에 매개변수로 Controller단에서 받아오는 result를 꼭 담아줘야 합니다. 돌아갈 result가 0인지 아닌지에 따라 성공인지 실패인지를 판단할 수 있기 때문입니다. 

     

     

     

    처리된 행수가 0보다 클 때 ( == insert가 정상적으로 되어 *행이 삽입되었습니다.인 상황인 경우)는 현재 페이지가 그대로 보이며, DB에 insert가 성공됩니다.  말 그대로 DB에 insert만 된 것일 뿐, (==기록만 된 것일 뿐) 하단의 댓글이 조회가 되기 위해서는 갱신된 리스트를  다시 조회를 해야합니다. 댓글 작성에 성공을 했으면 댓글 조회하는 ajax를 selectReplyList()를 재호 출하면 됩니다. 아무리 잘 insert가 되었다고 해도, 사용자가 작성한 댓글의 값이 알아서 초기화가 되지 않기 때문에 초기화 (비어있는 댓글창)을 위해서 이때 id가 usr인 val에 ""로 초기화시켜줍니다. 

     

     

     


     

    3. Controller

    	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    		
    		String replyContent = request.getParameter("content");
    		int recipeNo = Integer.parseInt(request.getParameter("recipeNo"));
    		int userNo = Integer.parseInt(request.getParameter("userNo"));
    		
    		Reply r = new Reply();
    		r.setReplyWriter(String.valueOf(userNo));
    		r.setRecipeNo(recipeNo);
    		r.setReplyContent(replyContent);
    		
    		int result = new RecipeService().insertReply(r);
    		
    		response.getWriter().print(result);
    		
    	}

     

    Servlet 이름은 AjaxReplyInsertController로 명명했습니다. 저는 Servlet단을 만들면 습관적으로 다른 페이지로 이동하는 구문을 작성하기 때문에 일부러 Ajax라고 지었습니다. 다른 페이지로 보내지 말라는 .... 일종의 미래의 저에게 보내는 신호 그런 느낌입니다. 

     

    우리가 필요한 3개의 내용 (댓글 작성자 , 레시피 번호, 댓글 번호)를 각각 getParameter를 이용해 key값을 이용해 value값을 가져옵니다. 각각 필요한 변수에 담아서 Reply VO 클래스 안에 담아주었습니다. 

     

    작성자를 Reply 객체에 담을 때, String.valueOf(userNo)를 사용했습니다. 그 이유는 3번에서와 마찬가지로 replyWriter가 String으로 선언되었기 때문입니다. 

     

    * 지금 생각해보면 이 방법이 좀 비효율적인 것 같기도 합니다. int로 담은 값을 Controller에서 String으로 바꾸고 그걸 Dao단에서 다시 int로 바꾸는 방법이라서.. 코드 실행하는 데는 문제가 없었습니다. 지금의 제 실력은 일단 실행만 되면 된다. 의 수준이라 일단 넘어가겠습니다.

     

    Reply에 사용자가 입력한 값들이 담겼고, 그것을 Service단으로 넘겨주었습니다.

     

     


     

    4. Service

    	public int insertReply(Reply r) {
    		
    		Connection conn = getConnection();
    		int result = new RecipeDao().insertReply(conn, r);
    		
    		if(result>0) {
    			commit(conn);
    		}else {
    			rollback(conn);
    		}
    		
    		close(conn);
    		
    		return result;
    		
    	}
    	

     

    Service단에서는 Controller단에서 가져온 매개변수인 Reply 객체와 insertReply 메소드 안에서 선언한 Connection를 DAO단으로 넘겨줍니다.

     

    DAO단에서는 실행된 insert 된 행수가 돌아오기 때문에 int result로 돌아오는 결괏값을 받아줍니다. 

    result를 조건문을 통해 commit과 rollback을 해줍니다.

    그 후에는 반드시 사용이 끝난 Connection 객체를 반납해줍니다.

     

    result를 Controller로 돌려줍니다. 

     

     


     

    5. DAO

    	public int insertReply(Connection conn, Reply r) {
    		
    		int result = 0;
    		PreparedStatement pstmt = null;
    		String sql = prop.getProperty("insertReply");
    		
    		try {
    			pstmt = conn.prepareStatement(sql);
    			
    			pstmt.setInt(1, Integer.parseInt(r.getReplyWriter()));
    			pstmt.setInt(2, r.getRecipeNo());
    			pstmt.setString(3, r.getReplyContent());
    			
    			result = pstmt.executeUpdate();
    			
    			
    		} catch (SQLException e) {
    			e.printStackTrace();
    		}finally {
    			close(pstmt);
    		}
    		
    		return result;
    		
    		
    	}

    XML(편의상 SQL이라고 했습니다)의 키 값이 insertReply이기 때문에 메소드명과 prop.getProperty("insertReply")를 모두 동일한 키 값으로 제시했습니다. 메소드 명은 몰라도  prop.getProperty("") < 이 안의 값은 반드시 xml의 키 값과 일치해야 합니다. SQL도 완벽하고 다른 코드도 완벽한데 아무리 해도 실행이 안된다면 저 부분을 확인하셔도 좋을 것 같습니다.

     

    1번째 인자를 Integer.parseInt로 한 이유는 VO 클래스에 replyWriter를 String으로 선언했기 때문입니다. 

    왜 String으로 담았냐면, 로그인한 회원의 아이디 값이 필요할 수도 있고, 회원 번호가 필요할 수도 있기 때문에 String으로 담았습니다. String이기 때문에 파싱을 해줘야 int 값으로 변환이 됩니다. 

     

    2번째 인자는 레시피 번호, 3번째 인자는 댓글 내용입니다. 

     

    저 순서는 반드시 SQL 문의 순서와 일치해야 합니다.

    다르면 SQL 구문 오류가 출력됩니다. 

     

     

     


     

    댓글 작성 성공 시 다음과 같은 화면이 출력됩니다. 

     

     

     

    728x90

    댓글