- I. 스프링 부트 프로젝트 생성
- II. 엔티티 구현
- III. 레파지토리 구현
- IV. REST API 구현
- IV. ApplicationRunner 클랙스 추가
- IV. REST API 확인
스프링 부트 (Spring boot) 기반으로 JPA, Lombok을 사용하여 H2 데이타베이스에 임시 데이타를 기록한뒤 REST API 에서 이를 읽고 리턴하는 웹서비스를 구현해 본다.
I. 스프링 부트 프로젝트 생성
스프링 부트 프로젝트를 생성하는것은 이전 글 스프링 부트 (Spring boot) 소개 를 참고할 수 있다. 이번 프로젝트 생성시에는 “Lombok”, “Web”, “JPA”, “H2” 4가지 모듈을 넣어서 생성하도록 한다.
각 스프링 부트 모듈들의 기능은 다음과 같다.
1. Lombok
- 자바 모델 클래스 작성시에 Lombok을 사용하면 Constructor, Getter/Setter, toString 등을 컴파일시에 자동으로 생성이된다.
- Constructor 의 경우, 파라메터가 없는 경우와 파라메터를 모두 받는 경우 2가지를 생성이된다.
- @EqualsAndHashCode 어노테이션을 사용하면 equals, hashCode 메소드가 생성이된다.
- @Log 어노테이션을 사용하면 log 필드가 생성이된다.
- @Cleanup 어노테이션을 사용하면 해당 자원이 자동으로 닫히게 (close 메소드 호출) 된다.
2. Web
- 스프링 부트 어플리케이션 실행시에 내부적으로 Tomcat, Netty, Undertow 웹어플리케이션서버(WAS)를 포함해서(embed) 실행이 된다.
- Web 모듈을 사용하면 REST API 를 쉽게 구현 할 수 있다.
3. JPA
- JPA(Java Persistence API) 는 자바 응용프로그램에서 관계형 데이터베이스의 관리를 표현하는 자바 API이다.
- 자바 모델 클래스에 @Entity 어노테이션을 달면 DB테이블 엔티티로 맵핑되고, 자바 레파지토리 인터페이스에 @Repository 어노테이션을 달면 DB테이블 CRUD 명령을 자동으로 생성해준다.
4. H2
- 인메모리(In-memory) 데이타베이스로서 스프링 부트 어플리케이션이 실행시에 내부적으로 포함되어 자동으로 실행된다.
- 스프링 부트 내부에 포함되어 자동 실행되므로, 따로 데이타베이스 연결 설정이 필요없다.
- 인메모리 데이타베이스이기 때문에 모든 데이타는 휘발성이다. 서버의 임시데이타(테스트용 데이타베이스, REST API 결과데이타 캐쉬, 사용자 로그인 세션 값)를 저장하는데 용이하다.
이번 프로젝트 생성에도 IntelliJ 를 사용해서 프로젝트를 생성해 보았다.
Eclipse(Spring Tool 4) 를 사용한다면 File -> New -> Spring Starter Project 를 클릭하 된다.
II. 엔티티 구현
1. 엔티티 클래스 생성
- 프로젝트내의 /src/main 아래에 “model” 패케지(디렉토리)를 만들고, “Product” 클래스를 생성한다.
2. 속성 추가
- Product 클래스에 아래와 같은 속성을 추가해준다.
public class Product { int id; // ID String title; // 제품이름 double price; // 제품가격 int inventory; // 재고수량 }
3. Lombok 어노테이션 추가
- 이 클래스에 Getter/Setter 생성을 위해 Lombok 어노테이션 @Data를 달아준다.
- 이 클래스에 모든 파라메터를 다 받아들이는 생성자가 필요하므로 Lombok 어노테이션 @AllArgsConstructor를 달아준다.
- 이 클래스에 빈 파라메터 생성자가 필요하므로 Lombok 어노테이션 @NoArgsConstructor를 달아준다.
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Product {
int id; // ID
String title; // 제품이름
double price; // 제품가격
int inventory; // 재고수량
}
4. JPA 어노테이션 추가
- 이 클래스는 JPA의 엔티티(Entity) 이기 때문에 , JPA 어노테이션 @Entity를 달아준다.
- 이 클래스의 “id” 속성값의 엔티티의 키(key)가 되므로, JPA 어노테이션 @Id를 달아준다.
@Data
@AllArgsConstructor
@NoArgsConstructor
@Entity
public class Product {
@Id
int id;
String title;
double price;
int inventory;
}
III. 레파지토리 구현
1. 레파지토리 클래스 생성
- 프로젝트내의 /src/main 아래에 “repository” 패케지(디렉토리)를 만들고, “ProductRepository” 인터페이스를 생성한다.
2. JPA 어노테이션 추가
- 이 클래스는 JPA의 레파지토리(Repository) 이기 때문에 , JPA 어노테이션 @Repository 달아준다.
@Repository
public interface ProductRepository {
}
3. JPA 레파토리 상속
-
이 클래스에서 JPA의 레파지토리(Repository) 구현을 위해 JpaRepository 클래스를 상속받는다.
-
이때 제네릭타입 첫번째(T)는 앞에서 생성한 “Product”, 두번째(ID)는 Product의 키 타입 “Integer”를 넣어준다.
(두번째 타입에 원시타입들 “int”, “long” 등을를 넣으면 안되고 랩퍼클래스 “Integer”, “Long” 등을 사용하여야 한다.)
@Repository
public interface ProductRepository extends JpaRepository<Product, Integer> {
}
IV. REST API 구현
1. 컨트롤러 클래스 생성
- 프로젝트내의 /src/main 아래에 “controller” 패케지(디렉토리)를 만들고, “ProductController” 클래스를 생성한다.
2. 레파지토리 속성 추가
- 이 클래스의 속성으로 ProductRepository 을 추가하고, 자동으로 주입(Injection) 받기 위해 스프링 어노테이션 @Autowired 를 추가한다.
(아마도 이 부분에서 경고가 뜰 수 있는데, 여기서는 예제 목적으로 코드를 작성하는것이므로 그냥 넘어가도록 한다.)
public class ProductController {
@Autowired
private ProductRepository productRepository;
}
3. REST API 함수 추가
- 이 클래스는 REST API 를 제공하는 컨트롤이기 때문에 스프링 어노테이션 @RestController 를 추가한다.
@RestController
public class ProductController {
@Autowired
private ProductRepository productRepository;
}
4. /product 요청핸들러 추가
- “/product” 경로의 요청을 처리하기 위해 “getProducts” 메소드를 추가하고 스프링 어노테이션 @RequestMapping 을 추가한다.
- “getProcuts” 메소드안에 “ProductRepository.findAll” 을 호출하는 코드를 넣어준다.
@RestController
public class ProductController {
@Autowired
private ProductRepository productRepository;
@RequestMapping("/product")
public List<Product> getProducts() {
return productRepository.findAll();
}
}
- “/product/{id}” 경로의 요청을 처리하기 위해 “getProductById” 메소드를 추가하고 스프링 어노테이션 @RequestMapping 을 추가한다.
- “getProcutById” 메소드안에 “ProductRepository.findById” 를 호출하는 코드를 넣어준다.
- 여기서 id는 경로변수(Path variable)이 되므로 어노테이션 @PathVariable 를 달아준자.
@RestController
public class ProductController {
@Autowired
private ProductRepository productRepository;
@RequestMapping("/product")
public List<Product> getProducts() {
return productRepository.findAll();
}
@RequestMapping("/product/{id}")
public Product getProductById(@PathVariable("id") int id) {
return productRepository.findById(id).get();
}
}
IV. ApplicationRunner 클랙스 추가
본 스프링 부트 어플리케이션 실행시에 H2 데이타베이스가 같이 실행이 된다.
그런데 이 데이타베이스에는 샘플 데이타가 없기 때문에 스프링 부트 어플리케이션 실행시에 샘플 데이타를 넣어주기로 한다.
ApplicationRunner 객체를 생성해 놓으면 스프링 부트 어플리케이션 실행시에 자동으로 이 객체의 run() 메소드가 실행이된다.
이 프로젝트를 테스트 목적으로 만드는것이므로, 메인 클래스(Sbtest03Application.java)에 정적 클래스를 추가하기로 한다.
1. 레파지토리 속성 추가
- 메인 클래스(프로젝트 시작시 존재했던 main() 함수를 가지고 있는 클래스)를 연다.
- 이 클래스의 속성으로 ProductRepository 을 추가하고, 자동으로 주입(Injection) 받기 위해 스프링 어노테이션 @Autowired 를 추가한다.
(아마도 이 부분에서 경고가 뜰 수 있는데, 여기서는 예제 목적으로 코드를 작성하는것이므로 그냥 넘어가도록 한다.)
@SpringBootApplication
public class Sbtest03Application {
@Autowired
private ProductRepository productRepository;
public static void main(String[] args) {
SpringApplication.run(Sbtest99Application.class, args);
}
}
2. ApplicationRunner 클래스 추가
- ApplicationRunner 빈(Bean)을 생성해주는 applicationRunner 메소드를 만든다.
- 스프링 부트 어플리케이션 실행시에 자동으로 이 객체의 run() 메소드가 실행이된다.
- 이 메소드는 Bean 을 생성해야 인식해야하므로 스프링 어노테이션 @Bean 을 달아준다.
@SpringBootApplication
public class Sbtest03Application {
@Autowired
private ProductRepository productRepository;
@Bean
public ApplicationRunner applicationRunner() {
return new ApplicationRunner() {
};
}
public static void main(String[] args) {
SpringApplication.run(Sbtest99Application.class, args);
}
}
3. ApplicationRunner 클래스에서 run() 메소드를 구현한다.
- 이 클래스에서 상속 받았던 ApplicationRunner 인터페이스에서는 run() 메소드를 구현하여야 하므로 아래와 이를 구현한다.
- run() 메소드 안에서는 Product 객체를 생성하고 ProductRepository.save() 함수를 실행해서 저장하는 코드를 넣어준다.
@SpringBootApplication
public class Sbtest03Application {
@Autowired
private ProductRepository productRepository;
@Bean
public ApplicationRunner appRunner() {
return new ApplicationRunner() {
@Override
public void run(ApplicationArguments args) throws Exception {
productRepository.save(new Product(1, "iPad 4 Mini", 500.01, 2));
productRepository.save(new Product(2, "H&M T-Shirt White", 10.99, 10));
productRepository.save(new Product(3, "Charli XCX - Sucker CD", 19.99, 5));
}
};
}
public static void main(String[] args) {
SpringApplication.run(Sbtest99Application.class, args);
}
}
[람다식(lambda expression)]
여기서 ApplicationRunner 는 추상메소드가 1개인 @FuctionalInterface 이기 때문에 람다식(lambda expression)으로 표현이 가능한다.
람다식은 최근 자바, 자바스크립트에서 많이 사용되고 있으니 숙지하면 도움이 많이 된다.
람다식에 대한 설명은 이 글의 범위를 넘어가므로 나중에 따로 관련 글을 올려보도록 하겠다.
람다식으로 표현한 applicationRunner는 아래와 같다.
// 람다식으로 구현한 applicationRunner
@Bean
public ApplicationRunner applicationRunner() {
return args -> {
productRepository.save(new Product(1, "iPad 4 Mini", 500.01, 2));
productRepository.save(new Product(2, "H&M T-Shirt White", 10.99, 10));
productRepository.save(new Product(3, "Charli XCX - Sucker CD", 19.99, 5));
};
}
IV. REST API 확인
1. 프로젝트 실행
- 터미널 환경에서는 프로젝트 디렉토리에서 “mvn install” 실행 후에 “java -jar target/sbtest03-0.0.1-SNAPSHOT.jar”을 실행한다.
- Eclipse 와 IntelliJ에서는 Run -> Run 메뉴를 클릭하면 된다.
- 자세한것은 이전 글 스프링 부트 (Spring boot) 소개 를 참고하도록 한다.
2. /product 호출
-
웹브라우져에서 아래 링크로 접속한다. http://localhost:8080/product
-
위의 ApplicationRunner 에서 저장했던 3개의 Product 들이 JSON 결과로 리턴된다.
3. /product/{id} 호출
-
웹브라우져에서 아래 링크로 접속한다. http://localhost:8080/product/2
-
위의 ApplicationRunner 에서 저장했던 id가 2인 Product 가 JSON 결과로 리턴된다.
본 예제 결과물 sbtest03.zip 소스파일은 아래 링크에서 다운받을 수 있다.
sbtest03.zip 소스파일
아래의 동영상은 본 예제 프로젝트의 시작부터 빌드, 실행 까지의 모든 과정을 담아보았다.