跳至主要内容

JSF 2.3: UIData improvements

UIData improvements

In JSF 2.3, <h:dataTable/> and <ui:repeat /> support Iterable and Map.

Iterable example

Let's create a simple demo to try it.
The backing bean.
@Model
public class IterableBean {
    
    @Inject Logger LOG;

    private Iterable data = Arrays.asList("javaee 8", "jsf 2.3");

    public Iterable getData() {
        LOG.log(Level.INFO, "called IterableBean.getData");
        return data;
    }

}
And the faclets template.
<!DOCTYPE html>
<html lang="en" 
      xmlns="http://www.w3.org/1999/xhtml"
      xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
      xmlns:f="http://xmlns.jcp.org/jsf/core"
      xmlns:h="http://xmlns.jcp.org/jsf/html"
      >
    <f:view>
        <h:head>
            <title>JSF 2.3: DataModel Sample</title>
        </h:head>
        <h:body>
            <h1>JSF 2.3: Iterable interface Sample</h1>

            <h2> h:dataTable Iterable interface</h2>
            <h:dataTable var="entry" value="#{iterableBean.data}">
                <h:column>#{entry}</h:column>
            </h:dataTable>
            <h2> ui:repeat Iterable interface</h2>
            <ui:repeat var="item" value="#{iterableBean.data}">
                Item: #{item}
            </ui:repeat>
        </h:body> 
    </f:view>
</html>

Map example

The backing bean.
@Model
public class MapBean {

    @Inject
    Logger LOG;

    private Map<Integer, String> data = new HashMap<>();

    public Map<Integer, String> getData() {
        LOG.log(Level.INFO, "called MapBean.getData");
        data.put(1, "java ee 8");
        data.put(2, "jsf 2.3");
        return data;
    }

}
And the facelets template.
<!DOCTYPE html>
<html lang="en" 
      xmlns="http://www.w3.org/1999/xhtml"
      xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
      xmlns:f="http://xmlns.jcp.org/jsf/core"
      xmlns:h="http://xmlns.jcp.org/jsf/html"
      >
    <f:view>
        <h:head>
            <title>JSF 2.3: DataModel Sample</title>
        </h:head>
        <h:body>
            <h1>JSF 2.3:Map interface Sample</h1>

            <h2> UIRepeat: Map interface</h2>
            <ui:repeat var="entry" value="#{mapBean.data}">
                Key: #{entry.key}
                Value: #{entry.value}
            </ui:repeat>

            <h2>DataTable: Map Interface</h2>
            <h:dataTable var="entry" value="#{mapBean.data}">
                <h:column>#{entry.key}</h:column>
                <h:column>#{entry.value}</h:column>
            </h:dataTable>
        </h:body> 
    </f:view>
</html>

Iteration without backing data

In former versions, when you want to iterate a number collection from 0 to 10, you have to use c:forEach which from legacy JSP taglibs.
Now the new ui:repeat added this feature finally.
<ui:repeat begin="0" end="10" step="2" var="i">
 #{i}<br />
</ui:repeat>

Custom DataModel

JSF 2.3 provides a new @FacesDataModel to simplfy the customization of your own DataModel.
The backing bean.
@Model
public class CustomBean {

    @Inject
    Logger LOG;

    public UserData getUserData() {
        LOG.log(Level.INFO, "called CustomBean.getUserData");

        List<User> data = IntStream.of(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
                .mapToObj(i -> new User("first " + i, "last " + i))
                .collect(Collectors.toList());

        return new UserData(data);
    }

}
UserData is just a POJO which wraps a list of User.
public class UserData {
    List<User> users = new ArrayList<>();

    public UserData() {
    }
    
    public UserData(List<User> users) {
        this.users = users;
    }
    
    public List<User> getUsers() {
        return users;
    }

    public void setUsers(List<User> users) {
        this.users = users;
    }
   
}
public class User implements Serializable {

    private String firstName;
    private String lastName;

    public User(String firstName, String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    @Override
    public String toString() {
        return "User{" + "firstName=" + firstName + ", lastName=" + lastName + '}';
    }

}
The facelets template.
<ui:repeat value="#{customBean.userData}" var="item">
 User : #{item}<br />
</ui:repeat>
We use UserData as UIRepeat backing data, it is not supported in JSF by default. Let's fill the gap via custom @FacesDataModel class.
@FacesDataModel(forClass = UserData.class)
public class UserDataModel extends DataModel<User> {

