Dorothy_YANG
With Dorothy
Dorothy_YANG
전체 방문자
오늘
어제
  • 분류 전체보기 (279)
    • Hi, I'm Dorothy 🕵️‍♂️ (21)
      • Slowly but Surely (18)
      • IT certifications (3)
    • 🤯TIL (80)
      • HTML & CSS (2)
      • Javascript & jQuery (13)
      • React (13)
      • C언어 (1)
      • JAVA (22)
      • Python (2)
      • Oracle SQL (10)
      • My SQL (5)
      • Spring (12)
    • 💻Programmers (17)
    • 🏫 Open API_JAVA (101)
    • 🌎 Project (10)
      • Shopping (10)
    • 💥 Error (24)
    • ⚙ Setting (23)

블로그 메뉴

  • 홈
  • 방명록

공지사항

인기 글

태그

  • 기간설정
  • 이것이자바다
  • 비쥬얼스튜디오코드
  • Javascript
  • 오류해결
  • HTML
  • 콜라보레이토리
  • oracle
  • Eclipse
  • 노마드코더
  • 기간쿼리
  • 서버등록
  • spring
  • sql기간
  • 독학후기
  • googlecolaboratory
  • 창초기화
  • 코딩앙마
  • SQLD합격후기
  • CSS
  • colaboratory
  • SQL
  • java
  • AllArgsConstructor
  • Database
  • 백준
  • 파이썬온라인
  • 시작일종료일
  • SQLD합격
  • 연습문제

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
Dorothy_YANG

With Dorothy

[78일차] REST 방식 / gson 라이브러리 추가 / 게시판에 댓글 기능 구현 (ex04)
🏫 Open API_JAVA

[78일차] REST 방식 / gson 라이브러리 추가 / 게시판에 댓글 기능 구현 (ex04)

2022. 11. 15. 22:27
728x90

20221114(월)

  • 목차
    - REST 방식
    - gson 라이브러리 추가
    - 게시판에 댓글 기능 구현


< REST 방식 >

  • Representational State Transfer
    하나의 URI는 하나의 고유한 리소스(Resource)를 대표하도록 설계된다는 개념
  • 전송방식을 결합해서 원하는 작업을 지정
  • 데이타베이스 기반에 의한 자원(Resource)
  • 자원 : 클라이언트와 서버간의 통신환경에서 보내고 받는 개념속에서 실질적인 대상

  • CRUD
작업 상태   전송 방식
Create SQL insert POST
Read SQL select GET
Update SQL update PUT
Delete SQL delete DELTE

     get, post 방식으로 CRUD 작업을 다 처리했다. ➡ 정확한 표현이 아니다.. ㅠ
     ✨ get, post, put, delete 요청방식을 사용.(더 정확하게 표현하기 위함)
     이제 요청방식만 봐도 어떤 작업인지 개발자가 이해할 수 있다! GET? 아~ READ구나~

 

  • 자원관리 주소에도 차이가 있다.
    - get 기본주소 http://www.abc.com/board?idx=1
    - REST 주소  http://www.abc.com/board/1 

  • @RestController
    해당 Controller의 모든 메서드의 리턴 타입을 기존과 다르게 처리한다는 것을 명시
    @RestController는 메서드의 리턴 타입으로 사용자가 정의한 클래스 타입을 사용할 수 있고, 
    이를 JSON이나 XML로 자동으로 처리
  • @RestController = @Controller + @ResponseBody

    ✨ REST 설계구현 
    1) @RestController
    2) ResponseEntity 클래스? 1)결과값(리턴값) 2)헤더작업 3)HTTP상태코드
    3) 주소 : 자원을 나타내는 의미로 정의
    4) 데이타 생성 주소 : Post, 데이타 조회 주소 : Get, 데이타 삭제 주소 : Delete, 데이타 수정 주소 : Put
    5) JSP와 같은 뷰를 리턴하는 것이 아니라, 데이타 그 자체를 리턴.
      ➡ 다양한 클라이언트 기기에 표준 데이타를 제공하여 서비스함.

 


