개발/스프링

23. 스프링 프레임워크 - REST API[자바 웹을 다루는 기술]

괴발자-K 2022. 6. 2. 10:53

REST 란?

네트워크에 대해 조금 알고 있다면 REST에 대해 이해하기 수월 할 수 있습니다.

REST(Representational State Transfer)의 약자로 자원을 이름으로 구분하여 해당 자원의 상태를 주고 받는 모든 것을

의미 합니다. REST API라는 것은 REST 방싱으로 제공되는 API를 말합니다.

 

1. HTTP URI를 통해 자원을 명시

2. HTTP 의 POST, GET, PUT, DELETE 메서드를 이용

3. 해당 자원에 대한 CRUD를 적용

 

CRUD는 기본적인 데이터 처리 기능을 말합니다.

1. CREATE - POST(데이터 생성)

2. Read - 데이터 조회(GET)

3. Update - 데이터 수정(PUT)

4. Delete - 데이터 삭제(DELETE)

 

 

REST 구성 요소

  • HTTP URI
  • HTTP Method
  • HTTP Message Pay Load

 

REST 특징

  • Server-Client 구조
  • Stateless
  • Cachable
  • Layered System
  • Uniform Interface

 

@RestController 사용하기

스프링4 번전에서 @RestController 애너테이션을 이용해 REST 방싱의 데이터 처리를 지원 합니다.

Maven Dependencies에서 스프링4 번전으로 업그레이드 된 것을 확인 할 수 있습니다.

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/maven-v4_0_0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.myspring</groupId>
	<artifactId>pro29</artifactId>
	<name>pro29</name>
	<packaging>war</packaging>
	<version>1.0.0-BUILD-SNAPSHOT</version>
	<properties>
		<java-version>1.6</java-version>
		<org.springframework-version>4.1.1.RELEASE</org.springframework-version>
		<org.aspectj-version>1.6.10</org.aspectj-version>
		<org.slf4j-version>1.6.6</org.slf4j-version>
	</properties>

 

 

@RestController 사용하여 문자열 전송

 

TestController.java

JSP 같은 뷰를 반환하는게 아니라, JSON, XML 같은 데이터를 브라우저 전송하는 컨트롤러을 설정합니다.

package com.myspring.pro29.ex01;

.................

@RestController
@RequestMapping("/test/*")
public class TestController {
     
