1. 개요

요즘에는 웹 애플리케이션 개발에 사용할 수 있는 Spring , PlayGrails 와 같은 많은 JEE 기반 프레임워크가 있습니다.

우리는 그들 중 하나를 다른 것보다 선택해야 할 이유가 있을 수 있습니다. 그러나 선택은 사용 사례와 해결하려는 문제에 따라 달라집니다.

이 소개 사용방법(예제)에서는 Ninja 웹 프레임워크를 살펴보고 간단한 웹 애플리케이션을 만듭니다. 동시에 제공되는 몇 가지 기본 기능을 살펴보겠습니다.

2. 닌자

Ninja 는 기존 Java 라이브러리를 활용하여 작업을 수행하는 전체 스택이지만 가벼운 웹 프레임워크입니다.

HTML에서 JSON 렌더링, 지속성, 테스트에 이르는 기능을 갖추고 있어 확장 가능한 웹 애플리케이션을 구축하기 위한 원스톱 솔루션입니다.

구성에 대한 규칙을 따르고  모델 , 컨트롤러서비스 와 같은 패키지의 코드를 분류합니다 .

Ninja는 JSON/XML 렌더링을 위한 Jackson , 의존성 관리를 위한 Guice , 지속성을 위한 Hibernate , 데이터베이스 마이그레이션을 위한 Flyway 와 같은 주요 기능에 인기 있는 Java 라이브러리를 사용합니다 .

신속한 개발 을 위해 코드의 핫 리로딩을 위한 SuperDevMode 를 제공합니다. 따라서 개발 환경에서 변경 사항을 즉시 확인할 수 있습니다.

3. 설정

Ninja는 웹 애플리케이션을 생성하기 위해 표준 도구 세트가 필요합니다.

  • 자바 1.8 이상
  • 메이븐 3 이상
  • IDE(Eclipse 또는 IntelliJ)

Maven 원형 을 사용 하여 Ninja 프로젝트를 빠르게 설정합니다. 그룹 ID, 아티팩트 ID 및 버전 번호와 프로젝트 이름을 제공하라는 메시지가 표시됩니다.

mvn archetype:generate -DarchetypeGroupId=org.ninjaframework \
  -DarchetypeArtifactId=ninja-servlet-archetype-simple

또는 기존 Maven 프로젝트의 경우 최신 ninja-core 의존성을 pom.xml 에 추가할 수 있습니다 .

<dependency>
    <groupId>org.ninjaframework</groupId>
    <artifactId>ninja-core</artifactId>
    <version>6.5.0</version>
</dependency>

그런 다음 Maven 명령을 실행하여 처음으로 파일을 컴파일합니다.

mvn clean install

마지막으로 Ninja에서 제공하는 Maven 명령을 사용하여 앱을 실행해 보겠습니다.

mvn ninja:run

짜잔! 애플리케이션이 시작되고 localhost:8080 에서 액세스할 수 있습니다 .
홈 스케일링 1

4. 프로젝트 구조

Ninja가 만든 Maven과 유사한 프로젝트 구조를 살펴보겠습니다.

이클립스 프로젝트 구조-1프레임워크는 규칙에 따라 몇 가지 패키지를 만듭니다.

Java 클래스는 src/main/java 의 conf , controllers , modelsservices 디렉토리 아래에 분류됩니다.

마찬가지로  src/test/java 에는 해당 단위 테스트 클래스가 있습니다.

src/main/java 아래 의 보기 디렉토리 에는 HTML 파일이 포함되어 있습니다. 그리고 src/main/java/assets 디렉토리에는 이미지, 스타일시트 및 JavaScript 파일과 같은 리소스가 포함되어 있습니다.

5. 컨트롤러

이제 프레임워크의 몇 가지 기본 기능에 대해 논의할 준비가 되었습니다. 컨트롤러는 요청을 수신하고 특정 결과와 함께 응답을 반환하는 클래스입니다.

먼저 따라야 할 몇 가지 규칙에 대해 논의해 보겠습니다.

  • 컨트롤러 패키지 에 클래스를 생성 하고 이름에 Controller 접미사를 붙입니다.
  • 요청을 처리하는 메서드는 Result 클래스 의 개체를 반환해야 합니다.

