Como crear un custom taglib en Liferay
Para usar reCAPTCHAv3
Un taglib es un conjuntos de etiquetas que podemos usar en los ficheros JSP, similares en apariencia a una etiqueta html o xml, a las que podemos añadir una funcionalidad específica normalmente repetitiva que hará nuestro código más legible.
En Liferay 7, como no podía ser de otra manera, podemos añadir taglibs creando un module osgi con una configuración especial que permitirá el uso de estos taglibs entre los distintos modules.
Por seguir el hilo del anterior post donde explicaba como usar reCAPTCHAv3 en Liferay 7.1, vamos a crear en este post un taglib que simplificará el código que tenemos que poner en nuestros .jsp para usar esta nueva tecnología de Google.
Crear un custom taglib
Lo que debemos hacer es crear un nuevo module osgi (yo lo he llamado recaptcha-taglib) y dentro de él vamos a hacer varias cosas:
Crear el package con las clases java necesarias
Aquí vamos a definir el componente osgi y la configuración del Tag. En la configuración del Tag es donde indicamos los parámetros de entrada, en este caso un solo atributo action, y el .jsp a renderizar a la hora de mostrarse en pantalla
@Component(immediate = true) public class ServletContextUtil { public static final ServletContext getServletContext() { return _instance._getServletContext(); } @Activate protected void activate() { _instance = this; } @Deactivate protected void deactivate() { _instance = null; } @Reference( target = "(osgi.web.symbolicname=com.miguelangeljulvez.recaptcha.taglib)", unbind = "-" ) protected void setServletContext(ServletContext servletContext) { _servletContext = servletContext; } private ServletContext _getServletContext() { return _servletContext; } private static ServletContextUtil _instance; private ServletContext _servletContext; }
public class CaptchaTag extends IncludeTag { @Override public void setPageContext(PageContext pageContext) { super.setPageContext(pageContext); setServletContext(ServletContextUtil.getServletContext()); } public void setAction(String action) { _action = action; } @Override protected void cleanUp() { super.cleanUp(); _action = null; } @Override protected String getPage() { return _PAGE; } @Override protected void setAttributes(HttpServletRequest request) { request.setAttribute("maj-captcha:recaptcha:action", _action); } private static final String _PAGE = "/recaptcha/page.jsp"; private String _action; }
Crear los .jsp de nuestro taglib
Aquí indicamos el código html que debe mostrar este nuevo taglib. Como ves, este es el mismo texto prácticamente que en el post anterior añadíamos “manualmente”
<c:if test="<%= captchaEnabled %>"> <input type="hidden" name="g-recaptcha-response" id="g-recaptcha-response" value="" /> <input type="hidden" name="g-recaptcha-response-action" id="g-recaptcha-response-action" value="<%=action%>" /> <script data-senna-track="temporary"> grecaptcha.ready(function() { grecaptcha.execute('<%= captchaConfiguration.reCaptchaPublicKey() %>', {action: '<%=action%>'}).then(function(token) { $('#g-recaptcha-response').val(token); }); }); </script> </c:if>
Crear el fichero .tld que define el taglib
<?xml version="1.0"?> <taglib version="2.1" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-jsptaglibrary_2_1.xsd" > <tlib-version>1.0</tlib-version> <short-name>maj-captcha</short-name> <uri>http://miguelangeljulvez.com/tld/recaptcha</uri> <tag> <description>Crea los elementos necesarios para usar reCAPTCHAv3</description> <name>recaptcha</name> <tag-class>com.miguelangeljulvez.recaptcha.taglib.servlet.taglib.CaptchaTag</tag-class> <body-content>JSP</body-content> <attribute> <description>La action a supervisar por el captcha</description> <name>action</name> <required>true</required> <rtexprvalue>true</rtexprvalue> </attribute> </tag> </taglib>
Aquí lo importantes es que el tag-class coincida con la ruta a la clase de configuración del Tag
Configurar el bnd.bnd para exportar este taglib
Bundle-Name: reCAPTCHA Taglib Bundle-SymbolicName: com.miguelangeljulvez.recaptcha.taglib Bundle-Version: 1.0.0 Export-Package: com.miguelangeljulvez.recaptcha.taglib Provide-Capability: osgi.extender;osgi.extender="jsp.taglib";uri="http://miguelangeljulvez.com/tld/recaptcha";version:Version="${Bundle-Version}" Web-ContextPath: /recaptcha-taglib
Aquí lo importante es que el valor del campo uri coincida con el valor definido en el .tld
De esta manera, ahora para poder usar reCAPTCHAv3 en nuestros desarrollos lo único que tenemos que hacer es lo siguiente
Añadir la nueva dependencia al portlet del formulario
compileOnly project(":modules:com.miguelangeljulvez.recaptcha:recaptcha-taglib")
Añadir el nuevo taglib a nuestro formulario
<%@ taglib prefix="maj" uri="http://miguelangeljulvez.com/tld/recaptcha" %> <aui:form action="${addContactoURL}" method="post" name="fm"> <liferay-ui:error exception="<%= CaptchaTextException.class %>" message="text-verification-failed" /> <liferay-ui:error exception="<%= CaptchaConfigurationException.class %>" message="a-captcha-error-occurred-please-contact-an-administrator" /> <liferay-ui:error exception="<%= CaptchaException.class %>" message="a-captcha-error-occurred-please-contact-an-administrator" /> <aui:input type="textarea" name="message" label="message" /> <maj:recaptcha action="contacto" /> <aui:button name="submit" type="submit" value="Enviar"/> </aui:form>
Verificar el captcha recibido
public void addContacto(ActionRequest actionRequest, ActionResponse actionResponse) { //Recoger parámetros y validar try { CaptchaUtil.check(actionRequest); //Llamar al backend para guardar el contacto } catch (CaptchaConfigurationException e) { SessionErrors.add(actionRequest, CaptchaConfigurationException.class.getName()); } catch (CaptchaTextException e) { SessionErrors.add(actionRequest, CaptchaTextException.class.getName()); } catch (CaptchaException e) { SessionErrors.add(actionRequest, CaptchaException.class.getName()); } }