    UserData data = null;
    int index = 0;

    public UserDataModel() {
        this(null);
    }

    public UserDataModel(UserData data) {
        this.data = data;
    }

    @Override
    public boolean isRowAvailable() {
        return this.index >= 0 && this.index < this.getRowCount();
    }

    @Override
    public int getRowCount() {
        return this.data != null ? this.data.getUsers().size() : 0;
    }

    @Override
    public User getRowData() {
        if (this.index >= 0 && this.index < this.getRowCount()) {
            return this.data.getUsers().get(this.index);
        }

        return null;
    }

    @Override
    public int getRowIndex() {
        return this.index;
    }

    @Override
    public void setRowIndex(int rowIndex) {
        this.index = rowIndex;
    }

    @Override
    public Object getWrappedData() {
        return this.data;
    }

    @Override
    public void setWrappedData(Object data) {
        this.data = (UserData) data;
    }

}
Run this application on Glassfish, open your browser and navigate to http://localhost:8080/jsf-data-model/custom-datamodel.faces.
custom datamodel
Grab the source codes from my github account, and have a try.

评论

此博客中的热门博文

Build a Reactive application with Angular 5 and Spring Boot 2.0

I have created a post to describe Reactive programming supports in Spring 5 and its subprojects, all codes of this article are updated the latest Spring 5 RELEASE, check spring-reactive-sample under my Github account.
In this post, I will create a simple blog system, including:
A user can sign in and sign out.An authenticated user can create a post.An authenticated user can update a post.Only the user who has ADMIN role can delete a post.All users(including anonymous users) can view post list and post details.An authenticated user can add his comments to a certain post. The backend will be built with the latest Spring 5 reactive stack, including:
Spring Boot 2.0, at the moment the latest version is 2.0.0.M7Spring Data MongoDB supports reactive operations for MongoDBSpring Session adds reactive support for WebSessionSpring Security 5 aligns with Spring 5 reactive stack The frontend is an Angular based SPA and it will be generated by Angular CLI.
The source code is hosted on Github, …

Activating CDI in JSF 2.3

Activating CDI in JSF 2.3 When I upgraed my Java EE 7 sample to the newest Java EE 8, the first thing confused me is the CDI beans are not recoganized in Facelects template in a JSF 2.3 based web applicaiton, which is working in the development version, but in the final release version, they are always resolved as null. I filed an issue on Mojarra and discussed it with the developers from communities and the JSF experts.
According to the content of README, In a JSF 2.3 application, to activate CDI support, declaring a 2.3 versioned faces-config.xml and adding javax.faces.ENABLE_CDI_RESOLVER_CHAIN in web.xml is not enough, you have to declare @FacesConfig annotated class to enable CDI.
Here is the steps I created a workable JSF 2.3 applicatoin in Java EE 8.
Create a Java web application, this can be done easily by NetBeans IDE, or generated by Maven archetype, for exmaple.
$ mvn archetype:generate -DgroupId=com.example -DartifactId=demo -DarchetypeArtifactId=maven-archetype-w…

JSF 2.3:Websocket support

Websocket support One of the most attractive features is JSF 2.3 added native websocket support, it means you can write real-time applications with JSF and no need extra effort.
To enable websocket support, you have to add javax.faces.ENABLE_WEBSOCKET_ENDPOINT in web.xml.
<context-param> <param-name>javax.faces.ENABLE_WEBSOCKET_ENDPOINT</param-name> <param-value>true</param-value> </context-param> Hello Websocket Let's start with a simple example.
@ViewScoped@Named("helloBean") publicclassHelloBeanimplementsSerializable { privatestaticfinalLoggerLOG=Logger.getLogger(HelloBean.class.getName()); @Inject@PushPushContext helloChannel; String message; publicvoidsendMessage() { LOG.log(Level.INFO, "send push message"); this.sendPushMessage("hello"); } privatevoidsendPushMessage(Objectmessage) { helloChannel.send(""+ message +" at &…