跟我一起学extjs5(37--单个模块的设计[5取得模块列表数据])

跟我一起学extjs5(37--单个模块的设计[5取得模块列表数据])

写了几个月,总算有点盼头了,最终要从后台取得数据了。后台的spring mvc 和 service 仅仅能简单的说说了,里面加了几十个类。有兴趣的下载了源代码自己看。以下画张通用的模块列表取数据的流程,这个流程是适用于全部的模块。我这个后台处理程序也是对全部的模块进行统一处理,包含数据查找,新增,改动,删除都是同样的。



watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvamZvaw==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" >

绘图不是强项。看得懂即可。

1、grid在渲染好后就会通过Stroe来取得数据;

2、Stroe会发送ajax请求至后台server,spring mvc 会依据请求找到 ModuleController 中的对应取得数据的函数;

3、控制器中调用ModuleService中的函数取得数据。

4、Service再调用 ModuleDAO的函数从数据库中取得数据,然后一级级的返回到Store中。再显示在Grid之中。

如今我们先做extjs5端的改动。原来的Store使用的是本地数据,如今要改成远程调用的数据,

1、先改动model的生成函数ModelFactory.js。这个函数依据传入的module的定义来生成model,主要生成的有fields属性和proxy。另一些以后要用到的函数。比方推断此条记录能否改动、删除等的函数。

另一个是取得本条记录的标志字段的函数。

/**
 * 依据module的数据来生成模块的model
 */
Ext.define('app.view.module.factory.ModelFactory', {

	statics : {
		getModelByModule : function(module) {

			var model = Ext.define('app.model.' + module.tf_moduleName, {
				extend : 'Ext.data.Model',
				module : module,
				idProperty : module.tf_primaryKey,
				nameFields : module.tf_nameFields,
				titleTpl : module.tf_titleTpl,
				titleTemplate : null,
				fields : this.getFields(module),
				proxy : {
					type : 'rest',
					batchActions : true,
					extraParams : {
						moduleName : module.tf_moduleName
					},
					api : {
						// 在这里加rest/是由于在web.xml中
						// <url-pattern>/rest/*</url-pattern>这一句。spring会依据rest
						// 后面的參数去进行匹配
						read : 'rest/module/fetchdata.do',
						update : 'rest/module/update.do',
						create : 'rest/module/create.do',
						destroy : 'rest/module/remove.do'
					},
					actionMethods : {
						create : 'POST',
						read : 'GET',
						update : 'PUT',
						destroy : 'DELETE'
					},
					reader : {
						type : 'json',
						root : 'records',
						totalProperty : 'totalCount'
					},
					writer : {
						type : 'json',
						writeRecordId : true,
						writeAllFields : false
						// 没有改动过的字段不增加到update和delete的json中去
					},
					listeners : {
						exception : function(proxy, response, operation) {
							// 将出错信息加到proxy中去,传递到store的sync中显示出错信息。显示后将此属性删除
							proxy.errorInfo = Ext.decode(response.responseText, true);
							// 假设出错信息解析出错,则增加一个缺省的
							if (!proxy.errorInfo)
								proxy.errorInfo = {
									resultCode : -1,
									errorMessage : '未知原因:' + response.responseText
								}
						}
					}
				},

				getTitleTpl : function() {
					if (!this.titleTemplate) {
						if (this.titleTpl)
							this.titleTemplate = new Ext.Template(this.titleTpl);
						else
							this.titleTemplate = new Ext.Template('{' + this.nameFields + '}');
					}
					return this.titleTemplate.apply(this.getData())
				},

				// 此条记录能否够改动
				canEdit : function() {
					if (this.module.tf_hasAuditing && this.get('tf_auditinged'))
						return false;
					if (this.module.tf_hasApprove && this.get('tf_shNowCount') > 0)
						return false;
					return true;
				},

				// 此条记录能否够进行操作
				canOperate : function() {
					if (this.module.tf_hasAuditing && this.get('tf_auditinged'))
						return false;
					return true;
				},

				// 此条记录能否够删除
				canDelete : function() {
					if (this.module.tf_hasAuditing && this.get('tf_auditinged'))
						return {
							canDelete : false,
							message : '【' + this.getTitleTpl() + '】已进行过审核,不同意进行删除操作!'
						};
					if (this.module.tf_hasApprove && this.get('tf_shNowCount') > 0)
						return {
							canDelete : false,
							message : '【' + this.getTitleTpl() + '】正在审批或已经审批完毕,不同意进行删除操作!'
						};
					return true;
				},

				// 取得主键值
				getIdValue : function() {
					return this.get(this.idProperty);
				},

				// 取得当前记录的名字字段
				getNameValue : function() {
					if (this.nameFields)
						return this.get(this.nameFields);
					else
						return null;
				}

			});
			return model;
		},
		// String("String"), Boolean("Boolean"), Integer("Integer"),
		// Date("Date"), Double("Double"), Float("Float"); Percent

		getFields : function(module) {
			var fields = [];

			for (var i in module.moduleFields) {
				var fd = module.moduleFields[i];

				var field = {
					name : fd.tf_fieldName,
					title : fd.tf_title,
					type : this.getTypeByStr(fd.tf_fieldType)
				};
				if (field.type == 'string') {
					field.useNull = true;
					field.serialize = this.convertToNull;
				}

				if (fd.tf_fieldType == 'Date') {
					field.dateWriteFormat = 'Y-m-d';
					field.dateReadFormat = 'Y-m-d';
				}
				if (fd.tf_fieldType == 'Datetime')
					field.dateReadFormat = 'Y-m-d H:i:s';
				field.tf_haveAttachment = fd.tf_haveAttachment;
				fields.push(field);
			}

			return fields;

		},

		getTypeByStr : function(str) {
			console.log(str);
			switch (str) {
				case 'String' :
					return 'string';
				case 'Boolean' :
					return 'boolean';
				case 'Integer' :
					return 'int';
				case 'Date' :
					return 'date';
				case 'Datetime' :
					return 'date';
				case 'Double' :
				case 'Float' :
				case 'Percent' :
					return 'float';
				default :
					return 'string';
			}
		},

		// 假设是空字符串,返回null
		convertToNull : function(v) {
			return v ?

v : null;
		}

	}

});

