1. 개요

Ratpack 은 최신 고성능 실시간 애플리케이션용으로 구축된 JVM 기반 라이브러리 세트입니다 . 임베디드 Netty 이벤트 기반 네트워킹 엔진 위에 구축되었으며 반응형 디자인 패턴을 완벽하게 준수합니다.

이 기사에서는 Ratpack을 사용하는 방법을 배우고 이를 사용하여 작은 애플리케이션을 빌드할 것입니다.

2. 왜 랫팩인가?

Ratpack의 주요 장점:

  • 매우 가볍고 빠르고 확장 가능합니다.
  • DropWizard와 같은 다른 프레임워크보다 적은 메모리를 사용합니다. 흥미로운 벤치마크 비교 결과는 여기 에서 찾을 수 있습니다.
  • Netty 위에 구축되었기 때문에 Ratpack은 본질적으로 완전히 이벤트 중심이며 차단되지 않습니다.
  • Guice 의존성 관리 를 지원합니다.
  • Spring Boot 와 마찬가지로 Ratpack에는 테스트 케이스를 빠르게 설정하기 위한 자체 테스트 라이브러리가 있습니다.

3. 애플리케이션 생성

Ratpack의 작동 방식을 이해하기 위해 먼저 Ratpack을 사용하여 작은 애플리케이션을 만들어 보겠습니다.

3.1. 메이븐 의존성

먼저 pom.xml 에 다음 의존성을 추가해 보겠습니다.

<dependency>
    <groupId>io.ratpack</groupId>
    <artifactId>ratpack-core</artifactId>
    <version>1.4.5</version>
</dependency>
<dependency>
    <groupId>io.ratpack</groupId>
    <artifactId>ratpack-test</artifactId>
    <version>1.4.5</version>
</dependency>

Maven Central 에서 최신 버전을 확인할 수 있습니다 .

Ratpack 권장 사항 에 따라 빌드 시스템으로 Maven을 사용하고 있지만 Ratpack에는 Ratpack의 Gradle 플러그인 을 통해 제공되는 일류 Gradle 지원이 있으므로 Gradle 을 빌드 도구로 사용하는 것이 좋습니다 .

다음 빌드 Gradle 스크립트를 사용할 수 있습니다.

buildscript {
    repositories {
      jcenter()
    }
    dependencies {
      classpath "io.ratpack:ratpack-gradle:1.4.5"
    }
}
 
apply plugin: "io.ratpack.ratpack-java"
repositories {
    jcenter()
}
dependencies {
    testCompile 'junit:junit:4.11'
    runtime "org.slf4j:slf4j-simple:1.7.21"
}
test {
    testLogging {
      events 'started', 'passed'
    }
}

3.2. 애플리케이션 구축

빌드 관리가 구성되면 포함된 Netty 서버를 시작하고 기본 요청을 처리하기 위한 간단한 컨텍스트를 빌드하기 위한 클래스를 생성해야 합니다.

public class Application {
	
    public static void main(String[] args) throws Exception {
        RatpackServer.start(server -> server.handlers(chain -> chain
          .get(ctx -> ctx.render("Welcome to Baeldung ratpack!!!"))));
    }
}

보시다시피 RatpackServer 를 사용하여 이제 서버를 시작할 수 있습니다(기본 포트 5050). handlers() 메서드 는 모든 들어오는 요청을 매핑하는 Chain 개체 를 받는 함수를 사용 합니다. 이 "Handler Chain API"는 응답 처리 전략을 구축하는 데 사용됩니다.

이 코드 조각을 실행하고 http://localhost:5050에서 브라우저를 누르면 "Welcome to Baeldung ratpack!!!" 표시되어야 합니다.

마찬가지로 HTTP POST 요청을 매핑할 수 있습니다.

3.3. URL 경로 매개변수 처리

다음 예에서는 애플리케이션에서 일부 URL 경로 매개변수를 캡처해야 합니다. Ratpack에서는 PathToken을 사용 하여 캡처합니다.

RatpackServer.start(server -> server
  .handlers(chain -> chain
  .get(":name", ctx -> ctx.render("Hello " 
  + ctx.getPathTokens().get("name") + " !!!"))));

여기서 이름 URL 매개변수를 매핑합니다. http://localhost:5050/John 과 같은 요청 이 올 때마다 응답은 "Hello John !!!"입니다.

3.4. 필터를 사용하거나 사용하지 않고 요청/응답 헤더 수정

경우에 따라 필요에 따라 인라인 HTTP 응답 헤더를 수정해야 합니다. Ratpack에는 나가는 응답을 사용자 지정하기 위한 MutableHeaders 가 있습니다.

예를 들어 응답에서 Access-Control-Allow-Origin , Accept-LanguageAccept-Charset 헤더를 변경해야 합니다 .

RatpackServer.start(server -> server.handlers(chain -> chain.all(ctx -> {
    MutableHeaders headers = ctx.getResponse().getHeaders();
    headers.set("Access-Control-Allow-Origin", "*");
    headers.set("Accept-Language", "en-us");
    headers.set("Accept-Charset", "UTF-8");
    ctx.next();
}).get(":name", ctx -> ctx
    .render("Hello " + ctx.getPathTokens().get("name") + "!!!"))));

우리가 설정한 MutableHeaders 를 사용 하여 세 개의 헤더를 설정하고 이를 Chain 에 푸시합니다 .

같은 방식으로 들어오는 요청 헤더도 확인할 수 있습니다.

ctx.getRequest().getHeaders().get("//TODO")

필터를 생성하여 동일한 작업을 수행할 수 있습니다. Ratpack에는 필터를 생성하기 위해 구현할 수 있는 핸들러 인터페이스 가 있습니다. 여기에는 현재 컨텍스트 를 매개변수로 사용하는 handle() 메서드가 하나만 있습니다.

