Introdução ao ActiveWeb

Introdução ao ActiveWeb

1. Visão geral

Neste artigo, vamos ilustrar oActiveweb - uma estrutura web full stack de JavaLite - fornecendo tudo o que é necessário para o desenvolvimento de aplicativos web dinâmicos ou serviços web REST-ful.

2. Conceitos e princípios básicos

Activeweb aproveita "convenção sobre configuração" - o que significa que é configurável, mas tem padrões razoáveis ​​e não requer configuração adicional. Nós apenas precisamos seguir algumas convenções predefinidas, como nomear classes, métodos e campos em um determinado formato predefinido.

Também simplifica o desenvolvimento recompilando e recarregando a fonte no contêiner em execução (Jetty por padrão).

Para gerenciamento de dependências, ele usa o Google Guice como a estrutura de DI; para saber mais sobre o Guice, dê uma olhada em nossoguide here.

3. Configuração do Maven

Para começar, vamos adicionar as dependências necessárias primeiro:


    org.javalite
    activeweb
    1.15

A versão mais recente pode ser encontradahere.

Além disso, para testar o aplicativo, precisaremos da dependênciaactiveweb-testing:


    org.javalite
    activeweb-testing
    1.15
    test

Verifique a versão mais recentehere.

4. Estrutura de Aplicação

Conforme discutimos, a estrutura do aplicativo precisa seguir uma certa convenção; aqui está o que parece para um aplicativo MVC típico:

image

Como podemos ver,controllers,service,config emodels devem estar localizados em seus próprios subpacotes no pacoteapp.

As visualizações devem estar localizadas no diretórioWEB-INF/views, cada uma tendo seu próprio subdiretório baseado no nome do controlador. Por exemplo,app.controllers.ArticleController deve ter um subdiretórioarticle/ contendo todos os arquivos de visualização para aquele controlador.

O descritor de implantação ouweb.xml deve conter normalmente um<filter>e o<filter-mapping>. correspondente. Como a estrutura é um filtro de servlet, em vez de uma configuração<servlet>, há uma configuração de filtro:

...

    dispatcher
    org.javalite.activeweb.RequestDispatcher
...

...

Também precisamos de<init-param>root_controller para definir o controlador padrão para o aplicativo - semelhante a um controladorhome:

...

    root_controller
    home

...

5. Controladores

Os controladores são os componentes principais de um aplicativo ActiveWeb; e, como mencionado anteriormente, todos os controladores devem estar localizados dentro do pacoteapp.controllers:

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

Observe que o controlador está estendendoorg.javalite.activeweb.AppController.

5.1. Mapeamento de URL do controlador

Os controladores são mapeados para um URL automaticamente com base na convenção. Por exemplo,ArticleController será mapeado para:

http://host:port/contextroot/article

Agora, isso os mapeará para o padrão, uma ação padrão no controlador. Ações não passam de métodos dentro do controlador. Nomeie o método padrão comoindex():

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

Para outros métodos ou ações, adicione o nome do método ao URL:

public class ArticleController extends AppController {
    // ...

    public void search() {
        render("search");
    }
}

O URL:

http://host:port/contextroot/article/search

Podemos até ter ações de controlador baseadas em métodos HTTP. Apenas anote o método com@POST, @PUT, @DELETE, @GET, @HEAD.. Se não anotarmos uma ação, ela é considerada um GET por padrão.

5.2. Resolução de URL do controlador

A estrutura usa o nome do controlador e o nome do subpacote para gerar a URL do controlador. Por exemploapp.controllers.ArticleController.java o URL:

http://host:port/contextroot/article

Se o controlador estiver dentro de um subpacote, a URL simplesmente se tornará:

http://host:port/contextroot/example/article

Para um nome de controlador com mais de uma palavra (por exemploapp.controllers.PublishedArticleController.java), o URL será separado por um sublinhado:

http://host:port/contextroot/published_article

5.3. Recuperando Parâmetros de Solicitação

Dentro de um controlador, obtemos acesso aos parâmetros de solicitação usando os métodosparam() ouparams() deAppController class. O primeiro método recebe um argumento String - o nome do parâmetro a ser recuperado:

public void search() {

    String keyword = param("key");
    view("search",articleService.search(keyword));

}

E podemos usar o posterior para obter todos os parâmetros se precisarmos:

public void search() {

    Map criterion = params();
    // ...
}

6. Visualizações

