flex4 + spring + blazeds , 使用anonation(注解)机制,利用push技术的实现例子和过程

原文 :
http://blog.csdn.net/remote_roamer/article/details/6578527

1.修改blazeds自动生成的WEB-INF/flex/services-config.xml文件。由于原来没有polling-amf的定义,所以需要加入。代码如下:

<?xml version="1.0" encoding="UTF-8"?>
<services-config>
    <services>
        <service-include file-path="remoting-config.xml" />
        <service-include file-path="proxy-config.xml" />
        <service-include file-path="messaging-config.xml" />       
    </services>
    <security>
        <login-command class="flex.messaging.security.TomcatLoginCommand" server="Tomcat"/>
        <!-- Uncomment the correct app server
        <login-command class="flex.messaging.security.TomcatLoginCommand" server="JBoss">
<login-command class="flex.messaging.security.JRunLoginCommand" server="JRun"/>       
        <login-command class="flex.messaging.security.WeblogicLoginCommand" server="Weblogic"/>
        <login-command class="flex.messaging.security.WebSphereLoginCommand" server="WebSphere"/>
        -->
        <!--
        <security-constraint id="basic-read-access">
            <auth-method>Basic</auth-method>
            <roles>
                <role>guests</role>
                <role>accountants</role>
                <role>employees</role>
                <role>managers</role>
            </roles>
        </security-constraint>
         -->
    </security>
    <channels>
        <channel-definition id="my-amf" class="mx.messaging.channels.AMFChannel">
            <endpoint url="http://{server.name}:{server.port}/{context.root}/messagebroker/amf" class="flex.messaging.endpoints.AMFEndpoint"/>
        </channel-definition>
        <channel-definition id="my-secure-amf" class="mx.messaging.channels.SecureAMFChannel">
            <endpoint url="https://{server.name}:{server.port}/{context.root}/messagebroker/amfsecure" class="flex.messaging.endpoints.SecureAMFEndpoint"/>
            <properties>
                <add-no-cache-headers>false</add-no-cache-headers>
            </properties>
        </channel-definition>
         <channel-definition id="my-polling-amf" class="mx.messaging.channels.AMFChannel">
            <endpoint url="http://{server.name}:{server.port}/{context.root}/messagebroker/amfpolling" class="flex.messaging.endpoints.AMFEndpoint"/>
            <properties>
                <polling-enabled>true</polling-enabled>
                <polling-interval-seconds>4</polling-interval-seconds>
            </properties>
        </channel-definition>
       
<channel-definition id="my-longpolling-amf" class="mx.messaging.channels.AMFChannel">
<endpoint url="http://{server.name}:{server.port}/{context.root}/messagebroker/amflongpolling" class="flex.messaging.endpoints.AMFEndpoint"/>
<properties>
<polling-enabled>true</polling-enabled>
<polling-interval-seconds>5</polling-interval-seconds>
<wait-interval-millis>60000</wait-interval-millis>
<client-wait-interval-millis>1</client-wait-interval-millis>
<max-waiting-poll-requests>200</max-waiting-poll-requests>
                <user-agent-settings>
<!-- MSIE 5, 6, 7 default max number of permanent HTTP connections is 2. -->
<user-agent match-on="MSIE" max-streaming-connections-per-session="1"/>
<!-- MSIE 8 max number is 6. -->
<user-agent match-on="MSIE 8" max-streaming-connections-per-session="5"/>
<!-- Firefox 1, 2 max number is 2. -->
<user-agent match-on="Firefox" max-streaming-connections-per-session="1"/>
<!-- Firefox 3 max number is 6. -->
<user-agent match-on="Firefox/3" max-streaming-connections-per-session="5"/>
<!-- Safari 3, 4 max number is 4. --> 
<user-agent match-on="Safari" max-streaming-connections-per-session="3"/>
<!-- Chrome 0, 1, 2 max number is 6. -->
<user-agent match-on="Chrome" max-streaming-connections-per-session="5"/>
<!-- Opera 7, 9 max number is 4.-->
<user-agent match-on="Opera" max-streaming-connections-per-session="3"/>
<!-- Opera 8 max number is 8. --> 
<user-agent match-on="Opera 8" max-streaming-connections-per-session="7"/>
<!-- Opera 10 max number is 8. -->
<user-agent match-on="Opera 10" max-streaming-connections-per-session="7"/>
                </user-agent-settings>
