Readers: 135 | Updated: 02-10

用Spring2.5和ICEFaces开发Java EE

Translate Into:

网站: JavaEye  作者: kyo100900  链接:http://superleo.javaeye.com/blog/161715  发表时间: 2008年02月08日

声明:本文系JavaEye网站发布的原创博客文章,未经作者书面许可,严禁任何网站转载本文,否则必将追究法律责任!

ICEFacesJSF组件的一个类库,并在此基础上添加了对AJAX特有的处理方法:在Server端绑定了DOM,并且通过AJAX的推技术将Server端上的改变传递给client。这就意味着Server端在与各种各样的后端数据服务交互后,获得表示层应如何变化的信息,利用推技术,立即可以异步发送动态数据给用户界面,而不需用户的介入。

 

ICEFaces组件套装相当完整,包括将普通JSF的组件改造成支持AJAX的一些特性。比如说,JSF里绑定HTML标签<input type=”text”/>inputText组件,通过ICEFaces现在可被感知,将所输入的数据“局部”提交。server得到的是刚才所输入的那小部分数据,而不再需要等到整个页面都提交完了再处理。

 

ICEFaces组件套装也包括styling, a menu bar, a connection status widget, effects (也就是highlights, pulses, fades), a progress bar, a file upload widget, charts, and a capable set of panels.

 

尽管价格不菲,但因此JavaEE本身对以上提及的组件支持就不完备,用ICEFacesJSF1.2来开发也算是弥补了JSF的不足。现在我们就来看看ICEFaces如何布署在JavaEE容器,如何在EJB3下轻松的进行开发和配置,甚至不需要EJB3

 

ICEFaces1.61.7版本仍然要使用先前的JavaEE规范,也就是说需要使用Servlet2.4,而不是2.5。按照JavaEE规范来说, Servlet2.4除了不能注入资源外,区别不大。但这也意味着Servlet2.4下访问EJB只能用以前的老办法了,无法享受通过注入带来的好处。

 

以下是在Servlet2.5下,使用Stateless Session EJB的实例:

MyManagedBean.java:

import com.tss.ejb.SLSBLocal;

public class MyManagedBean {
	@EJB
	SLSBLocal slsblocal;
	public String getValueFromEJB() {
		return slsblocal.getValue();
	}
}

 

 

Servlet2.4下,annotation会被忽略掉。这的确很闹心,但也不是没有办法。这个时候Spring就可以在没有任何EJB的情况下,帮助我们管理

 