< gson 라이브러리 추가 >

  • 데이터의 처리는 XML과 JSON을 이용할 것이므로 pom.xml을 변경 
  • jackson-databind와 Jackson-dataformat-xml 라이브러리 활용 
  • Java객체를 JSON으로 쉽게 변환할 수 있는 gson 라이브러리   
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.dataformat/jackson-dataformat-xml -->
 <!-- 
<dependency>
    <groupId>com.fasterxml.jackson.dataformat</groupId>
    <artifactId>jackson-dataformat-xml</artifactId>
    <version>2.14.0</version>
</dependency>
 -->

<!-- https://mvnrepository.com/artifact/com.google.code.gson/gson -->
<!-- 
<dependency>
    <groupId>com.google.code.gson</groupId>
    <artifactId>gson</artifactId>
    <version>2.10</version>
</dependency>
 -->

 


< 게시판에 댓글 기능 구현 >

  • 게시물은 고정이고 아래 댓글 목록 들이 따로 페이징되어 내용과 함께 부분 업데이트 되는 것

 



1. ReplyVO.java 코드

package com.demo.domain;

import java.util.Date;

import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

@Getter
@Setter
@ToString
public class ReplyVO {

	/*
	 CREATE TABLE TBL_REPLY (
    RNO     NUMBER(10,0),
    BNO     NUMBER(10,0) NOT NULL,
    REPLY   VARCHAR2(1000)  NOT NULL,
    REPLYER VARCHAR2(50)    NOT NULL,
    REPLYDATE   DATE    DEFAULT SYSDATE,
    UPDATEDATE  DATE    DEFAULT SYSDATE
);
	 */
	
	// rno, bno, reply, replyer, replydate, updatedate
	
	private Long rno;
	private Long bno;
	
	private String reply;
	private String replyer;
	private Date replydate;
	private Date updatedate;
}

2. ReplyController.java 코드

package com.demo.controller;

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

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
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.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.demo.domain.ReplyVO;
import com.demo.dto.Criteria;
import com.demo.dto.PageDTO;
import com.demo.service.ReplyService;

import lombok.extern.log4j.Log4j;

//댓글기능 : Ajax방식과 REST방식으로 구현.
//   /board/get.jsp 파일에서 모든작업이 진행(댓글목록, 쓰기, 수정, 삭제)

@RequestMapping("/replies/*")
// 메서드의 리턴타입은 jsp파일명으로 해석되는 것이 아니라, 리턴 값 . 그자체 데이터로 클라이언트에게 보내진다.
// 리턴값이 문자열이면 그냥 보내지고, 객체면 json으로 변환되어 보내진다.
@RestController  // @Controller + @ResponseBody
@Log4j
public class ReplyController {

	/*
	 REST 설계구현 
	 1)@RestController
	 2)ResponseEntity클래스? 1)결과값(리턴값) 2)헤더작업 3)HTTP상태코드
	 3)주소 : 자원을 나타내는 의미로 정의
	 4) 데이타 생성 주소 : Post, 데이타 조회 주소 : Get, 데이타 삭제 주소 : Delete, 데이타 수정 주소 : Put
	 5) JSP와 같은 뷰를 리턴하는 것이 아니라, 데이타 그 자체를 리턴. -> 다양한 클라이언트 기기에 표준 데이타를 제공하여 서비스함.
	 
	  3,4,5 REST 이론.
	 */
	@Autowired
	private ReplyService replyService;
	
	
	//특정게시물에 의한 댓글목록.   bno :게시물번호, page :페이지번호
	// @Controller 방식으로 리턴값을 jsp로 할 경우
	/*
	@GetMapping("/replyList")
	public void replyList(Long bno, Criteria cri, Model model) {
		
	}
	*/
	