HTML을 렌더링하는 간단한 메서드를 사용하여 ApplicationController 클래스를 생성해 보겠습니다 .

@Singleton
public class ApplicationController {
    public Result index() {
        return Results.html();
    }
}

여기서 index 메서드는 Results 클래스 의 html 메서드를 호출하여 HTML을 렌더링합니다 . Result 개체 는 응답 코드, 헤더 및 쿠키와 같은 콘텐츠를 렌더링하는 데 필요한 모든 것을 보유합니다.

참고: Guice의 @Singleton 어노테이션은 앱 전체에서 하나의 컨트롤러 인스턴스만 허용합니다 .

6. 보기

index 메서드의 경우 Ninja는 views /ApplicationController 디렉토리 아래에서 index .ftl.html HTML 파일을 찾습니다.

Ninja는 HTML 렌더링을 위해 Freemarker 템플릿 엔진을 사용합니다 . 따라서 보기 아래의 모든 파일은 .ftl.html 확장자 를 가져야 합니다.

index 메서드 에 대한 i ndex .ftl.html 파일생성해 보겠습니다 .

<html>  
<head>
    <title>Ninja: Index</title>
</head>
<body>
    <h1>${i18n("helloMsg")}</h1>
    <a href="/userJson">User Json</a>
</body>
</html>

여기에서는 Ninja가 제공한 i18n 태그를 사용하여 message.properties 파일 에서 helloMsg 속성 을 가져왔습니다. 이에 대해서는 나중에 국제화 섹션에서 자세히 설명하겠습니다.

7. 루트

다음으로 index 메서드 에 도달하기 위한 요청의 경로를 정의합니다 .

Ninja는 conf 패키지의 Routes 클래스를 사용 하여 URL을 컨트롤러의 특정 메서드에 매핑합니다.

ApplicationController 의 인덱스 메서드에 액세스하기 위한 경로를 추가해 보겠습니다 .

public class Routes implements ApplicationRoutes {
    @Override
    public void init(Router router) {          
        router.GET().route("/index").with(ApplicationController::index);
    }
}

그게 다야! localhost:8080/index 에서 인덱스 페이지에 액세스하도록 모두 설정되었습니다 .
인덱스 스케일링 1

8. JSON 렌더링

이미 논의한 바와 같이 Ninja는 JSON 렌더링을 위해 Jackson을 사용합니다. JSON 콘텐츠를 렌더링하기 위해 Results 클래스 의 json 메서드를 사용할 수 있습니다.

ApplicationController 클래스에 userJson 메서드를 추가하고 간단한 HashMap 의 콘텐츠 를 JSON으로 렌더링해 보겠습니다.

public Result userJson() {
    HashMap<String, String> userMap = new HashMap<>();
    userMap.put("name", "Norman Lewis");
    userMap.put("email", "norman@email.com");    
    return Results.json().render(user);
}

그런 다음 userJson 에 액세스하는 데 필요한 라우팅을 추가합니다 .

router.GET().route("/userJson").with(ApplicationController::userJson);

이제 localhost:8080/userJson 을 사용하여 JSON을 렌더링할 수 있습니다 .
userJson 스케일링 1

9. 서비스

비즈니스 로직을 컨트롤러와 별도로 유지하고 필요할 때마다 서비스를 주입하는 서비스를 만들 수 있습니다.

먼저 추상화를 정의하기 위해 간단한 UserService 인터페이스를 생성해 보겠습니다.

public interface UserService {
    HashMap<String, String> getUserMap();
}

그런 다음 UserServiceImpl 클래스에서 UserService 인터페이스를 구현하고 getUserMap 메서드 를 재정의합니다 .

public class UserServiceImpl implements UserService {
    @Override
    public HashMap<String, String> getUserMap() {
        HashMap<String, String> userMap = new HashMap<>(); 
        userMap.put("name", "Norman Lewis"); 
        userMap.put("email", "norman@email.com"); 
        return userMap;
    }
}

그런 다음 Guice에서 제공하는 Ninja의 의존성 주입 기능을 사용하여 UserServiceImpl 클래스와 UserService 인터페이스를 바인딩합니다 .

conf 패키지 에서 사용할 수 있는 Module 클래스 에 바인딩을 추가해 보겠습니다 .

