Introduzione ad ActiveWeb

Java Top

Ho appena annunciato il nuovo corso Learn Spring , incentrato sui fondamenti di Spring 5 e Spring Boot 2:

>> SCOPRI IL CORSO

1. Panoramica

In questo articolo illustreremo Activeweb, un framework web full stack di JavaLite, che fornisce tutto il necessario per lo sviluppo di applicazioni web dinamiche o servizi web REST-ful.

2. Concetti e principi di base

Activeweb sfrutta la "convenzione sulla configurazione", il che significa che è configurabile, ma ha impostazioni predefinite ragionevoli e non richiede configurazione aggiuntiva. Dobbiamo solo seguire alcune convenzioni predefinite, come la denominazione di classi, metodi e campi in un determinato formato predefinito.

Inoltre semplifica lo sviluppo ricompilando e ricaricando il sorgente nel contenitore in esecuzione (Jetty per impostazione predefinita).

Per la gestione delle dipendenze, utilizza Google Guice come framework DI; per saperne di più su Guice, dai un'occhiata alla nostra guida qui.

3. Installazione di Maven

Per iniziare, aggiungiamo prima le dipendenze necessarie:

 org.javalite activeweb 1.15  

L'ultima versione può essere trovata qui.

Inoltre, per testare l'applicazione, avremo bisogno della dipendenza activeweb-testing :

 org.javalite activeweb-testing 1.15 test 

Dai un'occhiata all'ultima versione qui.

4. Struttura dell'applicazione

Come abbiamo discusso, la struttura dell'applicazione deve seguire una certa convenzione; ecco come appare una tipica applicazione MVC:

Come possiamo vedere, controller , servizio , configurazione e modelli dovrebbero trovarsi nel proprio sotto-pacchetto nel pacchetto dell'app .

Le viste dovrebbero trovarsi nella directory WEB-INF / views , ciascuna con una propria sottodirectory basata sul nome del controller. Ad esempio app.controllers.ArticleController dovrebbe avere una sottodirectory / articolo contenente tutti i file di visualizzazione per quel controller.

Il descrittore di distribuzione o web.xml dovrebbe in genere contenere un filee il corrispondente . Poiché il framework è un filtro servlet, invece di un fileconfigurazione c'è una configurazione del filtro:

...  dispatcher org.javalite.activeweb.RequestDispatcher ...  ...

Abbiamo anche bisogno di un file root_controller per definire il controller predefinito per l'applicazione, simile a un controller domestico :

...  root_controller home  ...

5. Controller

I controller sono i componenti principali di un'applicazione ActiveWeb; e, come accennato in precedenza, tutti i controller dovrebbero trovarsi all'interno del pacchetto app.controllers :

