본문 바로가기

서버/Spring
[스프링(Spring)] RESTful


// REST(Representational State Transfer) API, RESTful Service
    - 웹상의 자원(문서, 이미지, 동영상, 데이터 등)을 자원명으로 표시해서 자원의 상태를 주고받는 행위
    - HTTP URI를 통해서 자원을 명시하고, HTTP Method를 통해서 자원에 대한 CRUD 처리하는 방식


// 게시판 구현

    1. 여태 사용한 구현 방식 > URI 표현
        - 목록보기 GET http://localhost/board/list.do
        - 추가하기 POST http://localhost/board/add.do
        - 수정하기 POST http://localhost/board/edit.do
        - 삭제하기 POST http://localhost/board/del.do
        - 검색하기 GET   http://localhost/board/list.do?word=검색어

    2. REST 방식
        - 목록보기  GET http://localhost/board
        - 추가하기  POST http://localhost/board + 데이터(패킷 저장)
        - 수정하기  PUT http://localhost/board/1 + 데이터(패킷 저장)
        - 삭제하기  DELETE http://localhost/board/1
        - 검색하기 GET http://localhost/board/검색어


// REST API 설계 규칙
    1. URI에 자원을 표시한다. > 마지막 단어가 자원 표현

    2. URI에 동사를 표시하지 않는다.

    3. HTTP Method를 사용해서 행동을 표현한다.
        a. GET : 리소스 요청
        b. POST : 데이터 전달 + 서버측 생성
        c. PUT : 데이터 전달 + 수정(전체 수정 > 레코드의 모든 컬럼 수정)
        d. PATCH : 데이터 전달 + 수정(전체 수정 > 레코드의 일부 컬럼 수정)
        e. DELETE : 데이터 삭제

    4. URI + HTTP Method = REST API

    5. 구분자는 '/'를 사용한다.

    6. URI의 마지막에 '/'를 적지 않는다.

    7. '-' 사용이 가능하다.(가끔)

    8. '_' 사용하지 않는다.

    9. 소문자로만 작성한다.

    10. 확장자를 작성하지 않는다. > 자원명으로 끝나기 때문(확장자 의미X)


~ "com.test.domain" > BoardDTO.java

package com.test.domain;

import lombok.Data;

@Data
public class BoardDTO {
	
	private String seq;
	private String subject;
	private String content;
	private String regdate;
	private String id;

}


~ "com.text.mapper" > BoardMapper.java

package com.test.mapper;

import java.util.List;

import com.test.domain.BoardDTO;

public interface BoardMapper {

	int add(BoardDTO dto);

	List<BoardDTO> list();

	BoardDTO get(String seq);

	int edit(BoardDTO dto);

	int del(String seq);

}


~ root-context.xml > mybatis scan

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:mybatis-spring="http://mybatis.org/schema/mybatis-spring"
	xsi:schemaLocation="http://mybatis.org/schema/mybatis-spring http://mybatis.org/schema/mybatis-spring-1.2.xsd
		http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd">

	<!-- Root Context: defines shared resources visible to all other web components -->
	<bean id="hikariConfig" class="com.zaxxer.hikari.HikariConfig">
		<property name="driverClassName"
			value="net.sf.log4jdbc.sql.jdbcapi.DriverSpy"></property>
		<property name="jdbcUrl"
			value="jdbc:log4jdbc:oracle:thin:@localhost:1521:xe"></property>
		<property name="username" value="hr"></property>
		<property name="password" value="java1234"></property>
	</bean>

	<bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource"
		destroy-method="close">
		<constructor-arg ref="hikariConfig"></constructor-arg>
	</bean>

	<bean id="sessionfactory"
		class="org.mybatis.spring.SqlSessionFactoryBean">
		<property name="dataSource" ref="dataSource"></property>
	</bean>
	
	<mybatis-spring:scan base-package="com.test.mapper"/>

</beans>


