Rocker es un motor de plantilla rápido optimizado de Java 8+, cerca de cero copias, que produce plantillas de objetos Java lisos de escrito estáticamente que se compilan junto con el resto de su proyecto. No más tiempo de "calentamiento" en la producción, lógica lenta basada en la reflexión o sorpresas desagradables que deberían haber sido capturadas durante el desarrollo.
Escriba sus plantillas usando una sintaxis intuitiva sin etiqueta con expresiones Java estándar para lógica, iteración y valores. ¿Usar Rocker's Special ?
Operador de presencia para evaluación nula a sabor. Todo el trabajo pesado es realizado por el analizador de rockeros durante el desarrollo, lo que mantiene las dependencias del tiempo de ejecución a solo un puñado de clases. Rocker analizará sus plantillas y generará archivos de origen Java bien documentados (para que pueda inspeccionar y comprender fácilmente cómo funciona).
Incluye las siguientes características:
?
El operador de presencia extiende la sintaxis para el manejo simplificado de valores nulos.Proyecto de Fizzed, Inc. (Siga en Twitter: @fizzed_inc)
Desarrollar y mantener proyectos de OpenSource requiere un tiempo significativo. Si encuentra este proyecto útil o necesita soporte comercial, nos encantaría chatear. Envíenos un correo electrónico a [email protected]
Los patrocinadores del proyecto pueden incluir los siguientes beneficios:
Basado en el siguiente punto de referencia de plantilla, Rocker es el claro ganador. ~ 250% más rápido que Freemarker al tiempo que requiere órdenes de magnitud menos memoria.
La mayoría de las plantillas se utilizan para sitios web, por lo que aquí hay una muestra rápida que muestra cómo funcionan las plantillas de balancín y pueden llamarse entre sí durante el proceso de renderizado. Cree una plantilla que contenga un encabezado y un pie de página común, así como un marcador de posición para el contenido del cuerpo. Crear plantilla src/main/java/views/main.rocker.html
@args (String title, RockerBody content)
< html >
< head >
< title > @title </ title >
</ head >
< body >
@content
</ body >
</ html >
La plantilla que planeamos mostrar a un usuario hará su contenido dentro del contexto del pie de página común/encabezado. En términos de Java, está pasando un bloque de código de representación para ser ejecutado dentro de otra plantilla. Crear plantilla src/main/java/views/index.rocker.html
@args (String message)
@views.main.template("Home") - > {
< h1 > Hello @message! </ h1 >
}
Oye, ¿qué pasa con el argumento RockerBody content
? Lo cubrimos con más detalle en la lectura de sintaxis, pero por ahora solo entendemos que es el único tipo especial de argumento e instruye al balancín que una plantilla espera que se le pase un "cuerpo".
El analizador de rocker generará un archivo fuente de Java para cada plantilla. Serán target/generated-sources/rocker/views/main.java
y target/generated-sources/rocker/views/index.java
. En su aplicación, puede representar la plantilla de índice como.
static public void main ( String [] args ) {
String output = views . index . template ( "World" )
. render ()
. toString ();
}
La salida es igual a:
< html >
< head >
< title > Home </ title >
</ head >
< body >
< h1 > Hello World! </ h1 >
</ body >
</ html >
Una vez que genere las fuentes de Java y consulte el código, es simple ver cómo funciona esto. La clase Views.index crea una instancia de plantilla de visión. Mayor y entrega de manualización hacia ella, al tiempo que pasa un bloque de sí mismo que renderizará cuando las vistas llamen a la variable @content
. La sintaxis es idéntica a cómo se define un Lambda en Java 8 (implementado con Lambdas para Java 8 y clases internas anónimas para Java 6/7). Rocker hace una serie de cosas detrás de escena para asegurarse de que las plantillas que creen otras plantillas compartan el mismo contexto de renderizado (búfer de salida, contexto específico de aplicación/estado implícito).
Consulte el archivo Syntax.md para obtener una inmersión profunda integral en la sintaxis del balancín.
Rocker tiene una creciente lista de marcos con los que se ha integrado sin problemas. Si desea vincular a un nuevo marco agregado, presente un problema o envíe un PR:
Estática (texto plano) para cada plantilla de balancín se almacena (por defecto) internamente como matrices de bytes estáticas ya convertidas en su charset objetivo (por ejemplo, UTF-8). Cuando se representa una plantilla, las matrices de bytes estáticas se reutilizan en todas las solicitudes. Rocker ofrece una corriente de salida optimizada que almacena una vista compuesta (lista vinculada) de las matrices de bytes reutilizadas más su contenido dinámico. Dado que las plantillas consisten principalmente en contenido estático que se convierte en el mismo charset una y otra vez, en lugar de asignar una nueva memoria, copiar ese contenido y luego convertirlo en su carro de destino para cada solicitud: el rockero simplemente usa un puntero una y otra vez. de nuevo. Esta técnica produce renders rápidos y de memoria eficientes.
Supongamos que tiene una plantilla que consta de 9000 bytes de texto estático simple y 1000 bytes de contenido dinámico. Sin esta optimización, requeriría ~ 100 MB de memoria para el servicio 10000 solicitudes (10000 bytes x 10000 solicitudes). Con esta optimización, requeriría ~ 10 MB de memoria para el servicio 10000 solicitudes (1000 bytes x 10000 solicitudes). Además de la memoria inferior, también corta 90 MB de copias de memoria y 90 MB de conversiones de bytes UTF-8 String->. Una optimización bastante útil.
Todo es compilado por el compilador de su proyecto junto con su otro código fuente de Java. Cualquier código dinámico en su plantilla se convierte en última instancia en Java estándar y compilado. No se usa reflexión.
La versión 0.10.0 introdujo el soporte para plantillas de recarga en caliente durante el desarrollo. La recarga en caliente le permite modificar el código fuente de la plantilla, guardarlo y tener los cambios activos en la siguiente solicitud, sin tener que reiniciar su JVM. Rocker ofrece dos sabores diferentes de recarga en caliente para flexibilidad.
La característica principal de las plantillas de rockeros es que sus plantillas se compilan en tiempo de compilación para su uso, argumentos, lógica, etc. por el compilador Java.
En la versión 0.10.0, la estructura subyacente de una plantilla se modificó donde una plantilla genera dos clases subyacentes. Cada plantilla genera una clase de modelo (su interfaz) y una clase de implementación (su renderizador). Su aplicación solo interactuará directamente con el modelo, lo que permitirá que el rocker recompire dinámicamente y vuelva a cargar la clase de implementación.
El principal beneficio del sabor uno es que su código de aplicación sigue siendo el mismo y es verificado por el tiempo de compilación por el compilador Java, mientras que el contenido de la plantilla puede ser modificado y recargado automáticamente en tiempo de ejecución. Solo en el caso en que realmente cambie los argumentos de la plantilla, necesitará reiniciar su solicitud.
Si prefiere la conveniencia de plantillas completamente dinámicas, el sabor dos admite la recarga en caliente de la clase de modelo de plantilla (su interfaz) y la clase de implementación (su renderizador). Su aplicación perderá parte de la verificación de tiempo de compilación y un pequeño éxito de rendimiento, pero obtendrá la comodidad de que todo sea recargable. La forma en que su aplicación usará plantillas también es diferente.
import com . fizzed . rocker . Rocker
...
// dynamic interfaces, dynamic implementation
String rendered = Rocker . template ( "views/index.rocker.html" )
. bind ( "val" , "ValueA" )
. render ()
. toString ();
La ruta de la plantilla y los argumentos se verán de tiempo de ejecución. Tenga en cuenta que cada valor vinculable debe coincidir con el nombre y el tipo declarado en su plantilla.
En caso de que su mapa vinculable pueda contener más valores que los requeridos hay un enlace relajado disponible. La alternativa relajada no fallará si un atributo es adicional a la lista requerida. Por ejemplo:
@args (String name)
Hello ${name}!
Se volverá en modo relajado como:
Map map = new HashMap ();
map . put ( "name" , "Joe" );
map . put ( "age" , 42 );
Rocker . template ( "views/hello.rocker.html" )
. relaxedBind ( map )
. render ();
// -> Hello Joe!
El soporte para la recarga en caliente se agrega a sus plantillas generadas de forma predeterminada en la versión 0.10.0. Si desea deshabilitar el soporte, configure la configuración/propiedad del sistema rocker.optimize
. Optimice a True durante su compilación. Dado que el código está presente en sus plantillas de forma predeterminada, simplemente necesita encenderlo en tiempo de ejecución.
La dependencia rocker-compiler
debe agregarse a su construcción. Esta dependencia solo debe estar presente durante el desarrollo y puede eliminarse en la producción. En Maven, esto significa que querrá agregar la dependencia en el alcance provided
.
< dependency >
< groupId >com.fizzed</ groupId >
< artifactId >rocker-compiler</ artifactId >
< version >2.1.0</ version >
< scope >provided</ scope >
</ dependency >
Active la recarga caliente en tiempo de ejecución. Puede activar la recarga en caliente, ya sea con una propiedad del sistema o mediante programación. Para activar la recarga en caliente con una propiedad del sistema en Maven.
mvn -Drocker.reloading=true ...rest of args...
Alternativamente, puede activar la recarga en caliente programáticamente.
import com . fizzed . rocker . runtime . RockerRuntime
...
RockerRuntime . getInstance (). setReloading ( true );
Hay un ejemplo simple que demuestra una recarga caliente en acción. Este proyecto usa Blaze para ayudar a las tareas de guión. Ejecutar lo siguiente
java -jar blaze.jar hot_reload
Apunte su navegador a http: // localhost: 8080
Luego modifique y guarde rocker-test-reload/src/test/java/views/index.rocker.html
y actualice su navegador.
Rocker consta de dos componentes: el analizador/generador y el tiempo de ejecución. Para usar rocker en su proyecto, agregue la dependencia del tiempo de ejecución a su aplicación, luego habilite el analizador en su herramienta de compilación, seguido de la creación de su primera plantilla.
Rocker se publica para Maven Central. Para agregar como dependencia en Maven:
< dependency >
< groupId >com.fizzed</ groupId >
< artifactId >rocker-runtime</ artifactId >
< version >2.1.0</ version >
</ dependency >
<!-- for hot-reloading support only during development -->
< dependency >
< groupId >com.fizzed</ groupId >
< artifactId >rocker-compiler</ artifactId >
< version >2.1.0</ version >
< scope >provided</ scope >
</ dependency >
Para agregar como dependencia en Gradle:
repositories {
mavenCentral()
}
dependencies {
compile group : ' com.fizzed ' , name : ' rocker-runtime ' , version : ' 2.1.0 '
// add rocker-compiler dependency as needed
}
Rocker apoya a Maven y Gradle fuera de la caja.
Agregue lo siguiente a su POM
< build >
< plugins >
< plugin >
< groupId >com.fizzed</ groupId >
< artifactId >rocker-maven-plugin</ artifactId >
< version >2.1.0</ version >
< executions >
< execution >
< id >generate-rocker-templates</ id >
< phase >generate-sources</ phase >
< goals >
< goal >generate</ goal >
</ goals >
</ execution >
</ executions >
</ plugin >
</ plugins >
</ build >
Por defecto, el rocker procesará recursivamente cualquier archivo de plantilla que termine con .rocker.html
en src/main/java
. El directorio que se guarda la plantilla se convertirá en el paquete Java estándar en los que se colocarán las clases Java generadas. Los archivos de origen Java generados se guardarán en target/generated-sources/rocker
. El complemento se encargará de agregar este directorio generado a la raíz de sus fuentes.
Se admiten las siguientes propiedades:
templateDirectory
es el directorio base para comenzar de manera recursiva desde la ubicación y el análisis de los archivos de plantilla. El package
Java se generará una plantilla para utilizará este directorio como base. Entonces, si tiene ${templateDirectory}/views/mytemplate.rocker.html
, el rocker generará ${outputDirectory}/views/mytemplate.java
. El valor predeterminado a ${project.build.sourceDirectory}
.
outputDirectory
es el directorio que el analizador generará fuentes para plantillas. El valor predeterminado a ${project.build.directory}/generated-sources/rocker
classDirectory
es el directorio que la función de recarga en caliente compilará (re) clases en tiempo de ejecución. El valor predeterminado a ${project.build.outputDirectory}
failOnError
determina si algún error de análisis/generación hace que Maven falle. El valor predeterminado es verdadero.
skip
determina si se debe omitir la ejecución del complemento. El valor predeterminado es falso.
touchFile
es el archivo para "tocar" después de generar con éxito fuentes Java. Útil para activar otro flujo de trabajo. Muchos IDE no recargarán automáticamente las fuentes generadas para su finalización de código a menos que se le digan explícitamente que recarga o si se cambia el archivo Maven pom.xml. Por lo tanto, este valor se establece de forma predeterminada en ${basedir}/pom.xml
. Por lo general, es inofensivo mantener esto habilitado.
skipTouch
deshabilita TouchFile. El valor predeterminado es falso.
addAsSources
agregará el Directory de salida a Maven como fuentes que se compilarán. El valor predeterminado es verdadero.
addAsTestSources
agregará el Directory de salida a Maven como fuentes de prueba que se compilarán. El valor predeterminado es falso. Si es cierto, esto se evalúa antes de admitSources y efectivamente le dice a MAVEN que compile sus plantillas como código de prueba.
También se admiten las siguientes propiedades, pero es importante comprender que estas son esencialmente anulaciones de transferencia al analizador y todos están predeterminados al valor predeterminado del rockero.
javaVersion
es la versión Java con la que le gustaría que sus plantillas compilen y tiempo de ejecución compatible. El valor predeterminado a la versión Java del JVM ejecutando Maven (por ejemplo, "1.8").
optimize
determina si el soporte de recarga en caliente se eliminará de las plantillas generadas. Falso por defecto.
extendsClass
es la clase que deberían extender todas las implementaciones de plantillas. Útil para las clases intermedias específicas de la aplicación que desea extender todas las plantillas. El valor predeterminado es el valor predeterminado del rocker.
extendsModelClass
es la clase que todos los modelos de plantilla deberían extender. Útil para las clases intermedias específicas de la aplicación que desea extender todos los modelos de plantilla. El valor predeterminado es el valor predeterminado del rocker.
plainTextStrategy
es la estrategia utilizada para integrar el texto plano como parte de las plantillas. El valor predeterminado es static_byte_arrays_via_unloaded_class, pero si necesita compatibilidad GRAALVM, probaría static_byte_arrays
discardLogicWhitespace
determina si se debe descartar el espacio en blanco en plantillas que se determina que es solo una parte de los bloques de lógica/control. Ayuda a que el contenido renderizado se vea más profesional, al tiempo que mantiene intacto gran parte de su formato. El valor predeterminado es el valor predeterminado del rocker.
targetCharset
es el carro de destino para la salida de plantilla. El valor predeterminado es el valor predeterminado del rocker.
suffixRegex
es la expresión regular que se puede usar para encontrar plantillas para analizar. El valor predeterminado es el valor predeterminado del rocker.
markAsGenerated
agrega una anotación @Generated a las clases generadas. La retención es de clase para que la anotación pueda ser utilizada por herramientas que solo dependen de los archivos de clase y no en el código fuente. El valor predeterminado es el valor predeterminado del rocker.
Gracias a @victory
y @mnlipp
por contribuir con el complemento de Gradle. @etiennestuder
también tenía un complemento de gradle alternativo que es posible que también desee considerar. Rocker's Gradle Plugin se publica en Gradle.org. Simplemente agregue lo siguiente a su script de compilación:
plugins {
id " com.fizzed.rocker " version " 2.1.0 "
}
sourceSets {
main {
rocker {
srcDir( ' src/main/java ' )
}
}
}
rocker {
// (All settings are shown with their defaults)
//
// Skips building templates all together
skip false
// Base directory for generated java sources, actual target is sub directory
// with the name of the source set. The value is passed through project.file().
outputBaseDirectory = " $b uildDir /generated-src/rocker "
// Base directory for the directory where the hot reload feature
// will (re)compile classes to at runtime (and where `rocker-compiler.conf`
// is generated, which is used by RockerRuntime.getInstance().setReloading(true)).
// The actual target is a sub directory with the name of the source set.
// The value is passed through project.file().
classBaseDirectory = " $b uildDir /classes "
failOnError true
skipTouch true
// must not be empty when skipTouch is equal to false
touchFile " "
javaVersion ' 1.8 '
extendsClass null
extendsModelClass null
optimize null
discardLogicWhitespace null
targetCharset null
suffixRegex null
postProcessing null
markAsGenerated null
}
La sintaxis de la plantilla se describe en detalle a continuación, pero por ahora crea un nuevo archivo en ${templateDirectory}/views/HelloWorld.rocker.html
@*
Example of hello world
*@
@args (String message)
Hello @message!
Es hora de compilar su proyecto y comenzar a usar la plantilla. Puedes llamarlo desde Java así:
static public void main ( String [] args ) {
String output = views . HelloWorld
. template ( "World" )
. render ()
. toString ();
}
Rocker está muy optimizado (por defecto) a las plantillas de salida como matrices de bytes. El RockerOutput
predeterminado a una plantilla a la que será del tipo com.fizzed.rocker.runtime.ArrayOfByteArraysOutput
. Esta es una excelente opción para matrices de bytes o IO asincrónico. Sin embargo, el marco tiene la capacidad de representación optimizada a cadenas (u otras salidas personalizadas).
Para renderizar eficientemente a una cadena:
import com . fizzed . rocker . runtime . StringBuilderOutput ;
static public void main ( String [] args ) {
StringBuilderOutput output = views . HelloWorld
. template ( "World" )
. render ( StringBuilderOutput . FACTORY );
String text = output . toString ();
}
Para renderizar eficientemente a una salida:
import com . fizzed . rocker . runtime . OutputStreamOutput ;
static public void main ( String [] args ) throws Exception {
final OutputStream os = new FileOutputStream ( new File ( "test" ));
OutputStreamOutput output = views . HelloWorld
. template ( "World" )
. render (( contentType , charsetName ) -> new OutputStreamOutput ( contentType , os , charsetName ));
}
Tenga en cuenta que si hay una excepción durante el renderizado, la salida de salida tendría una plantilla parcial representada (hasta el punto de la excepción). En la mayoría de los casos, sería mejor renderizar al predeterminado com.fizzed.rocker.runtime.ArrayOfByteArraysOutput
y escribir su búfer de las matrices de bytes directamente a su salida.
Hay numerosas demostraciones de rockeros en acción. Desde las plantillas de análisis en un modelo hasta enviar resultados asincrónicos en un servidor HTTP. Este proyecto usa Blaze para ayudar a las tareas de guión. Ejecute lo siguiente para una lista completa:
java -jar blaze.jar -l
Copyright (C) 2015+ Fizzed, Inc.
Este trabajo tiene licencia bajo la licencia Apache, versión 2.0. Vea la licencia para más detalles.