https://spring.io/guides/gs/rest-service/

  • 만들게 될 것:

    1. http://localhost:8080/greeting 에서 HTTP GET 리퀘스트를 받는 서비스를 만들어보자.

    2. 데이터는 JSON 으로 표현이 된다. {"id":1,"content":"Hello, World!"}

    3. http://localhost:8080/greeting?name=User 처럼 name 변수로 커스터마이징 할 수 있다. JSON 에는 World 대신에 name 변수의 값이 들어간다.

  • 필요한 것: IDE 에 Spring Tool Suite(STS) 를 설치할 수 있다.

Spring 프로젝트 만들기

퀵스타트에서 본 것처럼 start.spring.io에서 Spring 을 받아서 프로젝트 설정을 해 줄 수도 있지만, 이번 포스트에서 필요한 프로젝트를 깃 클론을 해 올 수도 있다.

git clone https://github.com/spring-guides/gs-rest-service.git


리소스를 보여주는 클래스 작성하기

서비스는 /greeting 에 대한 GET 리퀘스트를 다룰 것이다. GET 리퀘스트는 200 OK 리스폰스와 함께 다음과 같은 JSON 을 반환한다.

{
    "id": 1,
    "content": "Hello, World!"
}

Tip 앱은 Jackson JSON 라이브러리를 사용하여 Greeting 의 인스턴스를 자동으로 JSON 에 저장한다. Jackson JSON 은 웹 스타터에 디폴트로 포함되어있다.


src/main/java/com/example/restservice/Greeting.java 를 생성하고 다음 코드를 붙여넣는다.

package com.example.restservice;

public class Greeting {

	private final long id;
	private final String content;

	public Greeting(long id, String content) {
		this.id = id;
		this.content = content;
	}

	public long getId() {
		return id;
	}

	public String getContent() {
		return content;
	}
}


리소스 관리하기

컴포넌트들은 @RestController 주석에 따라 구분된다.

아래 코드의 GreetingController 는 /greeting 에 대한 GET 리퀘스트를 관리하고, Greeting 클래스의 새로운 인스턴스를 반환한다. src/main/java/com/example/restservice/Greeting.java

package com.example.restservice;

import java.util.concurrent.atomic.AtomicLong;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class GreetingController {

	private static final String template = "Hello, %s!";
	private final AtomicLong counter = new AtomicLong();

	@GetMapping("/greeting")
	public Greeting greeting(@RequestParam(value = "name", defaultValue = "World") String name) {
		return new Greeting(counter.incrementAndGet(), String.format(template, name));
	}
}

TIP @GetMapping 대신에 @PostMapping 을 쓰면 HTTP의 POST 리퀘스트를 의미하게 된다.또는 @RequestMapping 을 사용하여 둘 다 사용할 수 있다. (@RequestMapping(method=GET))

greeting() 메소드를 실행하면 idcontent 어트리뷰트를 갖는 Greeting 클래스의 새 오브젝트를 리턴하는데, 이 때 idcounter 의 다음 값을 가져온다. 파라미터로 주어진 name 변수는 greeting template 을 활용하여 포맷팅한다.

전통적인 MVC 관리와 RESTful 웹 서비스 관리의 차이점은 HTTP 응답이 생성되는 방식이다. 서버에서 greeting 데이터를 HTML 에 맞게 렌더링하는 뷰 기술과는 달리, RESTful 웹 서비스 관리는 오브젝트 자체를 반환한다. 오브젝트 데이터는 직접적으로 JSON 의 형식으로 HTTP 응답에 쓰여진다.

위의 코드는 Spring 의 @RestController 주석을 사용하는데, 이는 클래스의 모든 메소드가 뷰 대신 도메인 오브젝트를 반환하는 컨트롤러의 역할을 함을 의미한다. @Controller@Responsebody 둘 모두를 포함하는 역할이다.

Greeting 오브젝트는 항상 JSON 으로 변환되어야만 한다. 이는 Spring 의 MappingJackson2HttpMessageConverter 가 자동적으로 수행한다.

마지막으로 같은 폴더의 RestServiceApplication.java 를 확인해 보자.

package com.example.restservice;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class RestServiceApplication {

	public static void main(String[] args) {
		SpringApplication.run(RestServiceApplication.class, args);
	}

}

@SpringBootApplication 은 아래와 같은 것을 모두 포함한다.

  • @Configuration : 해당 클래스가 스프링 빈(bean) 의 근원이 됨을 명시한다.
  • @EnableAutoConfiguration : Spring Boot가 스프링 빈을 추가하도록 하는데, 클래스 경로의 세팅, 다른 빈들, 그리고 다양한 속성 설정에 따라 추가한다. 예를 들어, 만약 spring-webmvc 가 클래스 경로에 있다면, 이 주석은 해당 앱을 웹 앱으로 설정하고, DispatcherServlet을 하는 등의 주요 행동들을 실행한다.
  • @ComponentScan : 스프링이 com/example 패키지에 있는 다른 컴포넌트, 설정, 서비스를 확인하여 컨트롤러를 찾도록 한다.

main() 메소드는 스프링 부트의 SpringApplication.run() 메소드를 사용하여 앱을 실행한다. 이 웹 앱은 100% 자바로 이루어져있으며 XML 파일을 다루는 수고를 할 필요가 없다.


실행 가능한 JAR 파일 만들기

cmd 에서 Gradle 이나 Maven 을 사용해 앱을 실행할 수도 있지만, JAR 파일을 만들 수도 있다. 이 파일에는 꼭 필요한 클래스, 리소스, 디펜던시가 모두 포함되어 있다. jar 파일을 만들면 개발 환경이나 버전에 상관없이 앱을 실행할 수 있다.

  • Gradle 을 사용한다면, ./gradlew bootRun 으로 앱을 실행한다. ./gradlew build 을 실행하면 jar 파일을 빌드할 수 있으며 다음과 같이 jar 을 실행할 수 있다.

java -jar build/libs/gs-rest-service-0.1.0.jar

  • Maven 을 사용한다면, ./mvnw spring-boot:run 으로 앱을 실행한다. ./mvnw clean package 로 jar 파일을 만들 수 있다.

java -jar target/gs-rest-service-0.1.0.jar


서비스 테스트하기

http://localhost:8080/greeting 에 들어가면

{"id":1,"content":"Hello, World!"} 가 보일 것이다.

새로고침을 할 수록 id 값이 증가한다.

http://localhost:8080/greeting?name=User 를 들어가면, World 대신 주어진 User 가 표시된다.