public class RequestValidatorFilter implements Handler {

    @Override
    public void handle(Context ctx) throws Exception {
        MutableHeaders headers = ctx.getResponse().getHeaders();
        headers.set("Access-Control-Allow-Origin", "*");
        ctx.next();
    }
}

이 필터는 다음과 같은 방식으로 사용할 수 있습니다.

RatpackServer.start(
    server -> server.handlers(chain -> chain
      .all(new RequestValidatorFilter())
      .get(ctx -> ctx.render("Welcome to baeldung ratpack!!!"))));
}

3.5. JSON 파서

Ratpack 은 JSON 구문 분석을 위해 내부적으로 빠른 잭슨 을 사용합니다. Jackson 모듈을 사용 하여 모든 객체를 JSON으로 구문 분석할 수 있습니다.

구문 분석에 사용할 간단한 POJO 클래스를 만들어 보겠습니다.

public class Employee {

    private Long id;
    private String title;
    private String name;

    // getters and setters 

}

여기에서 Employee 라는 이름의 간단한 POJO 클래스를 만들었습니다. 여기 에는 id, titlename 의 세 가지 매개 변수가 있습니다. 이제 이 Employee 객체를 사용하여 JSON으로 변환하고 특정 URL에 도달했을 때 동일한 결과를 반환합니다.

List<Employee> employees = new ArrayList<Employee>();
employees.add(new Employee(1L, "Mr", "John Doe"));
employees.add(new Employee(2L, "Mr", "White Snow"));

RatpackServer.start(
    server -> server.handlers(chain -> chain
      .get("data/employees",
      ctx -> ctx.render(Jackson.json(employees)))));

보시다시피 List에 두 개의 Employee 객체를 수동으로 추가하고 Jackson 모듈 을 사용하여 JSON으로 구문 분석합니다 . /data/employees URL에 도달 하는 즉시 JSON 개체가 반환됩니다.

여기서 주목할 점은 Ratpack의 Jackson 모듈이 필요한 작업을 즉석에서 수행하기 때문에 ObjectMapper전혀 사용하지 않는다는 것입니다.

3.6. 인메모리 데이터베이스

Ratpack은 메모리 내 데이터베이스에 대한 최고 수준의 지원을 제공합니다. JDBC 연결 풀링에 HikariCP 를 사용합니다 . 이를 사용 하려면 pom.xml 에 Ratpack의 HikariCP 모듈 의존성 을 추가해야 합니다 .

<dependency>
    <groupId>io.ratpack</groupId>
    <artifactId>ratpack-hikari</artifactId>
    <version>1.4.5</version>
</dependency>

Gradle 을 사용 하는 경우 Gradle 빌드 파일에 동일한 항목을 추가해야 합니다.

compile ratpack.dependency('hikari')

이제 서버가 시작되고 실행되는 즉시 테이블이 생성되도록 테이블 DDL 문이 포함된 SQL 파일을 생성해야 합니다. src/main/resources 디렉토리에 DDL.sql 파일을 생성하고 여기 에 몇 가지 DDL 문을 추가합니다.

H2 데이터베이스를 사용하고 있으므로 이에 대한 의존성도 추가해야 합니다.

이제 HikariModule을 사용하여 런타임에 데이터베이스를 초기화할 수 있습니다.

RatpackServer.start(
    server -> server.registry(Guice.registry(bindings -> 
      bindings.module(HikariModule.class, config -> {
          config.setDataSourceClassName("org.h2.jdbcx.JdbcDataSource");
          config.addDataSourceProperty("URL",
          "jdbc:h2:mem:baeldung;INIT=RUNSCRIPT FROM 'classpath:/DDL.sql'");
      }))).handlers(...));

4. 테스트

앞서 언급한 바와 같이 Ratpack은 jUnit 테스트 케이스에 대한 최고 수준의 지원을 제공합니다. MainClassApplicationUnderTest 를 사용하여 쉽게 테스트 사례를 만들고 Endpoints을 테스트할 수 있습니다.

@RunWith(JUnit4.class)
public class ApplicationTest {

    MainClassApplicationUnderTest appUnderTest
      = new MainClassApplicationUnderTest(Application.class);

    @Test
    public void givenDefaultUrl_getStaticText() {
        assertEquals("Welcome to baeldung ratpack!!!", 
          appUnderTest.getHttpClient().getText("/"));
    }

    @Test
    public void givenDynamicUrl_getDynamicText() {
        assertEquals("Hello dummybot!!!", 
          appUnderTest.getHttpClient().getText("/dummybot"));
    }

    @Test
    public void givenUrl_getListOfEmployee() 
      throws JsonProcessingException {
 
        List<Employee> employees = new ArrayList<Employee>();
        ObjectMapper mapper = new ObjectMapper();
        employees.add(new Employee(1L, "Mr", "John Doe"));
        employees.add(new Employee(2L, "Mr", "White Snow"));

        assertEquals(mapper.writeValueAsString(employees), 
          appUnderTest.getHttpClient().getText("/data/employees"));
    }
 
    @After
    public void shutdown() {
        appUnderTest.close();
    }

}

JVM 리소스를 불필요하게 차단할 수 있으므로 close() 메서드를 호출하여 실행 중인 MainClassApplicationUnderTest 인스턴스 를 수동으로 종료해야 합니다. 그래서 테스트 케이스가 실행되면 인스턴스를 강제로 종료하기 위해 @After 어노테이션을 사용했습니다.

5. 결론

이 기사에서 우리는 Ratpack 사용의 단순성을 보았습니다.

항상 그렇듯이 전체 소스 코드는 GitHub에서 사용할 수 있습니다 .

res – REST with Spring (eBook) (everywhere)