Pengenalan Rangka Kerja Ninja

1. Gambaran keseluruhan

Pada masa kini, terdapat banyak kerangka kerja berasaskan JEE seperti Spring, Play, dan Grails yang tersedia untuk pengembangan aplikasi web.

Kami mungkin mempunyai alasan untuk memilih salah satu daripada yang lain. Namun, pilihan kami juga bergantung pada kes penggunaan dan masalah yang ingin kami selesaikan.

Dalam tutorial pengenalan ini, kita akan meneroka kerangka web Ninja dan membuat aplikasi web yang mudah. Pada masa yang sama, kami akan mengkaji beberapa ciri asas yang disediakannya.

2. Ninja

Ninja adalah kerangka web tumpukan penuh, namun ringan yang menggunakan perpustakaan Java yang ada untuk menyelesaikan kerja.

Memiliki ciri dari HTML hingga rendering JSON, ketekunan hingga pengujian, ini adalah penyelesaian sehenti untuk membangun aplikasi web yang berskala.

Ini mengikuti paradigma konvensyen-over-konfigurasi dan mengkategorikan kod dalam pakej seperti model , pengawal, dan perkhidmatan .

Ninja menggunakan perpustakaan Java yang popular untuk ciri utama seperti Jackson untuk rendering JSON / XML, Guice for dependency management, Hibernate for persistence, dan Flyway untuk migrasi pangkalan data .

Untuk perkembangan pesat, ia menawarkan SuperDevMode untuk memuat semula kod yang panas. Oleh itu, ini membolehkan kita melihat perubahan secara langsung dalam persekitaran pembangunan.

3. Persediaan

Ninja memerlukan sekumpulan alat standard untuk membuat aplikasi web:

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

Kami akan menggunakan pola dasar Maven untuk menyiapkan projek Ninja dengan cepat. Ini akan meminta kami memberikan id kumpulan, id artifak, dan nombor versi, diikuti dengan nama projek:

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

Atau, untuk projek Maven yang ada, kita dapat menambahkan kebergantungan inti ninja terbaru ke pom.xml :

 org.ninjaframework ninja-core 6.5.0 

Kemudian, kami akan menjalankan perintah Maven untuk menyusun fail untuk pertama kalinya:

mvn clean install

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

mvn ninja:run

Voila! Permohonan kami dimulakan dan akan dapat diakses di localhost: 8080 :

4. Struktur Projek

Mari lihat struktur projek seperti Maven yang dibuat oleh Ninja:

Rangka kerja membuat beberapa pakej berdasarkan konvensyen.

Kelas Java dikategorikan di bawah direktori conf , pengendali , model , dan perkhidmatan di src / main / java.

Begitu juga, src / test / java mengadakan kelas ujian unit yang sesuai.

The pandangan direktori bawah src / utama / java mengandungi fail HTML. Direktori src / main / java / aset mengandungi sumber seperti gambar, helaian gaya, dan fail JavaScript.

5. Pengawal

Kami sudah bersedia untuk membincangkan beberapa ciri asas kerangka. Pengawal adalah kelas yang menerima permintaan dan mengembalikan respons dengan hasil tertentu.

Pertama, mari kita bincangkan beberapa konvensyen untuk diikuti:

  • Buat kelas dalam pakej pengawal dan akhiran nama dengan Pengawal
  • Kaedah melayani permintaan mesti mengembalikan objek kelas Hasil

Mari buat kelas ApplicationController dengan kaedah mudah untuk membuat HTML:

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

Di sini, kaedah indeks akan menghasilkan HTML dengan memanggil kaedah html dari kelas Hasil . The Keputusan objek memegang segala sesuatu yang diperlukan untuk menjadikan kandungan seperti kod respons, tajuk, dan cookies.

Catatan: Anotasi Guice's @Singleton hanya membenarkan satu contoh pengawal di seluruh aplikasi .

6. Pandangan

Untuk kaedah indeks , Ninja akan mencari fail HTML - index .ftl.html di bawah paparan / direktori ApplicationController .

Ninja menggunakan mesin templat Freemarker untuk rendering HTML . Jadi, semua fail dalam paparan harus mempunyai pelanjutan .ftl.html .

Mari buat fail i ndex .ftl.html untuk kaedah indeks :

 Ninja: Index User Json 

Di sini, kami telah menggunakan Ninja yang disediakan i18n tag untuk mendapatkan helloMsg hartanah dari message.properties fail. Kami akan membincangkannya lebih lanjut di bahagian pengantarabangsaan di kemudian hari.

7. Laluan

Seterusnya, kami akan menentukan laluan permintaan untuk mencapai kaedah indeks .

Ninja menggunakan kelas Routes dalam paket conf untuk memetakan URL ke kaedah pengawal tertentu.

Mari tambahkan laluan untuk mengakses kaedah indeks ApplicationController :

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

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

8. JSON Rendering

Seperti yang telah dibincangkan, Ninja menggunakan Jackson untuk rendering JSON. Untuk membuat kandungan JSON, kita dapat menggunakan kaedah json dari kelas Hasil .

Mari tambahkan kaedah userJson di kelas ApplicationController dan berikan kandungan HashMap ringkas 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 penghalaan yang diperlukan untuk mengakses userJson :

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

Sekarang, kita boleh membuat JSON menggunakan localhost: 8080 / userJson :

9. Perkhidmatan

Kami boleh membuat perkhidmatan untuk memisahkan logik perniagaan daripada pengawal dan menyuntik perkhidmatan kami di mana sahaja diperlukan.

Pertama, mari kita buat antara muka UserService yang mudah untuk menentukan abstraksi:

public interface UserService { HashMap getUserMap(); }

Kemudian, kami akan melaksanakan antara muka UserService dalam kelas UserServiceImpl dan menimpa kaedah 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.