Pengantar Kerangka Ninja

1. Ikhtisar

Saat ini, ada banyak framework berbasis JEE seperti Spring, Play, dan Grails yang tersedia untuk pengembangan aplikasi web.

Kami mungkin memiliki alasan kami untuk memilih salah satu dari mereka. Namun, pilihan kami juga bergantung pada kasus penggunaan dan masalah yang ingin kami selesaikan.

Dalam tutorial pengantar ini, kita akan menjelajahi kerangka web Ninja dan membuat aplikasi web sederhana. Pada saat yang sama, kami akan memeriksa beberapa fitur dasar yang disediakannya.

2. Ninja

Ninja adalah kerangka kerja web lengkap, namun ringan, yang memanfaatkan perpustakaan Java yang ada untuk menyelesaikan pekerjaan.

Memiliki fitur mulai dari rendering HTML hingga JSON, persistensi hingga pengujian, ini adalah solusi satu atap untuk membangun aplikasi web yang dapat diskalakan.

Ini mengikuti paradigma konvensi-over-konfigurasi dan mengkategorikan kode dalam paket seperti model , pengontrol, dan layanan .

Ninja menggunakan pustaka Java yang populer untuk fitur-fitur utama seperti Jackson untuk rendering JSON / XML, Guice untuk manajemen ketergantungan, Hibernate untuk persistensi, dan Jalur Terbang untuk migrasi database .

Untuk pengembangan cepat, ia menawarkan SuperDevMode untuk memuat ulang kode secara panas. Jadi, ini memungkinkan kita untuk melihat perubahan secara instan di lingkungan pengembangan.

3. Penyiapan

Ninja membutuhkan seperangkat alat standar untuk membuat aplikasi web:

  • Java 1.8 atau lebih baru
  • Maven 3 atau lebih baru
  • IDE (Eclipse atau IntelliJ)

Kami akan menggunakan pola dasar Maven untuk menyiapkan proyek Ninja dengan cepat. Ini akan meminta kita untuk memberikan id grup, id artefak, dan nomor versi, diikuti dengan nama proyek:

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

Atau, untuk proyek Maven yang sudah ada, kita dapat menambahkan ketergantungan ninja-core terbaru ke pom.xml :

 org.ninjaframework ninja-core 6.5.0 

Kemudian, kami akan menjalankan perintah Maven untuk mengompilasi file untuk pertama kalinya:

mvn clean install

Terakhir, mari jalankan aplikasi menggunakan perintah Maven yang disediakan Ninja:

mvn ninja:run

Voila! Aplikasi kami dimulai dan akan dapat diakses di localhost: 8080 :

4. Struktur Proyek

Mari kita lihat struktur proyek mirip Maven yang dibuat oleh Ninja:

Kerangka kerja membuat beberapa paket berdasarkan konvensi.

Kelas Java dikategorikan dalam direktori conf , controllers , models , dan services di src / main / java.

Demikian pula, src / test / java memiliki kelas pengujian unit yang sesuai.

Direktori views di bawah src / main / java berisi file HTML. Dan, direktori src / main / java / assets berisi sumber daya seperti gambar, lembar gaya, dan file JavaScript.

5. Pengontrol

Kami siap untuk membahas beberapa fitur dasar kerangka kerja. Pengontrol adalah kelas yang menerima permintaan dan mengembalikan respons dengan hasil tertentu.

Pertama, mari kita bahas beberapa konvensi untuk diikuti:

  • Buat kelas dalam paket pengontrol dan sufiks nama dengan Controller
  • Metode yang melayani permintaan harus mengembalikan objek kelas Hasil

Mari buat kelas ApplicationController dengan metode sederhana untuk merender HTML:

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

Di sini, metode indeks akan merender HTML dengan memanggil metode html dari kelas Hasil . The Hasil obyek memegang segala sesuatu yang diperlukan untuk membuat konten seperti kode respon, header, dan cookies.

Catatan: Anotasi @Singleton Guice hanya mengizinkan satu instance dari pengontrol di seluruh aplikasi .

6. Lihat

Untuk metode indeks , Ninja akan mencari file HTML - index .ftl.html di bawah direktori views / ApplicationController .

Ninja menggunakan mesin template Freemarker untuk rendering HTML . Jadi, semua file di bawah tampilan harus memiliki ekstensi .ftl.html .

Mari buat file i ndex .ftl.html untuk metode indeks :

 Ninja: Index User Json 

Di sini, kami telah menggunakan tag i18n yang disediakan Ninja untuk mendapatkan properti helloMsg dari file message.properties . Kami akan membahas ini lebih lanjut di bagian internasionalisasi nanti.

7. Rute

Selanjutnya, kami akan menentukan rute permintaan untuk mencapai metode indeks .

Ninja menggunakan kelas Rute dalam paket conf untuk memetakan URL ke metode tertentu dari pengontrol.

Mari tambahkan rute untuk mengakses metode indeks ApplicationController :

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

Itu dia! Kami siap untuk mengakses halaman indeks di localhost: 8080 / index :

