文档章节

聊聊视图层切面实现方案

悠悠然然
 悠悠然然
发布于 2016/05/30 22:12
字数 2026
阅读 1359
收藏 10

前面发过一篇《谈谈应用层切面设计》@HulkZ说看了好几遍也没看懂,然后我又拉他到小黑屋面壁思过了好几次;也有人关心个性与扩展性如何得到平衡;也有人说,悠然就会扯淡,如何实现呢?那么今天继续来扯扯淡看看如何实现。

需求由来

  • 在页面的某一个固定区域内,根据配置动态的增加新的功能。
  • 新增功能元素可以增量添加,不影响原有功能,无时序问题。
  • 支持模块化,自动加载配置。
  • 可以自定义功能元素展现顺序。
  • 满足各种功能模块的数据调用。

##实现思路 为了实现上述需求我们需要在前端页面上设计一种扩展机制,就像在页面上埋下一个“桩子”,一个个功能在需要的时候就往里放,界面上就加载这些功能;当不需要的时候,从里面拿出来,当然需要做到各个功能模块是高内聚低耦合。

从平台的角度上来说就是可以通过配置的方式往某个扩展点不断的添加新内容。而这个扩展点里的内容是有由各个功能模块组合而成,在加载显示的时候根据配置显示的顺序而加载。各个功能模块上高内聚,页面风格各自保持一致。

扩展点的配置可以放到XML文件中,各个功能模块有自己的配置文件,在框架启动过程中自动整合加载相关的配置文件,从而实现自动装配,同时也实现了增量添加功能模块。

在扩展点的调用要做到输入参数的统一调度,可以把公用的参数提到接口上,同时也要兼顾一些功能点的额外需求,因此一个Map参数是不可或缺的。

##实现关键 实现方法多种多样,这里以使用tiny平台为例。 在页面上埋坑也有多种方式,这里通过调用模板语言宏来实现,说到模板语言不得不用用我家的tiny模板语言。 定义切点宏,也就是上文所说的扩展点:

#macro extensionPoint(type objectType objectId foundationMap)

    ##获取扩展点内容
    #set(text = extensionPointManager.getExtensionPointMacroByType(type))

    ##解析扩展点内容
    ${eval(text)}

#end

从上面的代码可以出扩展点调用时,需要声明扩展点类型type,业务对象类型objectType和业务对象标识符objectId。这几个参数都是通用参数因此显示的声明,对于不同功能模块需要的额外参数通通放进foundationMap里面。而对于这个宏的实体内容实际上是通过一个扩展点管理器获取各个功能的模板宏,然后再调用eval来解析各宏的内容。

扩展点的定义是声明在XML中,格式如下:

<extension-points>
    <extension-point type="扩展点类型" order="排序" name="扩展点名称">
        扩展点内容
    </extension-point>    
</extension-points>

扩展点的定义可以分散在各个模块各自不同的文件。各扩展点由框架的文件搜索器fileResolver根据配置文件后缀*.ext-point.xml进行搜索动态加载。 对平台中扩展点的整合是通过ExtensionPointManager进行管理,他的作用包括读取XML后存储扩展点信息、获取扩展点信息、删除扩展点等等。

public interface ExtensionPointManager {
    String XSTREAN_PACKAGE_NAME = "extensions";

    /**
     * 添加扩展点
     *
     * @param extensionPoint
     */
    void addExtensionPoint(ExtensionPoint extensionPoint) throws ExtensionPointException;

    /**
     * 添加扩展点
     *
     * @param extensionPoints
     */
    void addExtensionPoints(ExtensionPoints extensionPoints) throws ExtensionPointException;

    /**
     * 移除扩展点
     *
     * @param extensionPoint
     */
    void removeExtensionPoint(ExtensionPoint extensionPoint);

    /**
     * 移除扩展点
     *
     * @param extensionPoints
     */
    void removeExtensionPoints(ExtensionPoints extensionPoints);

    /**
     * 根据扩展类型查找所有符合的扩展点内容
     *
     * @param type
     * @return
     */
    String getExtensionPointMacroByType(String type);

