`

Arch-03-16- RIA 最佳实践摸索

 
阅读更多

RIA 是必须的了,实现 RIA 的路径也特别的多,摸索正确的框架搭档和最佳实践路径也成了必须。

 

1、基调

(1)后端用: java

(2)前端用: Dojo 或 JQuery

(3)前端组件库:smartClient 或 dojo/jquery官方组件库

 

2、路径

(1)struts,chain,tile,dojo,smartClient

(2)struts,dwr,jquery,自写UI组件

 

3、路径 1 解剖(struts,chain,tile,dojo,smartClient)

(1)目录


 


(2)应用按模块方式组织,一个模块分三个部份存放

      。class 直接放入 classes 或 lib

      。jsp 页面和struts 配置放入 /WEB-INF/services-xxx 下的 config 和 pages

      。前端脚本放入应用根目录 /service-xxx/js/

 

(3)载入

      。跳到独立页面 uum.jsp

 

<%@ include file="uum.jsinc" %>

其中载入应用模块 js 文件
...
<c:set var="services-uum/js/uum.js" value="true" scope="request"/>
...
 

      。初始化 isomorhpic

      。session 中取得 userData

      。初始化 dojo

      。载入应用

 

// uum.js

var acUnifiedUserManagement = new function() {
    
    this.load = function() {
        dojo.require("dojo.event.*");
    
        // Specify non-Dojo module prefixes
        dojo.setModulePrefix("infa", "../../services-uum/js/infa");
        
        // Load Informatica common code
        dojo.require("infa.ajax.*");

        // Load application
        dojo.require("infa.ajax.application.Application");
        dojo.require("infa.tools.uum.ApplicationProperties");
        dojo.hostenv.writeIncludes();
        
        // TODO should move to ApplicationProperties
        isc.Page.setAppImgDir(isc.Page.getAppDir() + "services-uum/images/");
    }

}

 <!----- Load the dojo toolkit ----->

 

<script type="text/javascript" src="${acGlobalVars.jsPath}/dojo/dojo.js"></script>

<script type="text/javascript">
    acUnifiedUserManagement.load();
</script>

<body scroll="no" style="overflow:hidden">
  <script type="text/javascript">
    // set flag indicating which perspective appears by default
    window.infa_defaultPerspective = "admin";
    
    infa.ajax.application.Application.run(
        new infa.tools.uum.ApplicationProperties(window.infa_defaultPerspective)
    );
    
    infa.ajax.application.Application.baseURL = "${acGlobalVars.ctxPath}";
  </script>
</body>

 (4)应用模块调用入口

      。infa.ajax.application.Application.run()

      。this._run(), 初始化 title,history,bookmark,perspective,_init(),layout.show(),_runSession()

      。this._init(), 初始化 本地语言,创建 layout 

 

        // create layout
        dojo.require("infa.ajax.application.View");
        this.layout = infa.ajax.application.View.create({
            ID: "infa_app_layout",
            left: 0,
            top: 0,
            className: this.properties.layoutStyle,
            width: "100%",
            height: "100%",
            showToolbar: this.properties.showToolbar,
            showHeader: this.properties.showHeader,
            helpMenuItems: this.properties.helpMenuItems,
            toolbarClassName: "infa_applicationToolbar",
            toolbarHeight: 27,
            bundle: this.bundle,
            application: this,
            initWidget: function() {
                this.Super("initWidget", arguments);
                if (this.showToolbar) {
                    dojo.require("infa.ajax.widgets.Menu");
                    this.helpMenu = infa.ajax.widgets.Menu.create({
                        data: this.helpMenuItems,
                        width: 200,
                        variableWidth: true
                    });
                    this.commands = [
                        {cmd:"account", title:this.bundle.applicationAccountCommand, showTitle:true, icon:"account.gif"},
                        {cmd:"helpMenu", title:this.bundle.applicationHelpMenu, showTitle:true, submenu:this.helpMenu, showMenuButtonImage:true}
                    ];
                    this.toolbarCommands = [ "helpMenu" ];
                }
            },
            createHeader: function() {
                return this.application._createHeader();
            },
            doCommand: function(cmd) {
                var handled = this.Super("doCommand", arguments);
                if (cmd == "account") {
                    this.application.showAccount();
                    handled = true;
                } else if (!handled) {
                    handled = this.application.perspectives[this.application.activePerspective].instance.doCommand(cmd);
                }
                return handled;
            },
            enableCommand: function(cmd) {
                switch(cmd) {
                    case "account":
                    case "helpMenu":
                        return true;
                    default:
                        return this.application.perspectives[this.application.activePerspective].instance.enableCommand(cmd);
                }
            }
        });
 

(5)View 是继承于 isc.VLayout

 

// define class
isc.ClassFactory.definePackageClass(
    "infa.ajax.application.View",   // class name
    isc.VLayout                     // superclass
);

 

 

(6)View.initWidget()

 

// initialize CSS classes
// initialize images
// call overridden method
// get base resource bundle
// command bars array holds on to menus and toolbars whose state
// will get updated in response to events (such as selection changed)
// create header
// create toolbar
// by default, detach/attach and min/maximization occurs to this class
// force toolbar/menu commands to be updated at a point later in time
// when this view has been fully initialized
 

 

(7)数据源

      。集中一个文件存放模块内的全部数据源 /infa/tools/uum/ds/DataSources.js , 标准的 smartClient 数据源格式

 

infa.tools.uum.ds.user = isc.DataSource.create({
    fields:{
        id:{type:"text", required:true, primaryKey:true, title:"ID", name:"id", canEdit:false},
        userName:{type:"text", required:true, title:"Login", name:"userName", canEdit:false},
        namespace:{type:"text", required:true, title:"Namespace", name:"namespace", canEdit:false},
        fullName:{type:"text", title:"Full Name", name:"fullName"},
        description:{type:"text", title:"Description", name:"description"},
        password:{type:"text", title:"Password", name:"password"},
        email:{type:"text", title:"Email", name:"email"},
        phone:{type:"text", title:"Phone Number", name:"phone"},
        disable:{type:"boolean", hidden:true, name:"disable"},
        administrator:{type:"boolean", hidden:true, name:"administrator"},
        path:{type:"text", required:true, hidden:true, name:"path"}
    },
    ID:"infa_uum_ds_user"
})

       。UsersView 中 doCommand 新增用户,将弹窗的 saveData 事件绑定到 View._addUserFromDialog 事件

       。_addUserFromDialog 从弹窗中获取数据,调用 user 数据源增加事件。

 

(8)前后端数据传送

      。前端数据源 ID:"infa_uum_ds_user"

      。后端 chain-config.xml 配置 chain 操作

 

    <chain name="infa_uum_ds_user">
      <command className="app.services.uum.chain.commands.GetUserInfoCommand"/>
      <command className="app.services.uum.chain.commands.AddUserCommand"/>
      <command className="app.services.uum.chain.commands.UpdateUserCommand"/>
      <command className="app.services.uum.chain.commands.DeleteUserCommand"/>
    </chain>

 

       。AddUserCommand -> UserBaseCommand -> BaseDSCommand -> DSCommand -> RPCCommand -> AbstractCommand -> implements org.apache.commons.chain.Command

      。增加用户的 java 代码

 

 protected boolean executeOperation(WebContext actionCtx, ISCRequest request, ISCResponse response)
    throws Exception
  {
    logger.debug("\n\n\n.....addData for " + request.getDSRequest().getDataSourceName() + "\n\n\n");

    UserFacade facade = (UserFacade)getFacade(UserFacade.class);
    try {
      Map newValues = request.getData();

      String userName = newValues.get("userName") == null ? "" : (String)newValues.get("userName");

      String fullName = newValues.get("fullName") == null ? "" : (String)newValues.get("fullName");

      String password = newValues.get("password") == null ? "" : (String)newValues.get("password");

      String description = newValues.get("description") == null ? "" : (String)newValues.get("description");

      String email = newValues.get("email") == null ? "" : (String)newValues.get("email");
      String phone = newValues.get("phone") == null ? "" : (String)newValues.get("phone");

      User user = new User();
      user.setUserName(userName);
      user.setNameSpace("Native");
      try {
        user.setEncryptedPassword(Cryptographer.encryptData(password));
      } catch (PCSFException e) {
        e.printStackTrace();
      }
      UserInfo info = new UserInfo();
      info.setFullName(fullName);
      info.setDescription(description);
      info.setEmail(email);
      info.setPhone(phone);
      info.setDisable(false);
      user.setInfo(info);

      facade.addUser(user);

      newValues.put("disable", Boolean.valueOf(false));
      newValues.put("path", UserTreeNode.buildPath(user.getNameSpace(), user.getUserName()));

      response.setData(newValues);
    } catch (UUMOperationException e) {
      response.addError(null, e.getISCErrorMessage());
    }
    return true;
  }

       。然后调用 service 操作数据库。

 

 

 

4、路径 2 解剖(struts,freemarker,dwr,jquery,自写UI组件)

 

(1)目录

    。整个站点以 freemarker + struts 显示,

    。/WEB-INF/classes/template ,全部页面模板文件 ftl,没有明确独立模块存放标志。

    。/WEB-INF/classes/spring-*.xml 配置文件,

 

(2)/WEB-INF/classes/template/decorator/default/template.ftl - 主页全局文件,全站唯一入口。

 

<!---->
<html>
<head>
...
</head>
<body class="${page.getProperty("body.class")!}" >
    <div id="plus-wrapper" class="clearfix">
        <#include "/template/decorator/default/page-header.ftl" />
        <#if !page.getProperty("meta.nouserbar")??>
            <#include skin.userBar.pageUserBarTemplate />
        </#if>
        <div id="${bodyID!('plus-body')}">
            <#include "/template/decorator/default/page-breadcrumb.ftl" />
            ${page.body}
        </div>
        <#if !page.getProperty("meta.nofooter")??>
            <#include "/template/decorator/default/page-footer.ftl" />
        </#if>
    </div> 
...
</body>
</html>
 

 

 

 

(3)sturts-config.xml

 

 

	// struts-config.xml
    <action name="profile" class="com.plusrun.community.action.ViewProfile">
        <interceptor-ref name="defaultStack"/>
        <interceptor-ref name="profileUserHistory"/>
        <interceptor-ref name="store">
            <param name="operationMode">RETRIEVE</param>
        </interceptor-ref>
        <result name="refresh" type="redirect">/people/${targetUser.username}</result>
        <result name="success">/template/global/view-profile.ftl</result>
        <result name="success-projects">/template/global/view-profile-projects.ftl</result>
        <result name="success-communities">/template/global/view-profile-communities.ftl</result>
        <result name="success-watches">/template/global/view-profile-watches.ftl</result>
...
    </action>
 

 

 

(4)view-profile-communities.ftl

 

 

 

		// view-profile-communities.ftl
		<@resource.dwr file="FollowingActionBean" />
		...
    function startFollowing() {
        FollowingActionBean.followContainer(14, communityID, true, {
            callback:function() {
                $j('#plus-link-community-startFollowing').hide();
                $j('#plus-link-community-stopFollowing').show();
                Plus.AlertMessage('thread.watch.notify', {
                        beforeStart:function() {
							<#assign indexStartFollowingCommunityDesc><@s.text name="index.startFollowingCommunity.desc" /></#assign>
                            $j('[id=thread.watch.notify]').html('<div><span class="plus-icon-med plus-icon-info"></span>' + '${indexStartFollowingCommunityDesc?html?js_string}' + '</div>');
                        }
                 });
            },
            errorHandler:function(msg, e) {
                alert("<@s.text name='global.follow.error.messsage'/>");
            }
        });
    }

    function stopFollowing() {
        FollowingActionBean.followContainer(14, communityID, false, {
            callback:function() {
                $j('#plus-link-community-startFollowing').show();
                $j('#plus-link-community-stopFollowing').hide();
                Plus.AlertMessage('thread.watch.notify', {
                        beforeStart:function() {
							<#assign indexStopFollowingCommunityDesc><@s.text name="index.stopFollowingCommunity.desc" /></#assign>
                            $j('[id=thread.watch.notify]').html('<div><span class="plus-icon-med plus-icon-info"></span>' + '${indexStopFollowingCommunityDesc?html?js_string}' + '</div>');
                        }
                 });
            },
            errorHandler:function(msg, e) {
                alert("<@s.text name='global.follow.error.messsage'/>");
            }
        });
    }

 

 

(5)dwr 配置 spring-dwrContext.xml

 

 

    <bean id="followingActionBean" class="com.plusrun.community.follow.dwr.FollowingActionBean"
          parent="remoteSupport">
        <property name="followingManager" ref="followingManager"/>
        <property name="plusContainerManager" ref="plusContainerManager"/>
        <dwr:remote javascript="FollowingActionBean">
            <dwr:include method="followContainer"/>
        </dwr:remote>
    </bean>

    <bean id="remoteSupport" class="com.plusrun.community.dwr.RemoteSupport" abstract="true">
        <property name="authenticationProvider" ref="authenticationProvider"/>
        <property name="userManager" ref="userManager"/>
        <property name="localeManager" ref="localeManager"/>
    </bean>

 

 (6)后台处理

public abstract class RemoteSupport implements LocaleProvider, TextProvider

public class FollowingActionBean extends RemoteSupport
...
  this.followingManager.followContainer(getUser(), container);
...

public class FollowingManagerImpl implements FollowingManager, EventSource
...
  this.followingDAO.create(user.getID(), descriptor);
...  
 

 

  • 大小: 30.5 KB
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics