[ 转载请注明出处 CSDN wangkaisine http://blog.csdn.net/wangkaisine/article/details/47832859 ]
最近在重构一个比成熟的Web应用,对这个应用页面中的数据对象进行了封装,对于很多系统甚至其他网站页面都用通用性,现在将主要的内容写出来,予以交流。
为什么要封装页面数据对象?
Web数据如何显示放在页面上,是我们需要解决的问题,数据对象能够实现通用的页面数据封装,大大减少后端代码数量,方便我们使用页面实例向页面中填塞数据,且程序更易读懂。
这是我们常见的web页面布局,其中header和footer区域,一般来说都是固定不变的,所以我们需要考虑content区域的数据元素。
而在content中,常见的数据对象包括以下的navigator、title、form、table等,其中navigator是统一的,因此也不必封装成后台对象。那么主要就是form和table对象需要在后台进行封装了。
navigator在页面中,可以直接使用js和静态div,来陈列它的内容和样式。我们已经说了导航栏完全可以放在前端去生成和操作,因此不再这里叙述。
下面我们来讲讲详细的页面数据封装:
我们定义页面中最小的数据元素就是cell,用来承载数据、保存链接以及定义样式class,我们从cell中分化成两种cell,一种叫做name cell,另外一种是data cell,它们有着不同的行为模式和方法。只在表现上有相同的地方,就是都属于表格或表单的一小块内容。然而name cell用来保存table表头的变量名值,或者form表单的属性名值,而data cell用来保存数据。
如上图所示,我们使用cell了组合成不同的row,作为form或者table的行,多个cell组成一个row。例如,多个data cell组成了一个data row,它用来包括表格内的数据。多个name cell组成了一个name row,它用来表示table的第一行表头变量。一个name cell和一个data cell组成了form row,它用来表示form中的每一行属性(attribute)以及值(value)。
如果你认为本文就是在简单讲这样的页面元素封装方法,那你就错了,这样的封装真的就只是方法,而不是技术。下面我们就讲讲技术的事情。
name cell:
name cell是一行属性数据,或者一列数据的表头,因此可以在它的属性中包括name,dbName,来映射它和数据库中某一字段的对应关系。在初始化页面content的时候,将table中的name row初始化,加入一个一个的name cell。
name cell还应该拥有一个helper类,来帮助我们改变和控制显示数据的格式与样式。可以创建接口NameCellHelper,其他的DefaultNameCellHelper,LinkNameCellHelper,NumberNameCellHelper,DateNameCellHelper等,来实现这个接口,这些类可以在后端对数据进行处理。
name cell helper作为一个属性(String)放在name cell中,在这个name cell被添加到table时,使用工厂获取这个属性对应的helper类示例,同时这个cell就有了对应的helper。像这样的helper,以及表格中的name cell,在启动应用的时候,就可以加载到应用中,也就是说,创建出了一个一个表格或表单的模板,它们只是还没有数据而已。在用户查询之后,表格才显示。
data table:
是从table类继承来的数据表格类,保存查询结果数据,作为一个通用的表格对象,它的name row和每一个data row都是等长的。
data table的列控制器主要就是由表头的NameCellHelper决定的,我们初始化的helper不多,但是每个name cell映射的helper确实绑定在每一个表的某一列上的,在每一行数据在输入时,需要每一列数据得到该列的helper,并输出自己的样式。
在之前我在写Java Web的时候,需要为每一个不同的功能模块的表格或者表单写一个form或者table类,来承载这些搜索前后的数据。但是有了这样统一化的数据对象,就可以实现更高层次的代码重用。
这样的数据对象定义我写到了一个文件夹下(domain),可以理解为一个页面数据对象的资源库,再使用这些资源库中的元素,拼装成我们需要完成的功能的content页面,content的属性就包括title、form、table等这些动态数据对象。方便content做统一的数据输出。
完成一个简单的搜索功能时,你只需要定义一个servlet(其实对于servlet也可以封装的更好,没必要每个功能都定义),在servlet执行完后,转到这个功能的搜索结果页面,在这个页面中引用通用的result页面,在页面中写的是设置table的各个属性,以及数据的值,这样所有的搜索功能都可以在跳转页面之后,共同引用这个页面,数据就被加载出来了。
name cell定义:
public class NameCell extends Cell {
private String name;
private String dbName;
private String nameCellHelper;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDbName() {
return dbName;
}
public void setDbName(String dbName) {
this.dbName = dbName;
}
public String getNameCellHelper() {
return nameCellHelper;
}
public void setNameCellHelper(String nameCellHelper) {
this.nameCellHelper = nameCellHelper;
}
public NameCell(String name,String dbName){
this.name = name;
this.dbName = dbName;
}
public NameCell(String name,String dbName,String nameCellHelper){
this.name = name;
this.dbName = dbName;
this.nameCellHelper = nameCellHelper;
}
}
使用cell、row拼装的table可以这样写:
import java.util.List;
public class Table {
private String title;
private String sql;
private List paramaternames;
private String sqlForTotal;
private String sqlForCount;
private String emptyMessage = "";
private String dbTableName;
private int columnIndex = 0;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getSql() {
return sql;
}
public void setSql(String sql) {
this.sql = sql;
}
public List getParamaternames() {
return paramaternames;
}
public void setParamaternames(List paramaternames) {
this.paramaternames = paramaternames;
}
public String getSqlForTotal() {
return sqlForTotal;
}
public void setSqlForTotal(String sqlForTotal) {
this.sqlForTotal = sqlForTotal;
}
public String getSqlForCount() {
return sqlForCount;
}
public void setSqlForCount(String sqlForCount) {
this.sqlForCount = sqlForCount;
}
public String getEmptyMessage() {
return emptyMessage;
}
public void setEmptyMessage(String emptyMessage) {
this.emptyMessage = emptyMessage;
}
public String getDbTableName() {
return dbTableName;
}
public void setDbTableName(String dbTableName) {
this.dbTableName = dbTableName;
}
public int getColumnIndex() {
return columnIndex;
}
public void setColumnIndex(int columnIndex) {
this.columnIndex = columnIndex;
}
}
data table就可以按照这样的方式封装:
import java.util.List;
import cn.***.com.wangkaisine.domain.row.DataRow;
import cn.***.com.wangkaisine.domain.row.NameRow;
public class DataTable extends Table {
private NameRow nameRow;
private List dataRow;
public NameRow getNameRow() {
return nameRow;
}
public void setNameRow(NameRow nameRow) {
this.nameRow = nameRow;
}
public List getDataRow() {
return dataRow;
}
public void setDataRow(List dataRow) {
this.dataRow = dataRow;
}
}
虽然用了很多的文字来说明这一方法,但还没有很详尽的表述如何封装和具体使用这些对象,希望以后继续加油!