@Singleton
public class Module extends AbstractModule {
    protected void configure() {        
        bind(UserService.class).to(UserServiceImpl.class);
    }
}

마지막으로 @Inject 어노테이션 을 사용하여 ApplicationController 클래스 에 UserService 의존성을 주입합니다.

public class ApplicationController {
    @Inject
    UserService userService;
    
    // ...
}

따라서 우리는 모두 ApplicationController 에서 UserServicegetUserMap 메서드 를 사용하도록 설정되었습니다 .

public Result userJson() {
    HashMap<String, String> userMap = userService.getUserMap();
    return Results.json().render(userMap);
}

10. 플래시 스코프

Ninja는 Flash Scope라는 기능을 통해 요청의 성공 및 오류 메시지를 처리하는 간단하면서도 효율적인 방법을 제공합니다.

컨트롤러에서 사용하기 위해 메서드에 FlashScope 인수를 추가합니다.

public Result showFlashMsg(FlashScope flashScope) {
    flashScope.success("Success message");
    flashScope.error("Error message");
    return Results.redirect("/home");
}

참고: 결과 클래스의 리디렉션 메서드는 대상을 제공된 URL로 리디렉션합니다.

그런 다음 showFlashMsg 메서드 에 라우팅 /flash 를 추가 하고 플래시 메시지를 표시하도록 보기를 수정합니다.

<#if (flash.error)??>
    <div class="alert alert-danger">
        ${flash.error}
    </div>
</#if>
<#if (flash.success)??>
    <div class="alert alert-success">
        ${flash.success}
    </div>
</#if>

이제 localhost:8080/flash 에서 FlashScope 가 작동 하는 것을 볼 수 있습니다 .

플래시 1 스케일 2

11. 국제화

Ninja는 구성하기 쉬운 기본 제공 국제화 기능을 제공합니다.

먼저 application.conf 파일에서 지원되는 언어 List을 정의합니다.

application.languages=fr,en

그런 다음 메시지 에 대한 키-값 쌍을 사용하여 기본 속성 파일( 영어의 경우 messages.properties )을 만듭니다.

header.home=Home!
helloMsg=Hello, welcome to Ninja Framework!

마찬가지로 언어별 속성 파일(예 : 프랑스어 의 경우 message_fr.properties 파일 )의 파일 이름에 언어 코드를 추가할 수 있습니다 .

header.home=Accueil!
helloMsg=Bonjour, bienvenue dans Ninja Framework!

구성이 준비되면 ApplicationController 클래스에서 쉽게 국제화를 활성화할 수 있습니다.

Lang 클래스 또는 Messages 클래스 를 사용하는 두 가지 방법이 있습니다 .

@Singleton
public class ApplicationController {
    @Inject
    Lang lang;

    @Inject
    Messages msg;
    
    // ...
}

그런 다음 Lang 클래스를 사용하여 결과 언어를 설정할 수 있습니다.

Result result = Results.html();
lang.setLanguage("fr", result);

마찬가지로 Messages 클래스를 사용하여 언어별 메시지를 가져올 수 있습니다.

Optional<String> language = Optional.of("fr");        
String helloMsg = msg.get("helloMsg", language).get();

12. 끈기

Ninja는 JPA 2.0을 지원하고 Hibernate를 활용하여 웹 애플리케이션에서 지속성을 활성화합니다. 또한 신속한 개발을 위해 내장된 H2 데이터베이스 지원을 제공합니다.

12.1. 모델

데이터베이스의 테이블과 연결하려면 Entity 클래스가 필요 합니다. 이를 위해 Ninja는 모델 패키지 에서 엔터티 클래스를 찾는 규칙을 따릅니다 . 따라서 거기에 User 엔터티 클래스를 만듭니다.

@Entity
public class User {
    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    Long id;
    public String firstName;
    public String email;  
}

그런 다음 Hibernate를 구성하고 데이터베이스 연결에 대한 세부 정보를 설정합니다.

12.2. 구성

Hibernate 구성의 경우 Ninja는 persistence.xml 파일이 src/main/java/META-INF 디렉토리에 있을 것으로 예상합니다.