	static Logger logger = LoggerFactory.getLogger(TestController.class);
	
	
	//브라우저로 문자열 전송
	@RequestMapping("/hello")
	public String hello() {
		return "Hello REST!!";
	}

 

http://iocaIhost:8090/pro29/test/hello로 요청하면 전송된 문자열을 표시 

Hello REST!!

F12를 누르고 NETWORK 탭에서 'Response Heads' 의 Content-Type 속성을 확인 합니다.

Content-Type 속성이 text/html로 지정된 것을 확인 할 수 있습니다.

 

@RestController 사용해서 VO 객체 전송

JSON 관련 라이브러리를 추가 합니다.

<!-- JSON  -->
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.13.1</version>
</dependency>

 

TestController.java

MemberVO 객체의 속성 값을 저장한 후 JSON으로 전송합니다.

//json형태로 출력
@RequestMapping("/member")
public MemberVO member() {
    MemberVO vo = new MemberVO();
    vo.setId("hong");
    vo.setPwd("1234");
    vo.setName("홍길동");
    vo.setEmail("hong@test.com");

    return vo;
}

 

http://iocaIhost:8090/pro29/test/member로 요청하면 JSON형태로 전달

{"id":"hong", "pwd":"1234", "name":"홍길동", "email":"hong@test.com"}

 

@RestController 사용해서 컬렉션 객체 전송

TestController.java

.......

@RequestMapping("/membersList")
public List<MemberVO> listMembers(){
    List<MemberVO> list = new ArrayList<MemberVO>();
    for (int i = 0; i < 10; i++) {
        MemberVO vo = new MemberVO();
        vo.setId("hong" + i);
        vo.setPwd("123" + i);
        vo.setName("홍길동" + i);
        vo.setEmail("hong" +i+"@test.com");
        list.add(vo);
    }
    return list;
}

1.  MebmerVO 객체를 저장할 ArrayList 객체를 생성 합니다.

2.  MmeberVO 객체를 10개 생성해 ArrayList에 저장 합니다.

3. ArrayList를 JSON으로 브라우저에 전송 합니다.

 

@RestController 사용해서 Map 전송

@RequestMapping("/membersMap")
public Map<Integer, MemberVO> membersMap(){
    Map<Integer, MemberVO> map = new HashMap<Integer, MemberVO>();
    for (int i = 0; i < 10; i++) {
        MemberVO vo = new MemberVO();
        vo.setId("hong" + i);
        vo.setPwd("123" + i);
        vo.setName("홍길동" + i);
        vo.setEmail("hong" + i + "@test.com");
        map.put(i, vo);
    }
    return map;
}

1. MemberVO 객체를 저장할 HashMap 객체를 생성 합니다.

2. MemberVO 객체를 HashMap에 저장합니다.

3. HashMap 객체를 브라우저로 전송 합니다.

 

@PathVariable 사용하기

@PathVariable을 사용하면 브라우저에서 요청  URL로 전달된 매개변수를 가져 올 수 있습니다.

//브라우저에서 요청 시 {num} 부분의 값이 @PathVariable로 지정
//요청 URL에서 지정된 값이 num에 자동으로 할당
@RequestMapping(value="/notice/{num}", method = RequestMethod.GET)
public int notice(@PathVariable("num") int num) throws Exception{
    return num;
}

 

@RequestBody와 @ResponseBody 사용하기

@RequestBody

브라우저에서 전달되는 JSON 데이터를 객체로 자동 변환

//JSON으로 전송된 데이터를 MemberVO 객체속성 자동으로 설정
@RequestMapping(value="/info", method = RequestMethod.POST)
public void modify(@RequestBody MemberVO vo) {
    logger.info(vo.toString());
}

JSONTest.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<c:set var="contextPath" value="${pageContext.request.contextPath}"/>    
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>JSONTest</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
<script>
   $(function(){
	   $("#checkJson").click(function() {
		   //회원정보를 JSON으로 생성
		   var member = {
		   id:"park",
		   name : "박지성",
		   pwd:"1234",
		   email:"park@test.com"			 
		 };
		 
		 $.ajax({
			 type:"post",
			 //test/info로 요청
			 url:"${contextPath}/test/info",
			 contentType: "application/json",
			 //회원 정보를 JSON 문자열로 변환
			 data :JSON.stringify(member),
			 success:function(data, textStatus){
				 
			 },
			 error:function(data, textStatus){
				 alert("에러가 발생했습니다.");
			 },
			 complete:function(data,textStatus){
				 
			 }
			 
		 });
	  });
   });
</script>
</head>
<body>
    <input type="button" id="checkJson" value="회원 정보 보내기"/><br><br>
    <div id="output"></div>
</body>
</html>

 

@ResponseBody

ResController.java

package com.myspring.pro29.ex02;

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

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

//@RestController로 지정 x
//@ResponseBody 메서드 호출 시 데이터를 전송하도록 설정
@Controller
public class RestController {
    
	//Map 데이터를 브라우저로 전송
	@RequestMapping(value="/res1")
	@ResponseBody
	public Map<String, String> res1(){
		Map<String, String> map = new HashMap<String, String>();
		map.put("id", "hong");
		map.put("name", "홍길동");
		
		return map;
	}
	