	// @RestController 방식으로 메서드의 리턴값을 그 데이타를 클라이언트에 반환
	// 1)클라이언트쪽에 댓글 목록과 2)댓글페이징정보. 2개의 정보를 Map컬렉션으로 작업하여, 클라이언트에게 보낸다.
	// 작업정보가 1개 인경우는 List컬렉션으로 작업하여, 클라이언트에게 보낸다.
	// 일반주소  /replies/pages/?bno=2562&page=1
	// REST주소  http://localhost:8888/replies/pages/2562/1.json
	@GetMapping(value = "/pages/{bno}/{page}", produces = {MediaType.APPLICATION_XML_VALUE, MediaType.APPLICATION_JSON_UTF8_VALUE})
	public ResponseEntity<Map<String, Object>> getList(@PathVariable("bno") Long bno, @PathVariable("page") int page ) {
		
		ResponseEntity<Map<String, Object>> entity = null;
		Map<String, Object> map = new HashMap<String, Object>();
		
		//1)댓글 목록
		Criteria cri = new Criteria(page, 5);
		// mapper인터페이스에 파라미터 전달시 cri, bno 파라미터 2개 전달
		List<ReplyVO> reList = replyService.getListWithPaging(cri, bno);
		
		map.put("replyList", reList);  //작업1
		
		//2)댓글페이징작업
		int total = replyService.getCountByBno(bno);
		PageDTO pageDTO = new PageDTO(total, cri);
		
		map.put("pageMaker", pageDTO); //작업2
		
		
		//최종 리턴되는 데이타작업
		entity = new ResponseEntity<Map<String,Object>>(map, HttpStatus.OK);
		
		
		return entity; // jsp파일명으로 해석되는 것이 아니라, json으로 변환되어 클라이언트에게 보내진다.
		
	}
}

3. ReplyMapper.java 코드

package com.demo.mapper;

import java.util.List;

import org.apache.ibatis.annotations.Param;

import com.demo.domain.ReplyVO;
import com.demo.dto.Criteria;

/*
 Mapper Interface의 메서드 파라미터가 2개 이상일 경우에는 @Param 어노테이션을 사용해야 한다. (중요)
 */

public interface ReplyMapper {

	//댓글목록
	public List<ReplyVO> getListWithPaging(@Param("cri") Criteria cri, @Param("bno") Long bno);
	
	//댓글개수
	public int getCountByBno(Long bno);
}

