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 |