</properties>
</channel-definition>       

        <channel-definition id="my-streaming-amf" class="mx.messaging.channels.StreamingAMFChannel">
            <endpoint url="http://{server.name}:{server.port}/{context.root}/messagebroker/streamingamf" class="flex.messaging.endpoints.StreamingAMFEndpoint"/>
        </channel-definition>
        <!--
        <channel-definition id="my-http" class="mx.messaging.channels.HTTPChannel">
            <endpoint url="http://{server.name}:{server.port}/{context.root}/messagebroker/http" class="flex.messaging.endpoints.HTTPEndpoint"/>
        </channel-definition>
        <channel-definition id="my-secure-http" class="mx.messaging.channels.SecureHTTPChannel">
            <endpoint url="https://{server.name}:{server.port}/{context.root}/messagebroker/httpsecure" class="flex.messaging.endpoints.SecureHTTPEndpoint"/>
            <properties>
                <add-no-cache-headers>false</add-no-cache-headers>
            </properties>
        </channel-definition>
        -->
    </channels>
    <logging>
        <target class="flex.messaging.log.ConsoleTarget" level="Error">
            <properties>
                <prefix>[BlazeDS] </prefix>
                <includeDate>false</includeDate>
                <includeTime>false</includeTime>
                <includeLevel>false</includeLevel>
                <includeCategory>false</includeCategory>
            </properties>
            <filters>
                <pattern>Endpoint.*</pattern>
                <pattern>Service.*</pattern>
                <pattern>Configuration</pattern>
            </filters>
        </target>
    </logging>
    <system>
        <redeploy>
            <enabled>false</enabled>
            <!--
            <watch-interval>20</watch-interval>
            <watch-file>{context.root}/WEB-INF/flex/services-config.xml</watch-file>
            <watch-file>{context.root}/WEB-INF/flex/proxy-config.xml</watch-file>
            <watch-file>{context.root}/WEB-INF/flex/remoting-config.xml</watch-file>
            <watch-file>{context.root}/WEB-INF/flex/messaging-config.xml</watch-file>
            <watch-file>{context.root}/WEB-INF/flex/data-management-config.xml</watch-file>
            <touch-file>{context.root}/WEB-INF/web.xml</touch-file>
             -->
        </redeploy>
    </system>
</services-config>


2.在spring的配置文件中定义 defaultMessageTemplate class="org.springframework.flex.messaging.MessageTemplate"


<bean id="defaultMessageTemplate" class="org.springframework.flex.messaging.MessageTemplate" />

之所以要定义这个bean,是为了在做service的时候。可以用注解@Autowired来引入这个MessageTemplate的实例。

3.在web.xml中定义spring和flex的集成。这个配置是使用spring和flex集成时候的配置,和push技术无关。

<!-- 定义 spring flex 集成的配置,使用单独的配置文件。
        不使用在一个applicatonContext.xml中import springFlex.xml的方法
        spring flex 一定要用DispatcherServlet 方法。不能用ContextLoaderListener -->
    <servlet>
        <servlet-name>MessagebrokerServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>/WEB-INF/classes/META-INF/springFlex.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <!-- Map /spring/* requests to the DispatcherServlet -->
    <servlet-mapping>
        <servlet-name>MessagebrokerServlet</servlet-name>
        <url-pattern>/messagebroker/*</url-pattern>
    </servlet-mapping>
    <!-- 定义 spring flex 集成的配置  结束-->
   
    <!--  访问RDS 定义开始-->
    <servlet>
        <servlet-name>RDSDispatchServlet</servlet-name>
        <servlet-class>flex.rds.server.servlet.FrontEndServlet</servlet-class>
        <init-param>
            <param-name>useAppserverSecurity</param-name>
            <param-value>false</param-value>
        </init-param>
        <init-param>
            <param-name>messageBrokerId</param-name>
            <param-value>_messageBroker</param-value>
        </init-param>
        <load-on-startup>10</load-on-startup>
    </servlet>
    <servlet-mapping id="RDS_DISPATCH_MAPPING">
        <servlet-name>RDSDispatchServlet</servlet-name>
        <url-pattern>/CFIDE/main/ide.cfm</url-pattern>
    </servlet-mapping>
    <!--  访问RDS 定义结束 -->

4.由于web.xml配置中引入了WEB-INF/classes/META-INF/springFlex.xml这个文件,所以在springFlex.xml文件中进行详细配置

5.springFlex.xml文件如下,主要是定义flex:message-destination ,既是监听的数据的关键词

<?xml version="1.0" encoding="UTF-8"?>
<beans
    xmlns="http://www.springframework.org/schema/beans"
    xmlns:flex="http://www.springframework.org/schema/flex"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
       http://www.springframework.org/schema/flex
       http://www.springframework.org/schema/flex/spring-flex-1.0.xsd">
  
   
     <flex:message-broker>
        <flex:message-service
            default-channels="my-polling-amf" />
    </flex:message-broker>
   
    <flex:message-destination id="simple-feed" />
    <flex:message-destination id="testJob-feed"/>
   
   
</beans>

6.编写后台推送的java service bean:

/***********************************************************************
  *
  *   TestJob.java
  *
  *   ****所有,
  *   受到法律的保护,任何公司或个人,未经授权不得擅自拷贝。
  *   @copyright       Copyright:   2000-2011 
  *   @creator          徐泽宇 <br/>
  *   @create-time   2011-6-27   下午11:51:16
  *   @revision         $Id:     *
  ***********************************************************************/