首先,我们建立一个web.xml来配置ICEFaces,同时建立的Web应用程序JSF必须是1.2版本。请看下面建好后的web.xml

 web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
         version="2.4">
    <servlet>
        <servlet-name>Faces Servlet</servlet-name>
        <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet>
        <servlet-name>Persistent Faces Servlet</servlet-name>
        <servlet-class>com.icesoft.faces.webapp.xmlhttp.PersistentFacesServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet>
        <servlet-name>Blocking Servlet</servlet-name>
        <servlet-class>com.icesoft.faces.webapp.xmlhttp.BlockingServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>Faces Servlet</servlet-name>
        <url-pattern>*.jspx</url-pattern>
    </servlet-mapping>

    <servlet-mapping>
        <servlet-name>Persistent Faces Servlet</servlet-name>
        <url-pattern>*.iface</url-pattern>
    </servlet-mapping>

    <servlet-mapping>
        <servlet-name>Persistent Faces Servlet</servlet-name>
        <url-pattern>/xmlhttp/*</url-pattern>
    </servlet-mapping>

    <servlet-mapping>
        <servlet-name>Blocking Servlet</servlet-name>
        <url-pattern>/block/*</url-pattern>
    </servlet-mapping>

    <servlet-mapping>
        <servlet-name>Faces Servlet</servlet-name>
        <url-pattern>/faces/*</url-pattern>
    </servlet-mapping>

    <servlet-mapping>
        <servlet-name>Faces Servlet</servlet-name>
        <url-pattern>*.faces</url-pattern>
    </servlet-mapping>

    <listener>
        <listener-class>
		com.icesoft.faces.util.event.servlet.ContextEventRepeater
	</listener-class>
    </listener>
</web-app>

 

 

现在我们还需要建立一个不断更新DOMBean。在这个例子中,我们使用了一个outputText来显示时钟(通过java.util.Date来实现),用另一个outputText来显示刷新的次数。更多详细内容可以在ICEFaces开发指南中找到,以下是faces-config.xmlTimeBean.java的源文件:

 

faces-config.xml:

<?xml version='1.0' encoding='UTF-8'?>
<faces-config 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-facesconfig_1_2.xsd"
              version="1.2">

    <managed-bean>
        <managed-bean-name>renderManager</managed-bean-name>
        <managed-bean-class>com.icesoft.faces.async.render.RenderManager</managed-bean-class>
        <managed-bean-scope>application</managed-bean-scope>
    </managed-bean>

    <managed-bean>
        <managed-bean-name>timebean</managed-bean-name>
        <managed-bean-class>com.tss.beans.TimeBean</managed-bean-class>
        <managed-bean-scope>request</managed-bean-scope>
        <managed-property>
            <property-name>renderManager</property-name>
            <value>#{renderManager}</value>
        </managed-property>
    </managed-bean>

</faces-config>

 

 

TimeBean.java:

 
package com.tss.beans;

import com.icesoft.faces.async.render.IntervalRenderer;
import com.icesoft.faces.async.render.RenderManager;
import com.icesoft.faces.async.render.Renderable;
import com.icesoft.faces.webapp.xmlhttp.PersistentFacesState;
import com.icesoft.faces.webapp.xmlhttp.RenderingException;

import java.util.Date;

public class TimeBean implements Renderable {
    static int refreshCount = 0;
    int interval = 1000;
    PersistentFacesState state;
    IntervalRenderer clock;

    public TimeBean() {
        init();
    }

    private void init() {
        state = PersistentFacesState.getInstance();
    }

    public int getRefreshCount() {
        return refreshCount;
    }

    public void setRefreshCount(int refreshCount) {
        this.refreshCount = refreshCount;
    }

    public Date getNow() {
        return new Date();
    }

    public String refresh() {
        refreshCount++;
        return null;
    }

    public void setRenderManager(RenderManager renderManager) {
        clock = renderManager.getIntervalRenderer("clock");
        clock.setInterval(interval);
        clock.add(this);
        clock.requestRender();
    }

    public PersistentFacesState getState() {
        return state;
    }

    public void renderingException(RenderingException renderingException) {
        if (clock != null) {
            clock.remove(this);
            clock = null;
        }
    }
}

 

 

最后,我们建立一个example.jsp页面,调用的时候名字叫“example.iface

example.jsp:

<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="f" uri="http://java.sun.com/jsf/core" %>
<%@ taglib prefix="h" uri="http://java.sun.com/jsf/html" %>
<%@ taglib prefix="ice" uri="http://www.icesoft.com/icefaces" %>
<%@ taglib prefix="comp" uri="http://www.icesoft.com/icefaces/component" %>
<f:view>
    <html>
    <head>
        <title>ICEFaces Example</title>
    </head>
    <body>
    <h:form>
        <comp:outputConnectionStatus/><br/>
        Time: <comp:outputText value="#{timebean.now}"/><br/>
        Refresh Count: <comp:outputText value="#{timebean.refreshCount}"/><br/>
        <comp:commandLink value="Refresh" action="#{timebean.refresh}"/>
    </h:form>
    </body>
    </html>
</f:view>

 

 

现在,将此应用程序发布在应用服务器里,然后打开两个session(假定一个是 IE,一个是FireFox) 都去访问该页面,你会看到两个浏览器上面都会显示一个时钟。这个时候,如果有一方单击了那个“Refresh”超连接,两个浏览器窗口都会被刷新。

 

这就是在server端使用AJAX的推技术来传递DOM的更新。微小的DOM更新,造成的带宽消耗一般是不要考虑的,但请记住带宽不并总是富足的,你仍然有必要去测量网络流量有没有超过你的限制。

 

现在的问题是直接使用的Servlet规范是2.4。如果使用EJB3的语法来构造是有问题的。而EJB2又是一个“又糟糕又过时的东西”,不得不要求使用remotehome接口。这个时候如果使用Spring的话,仅仅多一些配置就几乎可以给你提供所有你想要的东西。

 

因此我们不再需要像EJB这样的组件了,甚至在没有使用它的情况下仍然可以做到它所做的一切。在下面的例子里,我们打算忽略事务,因为它们在这个例子里没有多大意义。

 

再来看看Spring的实现方式:

 

Hello.java:

package com.tss.beans;

public interface Hello {
    String sayHello(String name);
}

 

HelloImpl.java:

package com.tss.beans;

import java.util.Date;

public class HelloImpl implements Hello {
    public String sayHello(String name) {
        return "Hello, "+name+" ("+new Date()+")";
    }
}

 

 

(在这里你也许就明白为什么说事务对于这个bean来说是无关紧要了吧)

 

现在需要在Web.xml配置Spring,加上context-param以及两个listener。于是Web.xml就多了以下内容:

 

web.xml(添加内容):

 <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/applicationContext*.xml</param-value>
    </context-param>

    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

    <listener>
        <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
    </listener>

同样,我们需要定义一个新的faces-config.xml文件,在里面设置允许Spring来帮助解析。faces-config.xml设置如下:

 

faces-config.xml:

<?xml version='1.0' encoding='UTF-8'?>
<faces-config 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-facesconfig_1_2.xsd"
              version="1.2">
    <application>
        <variable-resolver>org.springframework.web.jsf.DelegatingVariableResolver</variable-resolver>
    </application>
</faces-config>

再来看看applicationContext.xml,它在WEB-INF文件夹下:

applicationContext.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:jee="http://www.springframework.org/schema/jee"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
       http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-2.5.xsd
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd">
    <context:annotation-config />
    <bean id="renderManager" class="com.icesoft.faces.async.render.RenderManager" scope="singleton" />
    <bean id="timebean" class="com.tss.beans.TimeBean" lazy-init="true" scope="session">
        <property name="renderManager" ref="renderManager"/>
    </bean>
</beans>

 

 

在这里有一点很重要:每一个引用renderManagerbean都可以这样设置lazy-init=”true”,原因是当bean加载的时候PersistentFacesState可以不要求也跟着初始化。

 

一旦发生改变,你可以重新在两个浏览器之间调用“example.iface”来访问example.jsp页面,并且每秒都观察它们的更新,这与刚开始的那个非Spring版本是一样的。值得注意的是,尽管Spring2.5已经简化不少了,但如果要求再对TimeBean.java做一些修改,还是有意义的。

 

在这里我们需要修改setRenderManager()方法,把它重命名为“initClock()”并将参数去掉,然后把@PostConstruct加上,这样的话当这个bean被实例化后“initClock()”方法会立即被调用。

 

  @PostConstruct
    public void initClock() {
        System.out.println(renderManager);
        clock = renderManager.getIntervalRenderer("clock");
        clock.setInterval(interval);
        clock.add(this);
        clock.requestRender();
    }

 

 

当然少了setRenderManager(),就少了对renderManager的注入。我们可以加上@Autowired

@Autowired
    RenderManager renderManager;

 

再次来到applicationContext.xml,修改如下:

<bean id="renderManager" class="com.icesoft.faces.async.render.RenderManager" scope="singleton" />
    <bean id="timebean" class="com.tss.beans.TimeBean" lazy-init="true" scope="session" />

 

现在没有显示的将两个bean绑定在一起。Spring会通过autowire来自动检测TimeBean里的renderManager属性,并且通过在它的配置文件里注册的bean找到其唯一的实例,将其注入进去。这使得配置更加容易。

 

 

原文地址:http://www.theserverside.com/tt/knowledgecenter-is/knowledgecenter-is.tss?l=ICEFacesandSpringJavaEE


本文的讨论也很精彩,浏览讨论>>


JavaEye推荐
中国领先的电子商务网站-淘宝网招贤纳士,诚聘Java工程师



From The Blogs

Internet Observation

04-29
一封致Flash的情书
最最亲爱的Flash:      我发现就去年一年中,人们还是对你这么的不友善,说你没用,说你讨厌,说你在这个以内容为主的网络上就是个祸害。我也知道,有些暴徒仍旧在不断的败坏你的名声,他们侮辱你,用各... 查看全文

Internet Observation

2007
告别JAVA,迎接JavaFX时代的来临!
我邮箱中一封来自TheServerSide 的邮件告诉我说JAVA语言会逐渐失去生命力,但JAVA平台却是非常健壮,会一直有很强的发展潜力。这些都明显的告诉我们JAVA式的语法特点,如强壮的拼写能力,... 查看全文

Java开源大全

02-18
【BI商业智能工具→Mondrian】Mondrian是一个采用java开
Mondrian是一个采用java开发的OLAP服务器,能够分析存储在SQL数据库中的海量数据而不需要编写任何SQL脚本。Mondrian用于数据的多维探测。它支持把MDX(Multi-Dimensi... 查看全文

IntoMobile » Platforms

03-10
V-Circles Java mobile app lets you create communities, date on-the-go
Im not sure Ive seen something like this before. Yeah, there are Java ME clients for some mobile social networks, but the idea behind V-Circles is that all the action is on the client. You create or j... 查看全文

Electric Sheep Company

07-19
Action Script and Java Jedi Required
Youve read our blog posts, the Tech Crunch article and our WebFlock product website and youve realized we are tackling fun and complex software problems! Building small worlds is fun and even The GOOG... 查看全文

Mr.W's Blog

04-04
支持WIFI!PSP上的Java模拟器 PSPKVM v0.3.0新版下载
PSPKVM是一个在PSP上运行j2me程序的虚拟机。玩了几个游戏,好象不能竖屏玩了……获取自适应屏的可以,所以只能在240*320的模式,看字有些累。这文章好像很不错喔,... 查看全文

InfoWorld RSS Feed

03-09
Sun: We'll put Java on the iPhone
Sun Microsystems is developing a Java Virtual Machine for Apple's iPhone and plans to release the JVM some time after June, enabling Java applications to run on the popular mobile device.The JVM is to... 查看全文

IntoMobile » Platforms

03-09
Sun working to bring Java to iPhone - true mobile computing for enterprise and otherwise
Following hot on the heels of Apples iPhone SDK announcements, Sun has jumped into the fray and announced that theyll be making sure that Java plays nice with Apples iPhone and iPod Touch. The company... 查看全文

Slashdot

03-09
Sun Is Porting Java To the iPhone
krquet notes an InfoWorld article on Sun's plans for the iPhone. After studying Apple's newly released SDK docs for 24 hours, Sun decided it was feasible to develop a JVM, based on Java Micro Edition,... 查看全文

The Unofficial Apple Weblog (TUAW)

03-09
Sun working on Java for the iPhone
Filed under: Apple, iPhoneSun Microsystems is known for many things, but it is probably best known for Java. The promise of Java is that programmers can write an application once and run it on any mac... 查看全文
More Articles