~ "com.test.controller" > TestController.java > add()
~ Insomnia > 게시판 글쓰기(http://localhost/rest/board) > POST

package com.test.controller;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import com.test.domain.BoardDTO;
import com.test.mapper.BoardMapper;
@RestController
public class TestController {
	
	@Autowired
	private BoardMapper mapper;
	//Board > CRUD
	
	//글쓰기
	//1. http://localhost/rest/board
	//2. POST
	//3. return int
	//@RequestMapping(value="/board", method=RequestMethod.POST)
	
	//REST 서비스 > 테스트 > 클라이언트 툴(Postman, Insomnia, VS Code, 크롬 확장 프로그램 등)

	@PostMapping("/board")
	public int add(@RequestBody BoardDTO dto) {
		
		int result = mapper.add(dto);
		
		return result;
	}
}
<?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.test.mapper.BoardMapper">

	<insert id="add">
		insert into tblBoard(seq, subject, content, regdate, id) 
			values (seqBoard.nextVal, #{subject}, #{content}, default, #{id})
	</insert>

</mapper>



~ "com.test.controller" > TestController.java > list()
~ Insomnia > 게시판 목록 보기(http://localhost/rest/board) > GET

package com.test.controller;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import com.test.domain.BoardDTO;
import com.test.mapper.BoardMapper;

@RestController
public class TestController {
	//글쓰기
	//1. http://localhost/rest/board
	//2. POST
	//3. return int
	//@RequestMapping(value="/board", method=RequestMethod.POST)
	
	//REST 서비스 > 테스트 > 클라이언트 툴(Postman, Insomnia, VS Code, 크롬 확장 프로그램 등)

	@PostMapping("/board")
	public int add(@RequestBody BoardDTO dto) {
		
		int result = mapper.add(dto);
		
		return result;
	}
	
	//목록 가져오기
	//1. http://localhost/rest/board
	//2. GET
	//3. List<DTO> -> JSON 변환
	
	@GetMapping("/board")
	public List<BoardDTO> list() {
		
		return mapper.list();
	}
}

 

<?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.test.mapper.BoardMapper">
	
	<select id="list" resultType="com.test.domain.BoardDTO">
		select
			seq, subject, regdate, id
		from tblBoard
			order by seq desc		
	</select>

</mapper>



~ "com.test.controller" > TestController.java > edit()
~ Insomnia > 게시판 수정하기(http://localhost/rest/board/5) > PUT

package com.test.controller;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import com.test.domain.BoardDTO;
import com.test.mapper.BoardMapper;

@RestController
public class TestController {
	
	@Autowired
	private BoardMapper mapper;
		
	//글쓰기
	//1. http://localhost/rest/board
	//2. POST
	//3. return int
	//@RequestMapping(value="/board", method=RequestMethod.POST)
	
	//REST 서비스 > 테스트 > 클라이언트 툴(Postman, Insomnia, VS Code, 크롬 확장 프로그램 등)

	@PostMapping("/board")
	public int add(@RequestBody BoardDTO dto) {
		
		int result = mapper.add(dto);
		
		return result;
	}
	
	//목록 가져오기
	//1. http://localhost/rest/board
	//2. GET
	//3. List<DTO> -> JSON 변환
	
	@GetMapping("/board")
	public List<BoardDTO> list() {
		
		return mapper.list();
	}
	
	//요소 수정하기
	//1. http://localhost/rest/board/5
	//2. PUT or PATCH(보통 PUT)
	//3. return int
	
	@PutMapping("/board/{seq}") //경로 변수(PathVariable)
	public int edit(@RequestBody BoardDTO dto, @PathVariable("seq") String seq) {
		
		dto.setSeq(seq);
		
		return mapper.edit(dto);
	}
	
}

 

<?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.test.mapper.BoardMapper">

	<update id="edit">
		update tblBoard set
			subject = #{subject},
			content = #{content}
				where seq = #{seq}
	</update>
</mapper>



~ "com.test.controller" > TestController.java > del()
~ Insomnia > 게시판 삭제하기(http://localhost/rest/board/5) > DELETE

package com.test.controller;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import com.test.domain.BoardDTO;
import com.test.mapper.BoardMapper;


@RestController
public class TestController {
	
	@Autowired
	private BoardMapper mapper;
	
	//글쓰기
	//1. http://localhost/rest/board
	//2. POST
	//3. return int
	//@RequestMapping(value="/board", method=RequestMethod.POST)
	
	//REST 서비스 > 테스트 > 클라이언트 툴(Postman, Insomnia, VS Code, 크롬 확장 프로그램 등)

	@PostMapping("/board")
	public int add(@RequestBody BoardDTO dto) {
		
		int result = mapper.add(dto);
		
		return result;
	}
	
	//목록 가져오기
	//1. http://localhost/rest/board
	//2. GET
	//3. List<DTO> -> JSON 변환
	
	@GetMapping("/board")
	public List<BoardDTO> list() {
		
		return mapper.list();
	}
	
	//요소 수정하기
	//1. http://localhost/rest/board/5
	//2. PUT or PATCH(보통 PUT)
	//3. return int
	
	@PutMapping("/board/{seq}") //경로 변수(PathVariable)
	public int edit(@RequestBody BoardDTO dto, @PathVariable("seq") String seq) {
		
		dto.setSeq(seq);
		
		return mapper.edit(dto);
	}
	
	//삭제하기
	//1. http://localhost/rest/board/6
	//2. DELETE
	//3. return int
	
	@DeleteMapping("/board/{seq}")
	public int del(@PathVariable("seq") String seq) {
		
		return mapper.del(seq);
		
	}
}

 

<?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.test.mapper.BoardMapper">
	
	<delete id="del">
		delete from tblBoard
			where seq = #{seq}
	</delete>

</mapper>


~ "com.test.controller" > TestController.java > get()
~ Insomnia > 게시판 상세보기(http://localhost/rest/board/5) > GET

package com.test.controller;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import com.test.domain.BoardDTO;
import com.test.mapper.BoardMapper;

@RestController
public class TestController {
	
	@Autowired
	private BoardMapper mapper;

	
	//글쓰기
	//1. http://localhost/rest/board
	//2. POST
	//3. return int
	//@RequestMapping(value="/board", method=RequestMethod.POST)
	
	//REST 서비스 > 테스트 > 클라이언트 툴(Postman, Insomnia, VS Code, 크롬 확장 프로그램 등)

	@PostMapping("/board")
	public int add(@RequestBody BoardDTO dto) {
		
		int result = mapper.add(dto);
		
		return result;
	}
	
	//목록 가져오기
	//1. http://localhost/rest/board
	//2. GET
	//3. List<DTO> -> JSON 변환
	
	@GetMapping("/board")
	public List<BoardDTO> list() {
		
		return mapper.list();
	}
	
	//요소 수정하기
	//1. http://localhost/rest/board/5
	//2. PUT or PATCH(보통 PUT)
	//3. return int
	
	@PutMapping("/board/{seq}") //경로 변수(PathVariable)
	public int edit(@RequestBody BoardDTO dto, @PathVariable("seq") String seq) {
		
		dto.setSeq(seq);
		
		return mapper.edit(dto);
	}
	
	//삭제하기
	//1. http://localhost/rest/board/6
	//2. DELETE
	//3. return int
	
	@DeleteMapping("/board/{seq}")
	public int del(@PathVariable("seq") String seq) {
		
		return mapper.del(seq);
		
	}
	
	//상세보기
	//1. http://localhost/rest/board/6
	//2. GET
	//3. return DTO
	@GetMapping("/board/{seq}")
	public BoardDTO get(@PathVariable("seq") String seq) {
		
		return mapper.get(seq);
	}

}

 

<?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.test.mapper.BoardMapper">
	
	<select id="get" resultType="com.test.domain.BoardDTO">
		select 
			*
		from tblBoard
			where seq = #{seq}
	</select>
</mapper>



@RestController를 사용하면 메소드마다 @ResponseBody를 붙여주지 않아도 된다.
@RequestBody 붙여주기(JSON으로 받을 때...)