2、在app.store的文件夹下生成文件GridStore.js。这是grid的Store的类的定义。

Ext.define('app.store.GridStore', {
			extend : 'Ext.data.Store',

			modulePanel : null,
			remoteSort : true,
			autoLoad : true,
			autoSync : true,
			leadingBufferZone : 100,
			buffered : false, // buffered=true能够无限下拉。可是删除和新增,reload都有问题,临时不用

			config : {
				extraParams : {},
				navigates : []
				// 导航属性选中的情况
			},

			constructor : function(param) {
				var me = this;
				this.pageSize = 20;
				this.extraParams = {};
				this.navigates = [];
				// 有创建时加进来的导航约束
				if (param.modulePanel.param) {
					var dnv = param.modulePanel.param.defaultNavigateValues;
					this.setDefaultNavigates(dnv);
				}
				// ///////////
				this.callParent(arguments);
			},

			listeners : {
				// 调用proxy进行ajax的时候。将參数加进 store.proxy中,在调用完毕后。删除掉全部的extraParams參数
				// 这样model.proxy就能够多store,互相不干扰了
				beforeprefetch : function(store) {
					for (var i in store.extraParams)
						store.proxy.extraParams[i] = store.extraParams[i];
				},
				// buffered = true ,运行的是 prefetch
				prefetch : function(store, records, successful) {
					for (var i in store.extraParams)
						delete store.proxy.extraParams[i];
				},

				// buffered = false ,运行的是 load
				beforeload : function(store) {
					// console.log(store);
					for (var i in store.extraParams)
						store.proxy.extraParams[i] = store.extraParams[i];

				},

				load : function(store) {
					for (var i in store.extraParams)
						delete store.proxy.extraParams[i];
				}

			}

		});