    /**
     * 根据类型查找扩展点,排除不需要的扩展点名称
     *
     * @param type
     * @param excludeNames 多个排除扩展点名称以","分隔
     * @return
     */
    String getExcludeExtensionPointMacroByType(String type, String excludeNames);

    /**
     * 根据扩展点名称获取宏
     *
     * @param names
     * @return
     */
    String getExtensionPointMacroByNames(String names);
}

开发实例

基于应用切面我们已经做了一大批基本业务切面组件——foundation,它的诞生是为了给具体项目的快速开发提供基础的业务组件,并且以应用切面的方式做良好的插拔式使用,提高开发效率,同时是对资产的积累和重复利用。目前已经开发完成二十余个业务组件。并且在项目KMS(http://kms.tinygroup.org)中进行实践检验。

KMS是一个知识管理器系统,而对于这个系而言,他真正开发的工作只专注于他的自己的业务,就是知识管理,这时具体的项目开发就非常的简单。但具体项目开发简单并不意味着这个项目的最后呈现的功能效果简单。实际上他还包括对一篇文档的点赞、收藏、关注、评论、浏览信息记录、关联文档、历史版本管理等等一些列复杂的功能。而这些功能具体的项目中无需二次开发,只需依赖foundation提供的应用切面即可完成功能多样的扩展功能,而作为项目本身只需要关注自己应该专注的业务就好。

KMS效果 在这个界面中由于在不同的位置分布需要灵活的扩展点,因此埋下了两个桩,也就是调用了两次扩展点。

#extensionPoint("docMenu" "doc" doc?.docId)

一个是扩展类型为docMenu的扩展点,位于页面的上部,用于展现此片文章的浏览信息,关注、收藏、点赞等信息功能点。对象类型为doc文档的标识通过一个变量doc.docId传入。 每个扩展点的具体定义配置在如下的XML文件中,每个扩展点又对应着具体的宏,当然如果没有二次封装的必要也可以直接写模板语言具体的实现内容。

<extension-points>
    <!--浏览信息-->
    <extension-point type="docMenu" order="1" name="visitInfo">
        #visitInfo(objectId objectType foundationMap)
    </extension-point>

    <!--点赞信息-->
    <extension-point type="docMenu" order="2" name="goodInfo">
        #goodInfo(objectId objectType foundationMap)
    </extension-point>

    <!--踩信息-->
    <extension-point type="docMenu" order="3" name="badInfo">
        #badInfo(objectId objectType foundationMap)
    </extension-point>

    <!--收藏信息-->
    <extension-point type="docMenu" order="4" name="favoritesInfo">
        #favoritesInfo(objectId objectType foundationMap)
    </extension-point>

    <!--关注信息-->
    <extension-point type="docMenu" order="5" name="followInfo">
        #followInfo(objectId objectType foundationMap)
    </extension-point>

    <!--评论信息-->
    <extension-point type="docMenu" order="6" name="commentInfo">
        #commentInfo(objectId objectType foundationMap)
    </extension-point>

</extension-points>

另一个扩展点类型docBottom的扩展点,位于页面底部,可以动态添加多个附加功能模块。

#extensionPoint("docBottom" "doc" doc?.docId {"spaceId":spaceId,"docExt":docText,"status":status})

类型为docBottom的扩展点包括显示这篇文档对于的tag和关联信息及强大的评论功能

<extension-points>
    <!--标签扩展-->
    <extension-point type="docBottom" order="1" name="tagPannel">
        #tagPannel(objectId objectType foundationMap)
    </extension-point>    
    <!--关联扩展-->
    <extension-point type="docBottom" order="2" name="relationPannel">
        #relationPannel(objectId objectType foundationMap)
    </extension-point>    
    <!--评论扩展-->
    <extension-point type="docBottom" order="3" name="commentPannel">
        #commentPannel(objectId objectType foundationMap)
    </extension-point>    
</extension-points>

##总结 通过上述设计,我们初步实现了页面层上的切面设计。如果在具体功能模块设计可以真正的做到高内聚、松耦合,那么就可能就是我们想要的业务切面。

页面切面让人最直接的感受的是,新增的功能模块在页面上可以通过配置文件的配置增量添加,对于已有的功能模块可以通过卸载部分程序包拆卸对应功能模块,这样的用户体验是不是很酸爽呢?如果模块化做到了极致,再配上自动装配的黑科技,也许你也可以!

关于业务切面其实还有业务层、控制层一些特殊设计,并且其中夹杂一些关键小步骤,需要用心体会和设计,后面有时间的时候或许也会介绍。

有喜欢本人博客内容的同学请加关注,以便及时获知本人精品内容!

© 著作权归作者所有

悠悠然然

悠悠然然

粉丝 2472
博文 185
码字总数 363071
作品 14
杭州
架构师
私信 提问
加载中

评论(3)

ios122
ios122
好像,一般都把这个功能叫做 "钩子" hook
MinghuiGao
MinghuiGao
zheshi shenm gui ?
MinghuiGao
MinghuiGao
xie de bucuo ![12][12]
聊聊Spring AOP

开场白 现在主流的开发思想是OOP(面向对象编程),其中抽象、封装、继承、多态是其最重要的四个特性。而AOP(面向切面编程)是对OOP的增强和补充,其本质上也是对抽象和封装思想的运用。在O...

爱做梦的胖子
2017/11/23
0
0
学习总结

1 Spring之旅 Spring核心:依赖注入(dependency injection,DI)和面向切面编程(aspect-oriented programming,AOP) 简单老式Java对象(Plain Old Java Object,POJO) Spring最根本的使命:简化Jav...

杨意社
2018/01/13
27
0
Spring、SpringMVC、SpringBoot、SpringCloud的区别与联系

前言 Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架。Spring使你能够编写更干净、更可管理、并且更易于测试的代码。 Spring MVC是Spring的一个模块,一个web框架。通过Dispa...

Java架构师追风
09/30
0
0
entity服务器端验证

我想实现实体在保存到数据库的时候对其一些字段做服务器端验证.事先写好一些注解(如图). 对于要进行验证的一些实体类头家@Validate注解,然后对其中相应的字段进行@Chinese等注解.然后在保存的...

Crazy_Coder
2012/11/24
800
4
spring、springMvc、springBoot和springCloud的联系与区别

版权声明:本文为博主原创文章,如需转载,请标明出处。 https://blog.csdn.net/alan_liuyue/article/details/80656687 spring和springMvc: 1. spring是一个一站式的轻量级的java开发框架,...

尘光掠影
2018/06/11
0
0

没有更多内容

加载失败,请刷新页面

加载更多

Mybatis Plus删除

/** @author beth @data 2019-10-17 00:30 */ @RunWith(SpringRunner.class) @SpringBootTest public class DeleteTest { @Autowired private UserInfoMapper userInfoMapper; /** 根据id删除......

一个yuanbeth
今天
4
0
总结

一、设计模式 简单工厂:一个简单而且比较杂的工厂,可以创建任何对象给你 复杂工厂:先创建一种基础类型的工厂接口,然后各自集成实现这个接口,但是每个工厂都是这个基础类的扩展分类,spr...

BobwithB
今天
4
0
java内存模型

前言 Java作为一种面向对象的,跨平台语言,其对象、内存等一直是比较难的知识点。而且很多概念的名称看起来又那么相似,很多人会傻傻分不清楚。比如本文我们要讨论的JVM内存结构、Java内存模...

ls_cherish
今天
4
0
友元函数强制转换

友元函数强制转换 p522

天王盖地虎626
昨天
5
0
js中实现页面跳转(返回前一页、后一页)

本文转载于:专业的前端网站➸js中实现页面跳转(返回前一页、后一页) 一:JS 重载页面,本地刷新,返回上一页 复制代码代码如下: <a href="javascript:history.go(-1)">返回上一页</a> <a h...

前端老手
昨天
5
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部