package com.alcor.test.service.quartz;
import java.util.Date;
import java.util.UUID;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.flex.messaging.MessageTemplate;
import org.springframework.flex.remoting.RemotingDestination;
import org.springframework.flex.remoting.RemotingInclude;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import flex.messaging.messages.AsyncMessage;
@Service
@RemotingDestination
public class TestJob {
/**
* Logger for this class
*/
private static final Logger logger = LoggerFactory.getLogger(TestJob.class);
@Autowired
    MessageTemplate template;

private static FeedThread thread;

@RemotingInclude
public void work3 (){
if (thread == null) {
thread = new FeedThread(template);
thread.start();
}
}

public static class FeedThread extends Thread {
        public boolean running = false;
        private final MessageTemplate template;
        public FeedThread(MessageTemplate template) {
            this.template = template;
            run();
        }
        @Override
        public void run() {
            this.running = true;
            while (this.running) {
            logger.debug("testJob-feed send");
            this.template.send("testJob-feed", UUID.randomUUID().toString());
            // this.template.send("testJob-feed", UUID.randomUUID().toString());
                try {
                    Thread.sleep(300);
                } catch (InterruptedException e) {
                e.printStackTrace(System.out);
                }
            }
        }
}
}

注意:这里使用了@Service,@@RemotingDestination 注解和 @Autowired    MessageTemplate template; 这样就避免了在spring中利用配置文件进行定义bean。

如果要使用spring 配置文件来定义。可以参考下面代码(来自blazeds的官方例子中的spring配置文件)


<!-- MessageTemplate makes it easy to publish messages -->
    <bean id="defaultMessageTemplate" class="org.springframework.flex.messaging.MessageTemplate" />
    <!-- Pojo used to start and stop the data feed that pushes data in the 'simple-feed' destination -->
    <bean id="simpleFeedStarter" class="org.springframework.flex.samples.simplefeed.SimpleFeed">
        <constructor-arg ref="defaultMessageTemplate" />
        <flex:remoting-destination />
    </bean>

具体的业务实现是在 内联线程类FeedThread 里面的run()中实现。



这要做的目标是为了让这个线程启动,是一定要通过flex的一个客户端连上来,才能启动。而不能随着spring context启动而启动。否则会报告messageBroke没有设置在flexContext之类的错误。



那么:如果我们想后台在没有任何一个客户端连上来的情况下,也要启动这个发送服务应该如何做?

典型场景: 后台web应用启动,并且定义了一个定时器。每隔 5s 进行一个逻辑处理,然后把处理结果发送给前台 flex(无论是否有felx客户端连上)



这就需要用下面代码:

public String work2(){
if (logger.isDebugEnabled()) {
logger.debug("work2() - start"); //$NON-NLS-1$
}
String m_rtn  ="Spring 的TestJob任务work2被调用!" ;

String returnString =new Date().toLocaleString()+ m_rtn;
//------------------------------------------
MessageBroker msgBroker = MessageBroker.getMessageBroker("_messageBroker"); 
AsyncMessage am = new AsyncMessage(); 
         am.setDestination("testJob-feed"); 
         //am.setHeader("DSSubtopic", "tick"); 
         am.setClientId(UUID.randomUUID().toString()); 
         String msgID =UUID.randomUUID().toString(); 
         //System.out.println("MESSAGE ID:" + msgID); 
         am.setMessageId(msgID); 
         am.setTimestamp(System.currentTimeMillis()); 
         am.setBody(returnString); 
         if (msgBroker != null)
         {
        msgBroker.routeMessageToService(am, null);
         }
         //------------------------------------------

if (logger.isDebugEnabled()) {
logger.debug("work2() - end"); //$NON-NLS-1$
}
return returnString;
}


