通用灵活的网站内容展示数据结构设计与代码编写(借助AngularJs)
2015-11-08 15:08
651 查看
前言
假设公司需要快速构建一个CMS系统,同时支持灵活多变的内容展示形式。该CMS系统需要支持用户自定义内容的属性、值、以及展示方式。因此,不能仅仅使用固定的表字段来表示某个内容或者栏目的属性。同时,栏目与内容的展示,在某一程度上应该遵循固定的数据格式,便于最大限度的代码复用。数据结构
参考Jspxcms本文中将涉及几种主要数据结构:栏目命名为节点(Node)
某一具体内容命名为信息(Info)
页面展示模板资源命名为模型(Model)
可附加的属性定义(AttribueDefine)
属性值(AttributeValue)
节点(Node)
主要包含栏目(Node), 栏目属性关联(NodeAttribute)两个实体Node
记录栏目的基本属性,其中记录父节点和根两个属性即可令Node集合形成树,从而支持复杂的栏目组合。@Id @Column(name = "node_id") private int nodeId;//栏目ID @Column(name = "node_name", length = 100) private String nodeName;//栏目名称 @Column(name = "parent_id") private int parentId;//父节点 @Column(name = "node_model_id") private int nodeModelId;//栏目模板 @Column(name = "node_img_url", length = 1024) private String nodeImgUrl;//栏目图URL @Column(name = "node_sequence", length = 3) private String nodeSequence;//栏目顺序号 @Column(name = "is_root", length = 1) private String isRoot;//是否根栏目 @Column(name = "is_show", length = 1) private String isShow;//是否启用 @Column(name = "home_flag", length = 1) private String homeFlag;//首页展示 @Column(name = "version_no", length = 17) private String versionNo;//版本号
NodeAttribute
记录外挂属性定义与属性值的Id,通过外挂形式支持无限的属性/值集合。这里将值直接记录在该实体中。@Id @Column(name= "node_id") private int nodeId;//栏目id @Column(name = "attribute_define_id") private Long attributeDefineId;//属性定义id @Id @Column(name = "key_code", length = 50) private String keyCode;//key @Id @Column(name = "attribute_value", length = 2000) private String attributeValue;//属性值
内容(Info)
Info
Info作为栏目的内容,挂在某个栏目之下,同时也支持外挂属性定义和属性值。@Id @Column(name = "info_id",unique=true,nullable=false) private Long infoId;//内容ID info_id bigint 主键 @Column(name = "node_id",nullable=false) private Integer nodeId;//栏目ID node_id int not null @Column(name = "priority",length=2) private String priority;//优先级 priority @Column(name = "info_title",length=150,nullable=false) private String infoTitle;//标题 info_title varchar(150) not null @Column(name = "info_subtitle",length=150) private String infoSubtitle;//副标题 info_subtitle varchar(150) @Column(name = "info_link",length=1024) private String infoLink;//转向链接 info_link varchar(1024) @Column(name = "is_new_window",length=1) private String isNewWindow;//是否在新窗口打开 is_new_window char(1) 0否、1是 @Column(name = "info_path",length=1024) private String infoPath;//信息路径 info_path varchar(1024) @Column(name = "info_template_id") private int infoTemplateId;//内容模板 @Column(name = "meta_description",length=255) private String metaDescription;//描述 meta_description varchar(255) @Column(name = "info_author",length=100) private String infoAuthor;//作者 info_author varchar(100) @Column(name = "start_date",length=8) private String itartDate;//有效期起日期 start_date char(8) @Column(name = "stop_date",length=8) private String stopDate;//有效期止日期 stop_date char(8) @Column(name = "version_no",length=17,nullable=false) private String versionNo;//版本号 version_no varchar (17) not null 新增和更新时填写
InfoAttribute
通过外挂形式支持无限属性定义与属性值。这里将值直接记录在该实体中。@Id @Column(name = "info_id") private Long infoId;//内容ID @Column(name = "attribute_define_id") private Long attributeDefineId;//属性定义ID @Id @Column(name = "key_code", length = 50) private String keyCode;//key @Id @Column(name = "attribute_type") private String attributeType;//值
属性(Attribute)
将属性定义与属性值区分开,其中属性值(AttributeValue)仅与属性定义连接,作为记录某属性的多个备选值列表用。实际应用是,使用的值将直接记录在(NodeAttribute或者InfoAttribute中)。AttributeDefine
@Id @Column(name = "attribute_define_id") private Long attributeDefineId;//属性定义id @Column(name ="attribute_type", length =1) private String attributeType;//属性类型 @Column(name = "input_type", length = 50) private String inputType;//输入类型 @Column(name ="field_name", length = 100) private String fieldName;//字段名称 @Column(name = "field_code", length = 50) private String fieldCode;//字段代码 @Column(name = "attribute_sequence", length = 3) private String attributeSequence;//字段顺序 @Column(name = "is_mandatory",length = 1) private String isMandatory;//是否必填 @Column(name = "default_value", length = 100) private String defaultValue;//默认值 @Column(name = "information", length = 255) private String information;//提示信息
DefineValue
@Id @Column(name = "define_value_id") private Long defineValueId;//属性定义值id @Column(name = "attribute_define_id") private Long attributeDefineId;//属性定义id @Column(name = "value_attribute", length = 100) private String valueAttribute;//值 @Column(name = "sequence_attribute", length = 3) private String sequenceAttribute;//排序
后台代码
数据包装
因为需要同时返回栏目(内容)以及相应属性,因此需要将数据集合封装好并回传。以栏目封装为例。最外层为NodeItem,其中包含Node以及一个属性/值集合NodeAttributeDefinePair 。类定义如下
public class NodeItem { Node node; List<NodeAttributeDefinePair> pairs; public NodeItem(){} public NodeItem(Node node, List<NodeAttributeDefinePair> pairs){ this.node =node; this.pairs = pairs; } public Node getNode() { return node; } public void setNode(Node node) { this.node = node; } public List<NodeAttributeDefinePair> getPairs() { return pairs; } public void setPairs(List<NodeAttributeDefinePair> pairs) { this.pairs = pairs; } } public class NodeAttributeDefinePair { private NodeAttribute nodeAttribute; private AttributeDefine define; private AttributeDefineValue value; public NodeAttributeDefinePair(){} public NodeAttributeDefinePair(NodeAttribute attr, AttributeDefine define, AttributeDefineValue value){ this.nodeAttribute = attr; this.define = define; this.value = value; } public NodeAttributeDefinePair(NodeAttribute attr, AttributeDefine define){ this.nodeAttribute =attr; this.define = define; } public NodeAttribute getNodeAttribute() { return nodeAttribute; } public void setNodeAttribute(NodeAttribute nodeAttribute) { this.nodeAttribute = nodeAttribute; } public AttributeDefine getDefine() { return define; } public void setDefine(AttributeDefine define) { this.define = define; } public AttributeDefineValue getValue() { return value; } public void setValue(AttributeDefineValue value) { this.value = value; } }
接口整理
初步考虑,用于获取数据的接口应该包含一下几个:1、获取某栏目以及相应属性
2、获取某内容以及相应属性
3、获取某栏目的子栏目列表以及属性
4、获取某栏目的内容列表以及属性
具体实现
就是根据父子关系按照id进行搜索,比较简单,结合数据包装返回即可,因此不做过多描述。前台代码(AngularJs)
根据上节的接口描述,可以将实现上述接口的方法统一封装为模块,并在需要的地方注入并调用即可。【使用$q 实现异步获取】模块定义
angular.module('nodeInfo',[]) /*列表类型服务*/ .service('nodeInfolistService', function(){ this.listSubNodes = function($scope, $http,$q,paramsxxxx){ var q = $q.defer(); var url = ctx + 'api/xxxxxxx'; var params = { params:paramsxxxx }; $http({method:'GET', params:params,url:url}) .success(function(response){ q.resolve(response); }) .error(function(response){ q.reject('服务器开小差了,请稍后重试'); }); return q.promise; }; //......略 }) /*内容获取类型服务*/ .service('nodeInfoitemService', function(){ //......略 });
模块使用
外部使用的时候,首先在页面引入相应的js文件,在页面的APP申明中注入该模块,并引用服务即可。代码如下:
/*注入nodeInfo*/ var app = angular.module('app',['nodeInfo']); app.service('appService',function(){ }); /*引入服务nodeInfolistService*/ app.controller('appCtrl', function($scope, $http,$q, appService, nodeInfolistService){ var currentNodeId = $('#currentNodeId').text(); var parentId = $('#parentId').text(); //promise方式异步获取 var subPromise = nodeInfolistService.listSubNodes($scope, $http, $q, currentNodeId); subPromise.then( function(subNodes){ $scope.subNodes = subNodes; }, function(err){ console.log(err); } ) });
通过归纳整理通用的数据获取接口库,并封装数据获取的相应服务,使网站的任意形式内容均可以以统一的方式获取,极大的简化了后期开发的代码量。同时,若后台逻辑变化时,也仅需要修改封装的服务即可,不需要修改其它页面。
效果
node列表info列表
node详情+info列表
这里的”第一集”就是一个info
info详情
相关文章推荐
- android 代码实现控件之间的间距
- [Android]在代码里运行另一个程序的方法
- 肯特·贝克:改变人生的代码整理魔法
- 一步一步跟我学易语言之第二个易程序菜单设计
- 网页恶意代码的预防
- 高手写的Tracer-Flash代码调试类代码下载
- CSS代码缩写技巧
- 非主流Q-zOne代码代码搜集第1/2页
- CreateWeb.vbs 代码
- Lua中编译执行代码相关的函数详解
- Lua教程(七):数据结构详解
- 试用Kesion CMS 4.0商城版 商业版
- 解析从源码分析常见的基于Array的数据结构动态扩容机制的详解
- C#数据结构揭秘一
- 基于逻辑运算的简单权限系统(原理,设计,实现) VBS 版
- C#中设计、使用Fluent API
- 更有效率的css代码编写第1/3页
- 代码中到底应不应当写注释?
- 数据结构之Treap详解
- SQL语言查询基础:连接查询 联合查询 代码