4. ReplyMapper.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="com.demo.mapper.ReplyMapper">

	<select id="getListWithPaging" resultType="com.demo.domain.ReplyVO">
	
	<![CDATA[ 
		SELECT RN, rno, BNO, REPLY, REPLYER, REPLYDATE, UPDATEDATE
FROM (
    SELECT ROWNUM RN, rno, BNO, REPLY, REPLYER, REPLYDATE, UPDATEDATE FROM TBL_REPLY
    WHERE BNO = #{bno} AND rownum <= #{cri.pageNum} * #{cri.amount}
)
where rn > (#{cri.pageNum} -1) * #{cri.amount}
	]]>
	
	</select>
	
	
	<select id="getCountByBno" resultType="int">
		SELECT count(*) FROM TBL_REPLY WHERE BNO = #{bno}
	</select>

</mapper>

5. ReplyService.java 코드

package com.demo.service;

import java.util.List;

import com.demo.domain.ReplyVO;
import com.demo.dto.Criteria;

public interface ReplyService {

	public List<ReplyVO> getListWithPaging(Criteria cri, Long bno);
	
	public int getCountByBno(Long bno);
}

6. ReplyServiceImpl.java 코드

package com.demo.service;

import java.util.List;

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

import com.demo.domain.ReplyVO;
import com.demo.dto.Criteria;
import com.demo.mapper.ReplyMapper;

@Service
public class ReplyServiceImple implements ReplyService {

	@Autowired
	private ReplyMapper replyMapper;

	@Override
	public List<ReplyVO> getListWithPaging(Criteria cri, Long bno) {
		// TODO Auto-generated method stub
		return replyMapper.getListWithPaging(cri, bno);
	}

	@Override
	public int getCountByBno(Long bno) {
		// TODO Auto-generated method stub
		return replyMapper.getCountByBno(bno);
	}
}

 


< SQL 코드 >

-- 11/14 댓글 기능
CREATE TABLE TBL_REPLY (
    RNO     NUMBER(10, 0),
    BNO     NUMBER(10, 0)      NOT NULL,
    REPLY   VARCHAR2(1000)  NOT NULL,
    REPLYER    VARCHAR2(50)    NOT NULL,
    REPLYDATE   DATE        DEFAULT SYSDATE,
    UPDATEDATE  DATE        DEFAULT SYSDATE
);

CREATE SEQUENCE SEQ_REPLY;

ALTER TABLE TBL_REPLY
ADD CONSTRAINT PK_REPLY PRIMARY KEY(RNO);

ALTER TABLE TBL_REPLY
ADD CONSTRAINT FK_REPLY_BOARD
FOREIGN KEY(BNO) REFERENCES TBL_BOARD(BNO);

-- rno, bno, reply, replyer, replydate, updatedate

-- 댓글데이타 작업

SELECT * FROM TBL_BOARD ORDER BY BNO DESC;

-- 아래 내용 5번 실행
INSERT INTO TBL_REPLY(rno, bno, reply, replyer)
VALUES(SEQ_REPLY.NEXTVAL, 3072, '댓글내용', 'USER01');

-- 아래 내용 여러번 실행
INSERT INTO TBL_REPLY(rno, BNO, REPLY, REPLYER)
(SELECT SEQ_REPLY.NEXTVAL, 3072, '댓글내용', 'USER01' FROM TBL_REPLY);

INSERT INTO TBL_REPLY(rno, BNO, REPLY, REPLYER)
(SELECT SEQ_REPLY.NEXTVAL, 3071, '댓글내용', 'USER01' FROM TBL_REPLY);

INSERT INTO TBL_REPLY(rno, BNO, REPLY, REPLYER)
(SELECT SEQ_REPLY.NEXTVAL, 3070, '댓글내용', 'USER01' FROM TBL_REPLY);

COMMIT;


-- 특정 게시물 번호의 댓글 데이타 조회
SELECT * FROM TBL_REPLY WHERE BNO = 3072;
SELECT * FROM TBL_REPLY WHERE BNO = 3071;
SELECT * FROM TBL_REPLY WHERE BNO = 3070;


-- 댓글 목록쿼리
SELECT RN, rno, BNO, REPLY, REPLYER, REPLYDATE, UPDATEDATE
FROM (
    SELECT ROWNUM RN, rno, BNO, REPLY, REPLYER, REPLYDATE, UPDATEDATE FROM TBL_REPLY
    WHERE BNO = 게시물번호 AND rownum <= #{pageNum} * #{amount}    
)
where rn > (#{pageNum} - 1) * #{amount};

 


< 보드매퍼와 리플라이매퍼 차이점 >

**Mapper Interface의 메서드 파라미터가 2개 이상일 경우에는 @Param 어노테이션을 사용해야 한다.

 

  • ReplyMapper.java 의  cri, bno는 ReplyMapper.xml 파일에서 동일하게 사용되어야 한다.

 

  • ReplyMapper.xml 


8. get.jsp 코드 추가하기

핸들바 작업?

<!-- 핸들바 작업1 -->
<script src="https://cdn.jsdelivr.net/npm/handlebars@latest/dist/handlebars.js"></script>
<!-- 핸들바 템플릿 작업2-->
<script id="replyTemplate" type="text/x-handlebars-template">
  {{#each .}}
  <div class="box-body">
    <div class="form-group row">
      <label for="replyer" class="col-3 col-form-label">작성자</label>
      <div class="col-5">
        <input type="text" name="rno" value="{{rno}}" readonly>
        <input type="text" class="form-control" name="replyer" value="{{replyer}}" readonly>
      </div>
      <label for="reply" class="col-4 col-form-label">등록일: <span>{{replydate}}</span> </label>
    </div>
    <div class="form-group row">
      <div class="col-8">
        <textarea class="form-control" name="reply" rows="3" readonly>{{reply}}</textarea>
      </div>
      <div class="col-4">
        <input type="button" name="btnModalModify" value="수정"><br>
        <input type="button" name="btnModalDelete" value="삭제">
      </div>
    </div>
  </div>
  <hr>
  {{/each}}
</script>

<!-- Optionally, you can add Slimscroll and FastClick plugins.
     Both of these plugins are recommended to enhance the
     user experience. -->
  <script>

    let bno = ${board.bno };  // 게시물번호
    let replyPage = 1;   // 댓글목록의 첫번째 페이지값.

    let url = "/replies/pages/" + bno + "/" + replyPage + ".json";

    getPage(url);

    // 사용자정의 함수
    function getPage(url) {
      console.log("댓글목록 주소: " + url);

      $.getJSON(url, function(replyData) {
        // let printReplyData = function(replyList, target, templateObject)
        printReplyData(replyData.replyList, $("div#replyListStr"), $("#replyTemplate"));

        /*
        let str = "";

        for(let i=0; i<result.replyList.length; i++) {
          str += result.replyList[i].rno;
          str += result.replyList[i].reply;
          str += result.replyList[i].replyer;
          str += "<button type='button'>delete</button>";
          str += "<hr>";
        }
        
        $("div#replyListStr").append(str);
        */

        /* json데이타 접근
        console.log(result.replyList.length);
        console.log("댓글일련번호: " + result.replyList[0].rno);
        console.log("댓글페이지정보: " + result.pageMaker.startPage);
        console.log("댓글페이지정보: " + result.pageMaker.endPage);
        */


      });
    }
    // 익명함수를 변수로 선언
    // replyList : json로 반환된 댓글데이타
    // target : 댓글목록이 출력될 위치.
    // templateObject : 핸들바 템플릿 참조변수.
    let printReplyData = function(replyList, target, templateObject) {
      //
      let template = Handlebars.compile(templateObject.html());
      let replyListHtml = template(replyList);
      target.empty();
      target.append(replyListHtml);
    }

  </script>

 

 

 

728x90
저작자표시 (새창열림)

'🏫 Open API_JAVA' 카테고리의 다른 글

[80일차] 게시판 댓글 수정 및 삭제 구현  (0) 2022.11.17
[79일차] 게시판 댓글 목록 / 페이징 / 모달창 구현 / jQuery 눈도장  (0) 2022.11.17
[77일차] 게시판에 페이징 기능 / 검색 기능 (ex03)  (0) 2022.11.13
[76일차] 게시판 기능구현 순서 / 의존성 주입 / 게시물 삭제 기능 구현 / 오라클 인덱스 힌트  (0) 2022.11.13
[75일차] 게시판 구조 생성 / 디자인 html 파일 ➡ jsp 형태로 만들기  (0) 2022.11.13
    '🏫 Open API_JAVA' 카테고리의 다른 글
    • [80일차] 게시판 댓글 수정 및 삭제 구현
    • [79일차] 게시판 댓글 목록 / 페이징 / 모달창 구현 / jQuery 눈도장
    • [77일차] 게시판에 페이징 기능 / 검색 기능 (ex03)
    • [76일차] 게시판 기능구현 순서 / 의존성 주입 / 게시물 삭제 기능 구현 / 오라클 인덱스 힌트
    Dorothy_YANG
    Dorothy_YANG
    Slowly but Surely, 비전공 문과생의 개발공부

    티스토리툴바