<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
  version="2.0">
   
    <!-- Database settings for development -->
    <persistence-unit name="dev_unit"
      transaction-type="RESOURCE_LOCAL">
        <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
        <properties>
            <property name="hibernate.connection.driver_class" value="org.h2.Driver" />
            <property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect" />
            <property name="hibernate.show_sql" value="true" />
            <property name="hibernate.format_sql" value="true" />
            <property name="hibernate.hbm2ddl.auto" value="update" />
            <property name="hibernate.connection.autocommit" value="true" />
        </properties>
    </persistence-unit>
</persistence>

그런 다음 데이터베이스 연결 세부 정보를 application.conf 에 추가합니다 .

ninja.jpa.persistence_unit_name=dev_unit
db.connection.url=jdbc:h2:./devDb
db.connection.username=sa
db.connection.password=

12.3. 엔티티매니저

마지막으로 Guice의 Provider 클래스 를 사용 하여 ApplicationController 에 EntityManager 의 인스턴스를 주입합니다.

public class ApplicationController {
    @Inject 
    Provider<EntityManager> entityManagerProvider;

    // ...
}

이제 EntityManager 를 사용하여 User 개체 를 유지할 준비가 되었습니다 .

@Transactional
public Result insertUser(User user) {
    EntityManager entityManager = entityManagerProvider.get();
    entityManager.persist(user);
    entityManager.flush();
    return Results.redirect("/home");
}

마찬가지로 EntityManager 를 사용 하여 DB에서 User 개체 를 읽을 수 있습니다.

@UnitOfWork
public Result fetchUsers() {
    EntityManager entityManager = entityManagerProvider.get();
    Query q = entityManager.createQuery("SELECT x FROM User x");
    List<User> users = (List<User>) q.getResultList();
    return Results.json().render(users);
}

여기에서 Ninja의 @UnitOfWork 어노테이션은 트랜잭션을 처리하지 않고 데이터베이스 연결에 대한 모든 것을 처리합니다. 따라서 일반적으로 트랜잭션이 필요하지 않은 읽기 전용 쿼리에 유용할 수 있습니다.

13. 검증

Ninja는 JSR303 사양에 따라 Bean 유효성 검사를 기본적으로 지원합니다 .

@NotNull 어노테이션 을 사용하여 User 엔터티 의 속성에 어노테이션을 달아 기능을 살펴보겠습니다 .

public class User {
    // ...
    
    @NotNull
    public String firstName;
}

그런 다음 ApplicationController 에서 이미 논의한 insertUser 메서드를 수정 하여 유효성 검사를 활성화합니다.

@Transactional
public Result insertUser(FlashScope flashScope, @JSR303Validation User user, Validation validation) {
    if (validation.getViolations().size() > 0) {
        flashScope.error("Validation Error: User can't be created");
    } else {
        EntityManager entityManager = entitiyManagerProvider.get();
        entityManager.persist(user);
        entityManager.flush();
        flashScope.success("User '" + user + "' is created successfully");
    }
    return Results.redirect("/home");
}

Ninja의 @JSR303Validation  어노테이션을 사용하여 User 개체의 유효성 검사를 활성화했습니다. 그런 다음 hasViolations , getViolations 및 addViolation 같은 메서드를 통해 유효성 검사 작업을 수행하기 위해 Validation 인수를 추가 했습니다.

마지막으로 FlashScope 개체는 유효성 검사 오류를 화면에 표시하는 데 사용됩니다.

참고: Ninja는 Bean 유효성 검사를 위해 JSR303 사양을 따릅니다. 그러나 JSR380 사양( Bean Validation 2.0 )이 새로운 표준입니다.

14. 결론

이 기사에서는 널리 사용되는 Java 라이브러리를 사용하여 편리한 기능을 제공하는 전체 스택 프레임워크인 Ninja 웹 프레임워크를 살펴보았습니다.

먼저 컨트롤러 , 모델서비스 를 사용하여 간단한 웹 애플리케이션을 만들었습니다 . 그런 다음 지속성을 위해 앱에서 JPA 지원을 활성화했습니다.

동시에 경로, JSON 렌더링, 국제화 및 플래시 범위와 같은 몇 가지 기본 기능을 확인했습니다.

마지막으로 프레임워크에서 제공하는 유효성 검사 지원을 살펴보았습니다.

평소와 같이 모든 코드 구현은  GitHub에서 사용할 수 있습니다 .

res – REST with Spring (eBook) (everywhere)