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 |