	//메서드 호출 시 home.jsp를 브라우저로 전소
	@RequestMapping(value="/res2")
	public ModelAndView res2() {
		return new ModelAndView("home");
	}
	
	
}

 

@ResponseEntity 사용하여 응답하기

@RestController는 별도의 View 제공하지 않고 데이터를 전달하여 예외가 발생 할 수 있습니다.

예외를 세밀하게 제어하기 위해 ResponseEntity를 사용 합니다.

 

ResponseEntityp  설정 할 수 있는 여러가지 HTTP 상태 코드는 아래 링크를 참조 하시기 바랍니다.

https://brunch.co.kr/@leedongins/65

 

HTTP 상태 코드 정리

와탭 블로그 | ALREADY REPORTED Client error responses 와탭에서 제공하는 URL Monitoring은 웹서비스의 장애를 알려주는 서비스 입니다. 웹서비스에서 반환되는 상태 코드가 4xx, 5xx 로 나타나는 경우 경고

brunch.co.kr

 

TestController.java

//ResponseEntity로 응답
//오류코드 500으로 응답
@RequestMapping("/membersList2")
public ResponseEntity<List<MemberVO>> listMembers2(){
    List<MemberVO> list = new ArrayList<MemberVO>();
    for (int i = 0; i < 10; i++) {
        MemberVO vo = new MemberVO();
        vo.setId("lee" + i);
        vo.setPwd("123" + i);
        vo.setName("이순신" + i);
        vo.setEmail("lee" +i+ "@test.com");
        list.add(vo);
    }
    return new ResponseEntity(list, HttpStatus.INTERNAL_SERVER_ERROR);
}

정상적으로 데이터를 표시합니다. Status Code를 확인해 보면 500으로 확인 할 수 있습니다.

 

HttpHeaders 클래스를 이용해 ResponseEntity로 전송할 데이터의 종류와 한글 인코딩을 설정

TestController.java

//ResponseEntity를 이용하면 JSON 뿐만 아니라 HTML이나 자바스크립트를 브라우저로 전송할수 있어
//결과 메시지나 오류 메시지를 전송할 때 편함
@RequestMapping(value="/res3")
public ResponseEntity res3() {
    //전송할 데이터의 종류와 인코딩을 설정
    HttpHeaders responseHeaders = new HttpHeaders();
    responseHeaders.add("Content-Type", "text/html; charset=utf-8");
    //전송할 자바스크립트 코드를 문자열로 작성
    String message = "<script>";
    message += " alert('새 회원을 등록 합니다.');";
    message += " location.href='/pro29/test/membersList2';";
    message += " </script>";

    //ResponseEntity를 이용해 HTML 형식으로 전송
    return new ResponseEntity(message, responseHeaders, HttpStatus.CREATED);
}

 

 

게시판 기능 REST API 만들기

package com.myspring.pro29.ex03;

import java.util.ArrayList;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/boards")
public class BoardController {
    Logger logger = LoggerFactory.getLogger(BoardController.class);
    
    @RequestMapping(value="/all", method=RequestMethod.GET)
    public ResponseEntity<List<ArticleVO>> listArticles() {
    	
      logger.info("listArticles 메서드 호출");
      List<ArticleVO> list = new ArrayList<ArticleVO>();
      
      for (int i = 0; i < 10; i++) {
    	  ArticleVO vo = new ArticleVO();
    	  vo.setArticleNO(i);
    	  vo.setWriter("이순신 " + i);
    	  vo.setTitle("안녕하세요" + i);
    	  vo.setContent("새 상품을 소개 합니다." + i);
    	  list.add(vo);
	   }
	return new ResponseEntity(list, HttpStatus.OK);
    }
   
    //GET방식으로 요청하면 글 번호를 전달 하므로 글 번호에 대한 글 정보를 조회 
    @RequestMapping(value= "/{articleNO}", method = RequestMethod.GET)
    public ResponseEntity<ArticleVO> findArticle(@PathVariable("articleNO") Integer articleNO){
    	logger.info("findArticle 메서드 호출");
    	ArticleVO vo = new ArticleVO();
    	vo.setArticleNO(articleNO);
    	vo.setWriter("홍길동");
    	vo.setTitle("안녕하세요");
    	vo.setContent("홍길동 글 입니다.");
    	return new ResponseEntity(vo, HttpStatus.OK);
    }
    
