- 关键技术简介
Blaseds是一款开源免费的插件,主要作用是实现flex调用java代码;
puremvc是一款针对flex的开源免费的mvc框架,主要作用是实现Flex代码解耦;
Hibernate框架是java持久层经典框架,帮助程序员更方便安全地访问数据库;
spring是java非常流行的框架,主要作用是管理java对象,其强大的低耦合机制能够与许多框架进行无缝整合(比如前面提到的Blaseds和Hibernate)。
- 实现机制
本实例实现用户管理的增删改查操作,前端完全使用flash展示,后台使用java服务器与mysql数据库交互。
Flex端使用puremvc进行解耦,Mediator监听页面事件和页面数据存取,Command处理页面复杂操作并调用Proxy方法,Proxy实现Java代码调用(使用RemoteObject的形式)。
Java端分为持久层(Dao层)和业务层(Service层),Flex调用的是Service层代码,使用spring mvc捕获flex的调用请求,Service再调用Dao层进行增删改查操作,最后将结果返回给Flex。
- 效果展示
①主页面

②下一页

③添加页面

④编辑页面

⑤详细页面

⑥删除操作

- Java端实现
Java端主要使用spring和Hibernate实现Dao层和Service层代码,具体spring和Hibernate配置网上有很多,在这就不赘述了。
关于Blaseds与spring整合的例子也很多,大家可以到我的博文中参考一下:http://blessht.iteye.com/admin/blogs/1131148。
①下面看Flex远程调用Service的接口定义:
public interface LoginService {
//新增
public void insertLoginInfo(Logininfo login);
//删除
public void deleteLoginInfo(int id);
//修改
public void updateLoginInfo(Logininfo login);
//详细
public LoginInfoDto getLoginInfo(int id);
//分页查询用户信息(用于显示到表格中)
public List<LoginTableDto> findLoginInfo(int pageNo,int pageSize);
//获取用户信息表的总数据
public long getLoginInfoTotalCounts();
//进入编辑页面时调用的方法
public Logininfo getLogin(int id);
//暂时无用
public List<FlexComboBoxDto> getSexList();
}
②看比较关键的web.xml配置:
<web-app version="2.4" 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">
<display-name>ssh2model</display-name>
<description>ssh2model Application</description>
<!-- spring mvc -->
<servlet>
<servlet-name>Spring MVC Dispatcher Servlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value></param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Spring MVC Dispatcher Servlet</servlet-name>
<url-pattern>/messagebroker/*</url-pattern>
</servlet-mapping>
<!-- 著名 Character Encoding filter -->
<filter>
<filter-name>encodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<!-- spring IOC -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath:com/bless/base/config/spring/springApplicationContext.xml,
classpath:com/bless/*/config/spring/spring-*-*.xml
</param-value>
</context-param>
<!-- blaseds监听器:用于获取服务器内置对象(request,application等) -->
<listener>
<listener-class>flex.messaging.HttpFlexSession</listener-class>
</listener>
<!--Spring ApplicationContext 载入 ,必须-->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- Spring 刷新Introspector防止内存泄露 -->
<listener>
<listener-class>org.springframework.web.util.IntrospectorCleanupListener</listener-class>
</listener>
<!-- session超时定义,单位为分钟 -->
<session-config>
<session-timeout>20</session-timeout>
</session-config>
<!--添加远程支持,用于远程数据服务-->
<servlet>
<display-name>RDSDispatchServlet</display-name>
<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>
</web-app>
③最后看service的IOC配置文件:
<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">
<!-- 为了把请求路由给 MessageBroker,添加以下 tag-->
<flex:message-broker />
<bean id="loginServiceBean" class="com.bless.logininfo.service.impl.LoginServiceImpl">
<!-- 指定当前bean被远程调用 -->
<flex:remoting-destination />
<property name="loginDao" ref="loginInfoDaoBean"></property>
</bean>
</beans>
④最后将Java项目部署到服务器上即可。
- Flex端实现
Flex端因为使用了puremvc,关于puremvc我在这不做过多介绍,因为我也是新手,可能很多东西写的都是错误,在以后对它有更深认识之后我会与大家分享使用经验。
整个项目的包结构如下图所示:

上图*.mxml就是flex的页面展示了,功能与jsp和html相似,也是由页面标签、事件等组成。mxml可以像纯jsp一样,将所有代码写在里面,但是这样会造成项目难以维护,所以为了尽量减少耦合度,我在mxml中基本没有写ActionScript代码,而是交给puremvc的Mediator处理。
下面以index.mxml为例,我在index.mxml中定义了一些变量,方便Mediator赋值,也就是说mxml不做逻辑操作,只是为了展示数据:
<?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" minWidth="955" minHeight="600"
creationComplete="facade.init_index(this)">
<!--整体布局-->
<s:layout>
<s:VerticalLayout horizontalAlign="center" verticalAlign="middle"/>
</s:layout>
<!--ActionScript代码块-->
<fx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
//定义puremvc核心Facade
private var facade:ApplicatioinFacade = ApplicatioinFacade.getInstance();
//总条数
[Bindable]
public var totals:int = 0;
//当前页数
[Bindable]
public var pageNo:int = 1;
//一页显示条数
[Bindable]
public var pageSize:int = 6;
//表格中的结果集
[Bindable]
public var logintablelist:ArrayCollection;
//被选中的值id
public var selectId:int = 0;
protected function table_loginInfo_clickHandler(event:MouseEvent):void
{
if(table_loginInfo.selectedItem != null){
selectId = table_loginInfo.selectedItem.id;
}
}
]]>
</fx:Script>
<!--
<s:HGroup width="70%" height="30" verticalAlign="middle" horizontalAlign="center">
<s:Label text="用户名:"/>
<s:TextInput id="txt_loginCode"/>
<s:Label text="姓名:"/>
<s:TextInput id="txt_name"/>
<s:Label text="性别:"/>
<s:ComboBox width="100" id="txt_sex"/>
<s:Button label="检索" id="btn_search"/>
<s:Button label="重置" id="btn_reset"/>
</s:HGroup>
-->
<!--操作区-->
<s:HGroup width="70%" height="30" verticalAlign="middle">
<mx:LinkButton label="刷新" id="refresh"/>
<mx:LinkButton label="添加" id="insert"/>
<mx:LinkButton label="编辑" enabled="{table_loginInfo.selectedIndex==-1?false:true}" id="edit"/>
<mx:LinkButton label="详情" enabled="{table_loginInfo.selectedIndex==-1?false:true}" id="detail"/>
<mx:LinkButton label="删除" enabled="{table_loginInfo.selectedIndex==-1?false:true}" id="link_delete"/>
</s:HGroup>
<!--表格区-->
<mx:DataGrid width="70%" id="table_loginInfo" dataProvider="{logintablelist}" click="table_loginInfo_clickHandler(event)">
<mx:columns>
<mx:DataGridColumn headerText="用户名" dataField="loginCode"/>
<mx:DataGridColumn headerText="姓名" dataField="name"/>
<mx:DataGridColumn headerText="性别" dataField="sex"/>
<mx:DataGridColumn headerText="联系电话" dataField="phone"/>
<mx:DataGridColumn headerText="电子邮箱" dataField="email"/>
</mx:columns>
</mx:DataGrid>
<s:HGroup width="70%" height="30" verticalAlign="middle">
<s:Label text="总共"/>
<s:Label text="{totals}"/>
<s:Label text="条数据"/>
<s:Label text=" 第"/>
<s:NumericStepper id="curPage" minimum="1" maximum="{(totals%pageSize)!=0?((uint)(totals/pageSize)+1):(totals/pageSize)}" value="{pageNo}"/>
<s:Label text="页"/>
<mx:LinkButton label="上一页" id="befor_page" enabled="{(pageNo==1)?false:true}"/>
<mx:LinkButton label="下一页" id="after_page" enabled="{(totals>((pageNo-1)*pageSize+(logintablelist.length)))?true:false}"/>
</s:HGroup>
</s:Application>
大家可以看到index.mxml中本应有很多事件的,不然怎么能实现增删改查操作,其实上面所有事件都写到了这里:
public class IndexMediator extends Mediator
{
public static const NAME:String = "IndexMediator";
public function IndexMediator(viewComponent:Object=null)
{
super(IndexMediator.NAME, viewComponent);
var indexApp:index = viewComponent as index;
//刷新
indexApp.refresh.addEventListener(MouseEvent.CLICK,function click():void{
sendNotification(LoadLoginCommand.NAME,indexApp);
});
//上下页选择事件
indexApp.curPage.addEventListener(Event.CHANGE,function change():void{
loadTable(indexApp.curPage.value);
});
//上一页事件
indexApp.befor_page.addEventListener(MouseEvent.CLICK,function click():void{
loadTable(indexApp.pageNo - 1);
});
//下一页事件
indexApp.after_page.addEventListener(MouseEvent.CLICK,function click():void{
loadTable(indexApp.pageNo + 1);
});
//打开添加操作事件
indexApp.insert.addEventListener(MouseEvent.CLICK,function click():void{
sendNotification(LoginAddOpenCommand.NAME,indexApp);
});
//打开编辑操作事件
indexApp.edit.addEventListener(MouseEvent.CLICK,function click():void{
sendNotification(LoginEditCommand.NAME,indexApp);
});
//打开详细操作事件
indexApp.detail.addEventListener(MouseEvent.CLICK,function click():void{
sendNotification(LoginDetailCommand.NAME,indexApp);
});
//执行删除操作事件
indexApp.link_delete.addEventListener(MouseEvent.CLICK,function click():void{
Alert.show("你确定该条数据吗?","删除提示",Alert.OK|Alert.NO,indexApp,function alert(e:CloseEvent):void{
//如果点击Cancel则不执行任何操作,否则执行删除操作
if(e.detail == Alert.OK){
sendNotification(LoginDeleteCommand.NAME,indexApp);
}
});
});
}
public function get indexApp():index{
return viewComponent as index;
}
//列举监听事件
override public function listNotificationInterests() : Array
{
return [
SearchLoginProxy.findLoginInfo,
SearchLoginProxy.getLoginInfoTotalCounts,
SearchLoginProxy.deleteLoginInfo
];
}
//处理监听事件
override public function handleNotification( note : INotification ) : void{
switch (note.getName()){
case SearchLoginProxy.findLoginInfo:
indexApp.logintablelist = note.getBody() as ArrayCollection;
break;
case SearchLoginProxy.getLoginInfoTotalCounts:
indexApp.totals = note.getBody() as int;
break;
case SearchLoginProxy.deleteLoginInfo:
sendNotification(LoadLoginCommand.NAME,indexApp);
break;
default:
break;
}
}
private function loadTable(pageNo:int):void{
indexApp.pageNo = pageNo;
sendNotification(LoadLoginCommand.NAME,indexApp);
}
}
那么上面IndexMediator类的构造方法就是关键了,构造方法必须传入index.mxml的实现对象,其实实现步骤很简单:
①index.mxml页面启动是触发creationComplete事件,该事件调用facade的init_index方法并且将当前对象作为参数传过去