Na terminologia do ActiveWeb, as visualizações são freqüentemente chamadas de modelos; isso ocorre principalmente porque ele usa o mecanismo de modelo ApacheFreeMarker em vez de JSPs. Você pode ler mais sobre o FreeMarkerin our guide, here.

Coloque os modelos no diretórioWEB-INF/views. Todo controlador deve ter um subdiretório com seu nome, contendo todos os modelos exigidos por ele.

6.1. Mapeamento de visualização do controlador

Quando um controlador é atingido, a ação padrãoindex() é executada e o framework escolherá o modeloWEB-INF/views/article/index.ftl do diretório de visualizações para esse controlador. Da mesma forma, para qualquer outra ação, a visualização seria escolhida com base no nome da ação.

Nem sempre é o que gostaríamos. Às vezes, podemos querer retornar algumas visualizações com base na lógica comercial interna. Neste cenário,we can control the process with the render() method da classe paiorg.javalite.activeweb.AppController:

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

Observe que o local das visualizações personalizadas também deve estar no mesmo diretório de visualização para esse controlador. Se não for o caso, prefixe o nome do modelo com o nome do diretório onde o modelo reside e passe para o métodorender():

render("/common/error");

6.3. Visualizações com dados

Para enviar dados para as visualizações, oorg.javalite.activeweb.AppController fornece o métodoview():

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

Isso leva dois parâmetros. Primeiro, o nome do objeto usado para acessar o objeto no modelo e depois um objeto que contém os dados.

Também podemos usar o métodoassign() para passar dados para as visualizações. Não há absolutamente nenhuma diferença entre os métodos view () eassign() - podemos escolher qualquer um deles:

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

Vamos mapear os dados no modelo:

<@content for="title">Articles
...
<#list articles as article>
    
        ${article.title}
        ${article.author}
        ${article.words}
        ${article.date}
    

7. Gerenciando dependências

Para gerenciar objetos e instâncias, o ActiveWeb usa o Google Guice como uma estrutura de gerenciamento de dependências.

Digamos que precisamos de uma classe de serviço em nosso aplicativo; isso separaria a lógica de negócios dos controladores.

Vamos primeiro criar uma interface de serviço:

public interface ArticleService {

    List
getArticles(); Article search(String keyword); }

E a implementação:

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", "example"); ar.set("words", "1250"); ar.setDate("date", Instant.now()); return ar; } }

Agora, vamos ligar este serviço como um módulo Guice:

public class ArticleServiceModule extends AbstractModule {

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

Por fim, registre isso no contexto do aplicativo e injete-o no controlador, conforme necessário:

public class AppBootstrap extends Bootstrap {

    public void init(AppContext context) {
    }

    public Injector getInjector() {
        return Guice.createInjector(new ArticleServiceModule());
    }
}

Observe que este nome de classe de configuração deve serAppBootstrape deve estar localizado no pacoteapp.config.

Finalmente, aqui está como injetamos no controlador:

@Inject
private ArticleService articleService;

8. Teste

Os testes de unidade para um aplicativo ActiveWeb são escritos usando a bibliotecaJSpec do JavaLite.

Usaremos a classeorg.javalite.activeweb.ControllerSpec do JSpec para testar nosso controlador e nomearemos as classes de teste seguindo uma convenção semelhante:

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

Observe que o nome é semelhante ao controlador que está testando com uma "Especificação" no final.

Aqui está o caso de teste:

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

Observe que o métodorequest() simula a chamada para o controlador e o método HTTP correspondenteget(), leva o nome da ação como um argumento.

Também podemos passar parâmetros para o controlador usando o métodoparams():

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

Para passar vários parâmetros, também podemos encadear o método, com essa API fluente.

9. Implantando o aplicativo

É possível implantar o aplicativo em qualquer contêiner de servlet como Tomcat, WildFly ou Jetty. Obviamente, a maneira mais simples de implantar e testar seria usando o plugin Maven Jetty:

...

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

...

A última versão do plugin éhere.

Agora, finalmente - podemos acioná-lo:

mvn jetty:run

10. Conclusão

Neste artigo, aprendemos sobre os conceitos e convenções básicas da estrutura ActiveWeb. Além disso, a estrutura possui mais recursos e capacidades do que discutimos aqui.

Consulte odocumentation oficial para obter mais detalhes.

E, como sempre, o código de amostra usado no artigo está disponívelover on GitHub.