Я начал несколько недель назад, чтобы посмотреть, что мы можем сделать с Grails и его корпоративной стороной, и потому что там, где я сейчас работаю, необходимо передать часть сообщений от серверной части к клиентам (клиентам Flex); Ну, я сделал некоторые модификации для плагина flex / grails (разработанного Marcel Overdijk), чтобы можно было отправлять сообщения из grails во Flex (потребитель).
Предполагая, что у нас уже есть наш домен, контроллеры и, возможно, некоторые представления, единственное, что нам нужно сделать, это установить плагин flex, сделать небольшие изменения исходного кода (плагин flex), создать вспомогательный класс (для отправки сообщениями), создайте службу (это определит наш пункт назначения), добавьте тег службы сообщений в конфигурацию flex (services-config.xml) и протестируйте его в приложении Flex. Для этих шагов я использую Grails IDE на Eclipse.
Итак, вот шаги:
1) Установите плагин Flex:
(Используя IDE Grails на eclipse, вы можете вызвать командную строку grails с помощью Ctrl + Alt + G для Windows или Cmd + Alt + G для Mac).
grails > install-plugin flex
2) Измените исходный код подключаемого модуля Flex:
изменяемыми файлами будут GrailsBootstrapService.java и FlexUtils.java.
GrailsBootstrapService.java, сервис начальной загрузки поможет динамически создавать места назначения.
(Это окончательная версия).
package org.codehaus.groovy.grails.plugins.flex;
import org.codehaus.groovy.grails.commons.GrailsApplication;
import org.codehaus.groovy.grails.commons.GrailsClass;
import org.codehaus.groovy.grails.commons.GrailsServiceClass;
import org.codehaus.groovy.grails.commons.ServiceArtefactHandler;
import org.codehaus.groovy.grails.web.util.WebUtils;
import flex.messaging.MessageBroker;
import flex.messaging.config.ConfigMap;
import flex.messaging.services.AbstractBootstrapService;
public class GrailsBootstrapService extends AbstractBootstrapService {
public void initialize(String id, ConfigMap properties) {
MessageBroker messageBroker = getMessageBroker();
// add spring factory if it's not yet registered
FlexUtils.addSpringFactory(messageBroker);
GrailsApplication application = WebUtils.lookupApplication(messageBroker.getInitServletContext());
GrailsClass[] grailsClasses = application.getArtefacts(ServiceArtefactHandler.TYPE);
for (int i = 0; i < grailsClasses.length; i++) {
GrailsServiceClass serviceClass = (GrailsServiceClass) grailsClasses[i];
if (FlexUtils.hasFlexRemotingConvention(serviceClass)) {
FlexUtils.createRemotingDestination(messageBroker, serviceClass);
}
if (FlexUtils.hasFlexMessagingConvention(serviceClass)){
FlexUtils.createMessagingDestination(messageBroker, serviceClass);
}
}
}
public void start() {}
public void stop() {}
}
Как видите, я добавил эти строки в исходный код:
if (FlexUtils.hasFlexMessagingConvention(serviceClass)){
FlexUtils.createMessagingDestination(messageBroker, serviceClass);
}
FlexUtils.java
Здесь я добавил несколько строк, и я знаю, что есть лучший способ реализовать это (возможно, добавить шаблон фабрики) для создания правильного сервиса.
(Это окончательная версия).
package org.codehaus.groovy.grails.plugins.flex;
import java.util.List;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.codehaus.groovy.grails.commons.GrailsClassUtils;
import org.codehaus.groovy.grails.commons.GrailsServiceClass;
import flex.messaging.MessageBroker;
import flex.messaging.services.RemotingService;
import flex.messaging.services.remoting.RemotingDestination;
import flex.messaging.services.MessageService;
import flex.messaging.MessageDestination;
public class FlexUtils {
private static final String SPRING_FACTORY_ID = "spring";
private static final String GRAILS_REMOTING_SERVICE_ID = "grails-remoting-service";
private static final String GRAILS_MESSAGING_SERVICE_ID = "grails-messaging-service";
private static final String EXPOSE_PROPERTY = "expose";
private static final String DESTINATION_PROPERTY = "destination";
private static final String FLEX_REMOTING = "flex-remoting";
private static final String FLEX_MESSAGING = "flex-messaging";
private static final Log LOG = LogFactory.getLog(FlexUtils.class);
public static void addSpringFactory(MessageBroker mb) {
// add spring factory if it's not yet registered
if (!mb.getFactories().containsKey(SPRING_FACTORY_ID)) {
mb.addFactory(SPRING_FACTORY_ID, new SpringFactory());
LOG.info("SpringFactory added to message broker");
}
}
public static RemotingService getGrailsRemotingService(MessageBroker mb) {
return (RemotingService) mb.getService(GRAILS_REMOTING_SERVICE_ID);
}
public static MessageService getGrailsMessagingService(MessageBroker mb) {
return (MessageService) mb.getService(GRAILS_MESSAGING_SERVICE_ID);
}
public static boolean hasFlexRemotingConvention(GrailsServiceClass serviceClass) {
List exposeList = (List) GrailsClassUtils.getStaticPropertyValue(serviceClass.getClazz(), EXPOSE_PROPERTY);
if (exposeList != null && exposeList.contains(FLEX_REMOTING)) {
return true;
}
return false;
}
public static boolean hasFlexMessagingConvention(GrailsServiceClass serviceClass) {
List exposeList = (List) GrailsClassUtils.getStaticPropertyValue(serviceClass.getClazz(), EXPOSE_PROPERTY);
if (exposeList != null && exposeList.contains(FLEX_MESSAGING)) {
return true;
}
return false;
}
public static void createRemotingDestination(MessageBroker mb, GrailsServiceClass serviceClass) {
RemotingService rs = getGrailsRemotingService(mb);
String destination = getDestination(serviceClass);
RemotingDestination rd = (RemotingDestination) rs.createDestination(destination);
rd.setFactory(SPRING_FACTORY_ID);
rd.setSource(serviceClass.getPropertyName());
// if the service is already started also start the destination
// this is needed for reloading and creating new Grails services
if (rs.isStarted()) {
rd.start();
}
LOG.info("Flex remoting destination created for " + serviceClass.getShortName());
}
public static void createMessagingDestination(MessageBroker mb, GrailsServiceClass serviceClass) {
MessageService ms = getGrailsMessagingService(mb);
String destination = getDestination(serviceClass);
MessageDestination md = (MessageDestination) ms.createDestination(destination);
md.setFactory(SPRING_FACTORY_ID);
md.setSource(serviceClass.getPropertyName());
// if the service is already started also start the destination
// this is needed for reloading and creating new Grails services
if (ms.isStarted()) {
md.start();
}
LOG.info("Flex messaging destination created for " + serviceClass.getShortName());
}
private static String getDestination(GrailsServiceClass serviceClass) {
String destination = (String) GrailsClassUtils.getStaticPropertyValue(serviceClass.getClazz(), DESTINATION_PROPERTY);
if (StringUtils.isBlank(destination)) {
destination = serviceClass.getPropertyName();
}
return destination;
}
}
а) я добавил две константы:
private static final String GRAILS_MESSAGING_SERVICE_ID = "grails-messaging-service";
private static final String FLEX_MESSAGING = "flex-messaging";
б) И эти методы:
public static MessageService getGrailsMessagingService(MessageBroker mb) {
return (MessageService) mb.getService(GRAILS_MESSAGING_SERVICE_ID);
}
public static boolean hasFlexMessagingConvention(GrailsServiceClass serviceClass) {
List exposeList = (List) GrailsClassUtils.getStaticPropertyValue(serviceClass.getClazz(), EXPOSE_PROPERTY);
if (exposeList != null && exposeList.contains(FLEX_MESSAGING)) {
return true;
}
return false;
}
public static void createMessagingDestination(MessageBroker mb, GrailsServiceClass serviceClass) {
MessageService ms = getGrailsMessagingService(mb);
String destination = getDestination(serviceClass);
MessageDestination md = (MessageDestination) ms.createDestination(destination);
md.setFactory(SPRING_FACTORY_ID);
md.setSource(serviceClass.getPropertyName());
// if the service is already started also start the destination
// this is needed for reloading and creating new Grails services
if (ms.isStarted()) {
md.start();
}
LOG.info("Flex messaging destination created for " + serviceClass.getShortName());
}
3) Создать вспомогательный класс.
Этот класс будет отправлять любое сообщение в любое место назначения (предоставляется созданной службой).
Просто создайте новый класс Groovy в папке src / groovy.
FlexMessageDispatcher.groovy
class FlexMessageDispatcher {
def sendMessageToClients(String messageBody,String destination){
AsyncMessage msg = new AsyncMessage()
msg.setClientId("Java-Based-Producer-For-Messaging")
msg.setTimestamp(new Date().getTime())
//Unique id
msg.setMessageId("Java-Based-Producer-For-Messaging-ID")
//destination to which the message is to be sent
msg.setDestination(destination)
//set message body
msg.setBody(messageBody != null?messageBody:"")
//set message header
msg.setHeader("sender", "From the server")
//send message to destination
MessageBroker.getMessageBroker(null).routeMessageToService(msg, null)
}
}
В этом классе этот метод может быть перегружен, чтобы мы могли передавать дополнительную информацию, такую как заголовки, идентификаторы и т. Д. Посмотрите AsyncMessage.java (из BlazeDS API) для получения дополнительной информации.
4) Создайте сервис:
создайте сервис с помощью команды grails. И поместите идентификатор свойства ( static expose = [ ‘flex-messaging’ ])
grails > create-service UpdateMessage
Окончательное обновлениеMessageService.groovy
class UpdateMessageService {
static expose = ['flex-messaging']
boolean transactional = true
}
Bootstrap создаст пункт назначения updateMessageService
5) Добавьте тег службы сообщений в конфигурацию Flex:
необходимо добавить новые теги в файл services-config.xml, расположенный в веб-приложении / WEB-INF / flex
Этот тег будет добавлен к тегу существующих сервисов .
<service id="grails-messaging-service" class="flex.messaging.services.MessageService">
<adapters>
<adapter-definition id="actionscript"
class="flex.messaging.services.messaging.adapters.ActionScriptAdapter" default="true" />
</adapters>
</service>
И это полный файл: services-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<services-config>
<services>
<service id="grails-remoting-service" class="flex.messaging.services.RemotingService">
<adapters>
<adapter-definition id="java-object" class="flex.messaging.services.remoting.adapters.JavaAdapter" default="true"/>
</adapters>
</service>
<service id="grails-messaging-service" class="flex.messaging.services.MessageService">
<adapters>
<adapter-definition id="actionscript" class="flex.messaging.services.messaging.adapters.ActionScriptAdapter" default="true" />
</adapters>
</service>
<!--
Grails bootstrap service. This service registers the SpringFactory and
creates destinations for the annotated Grails services.
-->
<service id="grails-service" class="org.codehaus.groovy.grails.plugins.flex.GrailsBootstrapService"></service>
<!--
Application level default channels. Application level default channels are
necessary when a dynamic destination is being used by a service component
and no ChannelSet has been defined for the service component. In that case,
application level default channels will be used to contact the destination.
-->
<default-channels>
<channel ref="grails-amf"/>
</default-channels>
</services>
<channels>
<channel-definition id="grails-amf" class="mx.messaging.channels.AMFChannel">
<endpoint url="http://localhost:8080/{context.root}/messagebroker/amf" class="flex.messaging.endpoints.AMFEndpoint"/>
</channel-definition>
</channels>
</services-config>
6) Тестирование во Flex.
Чтобы протестировать клиент Flex, нам сначала нужно создать тег потребителя и с любого контроллера (от Grails) использовать класс помощника для отправки сообщения в пункт назначения updateMessageService .
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" creationComplete="myConsumer.subscribe()">
<mx:Script>
<![CDATA[
import mx.messaging.messages.IMessage;
import mx.controls.Alert;
private function messageHandler(message:IMessage):void
{
Alert.show(message.body.toString());
}
]]>
</mx:Script>
<mx:Consumer id="myConsumer" destination="updateMessageService" message="messageHandler(event.message)" />
</mx:Application>
На Grails (в любом контроллере или любом другом источнике, где необходимо сообщение), просто используйте класс Helper для отправки сообщения:
def flex = FlexMessageDispatcher()
flex.sendMessageToClients("any message", "updateMessageService")
Чтобы получить файлы вы можете перейти в мой блог