Blade - Um guia completo

Blade - Um guia completo

1. Visão geral

Blade é uma pequena estrutura Java 8+ MVC, construída do zero com alguns objetivos claros em mente: ser independente, produtivo, elegante, intuitivo e super rápido.

Muitos frameworks diferentes inspiraram seu design:Express do nó,Flask do Python eMacaron /Martini de Golang.

O Blade também faz parte de um projeto ambiciosamente maior,Let’s Blade. Ele inclui uma coleção heterogênea de outras pequenas bibliotecas, da geração Captcha à conversão JSON, do modelo a uma conexão simples ao banco de dados.

No entanto, neste tutorial, vamos nos concentrar apenas no MVC.

2. Começando

Em primeiro lugar, vamos criar um projeto Maven vazio e adicionarthe latest Blade MVC dependency empom.xml:


    com.bladejava
    blade-mvc
    2.0.14.RELEASE

2.1. Agrupando um aplicativo de lâmina

Como nosso aplicativo será criado como um JAR, ele não terá uma pasta/lib, como em um WAR. Como resultado, isso nos leva ao problema de como fornecer o JARblade-mvc, junto com qualquer outro JAR de que possamos precisar, para nosso aplicativo.

As diferentes maneiras de fazer isso, cada uma com prós e contras, são explicadas no tutorialHow to Create an Executable JAR with Maven.

Para simplificar,we’ll use the Maven Assembly Plugin technique, que explode qualquer JAR importado empom.xml e subsequentemente agrupa todas as classes em um único uber-JAR.

2.2. Executando um Aplicativo Blade

Blade is based upon Netty, uma incrível estrutura de aplicativo de rede orientada a eventos assíncronos. Portanto, para executar nosso aplicativo baseado em Blade, não precisamos de nenhum Servidor de Aplicativos externo nem Contêiner de Servlet; o JRE será suficiente:

java -jar target/sample-blade-app.jar

Depois disso, o aplicativo estará acessível na URLhttp://localhost:9000.

3. Compreendendo a arquitetura

A arquitetura do Blade é muito direta:

image

Sempre segue o mesmo ciclo de vida:

  1. Netty recebe um pedido

  2. Middlewares são executados (opcional)

  3. WebHooks são executados (opcional)

  4. O roteamento é realizado

  5. A resposta é enviada ao cliente

  6. Limpar

Exploraremos as funções acima nas próximas seções.

4. Encaminhamento

Em resumo, o roteamento no MVC é o mecanismo usado para criar uma ligação entre uma URL e um Controlador.

O Blade fornece dois tipos de rotas: uma básica e uma anotada.

4.1. Rotas Básicas

As rotas básicas destinam-se a softwares muito pequenos, como microsserviços ou aplicativos da Web mínimos:

Blade.of()
  .get("/basic-routes-example", ctx -> ctx.text("GET called"))
  .post("/basic-routes-example", ctx -> ctx.text("POST called"))
  .put("/basic-routes-example", ctx -> ctx.text("PUT called"))
  .delete("/basic-routes-example", ctx -> ctx.text("DELETE called"))
  .start(App.class, args);

O nome do método usado para registrar uma rota corresponde ao verbo HTTP que será usado para encaminhar a solicitação. Tão simples como isso.

Nesse caso, estamos retornando um texto, mas também podemos renderizar as páginas, como veremos mais adiante neste tutorial.

4.2. Rotas Anotadas

Certamente, para casos de uso mais realistas, podemos definir todas as rotas necessárias usando anotações. Devemos usar classes separadas para isso.

Primeiramente, precisamos criar um Controller através da anotação@Path, que será varrido pelo Blade durante a inicialização.

Em seguida, precisamos usar a anotação de rota relacionada ao método HTTP que queremos interceptar:

@Path
public class RouteExampleController {

    @GetRoute("/routes-example")
    public String get(){
        return "get.html";
    }

    @PostRoute("/routes-example")
    public String post(){
        return "post.html";
    }

    @PutRoute("/routes-example")
    public String put(){
        return "put.html";
    }

    @DeleteRoute("/routes-example")
    public String delete(){
        return "delete.html";
    }
}