public class ArticleController extends AppController { // ... }

Si noti che il controller sta estendendo org.javalite.activeweb.AppController.

5.1. Mappatura URL del controller

I controller vengono mappati automaticamente a un URL in base alla convenzione. Ad esempio, ArticleController verrà mappato a:

//host:port/contextroot/article

Ora, questo sarebbe stato mappato come predefinito un'azione predefinita nel controller. Le azioni non sono altro che metodi all'interno del controller. Assegna al metodo predefinito il nome index ():

public class ArticleController extends AppController { // ... public void index() { render("articles"); } // ... }

For other methods or actions append the method name to the URL:

public class ArticleController extends AppController { // ... public void search() { render("search"); } }

The URL:

//host:port/contextroot/article/search

We can even have controller actions based on HTTP methods. Just annotate the method with either of @POST, @PUT, @DELETE, @GET, @HEAD. If we don't annotate an action, it's considered a GET by default.

5.2. Controller URL Resolution

The framework uses controller name and the sub-package name to generate the controller URL. For example app.controllers.ArticleController.java the URL:

//host:port/contextroot/article

If the controller is inside a sub-package, the URL simply becomes:

//host:port/contextroot/baeldung/article

For a controller name having more than a single word (for example app.controllers.PublishedArticleController.java), the URL will get separated using an underscore:

//host:port/contextroot/published_article

5.3. Retrieving Request Parameters

Inside a controller, we get access to the request parameters using the param() or params() methods from the AppController class. The first method takes a String argument – the name of the param to retrieve:

public void search() { String keyword = param("key"); view("search",articleService.search(keyword)); }

And we can use the later to get all parameters if we need to:

public void search() { Map criterion = params(); // ... }

6. Views

In ActiveWeb terminology, views are often referred as templates; this is mostly because it uses Apache FreeMarker template engine instead of JSPs. You can read more about FreeMarker in our guide, here.

Place the templates in WEB-INF/views directory. Every controller should have a sub-directory by its name holding all templates required by it.

6.1. Controller View Mapping

When a controller is hit, the default action index() gets executed and the framework will choose the WEB-INF/views/article/index.ftl template the from views directory for that controller. Similarly, for any other action, the view would be chosen based on the action name.

This isn't always what we would like. Sometimes we might want to return some views based on internal business logic. In this scenario, we can control the process with the render() method from the parent org.javalite.activeweb.AppController class:

public void index() { render("articles"); }

Note that the location of the custom views should also be in the same view directory for that controller. If it is not the case, prefix the template name with the directory name where the template resides and pass it to the render() method:

render("/common/error");

6.3. Views With Data

To send data to the views, the org.javalite.activeweb.AppController provides the view() method:

view("articles", articleService.getArticles());

This takes two params. First, the object name used to access the object in the template and second an object containing the data.

We can also use assign() method to pass data to the views. There is absolutely no difference between view() and assign() methods – we may choose any one of them:

assign("article", articleService.search(keyword));

Let's map the data in the template:

Articles ...  ${article.title}${article.author}${article.words}${article.date}

7. Managing Dependencies

In order to manage objects and instances, ActiveWeb uses Google Guice as a dependency management framework.

Let's say we need a service class in our application; this would separate the business logic from the controllers.

Let's first create a service interface:

public interface ArticleService { List getArticles(); Article search(String keyword); }

And the implementation:

public class ArticleServiceImpl implements ArticleService { public List getArticles() { return fetchArticles(); } public Article search(String keyword) { Article ar = new Article(); ar.set("title", "Article with "+keyword); ar.set("author", "baeldung"); ar.set("words", "1250"); ar.setDate("date", Instant.now()); return ar; } }

Now, let's bind this service as a Guice module:

public class ArticleServiceModule extends AbstractModule { @Override protected void configure() { bind(ArticleService.class).to(ArticleServiceImpl.class) .asEagerSingleton(); } }

Finally, register this in the application context and inject it into the controller, as required:

public class AppBootstrap extends Bootstrap { public void init(AppContext context) { } public Injector getInjector() { return Guice.createInjector(new ArticleServiceModule()); } }

Note that this config class name must be AppBootstrap and it should be located in the app.config package.

Finally, here's how we inject it into the controller:

@Inject private ArticleService articleService;

8. Testing

Unit tests for an ActiveWeb application are written using the JSpec library from JavaLite.

We'll use the org.javalite.activeweb.ControllerSpec class from JSpec to test our controller, and we'll name the test classes following a similar convention:

public class ArticleControllerSpec extends ControllerSpec { // ... }

Notice, that the name is similar to the controller it is testing with a “Spec” at the end.

Here's the test case:

@Test public void whenReturnedArticlesThenCorrect() { request().get("index"); a(responseContent()) .shouldContain("Introduction to Mule"); }

Notice that the request() method simulates the call to the controller, and the corresponding HTTP method get(), takes the action name as an argument.

We can also pass parameters to the controller using the params() method:

@Test public void givenKeywordWhenFoundArticleThenCorrect() { request().param("key", "Java").get("search"); a(responseContent()) .shouldContain("Article with Java"); }

To pass multiple parameters, we can chain method as well, with this fluent API.

9. Deploying the Application

È possibile distribuire l'applicazione in qualsiasi contenitore servlet come Tomcat, WildFly o Jetty. Ovviamente, il modo più semplice per distribuire e testare sarebbe utilizzare il plug-in Maven Jetty:

...  org.eclipse.jetty jetty-maven-plugin 9.4.8.v20171121  manual 10000   ...

L'ultima versione del plugin è qui.

Ora, finalmente, possiamo accenderlo:

mvn jetty:run

10. Conclusione

In questo articolo, abbiamo appreso i concetti e le convenzioni di base del framework ActiveWeb. Oltre a questi, il framework ha più caratteristiche e capacità di quanto abbiamo discusso qui.

Fare riferimento alla documentazione ufficiale per maggiori dettagli.

E, come sempre, il codice di esempio utilizzato nell'articolo è disponibile su GitHub.

Fondo Java

Ho appena annunciato il nuovo corso Learn Spring , incentrato sui fondamenti di Spring 5 e Spring Boot 2:

>> SCOPRI IL CORSO