REST(Representational State Transfer) : 자원(Resource)의 표현(Representation)에 의한 상태(State)를 전달(Transfer)하는 것을 의미
- @ResponseBody : 요청 처리 메소드의 반환값(문자열)을 리스폰즈 메세지 몸체부에 저장하여 클라이언트에게 직접 텍스트 데이타로 응답되도록 설정하는 어노테이션
- 반환되는 문자열을 ViewResolver 객체를 사용하여 뷰로 변환하여 응답하지 않고 리스폰즈 메세지 몸체부에 저장하여 Front Controller가 직접 응답 처리
- Java 객체는 리스폰즈 메세지 몸체부에 저장 불가능하므로 응답 불가능
@ResponseBody 어노테이션을 사용하여 요청 처리 메소드의 반환값(Member 객체)을 리스폰즈 메세지의 몸체부에 저장하여 텍스트 데이타의 회원정보를 클라이언트에게 전달하여 응답 처리
- @RequestBody : 리퀘스트 메세지 몸체부에 저장되어 모든 전달값을 문자열로 제공받기 위한 어노테이션
- POST, PUT, PATCH, DELETE 등의 요청방식에 의해 리퀘스트 메세지 몸체부에 저장되어 전달된 모든 값을 문자열로 제공받아 사용 가능
- GET 방식은 리퀘스트 메세지 몸체부가 비어 있으므로 @RequestBody 어노테이션 사용 불가능
- 리퀘스트 메세지 몸체부에 저장되어 전달된 JSON 형식(application/json)의 값은 매개변수에 Java 객체로 제공받아 사용 가능 (전달값은 객체 필드에 저장)
package xyz.itwill10.controller;
@Controller
public class RestfulController {
@RequestMapping(value = "/rest", method = RequestMethod.GET)
public String rest() {
return "rest/input";
}
/*
//@RequestParam 어노테이션을 사용하여 하나의 전달값을 하나의 매개변수에 저장받아 사용
@RequestMapping(value = "/rest", method = RequestMethod.POST)
public String rest(@RequestParam String id, @RequestParam String name, Model model) {
model.addAttribute("id", id);
model.addAttribute("name", name);
//반환되는 문자열(ViewName)을 이용하여 ViewResolver 객체가 뷰로 완성하여 응답 처리
return "rest/output";
}
*/
//@ResponseBody : 요청 처리 메소드의 반환값(문자열)을 리스폰즈 메세지 몸체부에 저장하여
//클라이언트에게 직접 텍스트 데이타로 응답되도록 설정하는 어노테이션
// => 반환되는 문자열을 ViewResolver 객체를 사용하여 뷰로 변환하여 응답하지 않고 리스폰즈
//메세지 몸체부에 저장하여 Front Controller가 직접 응답 처리
// => Java 객체는 리스폰즈 메세지 몸체부에 저장 불가능하므로 응답 불가능
//@RequestBody : 리퀘스트 메세지 몸체부에 저장되어 모든 전달값을 문자열로 제공받기 위한 어노테이션
// => POST, PUT, PATCH, DELETE 등의 요청방식에 의해 리퀘스트 메세지 몸체부에 저장되어 전달된
//모든 값을 문자열로 제공받아 사용 가능
// => GET 방식은 리퀘스트 메세지 몸체부가 비어 있으므로 @RequestBody 어노테이션 사용 불가능
// => 리퀘스트 메세지 몸체부에 저장되어 전달된 JSON 형식(application/json)의 값은 매개변수에
//Java 객체로 제공받아 사용 가능 - 전달값은 객체 필드에 저장
@RequestMapping(value = "/rest", method = RequestMethod.POST)
@ResponseBody
public String rest(@RequestBody String input) {
return input;
}
//@ResponseBody 어노테이션을 사용하여 요청 처리 메소드의 반환값(Member 객체)을 리스폰즈 메세지의
//몸체부에 저장하여 텍스트 데이타의 회원정보를 클라이언트에게 전달하여 응답 처리
//문제점)리스폰즈 메세지의 몸체부에 Java 객체를 저장 불가능 - 에러 발생(406)
//해결법)반환되는 Java 객체를 텍스트 데이타(XML 또는 JSON)의 문자열로 자동 변환되도록
//설정하여 응답 처리 가능
// => jackson-databind 라이브러리를 프로젝트에 빌드 처리하면 자동으로 Java 객체가 JSON
//형식의 텍스트 데이타로 변환하여 반환 - 메이븐 : pom.xml
@RequestMapping("/rest_member")
@ResponseBody
public Member restMember() {
Member member=new Member();
member.setId("abc123");
member.setPasswd("123456");
member.setName("홍길동");
member.setEmail("abc@itwill.xyz");
//jackson-databind 라이브러리에 의해 Member 객체가 JavaScript Object 객체로 변환되어 응답
return member;
}
//@ResponseBody 어노테이션을 사용하여 요청 처리 메소드의 반환값(List 객체)을 리스폰즈 메세지의
//몸체부에 저장하여 텍스트 데이타의 회원목록을 클라이언트에게 전달하여 응답 처리
@RequestMapping("/rest_list")
@ResponseBody
public List<Member> restMemberList() {
List<Member> memberList=new ArrayList<Member>();
Member member1=new Member();
member1.setId("abc123");
member1.setPasswd("123456");
member1.setName("홍길동");
member1.setEmail("abc@itwill.xyz");
memberList.add(member1);
Member member2=new Member();
member2.setId("xyz789");
member2.setPasswd("789456");
member2.setName("임꺽정");
member2.setEmail("xyz@itwill.xyz");
memberList.add(member2);
//jackson-databind 라이브러리에 의해 List 객체가 JavaScript Array 객체로 변환되어 응답
return memberList;
}
@RequestMapping("/rest_map")
@ResponseBody
public Map<String, Object> restMap() {
Map<String, Object> map=new HashMap<String, Object>();
map.put("id", "abc123");
map.put("passwd", "123456");
map.put("name", "홍길동");
map.put("email", "abc@itwill.xyz");
//jackson-databind 라이브러리에 의해 Map 객체가 JavaScript Object 객체로 변환되어 응답
return map;
}
@RequestMapping(value = "/rest/map", method = RequestMethod.GET)
public String restInput() {
return "rest/input";
}
//모든 전달값이 Map 객체의 엔트리에 저장되어 매개변수로 제공받아 사용 가능
// => 모든 전달값을 Map 객체로 제공받기 위해 반드시 @RequestParam 어노테이션 사용
@RequestMapping(value = "/rest/map", method = RequestMethod.POST)
@ResponseBody
public Map<String, Object> restOutput(@RequestParam Map<String, Object> map) {
return map;
}
}
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.14.2</version>
</dependency>
</dependencies>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>SPRING</title>
</head>
<body>
<h1>입력페이지</h1>
<hr>
<form method="post">
<table>
<tr>
<td>아이디</td>
<td><input type="text" name="id"></td>
</tr>
<tr>
<td>이름</td>
<td><input type="text" name="name"></td>
</tr>
<tr>
<td colspan="2"><button type="submit">입력완료</button></td>
</tr>
</table>
</form>
</body>
</html>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>SPRING</title>
</head>
<body>
<h1>출력페이지</h1>
<hr>
<p>아이디 = ${id }</p>
<p>이름 = ${name }</p>
</body>
</html>
CREATE TABLE RESTBOARD(NUM NUMBER PRIMARY KEY, WRITER VARCHAR2(50), CONTENT VARCHAR2(100), REGDATE DATE);
CREATE SEQUENCE RESTBOARD_SEQ;
package xyz.itwill10.dto;
import lombok.Data;
@Data
public class RestBoard {
private int num;
private String writer;
private String content;
private String regdate;
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="xyz.itwill10.mapper.RestBoardMapper">
<insert id="insertRestBoard">
<selectKey resultType="int" keyProperty="num" order="BEFORE">
select restboard_seq.nextval from dual
</selectKey>
insert into restboard values(#{num},#{writer},#{content},sysdate)
</insert>
<update id="updateRestBoard">
update restboard set writer=#{writer},content=#{content} where num=#{num}
</update>
<delete id="deleteRestBoard">
delete from restboard where num=#{num}
</delete>
<select id="selectRestBoardCount" resultType="int">
select count(*) from restboard
</select>
<select id="selectRestBoard" resultType="RestBoard">
select * from restboard where num=#{num}
</select>
<select id="selectRestBoardList" resultType="RestBoard">
select * from (select rownum rn, board.* from (select * from restboard
order by num desc) board) where rn between #{startRow} and #{endRow}
</select>
</mapper>
package xyz.itwill10.mapper;
public interface RestBoardMapper {
int insertRestBoard(RestBoard restBoard);
int updateRestBoard(RestBoard restBoard);
int deleteRestBoard(int num);
int selectRestBoardCount();
RestBoard selectRestBoard(int num);
List<RestBoard> selectRestBoardList(Map<String, Object> map);
}
package xyz.itwill10.dao;
public interface RestBoardDAO {
int insertRestBoard(RestBoard restBoard);
int updateRestBoard(RestBoard restBoard);
int deleteRestBoard(int num);
int selectRestBoardCount();
RestBoard selectRestBoard(int num);
List<RestBoard> selectRestBoardList(Map<String, Object> map);
}
package xyz.itwill10.dao;
@Repository
@RequiredArgsConstructor
public class RestBoardDAOImpl implements RestBoardDAO {
private final SqlSession sqlSession;
@Override
public int insertRestBoard(RestBoard restBoard) {
return sqlSession.getMapper(RestBoardMapper.class).insertRestBoard(restBoard);
}
@Override
public int updateRestBoard(RestBoard restBoard) {
return sqlSession.getMapper(RestBoardMapper.class).updateRestBoard(restBoard);
}
@Override
public int deleteRestBoard(int num) {
return sqlSession.getMapper(RestBoardMapper.class).deleteRestBoard(num);
}
@Override
public RestBoard selectRestBoard(int num) {
return sqlSession.getMapper(RestBoardMapper.class).selectRestBoard(num);
}
@Override
public List<RestBoard> selectRestBoardList(Map<String, Object> map) {
return sqlSession.getMapper(RestBoardMapper.class).selectRestBoardList(map);
}
@Override
public int selectRestBoardCount() {
return sqlSession.getMapper(RestBoardMapper.class).selectRestBoardCount();
}
}
package xyz.itwill10.service;
public interface RestBoardService {
void addRestBoard(RestBoard restBoard);
void modifyRestBoard(RestBoard restBoard);
void removeRestBoard(int num);
int getRestBoardCount();
RestBoard getRestBoard(int num);
List<RestBoard> getRestBoardList(Map<String, Object> map);
}
package xyz.itwill10.service;
@Service
@RequiredArgsConstructor
public class RestBoardServiceImpl implements RestBoardService {
private final RestBoardDAO restBoardDAO;
@Transactional
@Override
public void addRestBoard(RestBoard restBoard) {
restBoardDAO.insertRestBoard(restBoard);
}
@Transactional
@Override
public void modifyRestBoard(RestBoard restBoard) {
/*
if(restBoardDAO.selectRestBoard(restBoard.getNum())==null) {
throw new Exception("해당 게시글을 찾을 수 없습니다.");
}
*/
restBoardDAO.updateRestBoard(restBoard);
}
@Transactional
@Override
public void removeRestBoard(int num) {
restBoardDAO.deleteRestBoard(num);
}
@Override
public int getRestBoardCount() {
return restBoardDAO.selectRestBoardCount();
}
@Override
public RestBoard getRestBoard(int num) {
return restBoardDAO.selectRestBoard(num);
}
@Override
public List<RestBoard> getRestBoardList(Map<String, Object> map) {
return restBoardDAO.selectRestBoardList(map);
}
}
REST 기능을 제공하는 요청 처리 메소드의 페이지 요청방식
@RestController : REST 기능을 제공하는 요청 처리 메소드로만 작성된 Controller 클래스를 Spring Bean으로 등록하기 위한 어노테이션
페이지 번호를 전달받아 RESTBOARD 테이블에 저장된 게시글 목록 중 해당 페이지 번호의 범위에 게시글 목록 검색하여 JSON 형식의 데이타로 응답하는 요청 처리 메소드
- 게시글을 전달받아 RESTBOARD 테이블에 삽입하고 처리결과를 일반 텍스트로 응답하는 요청 처리 메소드
- [application/json] 형식으로 전달된 값을 Java 객체로 제공받기 위해 매개변수에 @RequestBody 어노테이션 사용
- HtmlUtils.htmlEscape(String str) : 전달받은 문자열에서 HTML 태그 관련 문자를 회피
- 문자(Escape Character)로 변환하여 반환하는 메소드 (XSS 공격에 대한 방어)
글번호를 전달받아 RESTBOARD 테이블에 저장된 해당 글번호의 게시글을 검색하여 JSON 형식의 텍스트 데이타로 응답하는 요청 처리 메소드
게시글을 전달받아 RESTBOARD 테이블에 저장된 해당 게시글을 변경하고 처리결과를 일반텍스트로 응답하기 위한 요청 처리 메소드
요청 URL 주소의 글번호를 전달받아 RESTBOARD 테이블에 저장된 해당 글번호의 게시글을 삭제하고 처리결과를 일반 텍스트로 응답하기 위한 요청 처리 메소드
- @PathVariable : URL 주소로 제공된 값을 요청 처리 메소드의 매개변수에 저장하기 위한 어노테이션
- 요청 URL 주소에서 표현된 이름과 매개변수의 이름이 반드시 같아야만 매개변수에 값 저장 가능
public String restBoardRemove(@PathVariable int num) {}
- @PathVariable 어노테이션에 value 속성값을 사용하여 요청 URL 주소에서 표현된 이름으로 제공된 값을 얻어와 매개변수에 저장 가능
package xyz.itwill10.controller;
@Controller
@RequiredArgsConstructor
public class RestBoardController {
private final RestBoardService restBoardService;
@RequestMapping("/board")
public String restBoard() {
return "rest/board";
}
//페이지 번호를 전달받아 RESTBOARD 테이블에 저장된 게시글 목록 중 해당 페이지 번호의 범위에
//게시글 목록을 검색하여 JSON 형식의 데이타로 응답하는 요청 처리 메소드
// => 게시글 목록을 페이징 처리하여 출력하기 위해 요청 페이지 번호의 게시글 목록과 페이지
//번호 출력 관련 값이 저장된 객체를 Map 객체의 엔트리로 저장하여 JSON 형식의 데이타로 응답
//처리되도록 반환
@RequestMapping(value="/board_list", method = RequestMethod.GET)
@ResponseBody
public Map<String, Object> restBoardList(@RequestParam(defaultValue = "1") int pageNum) {
//System.out.println("pageNum = "+pageNum);
//RESTBOARD 테이블에 저장된 모든 게시글의 갯수를 반환하는 메소드 호출
int totalBoard=restBoardService.getRestBoardCount();
int pageSize=5;//하나의 페이지에 출력될 게시글의 갯수 저장
int blockSize=5;//하나의 블럭에 출력될 페이지 번호의 갯수 저장
//페이징 처리 관련 값이 필드에 저장된 Pager 객체 생성
Pager pager=new Pager(pageNum, totalBoard, pageSize, blockSize);
//RestBoardService 클래스의 getRestBoardList() 메소드를 호출하기 위해 Map 객체 생성
// => Map 객체에는 요청 페이지의 시작 행번호와 종료 행번호를 엔트리로 저장하여 SQL 명령에서 사용
Map<String, Object> pageMap=new HashMap<String, Object>();
pageMap.put("startRow", pager.getStartRow());
pageMap.put("endRow", pager.getEndRow());
//요청 페이지 번호에 대한 게시글 목록을 List 객체로 반환받아 저장
List<RestBoard> restBoardList=restBoardService.getRestBoardList(pageMap);
//처리결과를 저장하여 반환하기 위한 Map 객체 생성
// => Map 객체에는 게시글 목록(List 객체)과 페이징 처리 관련 값이 저장된 객체(Pager 객체)를 엔트리로 저장
Map<String, Object> resultMap=new HashMap<String, Object>();
resultMap.put("restBoardList", restBoardList);//list객체
resultMap.put("pager", pager);//array객체
return resultMap;//Map 객체를 반환하여 JSON 형식의 데이타로 응답
}
//게시글을 전달받아 RESTBOARD 테이블에 삽입하고 처리결과를 일반 텍스트로 응답하는 요청 처리 메소드
// => [application/json] 형식으로 전달된 값을 Java 객체로 제공받기 위해 매개변수에 @RequestBody 어노테이션 사용
@RequestMapping(value="/board_add", method = RequestMethod.POST)
@ResponseBody
public String restBoardAdd(@RequestBody RestBoard restBoard) {
//HtmlUtils.htmlEscape(String str) : 전달받은 문자열에서 HTML 태그 관련 문자를 회피
//문자(Escape Character)로 변환하여 반환하는 메소드 - XSS 공격에 대한 방어
restBoard.setContent(HtmlUtils.htmlEscape(restBoard.getContent()));
restBoardService.addRestBoard(restBoard);
return "success";
}
//글번호를 전달받아 RESTBOARD 테이블에 저장된 해당 글번호의 게시글을 검색하여 JSON 형식의
//텍스트 데이타로 응답하는 요청 처리 메소드
@RequestMapping(value="/board_view", method = RequestMethod.GET)
@ResponseBody
public RestBoard restBoardView(@RequestParam int num) {
return restBoardService.getRestBoard(num);
}
//게시글을 전달받아 RESTBOARD 테이블에 저장된 해당 게시글을 변경하고 처리결과를 일반
//텍스트로 응답하기 위한 요청 처리 메소드
// => 페이지 요청 방식을 여러개로 설정할 경우 @RequestMapping 어노테이션의 method 속성값으로 배열 사용 가능
@RequestMapping(value="/board_modify", method = {RequestMethod.PUT, RequestMethod.PATCH})
@ResponseBody
public String restBoardModify(@RequestBody RestBoard restBoard) {
restBoardService.modifyRestBoard(restBoard);
return "success";
}
//요청 URL 주소의 글번호를 전달받아 RESTBOARD 테이블에 저장된 해당 글번호의 게시글을
//삭제하고 처리결과를 일반 텍스트로 응답하기 위한 요청 처리 메소드
// => 요청 URL 주소를 사용하여 전달된 값은 @RequestMapping 어노테이션의 value 속성값에서
//{이름} 형식으로 표현 가능 - @PathVariable 어노테이션을 사용하여 전달값을 매개변수에 저장
//@PathVariable : URL 주소로 제공된 값을 요청 처리 메소드의 매개변수에 저장하기 위한 어노테이션
// => 요청 URL 주소에서 표현된 이름과 매개변수의 이름이 반드시 같아야만 매개변수에 값 저장 가능
// => @PathVariable 어노테이션에 value 속성값을 사용하여 요청 URL 주소에서 표현된 이름으로
//제공된 값을 얻어와 매개변수에 저장 가능
@RequestMapping(value="/board_remove/{num}", method = RequestMethod.DELETE)
@ResponseBody
public String restBoardRemove(@PathVariable int num) {
restBoardService.removeRestBoard(num);
return "success";
}
}
package xyz.itwill10.util;
import lombok.Data;
//페이징 처리 관련 값을 필드에 저장하기 위한 클래스
@Data
public class Pager {
//생성자를 이용하여 초기값을 전달받아 필드에 저장
private int pageNum;//요청 페이지의 번호
private int totalBoard;//전체 게시글의 갯수
private int pageSize;//하나의 페이지에 출력될 게시글의 갯수
private int blockSize;//하나의 블럭에 출력될 페이지 번호의 갯수
//생성자로 초기화된 필드값을 계산하여 결과값을 필드에 저장
private int totalPage;//전체 페이지의 갯수
private int startRow;//요청 페이지에 출력될 게시글의 시작 행번호
private int endRow;//요청 페이지에 출력될 게시글의 종료 행번호
private int startPage;//현재 블럭에 출력될 시작 페이지 번호
private int endPage;//현재 블럭에 출력될 종료 페이지 번호
private int prevPage;//이전 블럭에 출력될 시작 페이지 번호
private int nextPage;//다음 블럭에 출력될 시작 페이지 번호
public Pager(int pageNum, int totalBoard, int pageSize, int blockSize) {
super();
this.pageNum = pageNum;
this.totalBoard = totalBoard;
this.pageSize = pageSize;
this.blockSize = blockSize;
calcPage();
}
//계산 결과값을 필드에 저장하는 메소드 - 생성자에서 호출하여 사용
private void calcPage() {
totalPage=(int)Math.ceil((double)totalBoard/pageSize);
if(pageNum<=0 || pageNum>totalPage) {
pageNum=1;
}
startRow=(pageNum-1)*pageSize+1;
endRow=pageNum*pageSize;
if(endRow>totalBoard) {
endRow=totalBoard;
}
startPage=(pageNum-1)/blockSize*blockSize+1;
endPage=startPage+blockSize-1;
if(endPage>totalPage) {
endPage=totalPage;
}
prevPage=startPage-blockSize;
nextPage=startPage+blockSize;
}
}
RESTBOARD 테이블에 저장된 게시글 목록을 페이징 처리하여 검색하고 처리결과를 JSON 형식의 데이타로 응답하는 페이지(board_list)를 AJAX 기능으로 요청
headers : 요청정보가 저장된 리퀘스트 메세지의 머릿부(Header)를 변경하기 위한 속성
headers: {"contentType":"application/json"},
contentType : 리퀘스트 몸체부에 저장된 전달값에 대한 문서형식을 변경하기 위한 속성
contentType: "application/json",
JSON.stringify(object) : JavaScript 객체를 전달받아 JSON 형식의 텍스트 데이터로 변환하는 메소드
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>SPRING</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<style type="text/css">
#btnDiv {
margin: 10px;
}
#restBoardTable {
border: 1px solid black;
border-collapse: collapse;
}
#restBoardTable td, #restBoardTable th {
border: 1px solid black;
padding: 3px;
}
.inputDiv {
width: 240px;
height: 80px;
border: 2px solid black;
background-color: gray;
position: absolute;
top: 50%;
left: 50%;
margin-top: -40px;
margin-left: -120px;
padding: 5px;
z-index: 100;
display: none;
}
</style>
</head>
<body>
<h1>RestBoard</h1>
<hr>
<div id="btnDiv">
<button type="button" id="writeBtn">글쓰기</button>
</div>
<%-- 게시글 목록을 출력하는 태그 --%>
<div id="restBoardListDiv"></div>
<%-- 페이지 번호를 출력하는 태그 --%>
<div id="pageNumDiv"></div>
<%-- 신규 게시글을 입력받기 위한 태그 --%>
<div id="insertDiv" class="inputDiv">
<table>
<tr>
<td>작성자</td>
<td><input type="text" id="insertWriter" class="insert"></td>
</tr>
<tr>
<td>내용</td>
<td><input type="text" id="insertContent" class="insert"></td>
</tr>
<tr>
<td colspan="2">
<button type="button" id="insertBtn">저장</button>
<button type="button" id="cancelInsertBtn">취소</button>
</td>
</tr>
</table>
</div>
<%-- 변경 게시글을 입력받기 위한 태그 --%>
<div id="updateDiv" class="inputDiv">
<input type="hidden" id="updateNum">
<table>
<tr>
<td>작성자</td>
<td><input type="text" id="updateWriter" class="update"></td>
</tr>
<tr>
<td>내용</td>
<td><input type="text" id="updateContent" class="update"></td>
</tr>
<tr>
<td colspan="2">
<button type="button" id="updateBtn">변경</button>
<button type="button" id="cancelUpdateBtn">취소</button>
</td>
</tr>
</table>
</div>
<script type="text/javascript">
//현재 요청 페이지의 번호를 저장하기 위한 전역변수
// => 모든 함수에서 사용 가능하며 프로그램 종료 전까지 값을 유지
var page=1;
//특정 페이지 번호의 게시글 목록을 출력하는 함수 호출
boardListDisplay(page);
//RESTBOARD 테이블에 저장된 게시글 목록을 페이징 처리하여 검색하고 처리결과를 JSON 형식의
//데이타로 응답하는 페이지(board_list)를 AJAX 기능으로 요청
// => 응답받은 JSON 형식의 데이타로 게시글 목록 출력 태그를 변경
function boardListDisplay(pageNum) {
page=pageNum;
$.ajax({
type: "get",
url: "${pageContext.request.contextPath}/board_list?pageNum="+pageNum,
dataType: "json",
success: function(result) {
//alert(result);//[object Object] >> 자바스크립트 Object 객체
//매개변수로 제공받은 자바스크립트 객체를 HTML로 변경하여 게시글 목록 출력 태그 변경
if(result.restBoardList.length==0) {//검색된 게시글이 없는 경우
var html="<table id='restBoardTable'>";
html+="<tr>";
html+="<th width='800' colspan='6'>검색된 게시글이 없습니다.</th>";
html+="</tr>";
html+="</table>";
$("#restBoardListDiv").html(html);
return;
}
var html="<table id='restBoardTable'>";
html+="<tr>";
html+="<th width='50'>번호</th>";
html+="<th width='100'>작성자</th>";
html+="<th width='350'>내용</th>";
html+="<th width='200'>작성일</th>";
html+="<th width='50'>변경</th>";
html+="<th width='50'>삭제</th>";
html+="</tr>";
$(result.restBoardList).each(function() {//게시글 목록을 반복 처리
html+="<tr>";
html+="<td align='center'>"+this.num+"</td>";
html+="<td align='center'>"+this.writer+"</td>";
html+="<td>"+this.content+"</td>";
html+="<td align='center'>"+this.regdate+"</td>";
html+="<td align='center'><button type='button' onclick='modify("+this.num+");'>변경</button></td>";
html+="<td align='center'><button type='button' onclick='remove("+this.num+");'>삭제</button></td>";
html+="</tr>";
});
html+="</table>";
$("#restBoardListDiv").html(html);
//페이지 번호를 출력하는 함수 호출
pageNumDisplay(result.pager)
},
error: function(xhr) {
alert("에러코드(게시글 목록 검색) = "+xhr.status)
}
});
}
//페이지 번호를 출력하는 태그를 변경하는 함수 - 페이지 번호 출력
function pageNumDisplay(pager) {
var html="";
if(pager.startPage > pager.blockSize) {
html+="<a href='javascript:boardListDisplay("+pager.prevPage+")'>[이전]</a>";
}
for(i=pager.startPage;i<=pager.endPage;i++) {
if(pager.pageNum!=i) {
html+="<a href='javascript:boardListDisplay("+i+")'>["+i+"]</a>";
} else {
html+="["+i+"]";
}
}
if(pager.endPage != pager.totalPage) {
html+="<a href='javascript:boardListDisplay("+pager.nextPage+")'>[다음]</a>";
}
$("#pageNumDiv").html(html);
}
//[글쓰기] 태그를 클릭한 경우 호출되는 이벤트 처리 함수
$("#writeBtn").click(function() {
//변경 게시글을 입력받기 위한 태그 초기화
$(".update").val("");//입력태그 초기화
$("#updateDiv").hide();//태그 숨김
//신규 게시글을 입력받기 위한 태그 출력
$("#insertDiv").show();
});
//신규 게시글을 입력받기 위한 태그에서 [저장] 태그를 클릭한 경우 호출되는 이벤트 처리 함수
// => 사용자 입력값을 얻어와 RESTBOARD 테이블에 삽입하는 페이지를 AJAX 기능으로 요청하여
//처리결과를 제공받아 응답 처리
$("#insertBtn").click(function() {
var writer=$("#insertWriter").val();
var content=$("#insertContent").val();
if(writer=="") {
alert("작성자를 입력해 주세요.");
return;
}
if(content=="") {
alert("내용 입력해 주세요.");
return;
}
$.ajax({
type: "post",
url: "${pageContext.request.contextPath}/board_add",
//headers : 요청정보가 저장된 리퀘스트 메세지의 머릿부(Header)를 변경하기 위한 속성
// => 리퀘스트 메세지의 머릿부에서 몸체부에 저장된 전달값에 대한 문서형식(MimeType)을 변경
//headers: {"contentType":"application/json"},
//contentType : 리퀘스트 몸체부에 저장된 전달값에 대한 문서형식을 변경하기 위한 속성
// => 리퀘스트 몸체부에 저장된 전달값을 JSON 형식의 텍스트 데이타로 전달
// => 요청 처리 메소드의 매개변수에서 @RequestBody 어노테이션을 사용하여 모든 전달값을
//Java 객체로 제공받아 사용 - 전달값은 Java 객체의 필드값으로 저장
contentType: "application/json",
//JSON.stringify(object) : JavaScript 객체를 전달받아 JSON 형식의 텍스트 데이타로 변환하는 메소드
data: JSON.stringify({"writer":writer,"content":content}),
dataType: "text",
success: function(result) {
if(result=="success") {
//신규 게시글을 입력받기 위한 태그 초기화
$(".insert").val("");//입력태그 초기화
$("#insertDiv").hide();//태그 숨김
//특정 페이지 번호의 게시글 목록을 출력하는 함수 호출
boardListDisplay(page);
}
},
error: function(xhr) {
alert("에러코드(게시글 삽입) = "+xhr.status)
}
});
});
//신규 게시글을 입력받기 위한 태그에서 [취소] 태그를 클릭한 경우 호출되는 이벤트 처리 함수
$("#cancelInsertBtn").click(function() {
//신규 게시글을 입력받기 위한 태그 초기화
$(".insert").val("");//입력태그 초기화
$("#insertDiv").hide();//태그 숨김
});
//게시글의 [변경] 태그를 클릭한 경우 호출되는 이벤트 처리 함수
// => 글번호를 전달받아 RESTBOARD 테이블에 저장된 해당 글번호의 게시글을 검색하여 반환하는
//페이지를 AJAX 기능으로 요청하여 처리결과를 JSON 형식의 데이타로 응답받아 변경 게시글을
//입력받기 위한 태그의 입력값으로 초기화 처리
function modify(num) {
//alert(num);
//신규 게시글을 입력받기 위한 태그 초기화
$(".insert").val("");//입력태그 초기화
$("#insertDiv").hide();//태그 숨김
//변경 게시글을 입력받기 위한 태그 출력
$("#updateDiv").show();
$.ajax({
type: "get",
//페이지 요청시 질의문자열(QueryString)을 사용하여 값 전달
// => 요청 처리 메소드의 매개변수에 @RequestParam 어노테이션을 사용하여 값을 제공받아 사용
url: "${pageContext.request.contextPath}/board_view?num="+num,
dataType: "json",
success: function(result) {
$("#updateNum").val(result.num);
$("#updateWriter").val(result.writer);
$("#updateContent").val(result.content);
},
error: function(xhr) {
alert("에러코드(게시글 검색) = "+xhr.status)
}
});
}
//변경 게시글을 입력받기 위한 태그에서 [변경] 태그를 클릭한 경우 호출되는 이벤트 처리 함수
// => 사용자 입력값을 얻어와 RESTBOARD 테이블에 저장된 게시글 변경하는 페이지를 AJAX
//기능으로 요청하여 처리결과를 제공받아 응답 처리
$("#updateBtn").click(function() {
var num=$("#updateNum").val();
var writer=$("#updateWriter").val();
var content=$("#updateContent").val();
if(writer=="") {
alert("작성자를 입력해 주세요.");
return;
}
if(content=="") {
alert("내용 입력해 주세요.");
return;
}
$.ajax({
type: "put",
url: "${pageContext.request.contextPath}/board_modify",
contentType: "application/json",
data: JSON.stringify({"num":num,"writer":writer,"content":content}),
dataType: "text",
success: function(result) {
if(result=="success") {
//변경 게시글을 입력받기 위한 태그 초기화
$(".update").val("");//입력태그 초기화
$("#updateDiv").hide();//태그 숨김
//특정 페이지 번호의 게시글 목록을 출력하는 함수 호출
boardListDisplay(page);
}
},
error: function(xhr) {
alert("에러코드(게시글 변경) = "+xhr.status)
}
});
});
//변경 게시글을 입력받기 위한 태그에서 [취소] 태그를 클릭한 경우 호출되는 이벤트 처리 함수
$("#cancelUpdateBtn").click(function() {
//변경 게시글을 입력받기 위한 태그 초기화
$(".update").val("");//입력태그 초기화
$("#updateDiv").hide();//태그 숨김
});
//게시글의 [삭제] 태그를 클릭한 경우 호출되는 이벤트 처리 함수
// => 글번호를 전달받아 RESTBOARD 테이블에 저장된 해당 글번호의 게시글을 삭제하는 페이지를
//AJAX 기능으로 요청하여 처리결과를 일반 텍스트로 제공받아 응답 처리
function remove(num) {
//alert(num);
if(confirm("게시글을 삭제 하시겠습니까?")) {
$.ajax({
type: "delete",
//페이지 요청시 요청 URL 주소를 사용하여 값 전달
// => 요청 처리 메소드의 매개변수에 @PathVariable 어노테이션을 사용하여 값을 제공받아 사용
url: "${pageContext.request.contextPath}/board_remove/"+num,
dataType: "text",
success: function(result) {
if(result=="success") {
//특정 페이지 번호의 게시글 목록을 출력하는 함수 호출
boardListDisplay(page);
}
},
error: function(xhr) {
alert("에러코드(게시글 삭제) = "+xhr.status)
}
});
}
}
</script>
</body>
</html>
$.ajax(setting) : AJAX 기능을 사용하여 요청과 응답을 처리하기 위한 메소드
$.ajax({
type: "post",//요청방식 설정
url: "welcome_two.jsp",//요청 웹프로그램의 URL 주소 설정
data: "name="+name,//요청 웹프로그램에 값을 전달하기 위한 이름과 값을 설정
dataType: "html",//응답결과에 대한 문서형식 설정 - 요소값 : text, html, script, xml, json 등
//정상적인 응답결과(200)를 제공받아 처리하기 위한 함수의 등록 설정
// => 처리함수의 매개변수에는 응답결과가 자동으로 저장되어 제공
success: function(result) {
$("#message").html(result);
},
//비정상적인 응답결과(4XX or 5XX)를 제공받아 처리하기 위한 함수의 등록 설정
// => 처리함수의 매개변수에는 XMLHttpRequest 객체가 자동으로 저장되어 제공
error: function(xhr) {
alert("에러코드 = "+xhr.status);
})