8. JSON Rendering

Seperti yang sudah dibahas, Ninja menggunakan Jackson untuk rendering JSON. Untuk merender konten JSON, kita dapat menggunakan metode json dari kelas Hasil .

Mari tambahkan metode userJson di kelas ApplicationController dan render konten HashMap sederhana di JSON:

public Result userJson() { HashMap userMap = new HashMap(); userMap.put("name", "Norman Lewis"); userMap.put("email", "[email protected]"); return Results.json().render(user); }

Kemudian, kami akan menambahkan perutean yang diperlukan untuk mengakses userJson :

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

Sekarang, kita dapat merender JSON menggunakan localhost: 8080 / userJson :

9. Layanan

Kami dapat membuat layanan untuk menjaga logika bisnis tetap terpisah dari pengontrol dan memasukkan layanan kami di mana pun diperlukan.

Pertama, mari buat antarmuka UserService sederhana untuk mendefinisikan abstraksi:

public interface UserService { HashMap getUserMap(); }

Kemudian, kami akan mengimplementasikan antarmuka UserService di kelas UserServiceImpl dan mengganti metode getUserMap :

public class UserServiceImpl implements UserService { @Override public HashMap getUserMap() { HashMap userMap = new HashMap(); userMap.put("name", "Norman Lewis"); userMap.put("email", "[email protected]"); return userMap; } }

Then, we'll bind the UserService interface with the UserServiceImpl class using Ninja's dependency injection feature provided by Guice.

Let's add the binding in the Module class available in the conf package:

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

Last, we'll inject the UserService dependency in the ApplicationController class using the @Inject annotation:

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

Thus, we're all set to use the UserService‘s getUserMap method in the ApplicationController:

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

10. Flash Scope

Ninja provides a simple yet efficient way to handle success and error messages from requests through its feature called Flash Scope.

To use it in the controller, we'll add the FlashScope argument to the method:

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

Note: The redirect method of the Results class redirects the target to the provided URL.

Then, we'll add a routing /flash to the showFlashMsg method and modify the view to show the flash messages:

 ${flash.error} ${flash.success} 

Now, we can see the FlashScope in action at localhost:8080/flash:

11. Internationalization

Ninja provides a built-in internationalization feature that is easy to configure.

First, we'll define the list of supported languages in the application.conf file:

application.languages=fr,en

Then, we'll create the default properties file – messages.properties for English – with key-value pairs for messages:

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

Similarly, we can add the language code in the file name for a language-specific properties file — for instance, message_fr.properties file for French:

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

Once the configurations are ready, we can easily enable internationalization in the ApplicationController class.

We've got two ways, either by using the Lang class or the Messages class:

@Singleton public class ApplicationController { @Inject Lang lang; @Inject Messages msg; // ... }

Then, using the Lang class, we can set the language of the result:

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

Similarly, using the Messages class, we can get a language-specific message:

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

12. Persistence

Ninja supports JPA 2.0 and utilizes Hibernate to enable persistence in the web application. Also, it offers built-in H2 database support for rapid development.

12.1. Model

We require an Entity class to connect with a table in the database. For this, Ninja follows the convention of looking for the entity classes in the models package. So, we'll create the User entity class there:

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

Then, we'll configure Hibernate and set the details for the database connection.

12.2. Configuration

For Hibernate configuration, Ninja expects the persistence.xml file to be in the src/main/java/META-INF directory:

    org.hibernate.jpa.HibernatePersistenceProvider          

Then, we'll add the database connection details to application.conf:

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

12.3. EntityManager

Last, we'll inject the instance of the EntityManager in the ApplicationController using Guice's Provider class:

public class ApplicationController { @Inject Provider entityManagerProvider; // ... }

So, we're ready to use the EntityManager to persist the User object:

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

Similarly, we can use the EntityManager to read the User object from the DB:

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

Here, Ninja's @UnitOfWork annotation will handle everything about the database connections without dealing with transactions. Hence, it can prove handy for read-only queries, where we usually don't require transactions.

13. Validation

Ninja provides built-in support for bean validations by following the JSR303 specifications.

Let's examine the feature by annotating a property in the User entity with the @NotNull annotation:

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

Then, we'll modify the already discussed insertUser method in the ApplicationController to enable the validation:

@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"); }

We've used Ninja's @JSR303Validation annotation to enable the validation of the User object. Then, we've added the Validation argument to work with validations through methods like hasViolations, getViolations, and addViolation.

Last, the FlashScope object is used to show the validation error on the screen.

Note: Ninja follows the JSR303 specifications for bean validations. However, the JSR380 specification (Bean Validation 2.0) is the new standard.

14. Conclusion

In this article, we explored the Ninja web framework — a full-stack framework that provides handy features using popular Java libraries.

To begin with, we created a simple web application using controllers, models, and services. Then, we enabled JPA support in the app for persistence.

At the same time, we saw a few basic features like Routes, JSON rendering, Internationalization, and Flash Scopes.

Last, we explored the validation support provided by the framework.

As usual, all the code implementations are available over on GitHub.