spring - REST

오늘·2021년 6월 10일
0

웹 페이지 연습

목록 보기
32/35

REST란

  • 모바일 쇼핑몰에서 '더보기'클릭 시 데이터만 전송받아 기존화면에 추가해서 표시하는 것
  • Representational State Transfer의 약자로, 하나의 URI가 고유한 리소스를 처리하는 공통방식이다
  • REST 방식으로 제공되는 API를 REST API(또는 RESTful API)라고 하며, 이는 트위터와 같은 Open API에서 많이 사용된다

버젼에 따른 어노테이션 차이

  • 스프링 3버전에서는 @ResponseBody 애너테이션을 지원하면서 REST 방식의 데이터 처리를 지원
  • 스프링4 버전에서는 @RestController 애너테이션을 이용해 REST 방식의 데이터 처리를 지원

@RestController 이용해보기

pom.xml 수정

스프링 버젼이 3.1.1로 되어있는데, 4.1.1로 변경하고 저장

lib를 확인해보면 4 버젼으로 업그레이드 된것을 확인 가능하다

TestController.java

파일 위치

JSP와 같은 뷰를 반환하는 것이 아니라 JSON, XML 같은 데이터를 브라우저로 전송하는 @Restcontroller 를 설정하는 곳이다

package com.myspring.pro29.ex01;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/test/*") // /test 밑의 모든 것
public class TestController {
	
	// /hello 로 요청시 브라우저로 문자열을 전송하겠다
	@RequestMapping("/hello")
	public String hello() {
		return "Hello REST!!";
	}
}

요청

http://localhost:8700/pro29/test/hello 주소로 값을 요청하면 아래와 같이 설정된 문자열이 표시된다.

F12 를 눌러 관리자 도구를 열고 -> Network 탭을 선택 -> All 클릭 후 F5로 새로고침 시키면 Content-Type 속성을 확인할 수 있다.


@RestController로 VO 객체 전달

MemberVO.java

파일 위치

package com.myspring.pro29.ex01;

public class MemberVO {
	private String id;
	private String pwd;
	private String name;
	private String email;
	
	// 기본 메소드
	public MemberVO() {	}
	
    	// 회원의 속성 정보를 출력할 것이기 때문에 오버라이드
	@Override
	public String toString() {
		String info = id + "," + pwd + "," + name + "," + email;
		return info;
	}
	
	// 이하 각 속성에 대한 getter/setter
	public String getId() {
		return id;
	}
	public void setId(String id) {
		this.id = id;
	}
	public String getPwd() {
		return pwd;
	}
	public void setPwd(String pwd) {
		this.pwd = pwd;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getEmail() {
		return email;
	}
	public void setEmail(String email) {
		this.email = email;
	}
}

pom.xml

JSON 기능을 이용하기 위해서 관련 라이브러리를 추가!

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

TestController.java 수정

MemberVo의 속성을 JSON으로 변환하여 전송

package com.myspring.pro29.ex01;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
// /test 밑의 모든 것
@RequestMapping("/test/*")
public class TestController {
	
	// /hello 로 요청시 브라우저로 문자열을 전송하겠다
	@RequestMapping("/hello")
	public String hello() {
		return "Hello REST!!";
	}
	
	
	// MemberVO 객체의 속성 값을 저장한 후 JSON으로 전송할 것이다
	@RequestMapping("/member")
	public MemberVO member() {
		MemberVO vo = new MemberVO();
		vo.setId("lee");
		vo.setPwd("1234");
		vo.setName("이자바");
		vo.setEmail("java@test.com");
		return vo;
	}
}

실행

이번에는 http://localhost:8700/pro29/test/member 으로 요청한다. 보이는 값 자체가 아까와는 확실히 다른 모습니다

F12 로 확인해보면 Content-Type 속성 값이 json 임을 확인할 수 있었다.

VO 객체를 만듦 -> josn의 라이브러리(jar) 주입 -> Controller에서 메소드를 만들어 리턴 -> 객체(vo)를 리턴하니까 josn으로 브라우저가 알아서 해석해 보여줌


@RestController로 컬렉션 객체 전달

TestController.java 수정

package com.myspring.pro29.ex01;

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

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
// /test 밑의 모든 것
@RequestMapping("/test/*")
public class TestController {
	
	// /hello 로 요청시 브라우저로 문자열을 전송하겠다
	@RequestMapping("/hello")
	public String hello() {
		return "Hello REST!!";
	}
	
	
	// MemberVO 객체의 속성 값을 저장한 후 JSON으로 전송할 것이다
	@RequestMapping("/member")
	public MemberVO member() {
		MemberVO vo = new MemberVO();
		vo.setId("lee");
		vo.setPwd("1234");
		vo.setName("이자바");
		vo.setEmail("java@test.com");
		return vo;
	}
	
    	// 컬렉션(list)로 전달해서 json 배열로(배열 요소는 vo의 자료)
	@RequestMapping("/membersList")
	public List<MemberVO> listMembers() {
		// MemberVo 객체를 저장할 ArrayList 객체를 생성한다
		List<MemberVO> list = new ArrayList<MemberVO>();
		
		// MemberVO 객체를 10개 생성해서 ArrayList에 저장
		for (int i=0; i<10; i++) {
			MemberVO vo = new MemberVO();
			vo.setId("lee" + i);
			vo.setPwd("1234" + i);
			vo.setName("이자바" + i);
			vo.setEmail("lee" + i + "@test.com");
			list.add(vo);
		}
		
		// ArrayList를 JSON으로 브라우저에 전송
		return list;
	}
}

실행

http://localhost:8700/pro29/test/membersList 요청 시 배열처럼 List의 객체들이 전송된게 보인다

컨텐츠 타입도 json으로 확인 가능


@RestController 로 Map 전달

TestController.java 수정

package com.myspring.pro29.ex01;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/test/*") // /test 밑의 모든 것
public class TestController {
	
    ...
    
	@RequestMapping("/membersMap")
	public Map<Integer, MemberVO> membersMap() {
		// MemberVO 객체를 저장할 HashMap 객체 생성
		Map<Integer, MemberVO> map = new HashMap<Integer, MemberVO>();
		
		// MemberVO 객체를 HashMap에 저장한다
		for (int i=0; i<10; i++) {
			MemberVO vo = new MemberVO();
			vo.setId("kim" + i);
			vo.setPwd("3456" + i);
			vo.setName("김길동" + i);
			vo.setEmail("kim" + i + "@test.com");
			map.put(i, vo);
		}
		return map;
	}
}

실행

http://localhost:8700/pro29/test/membersMap 으로 브라우저에게 요청

  • Map으로 전달한 값이 Josn의 객체 모습으로 나오도록 하는걸 확인.

  • json에서 name에 해당하는 것은 map의 key값이고, json에서 value에 해당하는 것은 map에서 value로 변환한다 (...?)


@PathVariable 사용

  • 이 어노테이션을 사용하면 브라우저에서 요청 URL로 전달된 매개변수를 가져올 수 있다

TestController.java 수정

package com.myspring.pro29.ex01;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/test/*") // /test 밑의 모든 것
public class TestController {
	
    ....
	
	@RequestMapping(value= "/notice/{num}", method = RequestMethod.GET)
	public int notice(@PathVariable("num") int num) throws Exception {
		return num;
	}
}

실행

http://localhost:8700/pro29/test/notice/112 이렇게 보내면 112가 num 에 할당된다. 컨텐츠 타입은 당연히 json

근데 만약에

	@RequestMapping(value= "/notice/{num}", method = RequestMethod.GET)
	public String notice(@PathVariable("num") String s) throws Exception {
		return s;
	}

이런식으로 작성하면 출력시 String 형식으로 가서 Content-Type: text/html 형식이 된다


@RequestBody 사용

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

관련 자바&jsp 파일 생성

JSONTest.jsp

회원정보 보내기 버튼을 클릭하면, Ajax를 이용해서 회원 정보를 JSON 으로 만들어 컨트롤러로 보낸다

<%@ page language="java" contentType="text/html; charset=utf-8"
	pageEncoding="EUC-KR" 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>
<meta charset="utf-8">
<title>JSONTest</title>
<script>
$(function() {
    $("#checkJson").click(function() {
    	// 회원 정보를 json으로 생성
    	var member = {
    			id:"kim", 
			    name:"김연아",
			    pwd:"1234", 
			    email:"kim@test.com" };
		$.ajax({
      	type:"post",
      	// /test/info 로 요청하기
      	url:"${contextPath}/test/info",
      	contentType: "application/json",
      	// 회원정보를 josn 문자열로 변환
      	data :JSON.stringify(member),
   		success:function (data,textStatus){
   		},
   		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>

TestController.java 수정

@RequestBody 를 이용해 json 데이터를 MemberVO 객체로 자동 변환한다

...
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
...
	static Logger logger = LoggerFactory.getLogger(TestController.class);
	
	@RequestMapping(value ="/info", method = RequestMethod.POST)
	// josn으로 전송된 데이터를 MemberVO 객체의 속성에 자동으로 설정
	public void modify(@RequestBody MemberVO vo) {
		logger.info(vo.toString());
	}
...

HomeController.java

/pro29로 요청하면 JsonTest.jsp를 표시하도록 설정

package com.myspring.pro29;

import java.util.Locale;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;


@Controller
public class HomeController {
	
	private static final Logger logger = LoggerFactory.getLogger(HomeController.class);
	
	@RequestMapping(value = "/", method = RequestMethod.GET)
	public String home(Locale locale, Model model) {
		return "JSONTest";
	}	
}

실행

요청 주소 http://localhost:8700/pro29/

버튼을 눌러도 화면에 어떤것도 뜨지 않아서 순간 당황했다. 값을 봐야하는건 콘솔인데! 잊고 있었다.

위와 같이 콘솔에 josn으로 회원정보가 전송된 모습을 확인할 수 있다. (버튼을 누르는 횟수만큼 뜬다. 그러니까 여러 개 떠있는건 당황해서 버튼을 연타했었기 때문...)


@ResponseBody 사용

컨트롤러의 특정 메소드에 달아놓으면 JSP가 아닌 텍스트나 json으로 결과를 전송할 수 있다.

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;

@Controller
public class ResController {
	@RequestMapping(value = "/res1")
	// 메소드 호출시 데이터를 전송하도록 설정
	@ResponseBody
	// Map 데이터를 브라우저로 전송 
	public Map<String, Object> res1() {
		Map<String, Object> map = new HashMap<String, Object>();
		map.put("id", "lee");
		map.put("name", "이자바");
		return map;
	}
	
	// 메소드 호출 시 home.jsp를 브라우저로 전송한다
	@RequestMapping(value = "/res2")
	public ModelAndView res2() {
		return new ModelAndView("home");
	}
}

실행

처음에 주소로 요청했더니 404 에러가 떠서 당황했다. 알고보니 이전에 사용하던 Controller 파일에 달아줬던 @Controller 를 지워주지 않아서 그런거였고.. 확인 잘하자.

확인 후 다시 요청하니 이렇게 json 식으로 떴다.

그 다음 res2를 요청했더니 수정없이 놔둔 기본의 "home.jsp"가 요청되었다


@ResponseEntity 사용해 응답하기

  • @RestController는 별도의 View를 제공하지 않은 채 데이터를 전달하므로 전달 과정에서 예외가 발생할 수 있다. 이 예외에 대해 좀 더 세밀한 제어가 필요한 경우 ResponseEntity 클래스를 사용하는 것

Http 상태 코드 표

TestController.java 수정

...
	@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.setName("이자바" + i);
			vo.setPwd("2345" + i);
			vo.setEmail("lee" + i + "@test.com");
			list.add(vo);
		}
		// 오류코드 500으로 응답
		return new ResponseEntity(list,HttpStatus.INTERNAL_SERVER_ERROR);
	}
}

실행

다른 곳에 @controller가 없는지 유의하자

F12를 보면 Status가 500인걸 확인할 수 있다

(아래 사진은 이전에 사용했던, status를 설정하지 않은 다른 페이지의 것)


@RequestBody와 @Responsebody

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

TestController.java

...
	@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);
	}
}

실행

http://localhost:8700/pro29/test/membersList2

아래와 같이 전송된 자바스크립트(의 경고) 메시지가 표시된다.

확인을 누르면 아래와 같이 membersList2의 화면으로 넘어간다


0개의 댓글