日期:2014-05-16  浏览次数:20857 次

运用struts2和ajax进行动态对象数据的加载

??? 现在的项目中,存在着许多的列表选择数据,比如在一个界面中有许多的选择项。通过这些选择项是由一个select下拉列表来进行选择的,而加载这些下拉列表,除普通的在action中主动获取之外,另外一种方式进行ajax方式在界面加载时加载。

?

??? 在我们的项目中,现在运用的即是在界面加载时,通过ajax方式来加载相应的列表数据,这样的好处即是不需要在表单加载时,由处理表单的action来生成相应的列表数据,而是交给产生这个列表数据的action来加载数据。现在存在的主要问题就是,每个列表的数据来源不一样,这就导致了需要写不同的加载代码来加载这些数据,而每个加载数据的action代码分布在不同的处理action中(比如用户数据由UserAction处理,字典数据由DictionaryAction处理),而每个加载逻辑还需要根据不同的参数进行不同的service转发,而经以dao来获取数据。在界面上,相应的js加载代码也不尽相同,但大体逻辑均是相同(即获取数据,填充列表)。

?

??? 解决问题的方法

??? 即是将所有的通用数据加载逻辑进行统一封装,前台js入口统一,后台逻辑统一。比如,通过load[User]用于加载用户数据,load[Dictionary]用于加载字典数据,用不同的参数来进行相应的数据加载。

?

??? 大致思路

??? 界面上传递几个关键性的参数(加载类,过滤参数,显示参数,以及排序参数),统一传递给action,action对加载类作判断,再对过滤参数进行参数处理(过滤非法参数),然后从数据库中进行数据加载(考虑排序),之后再对显示参数进行参数处理(过滤非法参数),最后将信息通过ajax的方法传递给界面,由界面进行列表数据构建并展现。

?

?? 界面实现效果

?? 1,用户选择一个加载数据类型,

??? 2,选择之后,根据选择的数据类,再由action将这个类可以供显示的字段列举出来,以选择要显示的字段信息。

??? 3,再在参数传递中,填入传递的过滤参数,比如username=bbbb,即限制加载的类的属性username应该为bbbb,最后点击(加载数据)按钮,由action处理,将数据展现在下面的table列表中。

?以上的展现只是一个实现上的展现,而下边的展现,则是应用上的展现。

??? 4,当点击(加载项目)或(加载用户)按钮时,相应的select便会根据相应的请求参数,加载相应的数据了。如下所示

??? 在实际的项目中,相应列表数据的加载,均是已知条件或条件已经可以确定了,所以实际的加载时,并不会点击某个按钮来加载,而是直接在启动函数(如jquery.onload)中写相应的数据加载代码,通过一个js函数调用,并可以直接加载相应的数据,而不需要再重新为不同的加载类型和参数重新定制后台代码了。

?

??? 技术实现

?

??? 数据模型

??? 我们构建以下这些数据模型,用于封装相应的参数及数据信息。

??? 1,Map<String, String> p:参数信息,由界面传递过来的参数。如p['username'](用户名)或['role.id'](角色id)

??? 2,Set<String> f:界面显示字段信息,最终哪些字段将会展现给界面,而不是全部数据均展现

??? 3,String order:排序字段,即结果按照哪个字段进行排序

??? 4,boolean by = true:排序是按照升序还是降序

??? 5,Class<? extends Entityable> clazz:请求的加载数据类型

??? 由于是采用struts2,所以相应的set和get还是少不了的。

?

??? 加载数据限制

??? 为避免加载的数据过多(实际上,能够用select列表封装的数据,条目肯定不会太多),我们在action中对加载的数据条目进行了限制,即是通过一个page参数,作相应限制,并最终传递给dao以通过hibernate进行数据加载限制。如下代码:

	@Override
	public void createPage() {
		super.createPage();
		page.setTotalCount(1);//不进行总数加载
		page.setPageSize(100);//最多加载100条数据
	}

?

??? action加载逻辑

??? 加载逻辑,即是首先创建分页参数(即限制条目,再将相应的参数传递给service进行处理,并返回加载数据结果,再处理显示字段参数,最后将结果通过ajax显示在界面上。相应的主要代码如下:

createPage();
entityableList = domainLoadService.loadDomain(clazz, p, order, by, page);
//准备输出字段信息
......
//处理显示字段,过滤掉不被支持的字段,如无效字段,非simpleType类型
//输出信息,通过ajax方式将结果中指定字段信息以json形式输出到界面上
AjaxSupport.sendSuccessTextOnly(null, entityableList, f.toArray(new String[f.size()]));

?

??? service处理逻辑

??? 处理逻辑首先分析传递参数,即进行非法参数过滤(不存在的字段参数,以及非简单类型参数),然后处理排序参数(是否需要排序),再根据加载类型,过滤参数,排序参数通过detachedCriteria进行条件构建,最后联合page参数一起由dao进行数据加载。大致代码如下:

???

		Map<String, Object> paramData = analyzeParam(clazz, p);
		logger.debug("valid param->" + paramData);
		boolean validOrder = StringUtils.hasText(order) && BeanUtils.getSimplePropertyType(clazz, order, true, true) != null;
		//准备构建条件语句
		DetachedCriteria detachedCriteria = DetachedCriteria.forClass(clazz);
		for(Map.Entry<String, Object> e : paramData.entrySet())
			detachedCriteria.add(Restrictions.eq(e.getKey(), e.getValue()));
		if(validOrder)
			detachedCriteria.addOrder(by ? Order.asc(order) : Order.desc(order));
		return baseDAO.listByCriteria(detachedCriteria, page);

?

?? 主要的难点在分析传递参数中,首先要排除空参数(即空字符串),然后再看这个参数字段是否存在于相应的类中(参数是否有效),再检查这个参数字段是否是简单类型(不支持复合类型,如l