3、改动app.view.module.Module类。把store 和 model的生成方式都改一下。

			initComponent : function() {
				console.log(this.moduleName + ' 正在创建');
				// 从MainModel中取得当前模块的定义数据。包含字段和各种设置的信息

				var mainmodel = this.up('app-main').getViewModel();
				this.module = mainmodel.getModuleDefine(this.moduleName);
				var viewmodel = new Ext.create('app.view.module.ModuleModel', {
							// 将该模块的定义信息传递给本模块的viewModel
							module : this.module
						});
				this.setViewModel(viewmodel);

				this.glyph = this.getViewModel().get('tf_glyph'); // 因为上面的glyph的bind无效,因此须要在这里增加glyph的设置
				this.model = app.view.module.factory.ModelFactory.getModelByModule(this.module);
				this.store = Ext.create('app.store.GridStore', {
							module : this.module,
							model : this.model,
							modulePanel : this
						});
				this.items = [{
							xtype : 'navigate', // 导航区域
							region : 'west',

4、后台服务器端在com.jfok.server.controller下增加ModuleController.java,这是spring mvc 的控制类。

package com.jfok.server.controller;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.exception.ConstraintViolationException;
import org.springframework.dao.DataAccessException;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import com.jfok.server.DAO.SystemBaseDAO;
import com.jfok.server.DAO.module.ModuleDAO;
import com.jfok.server.DAO.module.SqlModuleFilter;

import com.jfok.server.common.ModuleServiceFunction;

import com.jfok.server.hibernate.system._Module;
import com.jfok.server.service.ApplicationService;
import com.jfok.server.service.ModuleService;

import com.jfok.shared.module.DataDeleteResponseInfo;
import com.jfok.shared.module.DataFetchResponseInfo;
import com.jfok.shared.module.DataInsertResponseInfo;
import com.jfok.shared.module.DataUpdateResponseInfo;

@Controller
@RequestMapping(value = "/module")
/**
 * 所有模块的的CRUD都是调用这个类的函数来完毕的Controller里面完毕的
 *
 * @author jiangfeng
 *
 */
public class ModuleController {

	@Resource
	private SystemBaseDAO systemBaseDAO;

	@Resource
	private ModuleService moduleService;

	@Resource
	private ModuleDAO moduleDAO;

	private static final Log log = LogFactory.getLog(ModuleController.class);

	/**
	 * 依据前台的请求取得数据
	 */
	@RequestMapping(value = "/fetchdata.do", method = RequestMethod.GET)
	public @ResponseBody
	Map<String, Object> fetchData(String moduleName, Integer start, Integer limit, String sort,
			String query, String columns, String navigates, String parentFilter,
			HttpServletRequest request) {
		DataFetchResponseInfo response = moduleService.fetchDataInner(moduleName, start, limit, sort,
				query, columns, navigates, parentFilter, (SqlModuleFilter) null, request);
		Map<String, Object> result = new HashMap<String, Object>();
		result.put("records", response.getMatchingObjects());
		result.put("totalCount", response.getTotalRows());
		return result;
	}

	/**
	 * 新增记录的时候,在后台取得缺省值
	 *
	 * @param moduleName
	 * @param parentFilter
	 * @param navigates
	 * @param request
	 * @return
	 */

	@RequestMapping(value = "/getnewdefault.do", method = RequestMethod.POST)
	public @ResponseBody
	Object getRecordNewDefault(String moduleName, String parentFilter, String navigates,
			HttpServletRequest request) {

		return moduleService.getRecordNewDefault(moduleName, parentFilter, navigates, request);

	}

	@RequestMapping(value = "/fetchdata.do/{id}", method = RequestMethod.GET)
	public @ResponseBody
	Object getRecordById(String moduleName, @PathVariable("id") String id, HttpServletRequest request) {
		log.debug("依据主键取得模块的一条记录:" + moduleName + "," + id);
		Map<String, Object> result = new HashMap<String, Object>();
		result.put("totalCount", 1);
		List<Object> records = new ArrayList<Object>();
		try {
			records.add(moduleDAO.getModuleRecord(moduleName, id, request).toString());
		} catch (Exception e) {
			e.printStackTrace();
		}
		result.put("records", records);
		log.debug("getRecordById返回值:" + result.toString());
		return result;
	}

	/**
	 * 创建一条记录
	 *
	 * @param moduleName
	 * @param inserted
	 * @param request
	 * @return
	 */
	@RequestMapping(value = "/create.do", method = RequestMethod.POST)
	public @ResponseBody
	DataInsertResponseInfo addWithNoPrimaryKey(String moduleName, @RequestBody String inserted,
			HttpServletRequest request) {

		return add(moduleName, inserted, request);
	}

	@RequestMapping(value = "/create.do/{id}", method = RequestMethod.POST)
	public @ResponseBody
	DataInsertResponseInfo add(String moduleName, @RequestBody String inserted,
			HttpServletRequest request) {
		DataInsertResponseInfo result = null;
		try {
			result = moduleService.add(moduleName, inserted, request);
			if (result.getKey() != null) // 假设是空的话,那么就没有保存,错误原因已经在errorMessage里了
				result.getRecords().add(
						moduleDAO.getModuleRecord(moduleName, result.getKey(), request).toString());
		} catch (DataAccessException e) {
			e.printStackTrace();
			if (result == null)
				result = new DataInsertResponseInfo();
			result.setResultCode(ModuleService.STATUS_VALIDATION_ERROR);
		} catch (Exception e) {
			e.printStackTrace();
			if (result == null)
				result = new DataInsertResponseInfo();
			result.getErrorMessage().put("error", e.getMessage());
			result.setResultCode(ModuleService.STATUS_FAILURE);
		}
		return result;
	}

	/**
	 * 改动记录
	 *
	 * @param moduleName
	 * @param id
	 * @param oldid
	 * @param operType
	 * @param updated
	 * @param request
	 * @return
	 */
	@RequestMapping(value = "/update.do/{id}", method = RequestMethod.PUT)
	public @ResponseBody
	DataUpdateResponseInfo update(String moduleName, @PathVariable("id") String id, String oldid,
			String operType, @RequestBody String updated, HttpServletRequest request) {

		DataUpdateResponseInfo result = null;
		_Module module = ApplicationService.getModuleWithName(moduleName);
		// 假设主键值改动了,那么先进行主键的改动
		if (oldid != null && (!oldid.equals(id))) {
			try {
				result = moduleService.changeRecordId(moduleName, id, oldid);
			} catch (ConstraintViolationException e) {
				e.printStackTrace();
				result = new DataUpdateResponseInfo();
				if (e.getCause().toString().toLowerCase().indexOf("primary key") >= 0)
					result.getErrorMessage().put(module.getTf_primaryKey(), "改动过后的主键与原有的主键值反复!

");
				else
					result.getErrorMessage().put(module.getTf_primaryKey(), "当前主键与子模块有约束关系。不能够改动!");
				result.setResultCode(ModuleService.STATUS_VALIDATION_ERROR);
			}
			if (!result.getResultCode().equals(0))
				return result;
		}
		// 改动记录
		try {
			result = moduleService.update(moduleName, id, operType, updated, request);
			result.getRecords().add(moduleDAO.getModuleRecord(moduleName, id, request).toString());
		} catch (DataAccessException e) {
			result = new DataUpdateResponseInfo();
			result.setResultCode(ModuleService.STATUS_VALIDATION_ERROR);
		} catch (Exception e) {
			e.printStackTrace();
			result = new DataUpdateResponseInfo();
			result.getErrorMessage().put("error", e.getMessage());
			result.setResultCode(ModuleService.STATUS_FAILURE);
		}
		return result;
	}

	/**
	 * 删除记录
	 *
	 * @param moduleName
	 * @param id
	 * @param request
	 * @return
	 */
	@RequestMapping(value = "/remove.do/{id}", method = RequestMethod.DELETE)
	public @ResponseBody
	DataDeleteResponseInfo remove(String moduleName, @PathVariable String id,
			HttpServletRequest request) {
		DataDeleteResponseInfo result = null;
		try {
			result = moduleService.remove(moduleName, id, request);
		} catch (DataAccessException e) {
			result = new DataDeleteResponseInfo();
			String errormessage = ModuleServiceFunction.addPK_ConstraintMessage(e, moduleName);
			result.setResultMessage(-1, errormessage != null ? errormessage
					: "请检查与本记录相关联的其它数据是否所有清空!<br/>");
		} catch (Exception e) {
			result = new DataDeleteResponseInfo();
			result.setResultMessage(-1, e.getMessage());
		}
		return result;
	}

	@RequestMapping(value = "/removerecords.do")
	public @ResponseBody
	DataDeleteResponseInfo removeRecords(String moduleName, String ids, String titles,
			HttpServletRequest request) {
		DataDeleteResponseInfo result = null;
		String[] idarray = ids.split(",");
		String[] titlearray = titles.split("~~");

		result = new DataDeleteResponseInfo();

		for (int i = 0; i < idarray.length; i++) {
			try {
				DataDeleteResponseInfo recordDeleteResult = moduleService.remove(moduleName, idarray[i],
						request);
				if (recordDeleteResult.getResultCode() == 0)

					result.getOkMessageList().add(titlearray[i]);
				else {
					if (recordDeleteResult.getErrorMessageList().size() > 0)
						result.getErrorMessageList().add(
								"【" + titlearray[i] + "】" + recordDeleteResult.getErrorMessageList().get(0));
					else
						result.getErrorMessageList().add("【" + titlearray[i] + "】" + "未知错误!");
				}
			} catch (DataAccessException e) {
				String errormessage = ModuleServiceFunction.addPK_ConstraintMessage(e, moduleName);

				result.getErrorMessageList().add(
						"【" + titlearray[i] + "】" + (errormessage != null ?

errormessage : "关联的数据未清空!"));
			} catch (Exception e) {
				result.getErrorMessageList().add("【" + titlearray[i] + "】" + e.getMessage());
			}
		}
		result.setResultCode(result.getErrorMessageList().size());
		return result;
	}

}

5、在service包中增加ModuleService.java,用来完毕查询,新增,删除。改动的功能。

6、增加ModuleDAO.java ,用来依据模块名称。起始行,终止行,筛选条件等来从数据库中取得数据。这些类太多了,就不一一写明了。

时间: 2024-07-30 03:16:12

跟我一起学extjs5(37--单个模块的设计[5取得模块列表数据])的相关文章

跟我一起学extjs5(38--单个模块的设计[6取得模块列表数据])

跟我一起学extjs5(38--单个模块的设计[6取得模块列表数据]) 上一节中做好了前后台的程序,现在来看看取得数据的运行过程.在菜单中选择 "系统管理"--"模块分组".就可以看到下图,在渲染后grid后,会显示数据. 来看看ajax取得数据的url和数据. url的信息: Remote Address:[::1]:8888 Request URL:http://localhost:8888/app/rest/module/fetchdata.do?_dc=14

[译文]Domain Driven Design Reference(三)—— 模型驱动设计的构建模块

本书是Eric Evans对他自己写的<领域驱动设计-软件核心复杂性应对之道>的一本字典式的参考书,可用于快速查找<领域驱动设计>中的诸多概念及其简明解释. 其它本系列其它文章地址: [译文]Domain Driven Design Reference(一)—— 前言 [译文]Domain Driven Design Reference(二)—— 让模型起作用 [译文]Domain Driven Design Reference(三)—— 模型驱动设计的构建模块 Ⅱ.模型驱动设计的

跟我一起学extjs5(11--自定义模块的设计)

跟我一起学extjs5(11--自定义模块的设计) 从这一节开始我们来设计并完成一个自定义模块.我们先来确定一个独立的模块的所能定义的一些模块信息.以下信息只是我自己在开发过程中想到或用到的,希望有新的想法的或者有建议的跟贴回复. 一个独立模块包含以下信息: 1.模块的基本信息 模块ID号:一个数字的ID号,可以根据此ID号的顺序将相同分组的模块放在一块. 模块分组:模块分到哪个组里,比如说业务模块1.业务模块2.系统设置.系统管理等. 模块标识:系统中唯一的模块的标识,一般这个标识等同于数据库

跟我一起学extjs5(41--增加一个自定义模块(源码下载)[2销售合同加入菜单和模块展示])

跟我一起学extjs5(41--增加一个自定义模块[2销售合同加入菜单和模块展示]) 在前面一节销售合同模块的信息导入系统后,需要在菜单中加入这个模块,但是现在菜单模块没法利用此系统进行编辑(多模块的层次现在还没有加入),因此只能在数据库里加入一条记录了: 加入后,重新启动一下tomcat,进入系统,就能在菜单"合同管理"下,看到 "销售合同"的菜单条了,点击一下,看看结果吧. 以上是自动生成"销售合同"的模块界面,这个就是最初介绍的模块的列表.

跟我一起学extjs5(40--增加一个自定义模块[1建立表和bean文件])

跟我一起学extjs5(40--增加一个自定义模块[1建立表和bean文件]) 经过上面的工作,一个独立模块的CRUD已经可以运行了,为了更好的可以看到其他自定义功能,我们做一个自定义的独立模块,这个模块中包括了各种的数据类型. 新增一个"销售合同"的独立模块,模块名称为Agreement,里面包括了20几个字段,把主要的字段类型都设置了,有字符串型,整型,浮点型,金额型,日期型,布尔型,百分比,还包括计算字段. 建立表的sql语句如下: /****** 对象: Table [dbo]

跟我一起学extjs5(13--执行菜单命令在tabPanel中显示模块)

跟我一起学extjs5(13--执行菜单命令在tabPanel中显示模块) 上面设计好了一个模块的主界面,下面通过菜单命令的执行来把这个模块加入到主界面当中.在MainModule.js中有一个函数,生成了当前的菜单数据: // 根据data.systemMenu生成菜单条和菜单按钮下面使用的菜单数据 getMenus : function() { var items = []; var menuData = this.get('systemMenu'); // 取得定义好的菜单数据 Ext.A

跟我一起学extjs5(30--加入模块和菜单定义[3后台系统数据的组织和生成])

跟我一起学extjs5(30--加入模块和菜单定义[3后台系统数据的组织和生成]) 对于大多web程序来说,后台是完成控制和处理的,前台就是一个展示工具,这个系统也是这样.在上一节中建立了四个模块,下面开始设计前后台的交互.将系统信息和模块.菜单信息传到前台,由前台来进行展示. 首先新建一个java bean类用来存放各种需要传到前台的数据,里面包括:系统信息.操作人员信息.服务人员信息.模块信息.菜单.现在只加入了这几个,以后还要加入各种 各样的权限设置.在com.jfok.server.co

跟我一起学extjs5(28--加入模块和菜单定义[1建立数据库和表])

跟我一起学extjs5(28--加入模块和菜单定义[1建立数据库和表]) 下面我们开始进入自定义系统的设计和各个组成部分的搭建工作. 首先在sql server中建立数据库,这里的数据的名字我定义为extjs5,然后需要建立模块的定义表,这个表里将存着系统中所有模块的定义信息.为了能有个直观的前后台的互动,先把模块和菜单这二个部分加进去,可以把菜单数据组织好后发送到前台去进行展示. 由于系统中的模块很多,需要分类,因此在先要设计一个"模块分组"的表,对于菜单也是一样,需要有一个&quo

跟我一起学extjs5(42--单个模块的数据新增方式)

跟我一起学extjs5(42--单个模块的数据新增方式) 前面的章节中已经加入了一个自定义的模块,并且可以进行数据的新增.修改.删除的操作了,在这个基础上就可以大作文章了.这一节来设想几种新据新增的方式,并给出一些具体的解决方案. 看了我后台java源码的可以看出,所有的模块的新增.修改.删除全部是相同的处理,只是用了反射来生成各个实体bean,这样不管你有多少个业务bean,你的这部分代码是不用再增加了,只需要考虑一些逻辑处理上的操作即可,这些在后面会提到.基于这样的方式,我们可以定义多种数据