②在facade类中注册一个名叫InitCommand的类,通过sendNotification向InitCommand发送通知
public class ApplicatioinFacade extends Facade
{
public static const INIT:String = "init";
//得到ApplicationFacade单例的工厂方法
public static function getInstance() : ApplicatioinFacade
{
if ( instance == null ) instance = new ApplicatioinFacade( );
return instance as ApplicatioinFacade;
}
//注册Command,建立Command与Notification之间的映射
override protected function initializeController( ) : void{
super.initializeController();
registerCommand(InitCommand.NAME,InitCommand);
}
public function init_index(index_:index):void{
sendNotification(InitCommand.NAME,index_);
}
}
③InitCommand接到通知后运行execute方法,execute方式内完成MVC的注册(当然也包括IndexMediator的注册)。其实到这IndexMediator就已经开始监听index.mxml的事件了。
public class InitCommand extends SimpleCommand
{
public static const NAME:String = "InitCommand";
override public function execute(notification:INotification):void{
var index_:index = notification.getBody() as index;
//向facade中注册mvc
facade.registerMediator(new IndexMediator(index_));
facade.registerProxy(new SearchLoginProxy());
//注册command
facade.registerCommand(LoadLoginCommand.NAME,LoadLoginCommand);
facade.registerCommand(LoginDetailCommand.NAME,LoginDetailCommand);
facade.registerCommand(LoginDeleteCommand.NAME,LoginDeleteCommand);
facade.registerCommand(LoginEditCommand.NAME,LoginEditCommand);
facade.registerCommand(LoginAddReturnCommand.NAME,LoginAddReturnCommand);
facade.registerCommand(LoginEditSubmitCommand.NAME,LoginEditSubmitCommand);
facade.registerCommand(LoginAddOpenCommand.NAME,LoginAddOpenCommand);
facade.registerCommand(LoginEditCloseCommand.NAME,LoginEditCloseCommand);
//发送通知初始化页面
sendNotification(LoadLoginCommand.NAME,index_);
}
}
- puremvc运行流程简介
以打开新增页面为例,我简单介绍一下puremvc的调用原理:
①首先IndexMediator负责index.mxml的事件监听,当用户点击“新增”链接时向LoginAddOpenCommand发送通知,并且将index.mxml对象传给该command使用:
//打开添加操作事件
indexApp.insert.addEventListener(MouseEvent.CLICK,function click():void{
sendNotification(LoginAddOpenCommand.NAME,indexApp);
});
②发送通知后,facade调用LoginAddOpenCommand的execute方法,该方法创建一个insert.mxml对象,同时创建LoginAddMediator(该Mediator用于监听insert.mxml页面),并且以模式弹出窗的形式显示在界面中,这时需要初始化“性别”下拉列表,所以必须调用SearchLoginProxy的getSexList方法:
public class LoginAddOpenCommand extends SimpleCommand
{
public static const NAME:String = "LoginAddOpenCommand";
override public function execute(notification:INotification):void{
//新建添加窗口
var i:insert = new insert();
PopUpManager.addPopUp(i,notification.getBody() as index,true);
PopUpManager.centerPopUp(i);
facade.registerMediator(new LoginAddMediator(i));
(facade.retrieveProxy(SearchLoginProxy.NAME) as SearchLoginProxy).getSexList();
}
}
③SearchLoginProxy的getSexList方法主要封装“性别”下拉列表的数据,封装完成后会发出一个通知
//查询性别列表
public static const getSexList:String ="getSexList";
public function getSexList():void{
var list:ArrayCollection = new ArrayCollection([
{label:"保密",data:0},
{label:"男",data:1},
{label:"女",data:2}
]);
sendNotification(SearchLoginProxy.getSexList,list);
}
④在LoginAddMediator中会注册并收听到Proxy发过来的通知,最后通过LoginAddMediator将值赋给insert.mxml的combox组件:
//列举监听事件
override public function listNotificationInterests() : Array
{
return [
SearchLoginProxy.insertLoginInfo,
SearchLoginProxy.getSexList
];
}
//处理监听事件
override public function handleNotification( note : INotification ) : void{
switch (note.getName()){
case SearchLoginProxy.insertLoginInfo:
(insertApp.parentDocument as index).pageNo = 1;
sendNotification(LoginAddReturnCommand.NAME,insertApp);
break;
case SearchLoginProxy.getSexList:
//给“性别”combox赋初始值
insertApp.sexList = note.getBody() as ArrayCollection;
insertApp.cb_sex.selectedIndex = 0;
default :
break;
}
}
- 尚未实现的功能
- 项目环境
基于Flex与Java的用户管理系统
本文介绍了一种使用Flex和Java实现的用户管理系统,详细阐述了关键技术、实现机制及功能展示。系统采用纯MVC架构,实现了用户信息的增删改查操作,通过Blaseds、Hibernate和Spring等框架提高开发效率。
109

被折叠的 条评论
为什么被折叠?



