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:
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@content>
...
<#list articles as article>
${article.title}
${article.author}
${article.words}
${article.date}
#list>
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.