스프링프레임워크 :: 3.스프링부트 웹프로그래밍 Part1
스프링 부트(Spring Boot)
스프링 부트는 상용수준의 스프링프레임워크 기반 어플리케이션을 손쉽게 만들어주는 Spring project 중의 하나 입니다. 기본적으로 스프링 프레임워크에 대한 이해를 필요로 하지만 스프링에 대한 전문적인 지식이 없어도 특정 목적(MVC 기반 웹어플리케이션이나 Restful web service 혹은 JPA 기반 DB서비스 개발등)의 개발 환경과 프로젝트 구조를 자동으로 생성해 주고 바로 사용할 수 있도록 도와줍니다. Tomcat, Jetty 와 같은 WAS 도 내장하고 있으며 별도의 웹서버 실행없이 스프링 부트 어플리케이션을 실행하는 것으로 웹 어플리케이션의 구동이 가능합니다.
시작하기
스프링 부트를 사용하기 위해서는 최소한의 스프링 프레임워크에 대한 개념이해가 필요합니다. 최소한의 개념 정리를 위해 다음 항목들을 살펴보기를 권합니다.
- DI(Dependency Injection)
- AOP(Aspect Oriented Programming)
- Spring 주요 구성 요소
- Spring Annotation
스프링프레임워크 개발환경을 갖추기 위해서는 Eclipse, IntelliJ 등의 개발 도구가 필요 합니다. 풍부한 기능과 안정성을 갖춘 제품은 단연 IntelliJ 입니다. 다만 완전한 스프링기반 개발을 지원하는 Ultimate 버전의 경우 상용 이므로 여기서는 Eclipse 기반으로 스프링에서 제작한 STS(Spring Tool Suite)을 기본 환경으로 사용합니다. 대학생의 경우 학교 이메일 계정을 통해 인증받을 경우 IntelliJ Ultimate 버전을 무료로 사용할 수 있습니다.
STS는 https://spring.io/tools3/sts/all 에서 다운로드 할 수 있습니다.
본 강좌는 다음과 같이 두개의 파트로 구성 되어 있습니다.
Part-1
- Spring Boot 프로젝트 생성
- RestController 구현
Part-2
- MVC Controller 구현
- Thymeleaf 뷰 페이지 구현
Spring Boot 프로젝트 생성
File -> New -> Spring Starter Project
를 선택해 스프링 부트 프로젝트를 시작합니다. Spring Initializr 라고 하는 스프링 부트 프로젝트 생성기를 통해 필요한 모듈들로 구성된 스프링 부트 프로젝트를 생성할 수 있습니다. https://start.spring.io 에서도 동일한 작업을 수행할 수 있습니다.
예제 구성에 필요한 정보는 기본값들을 사용할 것이고 빌드 도구로는 Maven
과 Gradle
중 선택해서 사용 할 수 있습니다. 여기서는 Maven
을 사용 합니다.
다음은 스프링 부트 프로젝트를 구성하는 구성요소를 선택하는 화면 입니다. 검색창에서 필요한 모듈을 검색하거나 목록에서 선택하면 됩니다. 여기서는 web과 thymeleaf 를 추가 합니다. 추가로 필요한 모듈들은 추후 pom.xml 에 추가해도 됩니다.
다음 화면에서 Finish
를 누르면 자동으로 프로젝트를 생성하고 필요한 라이브러리들을 다운로드 합니다. 조금 시간이 소요될 수 있습니다.
기본적인 프로젝트 구성은 다음과 같습니다.
- src/main/java : 자바 소스 폴더 입니다.
- src/main/resources : 스프링 환경설정 파일, html, css, javascript, 이미지, Thymeleaf 템플릿 파일 등이 위치 합니다.
- src/test/java : 테스트코드가 위치하는 폴더 입니다.
기본 RestController 구현
Rest API 서비스를 제공하기 위한 컨트롤러 클래스를 생성 합니다. 스프링의 RestController 를 이용 할 수도 있고 자바의 JAX-RS 표준을 이용 할 수도 있습니다. JAX-RS를 이용하려면 프로젝트 생성때 JAX-RS 를 추가로 선택해 주어야 합니다.
DemoRestController 클래스 생성
DemoRestController 라는 이름으로 새로운 클래스를 하나 생성 합니다. 특정 인터페이스나 클래스를 상속 받지 않는 일반 자바 클래스 입니다. 클래스 생성후 클래스 선언부 위에 다음과 같이 애너테이션을 추가 합니다.
@RestController
@RequestMapping("/api")
public class DemoRestController {
- @RestController : 현재 클래스가 REST 컨트롤러로 동작하도록 지정.
- @RequestMapping : 현재 클래스로 동작하는 컨트롤러의 엔드포인트(end point)로 컨트롤러 클래스가 제공하는 서비스의 진입점.
- 여기서는
http://localhost:8080/api
로 시작하는 URL 요청들이 처리 될 클래스임을 지정하고 있음.
컨트롤러 메서드 구현
제공하기 원하는 기능을 메서드 단위로 지정해서 구현 하면 됩니다. 각각의 메서드는 HTTP 메서드 중 어떤 메서드 요청을 받아들일지 명시해 주어야 합니다. 대표적인 메서드는 다음과 같습니다.
GET
POST
PUT
DELETE
먼저 다음과 같이 GET 요청을 처리하기 위한 메서드를 하나 구현해 봅니다.
@GetMapping("/hello")
public String hello(@RequestParam(value="msg", required=false) String msg) {
return msg;
}
- URI 는
/api/hello
로 동작하게 되며 GET 요청에만 동작. - GET 방식의 경우 HTTP 요청에는 URL 에 파라미터 형식으로 데이터를 전송하는 방법이 사용됨.
- POST의 경우 HTTP Body 에 데이터를 전송하는 형식을 취하게 됨. 이 경우에는 @RequestBody 애너테이션이 사용되며 매핑될 자바 객체를 지정해 주어야 함.
required=false
를 명시하지 않으면 파라미터가 누락되는 경우 에러가 발생.- 여기서는 파라미터로 전달된 msg 값을 문자열 형태로 리턴 합니다.
실행 및 테스트
우선 여기까지 구현된 결과를 테스트해 보도록 합니다. REST 테스트를 위해서는 curl
이나 postman
등의 테스트 도구를 사용하는 것이 좋습니다만 GET 방식만 테스트 하는 경우라면 그냥 브라우저에서 URL을 입력해도 테스트할 수 있습니다.
먼저 스프링 부트 앱을 실행하기 위해 DemoApplication 을 선택하고 오른쪽 마우스를 눌러 Run as Spring Boot App
을 선택 합니다. 스프링 부트가 구동되면서 내장된 톰캣이 함께 동작하게 됩니다. 기본 포트는 8080 이며 브라우저에서 다음과 같이 URL을 입력해 봅니다.
http://localhost:8080/api/hello?msg=HelloWorld
RestController 확장
이제 본격적으로 실제 활용 가능한 REST API 서비스를 구현해 봅니다. 구현할 예제는 상품정보를 제공하는 서비스로 다음의 세가지 기능을 제공 합니다. 구현된 모델 구조는 Part-2 에서 Thymeleaf 를 이용한 웹페이지 구현과 연계 됩니다.
- 상품등록: JSON 구조의 상품정보를 POST 방식으로 서버에 등록.
- 전체 상품 조회: 전체 상품목록을 JSON 구조로 제공.
- 특정 상품 조회: 상품의 등록번호(등록된 순서)를 통해 해당 상품만 JSON 구조로 제공.
Product 클래스 구현
엔티티(Entity) 클래스로 상품정보를 표현하는 클래스 입니다. 데이터베이스를 사용한다면 테이블 구조로 매핑 할 수도 있습니다.
package com.example.demo;
public class Product {
private int id;
private String name;
private int price;
public Product() {}
public Product(int id, String name, int price) {
super();
this.id = id;
this.name = name;
this.price = price;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
}
ProductManager 클래스 구현
ProductManager 클래스는 상품정보를 관리하기 위한 클래스로 여기서는 ArrayList 를 사용해 데이터를 관리할 것입니다. 인스턴스 생성시 생성자에서 샘플 데이터를 4개 추가 하도록 구성 했습니다.
package com.example.demo;
import java.util.ArrayList;
import java.util.List;
import org.springframework.stereotype.Component;
@Component
public class ProductManager {
private List<Product> datas = new ArrayList<>();
public ProductManager() {
datas.add(new Product(1,"Apple Phone Xs",1300000));
datas.add(new Product(2,"Galaxy Note 9",1200000));
datas.add(new Product(3,"Google Pixel Phone",1100000));
datas.add(new Product(4,"LG G30",1230000));
}
public void addProduct(Product p) {
p.setId(datas.size()+1);
datas.add(p);
}
public List<Product> getDatas() {
return datas;
}
public void setDatas(List<Product> datas) {
this.datas = datas;
}
}
- ProductManager 클래스는 @Component 애너테이션을 사용해 스프링프레임워크에서 관리할 Bean 객체로 등록.
- 이 경우 ProductManager 클래스는 자동으로 초기화 되어 스프링 컨테이너에서 관리 되며 프로젝트의 다른 클래스에서 언제든 해당 객체를 사용할 수 있음.
- addProduct() 에서는 ArrayList 의 크기를 구해 다음에 들어갈 데이터의 id 값을 구해서 적용.
DemoController 클래스 업그레이드
앞에서 만들었던 DemoController 클래스를 상품정보를 처리할 수 있도록 업그레이드 합니다.
@Autowired
ProductManager pm;
- 먼저 상품정보를 가지고 있는 ProductManager 클래스의 인스턴스를 @Autowired 를 통해 가지고 온다.
- @Autowired 는 스프링의 특징중 하나인 DI 의 사용 형태중 하나로 필요한 객체를 직접 생성하지 않고 스프링컨테이너를 통해 주입해 사용.
다음으로 상품 목록을 제공하기 위한 getAll()
메서드를 작성 합니다. URI 는 /api/product
가 됩니다.
@GetMapping("/product")
public List<Product> getAll() {
return pm.getDatas();
}
- pm 으로 ProductManager 객체가 참조 되었기 때문에 getDatas() 메서드를 통해 List
를 리턴 하기만 하면 된다. - 이때 스프링의 RestController 는 리턴타입이 객체형인경우 자동으로 JSON 으로 변환.
- 따라서 리턴된 결과는 JSON 구조로 전달된다. 상품의 목록 이므로 Array 형태가 됨.
다음은 특정 상품을 가지고 오기 위한 getProduct()
메서드 입니다. getProduct()
는 파라미터로 번호를 받아 오고 해당 번호의 위치에 해당하는 상품을 리턴 합니다. 이때 파라미터는 Request Parameter
가 아닌 Path Variable
를 사용 합니다. 물론 Request Parameter 를 사용할 수 있으나 REST API 설계 원칙상 Path Variable
를 사용하는 것이 좋습니다. 예를 들어 1번 상품을 원한다고 하면 /api/product/1
과 같이 요청하면 됩니다.
@GetMapping("/product/{id}")
public Product getProduct(@PathVariable int id) {
return pm.getDatas().get(id-1);
}
- ArrayList 의 구조상
0
부터 인덱스가 시작되기 때문에 상품번호와 일치 시키기 위해id-1
을 해줌. - 샘플 데이터는 1~4 로 등록 했으며 ProductManager 의 addProduct() 메서드 에서는 List 의 크기를 구해 다음 id 번호를 자동으로 부여 하도록 되어 있음.
실행 및 테스트
이제 등록을 제외한 나머지 기능의 구현이 모두 마무리 되었습니다. 등록의 경우 POST 요청을 해야 하므로 우선 브라우저에서 테스트할 수 있는 내용들을 먼저 실행해 확인한 다음 구현해 보도록 합니다. 변경된 내용을 반영하기 위해서는 스프링 부트를 다시 실행 해야 합니다. 만일 스프링 부트 앱이 실행된 상태에서 변경된 사항을 자동으로 반영하게 하려면 pom.xml
과 resources/application.properties
파일에 다음과 같이 추가해 둡니다.
# pom.xml에 추가
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
# application.properties에 추가
spring.devtools.livereload.enabled=true
다음과 같이 URL을 입력해 결과를 확인 합니다.
http://localhost:8080/api/product
http://localhost:8080/api/product/2
POST 요청 구현
Part-1 의 마지막으로 DemoController 에 POST 요청 처리를 구현해 봅니다. 상품 등록을 위해 컨트롤러에 메서드를 추가 하고 postman 을 설치해 REST API 테스트 환경을 구축 합니다.
DemoRestController 클래스 수정
상품등록을 위한 메서드는 addProduct()
로 Product 객체를 인자로 받는다.
@PostMapping("/product")
public String addProduct(@RequestBody Product p) {
pm.addProduct(p);
return "product added!!";
}
- URI 는 상품목록을 가지고 오는 경우와 동일 하지만
@PostMapping
애너테이션인 점이 다르다. @RequestBody
는 POST 요청시 전달되는 HTTP Body 의 내용으로 JSON 형태로 전달되어야 하며 Product 클래스와 매핑된다.
postman 설치 및 테스트
postman은 대표적인 REST API 테스트 클라이언트 프로그램 입니다. 웹, PC, MAC 등 모든 플랫폼에서 사용할 수 있으며 클라우드 기반 동기화도 지원하기 때문에 여러 디바이스 에서 동일한 테스트 환경을 유지 하기 좋습니다. postman 홈페이지 에서 계정을 생성하고 다운로드 합니다.
실행 후 다음 그림과 같이 새로운 탭을 열어 POST 요청을 작성 합니다.
- HTTP Method 는
POST
로 지정. - URL 은
http://localhost:8080/api/product
- Headers 섹션에
Content-Type
을applicaton/json
으로 지정.
Body 섹션에는 다음과 같이 추가할 데이터를 JSON으로 작성 합니다. 이때 id 필드는 상품 등록시 자동으로 추가되므로 넣지 않습니다.
{
"name":"Samsung OLED TV",
"price":3500000
}
다음은 postman 에서의 작성 화면 입니다.
스프링 부트 앱을 실행하고 postman 에 등록된 url 을 SEND
버튼을 눌러 실행 합니다. 실행결과 문자열로 product added!!
를 볼 수 있으며 등록된 내용은 웹브라우저에서 확인하거나 postman 에서 GET 요청을 생성해 확인할 수 있습니다.