前一段时间,我编写了自己的定制JSF组件。 但是在那个时候,JSF 1.0仍然是最新的,并且该项目没有使用maven作为构建系统。 因此,我一直想用maven编写一个自定义JSF2组件。 因此,让我们开始:
首先,我们设置一个带有两个模块的Maven项目。 这是父项目的pom.xml文件:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"><modelVersion>4.0.0</modelVersion><groupId>martins-developer-world</groupId><artifactId>jsf-component</artifactId><packaging>pom</packaging><version>0.0.1-SNAPSHOT</version><name>jsf-component Maven Webapp</name><dependencies><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.11</version><scope>test</scope></dependency><dependency><groupId>javax.faces</groupId><artifactId>jsf-api</artifactId><version>2.1</version><scope>provided</scope></dependency><dependency><groupId>com.sun.faces</groupId><artifactId>jsf-impl</artifactId><version>2.2.0</version><scope>provided</scope></dependency><dependency><groupId>javax.servlet</groupId><artifactId>servlet-api</artifactId><version>2.5</version><scope>provided</scope></dependency><dependency><groupId>javax.servlet</groupId><artifactId>jsp-api</artifactId><version>2.0</version><scope>provided</scope></dependency><dependency><groupId>javax.servlet</groupId><artifactId>jstl</artifactId><version>1.2</version><scope>provided</scope></dependency></dependencies><build><finalName>jsf-component</finalName></build><modules><module>jsf-component-webapp</module><module>jsf-component-impl</module></modules>
</project>
如您所见,我们在顶级pom.xml中添加了JSF依赖关系,以便我们在子模块中继承它们。 因为我们将使用JBoss Application Server测试我们的Web应用程序,所以我们必须设置要提供的Maven依赖项的范围,以便我们的war文件和组件jar不会部署它们。 我们组件的实现将驻留在jsf-component-impl中,因此我们选择jar作为此模块的包装类型:
<?xml version="1.0"?>
<projectxsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><modelVersion>4.0.0</modelVersion><parent><groupId>martins-developer-world</groupId><artifactId>jsf-component</artifactId><version>0.0.1-SNAPSHOT</version></parent><artifactId>jsf-component-impl</artifactId><name>jsf-component-impl</name><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties><dependencies></dependencies>
</project>
现在,让我们实现一个扩展UIOutput的Java类。 之所以选择UIOutput是因为,第一步,我只想实现一个简单的helloWorld标签,该标签将在span元素中打印作为属性给出的名字和姓氏。 由于此组件未收到任何输入,因此UIOutput适当:
package martins.developer.world.jsf.component.impl;import java.io.IOException;import javax.faces.application.ResourceDependencies;
import javax.faces.application.ResourceDependency;
import javax.faces.component.FacesComponent;
import javax.faces.component.UIOutput;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;@ResourceDependencies({ @ResourceDependency(name = "css/jsf-component.css", target = "head") })
@FacesComponent("HelloWorld")
public class HelloWorldComponent extends UIOutput {private static final String COMPONENT_FAMILY = "martins.developer.world.jsf.component.helloWorld";private enum PropertyKeys {firstName, lastName};@Overridepublic String getFamily() {return COMPONENT_FAMILY;}@Overridepublic void encodeBegin(FacesContext context) throws IOException {ResponseWriter writer = context.getResponseWriter();writer.startElement("span", this);writer.writeAttribute("class", "helloWorldClass", "");writer.writeText(String.format("Hello %s %s!", getFirstName(), getLastName()), "");writer.endElement("span");}public String getFirstName() {return (String) getStateHelper().eval(PropertyKeys.firstName, "???firstName???");}public void setFirstName(String firstName) {getStateHelper().put(PropertyKeys.firstName, firstName);}public String getLastName() {return (String) getStateHelper().eval(PropertyKeys.lastName, "???lastName???");}public void setLastName(String lastName) {getStateHelper().put(PropertyKeys.lastName, lastName);}
}
getFamily()方法是我们必须实施的唯一方法。 这里有趣的是encodeBegin()方法。 这是我们实现span标签的地方。 因为它应该具有CSS类属性,所以我们使用Writer的writeAttribute()方法添加它。 使用getter和setter方法将所得JSF标记的两个属性建模为简单属性。 这些getter和setter的实现使用JSF 2.0中提供的StateHelper。 在encodeBegin()中,我们使用吸气剂来检索用户给定的值。
有趣的是@ResourceDependencies注释。 有了这个注释,我们可以告诉JSF框架,我们有一些依赖的文件。 在这种情况下,这是一个CSS文件,位于文件夹src / main / resources / META-INF / resources / css中。
注释@FacesComponent在JSF框架的引导过程中注册了此组件。 给定名称在taglib文件中用于引用此类:
<?xml version="1.0"?>
<facelet-taglib xmlns="http://java.sun.com/xml/ns/javaee"><namespace>http://martinsdeveloperworld.wordpress.com</namespace><tag><tag-name>helloWorld</tag-name><component><component-type>HelloWorld</component-type></component></tag>
</facelet-taglib>
在src / main / resources / META-INF下的这个taglib文件中,我们定义了可用的组件,这里仅是helloWorld标签。 标签的属性是从Java类的属性派生的。
最后,我们要测试我们新创建的组件。 为此,我们设置了一个简单的JSF2 webapp项目,并将以下代码段添加到web.xml中,以声明我们要使用自定义组件:
<context-param><param-name>facelets.FACELETS_LIBRARIES</param-name><param-value>/META-INF/jsf-component.taglib.xml</param-value></context-param>
现在,我们可以编写一个简单的JSF页面,该页面引用我们的新标记:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"xmlns:f="http://java.sun.com/jsf/core"xmlns:h="http://java.sun.com/jsf/html"xmlns:mdw="http://martinsdeveloperworld.wordpress.com">
<h:head>
<title>Hello JSF 2!</title>
</h:head>
<h:body><h2>Hello World!</h2><mdw:helloWorld firstName="Martin" lastName="Developer"/>
</h:body>
</html>
当我们将此应用程序部署到JBoss Application Server并调用相应的URL时,我们将获得以下HTML输出:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><title>Hello JSF 2!</title><link type="text/css" rel="stylesheet" href="/jsf-component-webapp/faces/javax.faces.resource/css/jsf-component.css" />
</head>
<body><h2>Hello World!</h2><span class="helloWorldClass">Hello Martin Developer!</span>
</body>
</html>
显然,我们可以看到带有CSS类和输出的span标签。 CSS文件在HTML文档的开头引用。
- 整个项目的资源可以在GitHub上找到: https : //github.com/siom79/jsf-component 。
翻译自: https://www.javacodegeeks.com/2013/11/implementing-a-custom-jsf-2-0-component-with-maven.html