    //POST 방식으로 요청하므로 요청 시 JSON으로 전달되는 객체를 새 글로 추가
    @RequestMapping(value = "", method = RequestMethod.POST)
    public ResponseEntity<String> addArticle(@RequestBody ArticleVO articleVO){
    	
    	ResponseEntity<String> resEntity = null;
    	try {
	    	logger.info("addArticle 메서드 호출");
	    	logger.info(articleVO.toString());
	    	resEntity = new ResponseEntity("ADD_SUCCEEDED", HttpStatus.OK);
    	} catch (Exception e) {
    		resEntity = new ResponseEntity(e.getMessage(), HttpStatus.BAD_REQUEST);
    	}
		return resEntity;
    	
    }
    
    //수정하기
  	@RequestMapping(value = "/{articleNO}", method = RequestMethod.PUT)
  	public ResponseEntity<String> modArticle (@PathVariable("articleNO") Integer articleNO, 
                                              @RequestBody ArticleVO articleVO) {
  		ResponseEntity<String>  resEntity = null;
  		try {
  			logger.info("modArticle 메서드 호출");
  			logger.info(articleVO.toString());
  			resEntity =new ResponseEntity("MOD_SUCCEEDED",HttpStatus.OK);
  		}catch(Exception e) {
  			resEntity = new ResponseEntity(e.getMessage(),HttpStatus.BAD_REQUEST);
  		}
  		
  		return resEntity;
  	}
    
    //삭제하기
    //DELETE 방식으로 요청하므로 전달되는 articleNO에 대한 글을 삭제
    @RequestMapping(value= "/{articleNO}", method = RequestMethod.DELETE)
    public ResponseEntity<String> removeAricle (@PathVariable("articleNO") Integer articleNO){
    	ResponseEntity<String> resEntity = null;
    	try {
			logger.info("removeArticle 메서드 호출");
			logger.info(articleNO.toString());
			resEntity = new ResponseEntity("REMOVE_SUCCEEDED", HttpStatus.OK);
		} catch (Exception e) {
			resEntity = new ResponseEntity(e.getMessage(), HttpStatus.BAD_REQUEST);
		}
    	
		return resEntity;
    }
}

 

새 글 등록, 수정, 삭제에 사용할 JSONTest2.jsp을 작성합니다. Ajax 사용

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"  isELIgnored="false" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"  %>

<c:set var="contextPath" value="${pageContext.request.contextPath}"  />
<!DOCTYPE html>
<html>
<head>
<title>JSONTest2</title>
<script src="http://code.jquery.com/jquery-latest.js"></script>  
<script>
  $(function() {
      $("#checkJson").click(function() {
      	var article = {articleNO:"114", 
	               writer:"박지성",
	               title:"안녕하세요", 
	               content:"상품 소개 글입니다."
	              };
  
  	$.ajax({
  	    //type:"POST",
        //url:"${contextPath}/boards",
        type:"PUT",
        url:"${contextPath}/boards/114",
        contentType: "application/json;charset=UTF-8",
        data :JSON.stringify(article),
      success:function (data,textStatus){
          alert(data);
      },
      error:function(data,textStatus){
        alert("에러가 발생했습니다.");
      },
      complete:function(data,textStatus){
      }
   });  //end ajax	

   });
});
</script>
</head>
<body>
  <input type="button" id="checkJson" value="새글 쓰기"/><br><br>
  <div id="output"></div>
</body>
</html>

1. 새글 정보를 JSON형태로 생성 합니다.

2. 새 글 등록은 POST 방식으로 요청하고, 그 에 맞는 controller에 있는 새 글 등록 메서드를 호출 합니다.

   글에 대한 수정은 PUT을 사용합니다.

3. 글 정보를 JSON 형식으로 전송 합니다.