这个work2 方法可以通过 quartz或者spring 的@Scheduled注解来进行定时器调用。

主要的关键代码是

MessageBroker msgBroker = MessageBroker.getMessageBroker("_messageBroker"); 



这个就是获得一个 _messageBroker的实例。"_messageBroker"字符串是由 <flex:message-broker > 标签中的id来指定。

如果没有id 指定,则缺省使用 “"_messageBroker"”这个字符串





7.前台的订阅flex程序:


<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
   xmlns:s="library://ns.adobe.com/flex/spark"
   xmlns:mx="library://ns.adobe.com/flex/mx">

<fx:Script>
<!--[CDATA[
import mx.controls.Alert;
import mx.messaging.messages.IMessage;

private function messageHandler(message:IMessage):void
{
pushedValue.text = ""+ message.body;
}

private function messageHandler1(message:IMessage):void
{
pushedValue1.text = ""+ message.body;
}

]]-->
</fx:Script>

<fx:Declarations>
<s:ChannelSet id="cs">
<s:StreamingAMFChannel uri="/Aerie/messagebroker/streamingamf"/>
<s:AMFChannel uri="/Aerie/messagebroker/amflongpolling"/>
<s:AMFChannel uri="/Aerie/messagebroker/amfpolling"/>
</s:ChannelSet>

<mx:Consumer id="consumer" destination="simple-feed" channelSet="{cs}"
message="messageHandler(event.message)"/>
<mx:Consumer id="consumer1" destination="testJob-feed" channelSet="{cs}"
message="messageHandler1(event.message)"/>
</fx:Declarations>
<s:HGroup>
<s:Group>
<s:TextInput id="pushedValue" width="250" verticalCenter="0" horizontalCenter="0"/>
<s:Button label="spimle-feed 订阅" click="consumer.subscribe()" enabled="{!consumer.subscribed}" verticalCenter="30" horizontalCenter="-50"/>
<s:Button label="Unsubscribe" click="consumer.unsubscribe()" enabled="{consumer.subscribed}" verticalCenter="30" horizontalCenter="50"/>
</s:Group>
<s:Group>
<s:TextInput id="pushedValue1" width="250" verticalCenter="0" horizontalCenter="0"/>
<s:Button label="testJob 订阅" click="consumer1.subscribe()" enabled="{!consumer1.subscribed}" verticalCenter="30" horizontalCenter="-50"/>
<s:Button label="Unsubscribe" click="consumer1.unsubscribe()" enabled="{consumer1.subscribed}" verticalCenter="30" horizontalCenter="50"/>
</s:Group>

</s:HGroup>



</s:Application>


其中关键代码是:

<fx:Declarations>
<s:ChannelSet id="cs">
<s:StreamingAMFChannel uri="/Aerie/messagebroker/streamingamf"/>
<s:AMFChannel uri="/Aerie/messagebroker/amflongpolling"/>
<s:AMFChannel uri="/Aerie/messagebroker/amfpolling"/>
</s:ChannelSet>

<mx:Consumer id="consumer" destination="simple-feed" channelSet="{cs}"
message="messageHandler(event.message)"/>
<mx:Consumer id="consumer1" destination="testJob-feed" channelSet="{cs}"
message="messageHandler1(event.message)"/>
</fx:Declarations>

注意:

<s:StreamingAMFChannel uri="/Aerie/messagebroker/streamingamf"/>

<s:AMFChannel uri="/Aerie/messagebroker/amflongpolling"/>

<s:AMFChannel uri="/Aerie/messagebroker/amfpolling"/>

这三个通道的设置中用到的

Aerie是代表context名字。

messagebroker 是代码 web.xml中的配置的MessagebrokerServlet中的url-pattern

amfpolling 等是指 在services-config.xml文件中设置的 channel-definition 下的endpoint 名字

你可能感兴趣的:(blazeds)