Também podemos usar a anotação@Route simples e especificar o método HTTP como parâmetro:

@Route(value="/another-route-example", method=HttpMethod.GET)
public String anotherGet(){
    return "get.html" ;
}

Por outro lado,if we don’t put any method parameter, the route will intercept every HTTP call to that URL, não importa o verbo.

4.3. Injeção de Parâmetro

Existem várias maneiras de passar parâmetros para nossas rotas. Vamos explorá-los com alguns exemplosfrom the documentation.

  • Parâmetro do formulário:

@GetRoute("/home")
public void formParam(@Param String name){
    System.out.println("name: " + name);
}
  • Parâmetro repousante:

@GetRoute("/users/:uid")
public void restfulParam(@PathParam Integer uid){
    System.out.println("uid: " + uid);
}
  • Parâmetro de upload de arquivo:

@PostRoute("/upload")
public void fileParam(@MultipartParam FileItem fileItem){
    byte[] file = fileItem.getData();
}
  • Parâmetro de cabeçalho:

@GetRoute("/header")
public void headerParam(@HeaderParam String referer){
    System.out.println("Referer: " + referer);
}
  • Parâmetro de cookie:

@GetRoute("/cookie")
public void cookieParam(@CookieParam String myCookie){
    System.out.println("myCookie: " + myCookie);
}
  • Parâmetro do corpo:

@PostRoute("/bodyParam")
public void bodyParam(@BodyParam User user){
    System.out.println("user: " + user.toString());
}
  • Parâmetro Value Object, chamado enviando seus atributos para a rota:

@PostRoute("/voParam")
public void voParam(@Param User user){
    System.out.println("user: " + user.toString());
}

5. Recursos estáticos

O Blade também pode servir a recursos estáticos, se necessário, simplesmente colocando-os dentro da pasta/resources/static.

Por exemplo,src/main/resources/static/app.css estará disponível emhttp://localhost:9000/static/app.css.

5.1. Personalizando os Caminhos

Podemos ajustar esse comportamento adicionando um ou mais caminhos estáticos programaticamente:

blade.addStatics("/custom-static");

O mesmo resultado é obtido por meio da configuração, editando o arquivosrc/main/resources/application.properties:

mvc.statics=/custom-static

5.2. Habilitando a Lista de Recursos

Podemos permitir a listagem do conteúdo de uma pasta estática, um recurso desativado por padrão por um motivo de segurança:

blade.showFileList(true);

Ou na configuração:

mvc.statics.show-list=true

Agora podemos abrir ohttp://localhost:9000/custom-static/ para mostrar o conteúdo da pasta.

5.3. Usando WebJars

Conforme visto no tutorialIntroduction to WebJars, recursos estáticos empacotados como JAR também são uma opção viável.

O Blade os expõe automaticamente sob o caminho/webjars/.

Por exemplo, vamos importarBootstrap empom.xml:


    org.webjars
    bootstrap
    4.2.1

Como resultado, ele estará disponível emhttp://localhost:9000/webjars/bootstrap/4.2.1/css/bootstrap.css

6. Solicitação HTTP

ComoBlade is not based on the Servlet Specification, objetos como sua interfaceRequest e sua classeHttpRequest são um pouco diferentes dos que estamos acostumados.

6.1. Parâmetros do formulário

Ao ler os parâmetros do formulário, o Blade faz grande uso deOptional do Java nos resultados dos métodos de consulta (todos os métodos abaixo retornam um objetoOptional):

  • consulta (nome da string)

  • queryInt (nome da string)

  • queryLong (nome da string)

  • queryDouble (nome da string)

Eles também estão disponíveis com um valor substituto:

  • Consulta de string (String name, String defaultValue)

  • int queryInt (String name, int defaultValue)

  • long queryLong (String name, long defaultValue)

  • double queryDouble (String name, double defaultValue)

Podemos ler um parâmetro de formulário através da propriedade automapped:

@PostRoute("/save")
public void formParams(@Param String username){
    // ...
}

Ou do objetoRequest:

@PostRoute("/save")
public void formParams(Request request){
    String username = request.query("username", "example");
}

6.2. Dados JSON

Vamos agora dar uma olhada em como um objeto JSON pode ser mapeado para um POJO:

curl -X POST http://localhost:9000/users -H 'Content-Type: application/json' \
  -d '{"name":"example","site":"example.com"}'

POJO (anotado comLombok para legibilidade):

public class User {
    @Getter @Setter private String name;
    @Getter @Setter private String site;
}

Novamente, o valor está disponível como a propriedade injetada:

@PostRoute("/users")
public void bodyParams(@BodyParam User user){
    // ...
}

E a partir deRequest:

@PostRoute("/users")
public void bodyParams(Request request) {
    String bodyString = request.bodyToString();
}

6.3. Parâmetros RESTful

Os parâmetros RESTFul em URLs bonitos comolocalhost:9000/user/42 também são cidadãos de primeira classe:

@GetRoute("/user/:id")
public void user(@PathParam Integer id){
    // ...
}

Como de costume, podemos confiar no objetoRequest quando necessário:

@GetRoute("/user")
public void user(Request request){
    Integer id = request.pathInt("id");
}

Obviamente, o mesmo método está disponível para os tiposLongeString também.

6.4. Ligação de dados

O Blade suporta os parâmetros de ligação JSON e Form e os anexa ao objeto de modelo automaticamente:

@PostRoute("/users")
public void bodyParams(User user){}

6.5. Atributos de solicitação e sessão

A API para leitura e gravação de objetos em aRequeste aSession é cristalina.

Os métodos com dois parâmetros, representando chave e valor, são os mutadores que podemos usar para armazenar nossos valores nos diferentes contextos:

Session session = request.session();
request.attribute("request-val", "Some Request value");
session.attribute("session-val", 1337);

Por outro lado, os mesmos métodos que aceitam apenas o parâmetro key são os acessadores:

String requestVal = request.attribute("request-val");
String sessionVal = session.attribute("session-val"); //It's an Integer

Um recurso interessante étheir Generic return type <T> T, que nos livra da necessidade de lançar o resultado.

6.6. Cabeçalhos

Os cabeçalhos da solicitação, pelo contrário, só podem ser lidos a partir da solicitação:

String header1 = request.header("a-header");
String header2 = request.header("a-safe-header", "with a default value");
Map allHeaders = request.headers();

6.7. Serviços de utilidade pública

Os seguintes métodos de utilitário também estão disponíveis prontos para uso e são tão evidentes que não precisam de mais explicações:

  • boolean isIE ()

  • boolean isAjax ()

  • String contentType ()

  • String userAgent ()

6.8. Lendo Cookies

Vamos ver como o objetoRequest nos ajuda a lidar com Cookies, especificamente ao ler oOptional<Cookie>:

Optional cookieRaw(String name);

Também podemos obtê-lo comoString especificando um valor padrão a ser aplicado se um Cookie não existir:

String cookie(String name, String defaultValue);

Finalmente, é assim que podemos ler todos os Cookies de uma vez (keys são nomes de Cookies,values são valores de Cookies):

Map cookies = request.cookies();

7. Resposta HTTP

Analogamente ao que foi feito comRequest, podemos obter uma referência ao objetoResponse simplesmente declarando-o como um parâmetro do método de roteamento:

@GetRoute("/")
public void home(Response response) {}

7.1. Saída simples

Podemos enviar facilmente uma saída simples para o chamador através de um dos métodos úteis de saída, junto com um código HTTP 200 e o Tipo de Conteúdo apropriado.

Em primeiro lugar, podemos enviar um texto sem formatação:

response.text("Hello World!");

Em segundo lugar, podemos produzir um HTML:

response.html("

Hello World!

");

Em terceiro lugar, também podemos gerar um XML:

response.xml("Hello World!");

Finalmente, podemos gerar JSON usando umString:

response.json("{\"The Answer\":42}");

E mesmo de um POJO, explorando a conversão JSON automática:

User user = new User("example", "example.com");
response.json(user);

7.2. Saída de arquivo

Baixar um arquivo do servidor não poderia ser mais simples:

response.download("the-file.txt", "/path/to/the/file.txt");

O primeiro parâmetro define o nome do arquivo que será baixado, enquanto o segundo (um objetoFile, aqui construído comString) representa o caminho para o arquivo real no servidor.

7.3. Renderização de modelo

O Blade também pode renderizar páginas através de um mecanismo de modelo:

response.render("admin/users.html");

O diretório padrão dos modelos ésrc/main/resources/templates/, portanto, o one-liner anterior irá procurar o arquivosrc/main/resources/templates/admin/users.html.

Aprenderemos mais sobre isso mais tarde, na seçãoTemplating.

7.4. Redirecionar

Um redirecionamento significa enviar um código HTTP 302 para o navegador, juntamente com um URL a seguir com um segundo GET.

Podemos redirecionar para outra rota ou também para um URL externo:

response.redirect("/target-route");

7.5. Escrevendo Cookies

Devemos nos acostumar com a simplicidade do Blade neste momento. Vejamos, portanto, como podemos escrever um Cookie ainda não expirado em uma única linha de código:

response.cookie("cookie-name", "Some value here");

De fato, remover um Cookie é igualmente simples:

response.removeCookie("cookie-name");

7.6. Outras Operações

Finalmente, o objetoResponse nos fornece vários outros métodos para realizar operações como escrever cabeçalhos, definir o tipo de conteúdo, definir o código de status e assim por diante.

Vamos dar uma olhada rápida em alguns deles:

  • Status de resposta (status interno)

  • Cabeçalhos do mapa ()

  • Resposta notFound ()

  • Cookies de mapa ()

  • Response contentType (String contentType)

  • void body (@NonNull byte [] data)

  • Cabeçalho de resposta (nome da string, valor da string)

8. WebHooks

Um WebHook é um interceptor por meio do qual podemosrun code before and after the execution of a routing method.

Podemos criar um WebHook simplesmente implementando a interface funcionalWebHook e substituindo o métodobefore():

@FunctionalInterface
public interface WebHook {

    boolean before(RouteContext ctx);

    default boolean after(RouteContext ctx) {
        return true;
    }
}

Como podemos ver,after() é um método padrão, portanto, vamos substituí-lo apenas quando necessário.

8.1. Interceptando cada solicitação

A anotação@Bean diz ao framework para fazer a varredura da classe com o contêiner IoC.

Um WebHook anotado com ele funcionará globalmente, interceptando solicitações para cada URL:

@Bean
public class exampleHook implements WebHook {

    @Override
    public boolean before(RouteContext ctx) {
        System.out.println("[exampleHook] called before Route method");
        return true;
    }
}

8.2. Restringindo a um URL

Também podemos interceptar URLs específicos, para executar o código apenas nesses métodos de rota:

Blade.of()
  .before("/user/*", ctx -> System.out.println("Before: " + ctx.uri()));
  .start(App.class, args);

8.3. Middlewares

Os middlewares são WebHooks priorizados, que são executados antes de qualquer WebHook padrão:

public class exampleMiddleware implements WebHook {

    @Override
    public boolean before(RouteContext context) {
        System.out.println("[exampleMiddleware] called before Route method and other WebHooks");
        return true;
    }
}

Eles simplesmente precisam ser definidos sem a anotação@Bean e, em seguida, registrados declarativamente por meio deuse():

Blade.of()
  .use(new exampleMiddleware())
  .start(App.class, args);

Além disso, o Blade vem com os seguintes Middlewares integrados relacionados à segurança, cujos nomes devem ser auto-explicativos:

9. Configuração

In Blade, the configuration is totally optional, because everything works out-of-the-box by convention. No entanto, podemos personalizar as configurações padrão e introduzir novos atributos, dentro do arquivosrc/main/resources/application.properties.

9.1. Lendo a configuração

Podemos ler a configuração de maneiras diferentes, com ou sem a especificação de um valor padrão, caso a configuração não esteja disponível.

  • Durante a inicialização:

Blade.of()
  .on(EventType.SERVER_STARTED, e -> {
      Optional version = WebContext.blade().env("app.version");
  })
  .start(App.class, args);
  • Dentro de uma rota:

@GetRoute("/some-route")
public void someRoute(){
    String authors = WebContext.blade().env("app.authors","Unknown authors");
}
  • Em um carregador personalizado, implementando a interfaceBladeLoader, substituindo o métodoload() e anotando a classe com@Bean:

@Bean
public class LoadConfig implements BladeLoader {

    @Override
    public void load(Blade blade) {
        Optional version = WebContext.blade().env("app.version");
        String authors = WebContext.blade().env("app.authors","Unknown authors");
    }
}

9.2. Atributos de configuração

As diversas configurações já configuradas, mas prontas para serem personalizadas, são agrupadas por tipo e listadasat this address em tabelas de três colunas (nome, descrição, valor padrão). Também podemos nos referir athe translated page, prestando atenção ao fato de que a tradução coloca erroneamente os nomes das configurações em maiúsculas. As configurações reais são totalmente minúsculas.

O agrupamento das definições de configuração por prefixo as torna legíveis de uma só vez em um mapa, o que é útil quando existem muitas delas:

Environment environment = blade.environment();
Map map = environment.getPrefix("app");
String version = map.get("version").toString();
String authors = map.get("authors","Unknown authors").toString();

9.3. Lidando com vários ambientes

Ao implantar nosso aplicativo em um ambiente diferente, talvez seja necessário especificar configurações diferentes, por exemplo, as relacionadas à conexão com o banco de dados. Em vez de substituir manualmente o arquivoapplication.properties, o Blade nos oferece uma maneira de configurar o aplicativo para diferentes ambientes. Podemos simplesmente manterapplication.properties com todas as configurações de desenvolvimento e depoiscreate other files in the same folder, like application-prod.properties, containing only the settings that differ.

Durante a inicialização, podemos especificar o ambiente que queremos usar, e a estrutura mesclará os arquivos usando as configurações mais específicas deapplication-prod.properties e todas as outras configurações do arquivoapplication.properties padrão:

java -jar target/sample-blade-app.jar --app.env=prod

10. Templating

A modelagem no Blade é um aspecto modular. Embora ele integre um mecanismo de modelo muito básico, para qualquer uso profissional das Views, devemos confiar em um mecanismo de modelo externo. Podemos entãochoose an engine from the ones available no repositórioblade-template-engines no GitHub, que sãoFreeMarker,Jetbrick,Pebble eVelocity, ou mesmo criando um wrapper para importar outro modelo de que gostamos.

O autor de Blade sugereJetbrick, outro projeto chinês inteligente.

10.1. Usando o mecanismo padrão

O modelo padrão funciona analisando variáveis ​​de diferentes contextos por meio da notação$\{}:

Hello, ${name}!

10.2. Conectando um motor externo

Mudar para um mecanismo de modelo diferente é muito fácil! Simplesmente importamos a dependência (o invólucro do Blade) do mecanismo:


    com.bladejava
    blade-template-jetbrick
    0.1.3

Neste ponto, é suficiente escrever uma configuração simples para instruir a estrutura a usar essa biblioteca:

@Bean
public class TemplateConfig implements BladeLoader {

    @Override
    public void load(Blade blade) {
        blade.templateEngine(new JetbrickTemplateEngine());
    }
}

Como resultado, agora todos os arquivos emsrc/main/resources/templates/ serão analisados ​​com o novo mecanismo, cuja sintaxe está além do escopo deste tutorial.

10.3. Envolvendo um Novo Motor

Encapsular um novo mecanismo de modelo requer a criação de uma única classe, que deve implementar a interfaceTemplateEngine e substituir o métodorender():

void render (ModelAndView modelAndView, Writer writer) throws TemplateException;

Para este propósito, podemos dar uma olhada emthe code of the actual Jetbrick wrapper para ter uma ideia do que isso significa.

11. Exploração madeireira

O Blade usaslf4j-api como interface de registro.

Também inclui uma implementação de registro já configurada, chamadablade-log. Portanto, não precisamos importar nada; funciona como está, simplesmente definindo umLogger:

private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(LogExample.class);

11.1. Personalizando o registrador integrado

Caso desejemos modificar a configuração padrão, precisamos ajustar os seguintes parâmetros como Propriedades do sistema:

  • Níveis de log (podem ser “rastreamento”, “depuração”, “informações”, “aviso” ou “erro”):

# Root Logger
com.blade.logger.rootLevel=info

# Package Custom Logging Level
com.blade.logger.somepackage=debug

# Class Custom Logging Level
com.blade.logger.com.example.sample.SomeClass=trace
  • Informações exibidas:

# Date and Time
com.blade.logger.showDate=false

# Date and Time Pattern
com.blade.logger.datePattern=yyyy-MM-dd HH:mm:ss:SSS Z

# Thread Name
com.blade.logger.showThread=true

# Logger Instance Name
com.blade.logger.showLogName=true

# Only the Last Part of FQCN
com.blade.logger.shortName=true
  • Logger:

# Path
com.blade.logger.dir=./logs

# Name (it defaults to the current app.name)
com.blade.logger.name=sample

11.2. Excluindo o registrador integrado

Embora ter um criador de logs integrado já configurado seja muito útil para iniciar nosso pequeno projeto, podemos facilmente terminar no caso em que outras bibliotecas importam sua própria implementação de criação de log. E, nesse caso, podemos remover o integrado para evitar conflitos:


    com.bladejava
    blade-mvc
    ${blade.version}
    
        
            com.bladejava
            blade-log
        
    

12. Personalizações

12.1. Tratamento de exceções personalizadas

Um manipulador de exceções também é incorporado por padrão na estrutura. Ele imprime a exceção no console e, seapp.devMode fortrue, o rastreamento de pilha também estará visível na página da web.

No entanto, podemos lidar com uma exceção de uma maneira específica, definindo um@Bean estendendo a classeDefaultExceptionHandler:

@Bean
public class GlobalExceptionHandler extends DefaultExceptionHandler {

    @Override
    public void handle(Exception e) {
        if (e instanceof exampleException) {
            exampleException exampleException = (exampleException) e;
            String msg = exampleException.getMessage();
            WebContext.response().json(RestResponse.fail(msg));
        } else {
            super.handle(e);
        }
    }
}

12.2. Páginas de erro personalizadas

Da mesma forma, os erros404 – Not Found e500 – Internal Server Error são tratados por meio de páginas padrão estreitas.

Podemos forçar a estrutura a usar nossas próprias páginas, declarando-as no arquivoapplication.properties com as seguintes configurações:

mvc.view.404=my-404.html
mvc.view.500=my-500.html

Certamente, essas páginas HTML devem ser colocadas na pastasrc/main/resources/templates.

Dentro do 500, podemos, além disso, recuperar a exceçãomessageestackTrace por meio de suas variáveis ​​especiais:



    
        
        500 Internal Server Error
    
    
        

Custom Error 500 Page

The following error occurred: "${message}"

 ${stackTrace} 

13. Tarefas agendadas

Outra característica interessante da estrutura é a possibilidade de agendar a execução de um método.

Isso é possível anotando o método de uma classe@Bean com a anotação@Schedule:

@Bean
public class ScheduleExample {

    @Schedule(name = "exampleTask", cron = "0 */1 * * * ?")
    public void runScheduledTask() {
        System.out.println("This is a scheduled Task running once per minute.");
    }
}

Na verdade, ele usa as expressões cron clássicas para especificar as coordenadasDateTime. Podemos ler mais sobre eles emA Guide to Cron Expressions.

Posteriormente, podemos explorar os métodos estáticos da classeTaskManager para realizar operações nas tarefas agendadas.

  • Obtenha todas as tarefas agendadas:

List allScheduledTasks = TaskManager.getTasks();
  • Obtenha uma tarefa pelo nome:

Task myTask = TaskManager.getTask("exampleTask");
  • Interrompa uma tarefa por nome:

boolean closed = TaskManager.stopTask("exampleTask");

14. Eventos

Como já foi visto na seção 9.1, é possível ouvir um evento especificado antes de executar algum código personalizado.

O Blade fornece os seguintes eventos prontos para uso:

public enum EventType {
    SERVER_STARTING,
    SERVER_STARTED,
    SERVER_STOPPING,
    SERVER_STOPPED,
    SESSION_CREATED,
    SESSION_DESTROY,
    SOURCE_CHANGED,
    ENVIRONMENT_CHANGED
}

Enquanto os seis primeiros são fáceis de adivinhar, os dois últimos precisam de algumas dicas:ENVIRONMENT_CHANGED nos permite realizar uma ação se um arquivo de configuração for alterado quando o servidor estiver ativo. SOURCE_CHANGED, em vez disso, ainda não foi implementado e está lá apenas para uso futuro.

Vamos ver como podemos colocar um valor na sessão sempre que ela for criada:

Blade.of()
  .on(EventType.SESSION_CREATED, e -> {
      Session session = (Session) e.attribute("session");
      session.attribute("name", "example");
  })
  .start(App.class, args);

15. Implementação de Sessão

Falando sobre a sessão, sua implementação padrão armazena os valores da sessão na memória.

Assim, podemos querer mudar para uma implementação diferente para fornecer cache, persistência ou outra coisa. Vejamos o Redis, por exemplo. Primeiro, precisaríamos criar nosso wrapperRedisSession implementando a interfaceSession, conforme mostradoin the docs for the HttpSession.

Então, seria apenas uma questão de informar ao framework que queremos usá-lo. Podemos fazer isso da mesma maneira que fizemos para o mecanismo de modelo personalizado, com a única diferença de que chamamos o métodosessionType():

@Bean
public class SessionConfig implements BladeLoader {

    @Override
    public void load(Blade blade) {
        blade.sessionType(new RedisSession());
    }
}

16. Argumentos da linha de comando

Ao executar o Blade na linha de comando, há três configurações que podemos especificar para alterar seu comportamento.

Em primeiro lugar, podemos alterar o endereço IP, que por padrão é o loopback local0.0.0.0:

java -jar target/sample-blade-app.jar --server.address=192.168.1.100

Em segundo lugar, também podemos alterar a porta, que por padrão é9000:

java -jar target/sample-blade-app.jar --server.port=8080

Finalmente, como visto na seção 9.3, podemos alterar o ambiente para permitir que um arquivoapplication-XXX.properties diferente seja lido sobre o padrão, que éapplication.properties:

java -jar target/sample-blade-app.jar --app.env=prod

17. Executando no IDE

Qualquer IDE Java moderno pode executar um projeto Blade sem precisar dos plugins Maven. Executar Blade em um IDE é especialmente útil ao executarBlade Demos, exemplos escritos expressamente para mostrar as funcionalidades do framework. Todos eles herdam um pom pai, então é mais fácil deixar o IDE fazer o trabalho, em vez de ajustá-los manualmente para serem executados como aplicativos independentes.

17.1. Eclipse

No Eclipse, é suficiente clicar com o botão direito no projeto e iniciarRun as Java Application, selecionar nossa classeApp e pressionarOK.

O console do Eclipse, no entanto, não exibirá cores ANSI corretamente, exibindo seus códigos em vez disso:

image

Felizmente, instalar a extensãoANSI Escape in Console corrige o problema para sempre:

image

17.2. IntelliJ IDEA

O IntelliJ IDEA trabalha com cores ANSI prontas para uso. Portanto, basta criar o projeto, clicar com o botão direito do mouse no arquivoApp e iniciarRun ‘App.main()' (que equivale a pressionarCtrl+Shift+F10):

image

17.3. Código do Visual Studio

Também é possível usar o VSCode, um IDE popular não centrado em Java, instalando previamente oJava Extension Pack.

PressionarCtrl+F5 executará o projeto:

image

18. Conclusão

Vimos como usar o Blade para criar um pequeno aplicativo MVC.

The entire documentation está disponível apenas no idioma chinês. Apesar de ser difundido principalmente na China, graças aits Chinese origins,the author recentemente traduziu a API e documentou as funcionalidades principais do projeto em inglês emGitHub.

Como sempre, podemos encontrar o código-fonte do exemplo emGitHub.