基于ExtJS 4.2.1 + Hibernate 4.1.7 + Spring MVC 3.2.8 的通用后台管理系统

一、系统介绍

1、基于最新的ExtJS 4.2.1.883开发。

2、支持MySQL、SQL Server、Oracle、DB2等关系数据库。

3、本系统可作为OA、网站、电子政务、ERP、CRM等基于B/S架构的应用软件系统的快速开发框架。

源码有50多M(包括Jar包和SQL文件),点此获取

二、特色功能
1、采用Spring MVC的静态加载缓存功能,在首页将Javascript文件、CSS文件和图片等静态资源文件加载进来放进内存,极大提高ExtJS的加载速度。
2、增加新的ExtJS Neptune Theme,让系统显得时髦,更具现代感,创造最佳的应用体验和多浏览器支持。

3、分别封装了模型层、控制层、业务逻辑层和数据持久层的通用操作模块,层次分明,大大减少代码冗余,二次开发效率高。

三、图片欣赏

1、修改信息


2、ExtJS的HtmlEditor的图片文件上传插件。


3、Grid列表,包含添加、删除、批量删除、修改、查看、图片查看等功能。


4、按条件查询列表。


5、导入Excel数据,支持xlsx和xls文件。


6、用户管理列表。


7、权限管理。不仅可管理各个功能模块的权限,也可以管理功能模块里的页面按钮权限。


8、报表统计。


9、采用开源的互动地图Javascript库Leaflet,处理自定义在线地图。Panel里包含2个组件,在2个组件间传递参数显示数据。

 

四、开发工具和采用技术
1、开发工具:MyEclipse 2014。
2、采用ExtJS 4.2.1.883商用版本。注:根据ExtJS License,只要不把ExtJS封装到工具软件里出售就不构成侵权,可放心用于网站开发。
3、采用Spring 3中最新最稳定的Spring MVC 3.2.8版本。
4、Spring MVC 3.2.8支持的最高Hibernate版本是4.1.7,更高的Hibernate版本和Spring MVC 3.2.8组合会遇到兼容问题。
5、Hibernate集成二级缓存框架Ehcache。
6、数据库是MySQL 5,Hibernate的Dialect可使程序移植到其他数据库。

7、采用开源的互动地图Javascript库Leaflet,处理自定义在线地图。

五、代码结构

部分代码作用:

1、BaseParameter、ExtJSBaseController、BaseService、BaseDao:分别封装了模型层、控制层、业务逻辑层和数据持久层的通用操作模块。

2、ListView、PageView和QueryResult:作为ExtJS的后台分页模块。

3、SystemInitListener:加载以XML格式的数据字典,放进内存供调用。
4、LoginFilter:处理登录各种情况,将session为null的操作重定向到登录页面。
5、CustomDateEditor:处理日期参数并注册到控制器里,否则Spring MVC的参数处理将出错。
6、ExceptionCode、ServiceException:处理异常信息。
7、CacheFactory:处理Ehcache二级缓存。

8、还有其他很多工具类等等。

六、技术要点讲解

1、处理POST和GET的中文乱码问题。

1.1、POST的中文乱码处理可在web.xml上加上Spring提供的字符编码处理Filter。

	<filter>
	    <filter-name>characterEncoding</filter-name>
	    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
	    <init-param>
		<param-name>encoding</param-name>
		<param-value>UTF-8</param-value>
	    </init-param>
	    <init-param>
                <param-name>forceEncoding</param-name>
                <param-value>true</param-value>
            </init-param>
	</filter>
	<filter-mapping>
	    <filter-name>characterEncoding</filter-name>
	    <url-pattern>/*</url-pattern>
	</filter-mapping>

1.2、GET的中文乱码处理可继承HttpServletRequestWrapper建立一个类来处理request。不用在应用服务器里设置URIEncoding。

package core.web;

import java.io.UnsupportedEncodingException;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;

public class GetHttpServletRequestWrapper extends HttpServletRequestWrapper {

	private String charset = "UTF-8";

	public GetHttpServletRequestWrapper(HttpServletRequest request) {
		super(request);
	}

	/**
	 * 获得被装饰对象的引用和采用的字符编码
	 *
	 * @param request
	 * @param charset
	 */
	public GetHttpServletRequestWrapper(HttpServletRequest request, String charset) {
		super(request);
		this.charset = charset;
	}

	/**
	 * 调用被包装的请求对象的getParameter方法获得参数,然后再进行编码转换
	 */
	public String getParameter(String name) {
		String value = super.getParameter(name);
		value = value == null ? null : convert(value);
		return value;
	}

	public String convert(String target) {
		try {
			return new String(target.trim().getBytes("ISO-8859-1"), charset);
		} catch (UnsupportedEncodingException e) {
			return target;
		}
	}
}

2、开发ExtJS的HtmlEditor的图片文件上传插件。建议:不要在ExtJS里集成百度编辑器、KindEditor或CKEditor等HTML编辑器,因为在某种情况下会遇到界面扭曲、浏览器兼容问题。

2.1、ExtJS的图片文件上传插件界面如下。

2.2.1、ExtJS的图片文件上传插件Javascript代码如下。

Ext.define(‘Ext.ux.custom.ImageHtmlEditor‘, {
	extend : ‘Ext.util.Observable‘,
	alias : ‘widget.imagehtmleditor‘,
	langTitle : ‘插入图片‘,
	langIconCls : ‘icon-image‘,
	init : function(view) {
		var scope = this;
		view.on(‘render‘, function() {
			scope.onRender(view);
		});
	},

	/**
	 * 添加"插入图片"按钮
	 */
	onRender : function(view) {
		var scope = this;
		view.getToolbar().add({
			iconCls : scope.langIconCls,
			tooltip : {
				title : scope.langTitle,
				width : 160,
				text : ‘上传本地图片或链接网络图片‘
			},
			handler : function() {
				scope.showImgWindow(view);
			}
		});
	},

	/**
	 * 显示"插入图片"窗体
	 */
	showImgWindow : function(view) {
		var scope = this;
		Ext.create(‘Ext.window.Window‘, {
			width : 400,
			height : 310,
			title : scope.langTitle,
			layout : ‘fit‘,
			autoShow : true,
			modal : true,
			resizable : false,
			maximizable : false,
			constrain : true,
			plain : true,
			enableTabScroll : true,
			border : false,
			items : [ {
				xtype : ‘tabpanel‘,
				enableTabScroll : true,
				bodyPadding : 10,
				items : [ {
					title : ‘上传本地图片‘,
					items : [ {
						xtype : ‘form‘,
						layout : ‘column‘,
						autoScroll : true,
						border : false,
						defaults : {
							columnWidth : 1,
							labelWidth : 80,
							labelAlign : ‘left‘,
							padding : 5,
							allowBlank : false
						},
						items : [ {
							xtype : ‘fileuploadfield‘,
							fieldLabel : ‘选择文件‘,
							afterLabelTextTpl : ‘<span style="color:#FF0000;">*</span>‘,
							buttonText : ‘请选择...‘,
							name : ‘uploadAttachment‘,
							emptyText : ‘请选择图片‘,
							blankText : ‘图片不能为空‘,
							listeners : {
								change : function(view, value, eOpts) {
									scope.uploadImgCheck(view, value);
								}
							}
						}, {
							xtype : ‘fieldcontainer‘,
							fieldLabel : ‘图片大小‘,
							layout : ‘hbox‘,
							defaultType : ‘numberfield‘,
							defaults : {
								flex : 1,
								labelWidth : 20,
								labelAlign : ‘left‘,
								allowBlank : true
							},
							items : [ {
								fieldLabel : ‘宽‘,
								name : ‘width‘,
								minValue : 1
							}, {
								fieldLabel : ‘高‘,
								name : ‘height‘,
								minValue : 1
							} ]
						}, {
							xtype : ‘textfield‘,
							fieldLabel : ‘图片说明‘,
							name : ‘content‘,
							allowBlank : true,
							maxLength : 100,
							emptyText : ‘简短的图片说明‘
						}, {
							columnWidth : 1,
							xtype : ‘fieldset‘,
							title : ‘上传须知‘,
							layout : {
								type : ‘table‘,
								columns : 1
							},
							collapsible : false,// 是否可折叠
							defaultType : ‘label‘,// 默认的Form表单组件
							items : [ {
								html : ‘1、上传图片大小不超过2MB.‘
							}, {
								html : ‘2、支持以下格式的图片:jpg,jpeg,png,gif,bmp.‘
							} ]
						} ],
						buttons : [ ‘->‘, {
							text : ‘保存‘,
							action : ‘btn_save‘,
							iconCls : ‘icon-save‘,
							handler : function(btn) {
								scope.saveUploadImg(btn, view);
							}
						}, {
							text : ‘取消‘,
							iconCls : ‘icon-cancel‘,
							handler : function(btn) {
								btn.up(‘window‘).close();
							}
						}, ‘->‘ ]
					} ]
				}, {
					title : ‘链接网络图片‘,
					items : [ {
						xtype : ‘form‘,
						layout : ‘column‘,
						autoScroll : true,
						border : false,
						defaults : {
							columnWidth : 1,
							labelWidth : 80,
							labelAlign : ‘left‘,
							padding : 5,
							allowBlank : false
						},
						items : [ {
							xtype : ‘textfield‘,
							fieldLabel : ‘图片地址‘,
							afterLabelTextTpl : ‘<span style="color:#FF0000;">*</span>‘,
							name : ‘url‘,
							emptyText : ‘请填入支持外链的长期有效的图片URL‘,
							blankText : ‘图片地址不能为空‘,
							vtype : ‘url‘
						}, {
							xtype : ‘fieldcontainer‘,
							fieldLabel : ‘图片大小‘,
							layout : ‘hbox‘,
							defaultType : ‘numberfield‘,
							defaults : {
								flex : 1,
								labelWidth : 20,
								labelAlign : ‘left‘,
								allowBlank : true
							},
							items : [ {
								fieldLabel : ‘宽‘,
								name : ‘width‘,
								minValue : 1
							}, {
								fieldLabel : ‘高‘,
								name : ‘height‘,
								minValue : 1
							} ]
						}, {
							xtype : ‘textfield‘,
							fieldLabel : ‘图片说明‘,
							name : ‘content‘,
							allowBlank : true,
							maxLength : 100,
							emptyText : ‘简短的图片说明‘
						} ],
						buttons : [ ‘->‘, {
							text : ‘保存‘,
							action : ‘btn_save‘,
							iconCls : ‘icon-save‘,
							handler : function(btn) {
								scope.saveRemoteImg(btn, view);
							}
						}, {
							text : ‘取消‘,
							iconCls : ‘icon-cancel‘,
							handler : function(btn) {
								btn.up(‘window‘).close();
							}
						}, ‘->‘ ]
					} ]
				} ]
			} ]
		});
	},

	/**
	 * 上传图片验证
	 */
	uploadImgCheck : function(fileObj, fileName) {
		var scope = this;
		// 图片类型验证
		if (!(scope.getImgTypeCheck(scope.getImgHZ(fileName)))) {
			globalObject.errTip(‘上传图片类型有误!‘);
			fileObj.reset();// 清空上传内容
			return;
		}
	},

	/**
	 * 获取图片后缀(小写)
	 */
	getImgHZ : function(imgName) {
		// 后缀
		var hz = ‘‘;
		// 图片名称中最后一个.的位置
		var index = imgName.lastIndexOf(‘.‘);
		if (index != -1) {
			// 后缀转成小写
			hz = imgName.substr(index + 1).toLowerCase();
		}
		return hz;
	},

	/**
	 * 图片类型验证
	 */
	getImgTypeCheck : function(hz) {
		var typestr = ‘jpg,jpeg,png,gif,bmp‘;
		var types = typestr.split(‘,‘);// 图片类型
		for (var i = 0; i < types.length; i++) {
			if (hz == types[i]) {
				return true;
			}
		}
		return false;
	},

	/**
	 * 上传图片
	 */
	saveUploadImg : function(btn, view) {
		var scope = this;
		var windowObj = btn.up(‘window‘);// 获取Window对象
		var formObj = btn.up(‘form‘);// 获取Form对象
		if (formObj.isValid()) { // 验证Form表单
			formObj.form.doAction(‘submit‘, {
				url : appBaseUri + ‘/sys/forestrytype/uploadAttachement‘,
				method : ‘POST‘,
				submitEmptyText : false,
				waitMsg : ‘正在上传图片,请稍候...‘,
				timeout : 60000, // 60s
				success : function(response, options) {
					var result = options.result;
					if (!result.success) {
						globalObject.errTip(result.msg);
						return;
					}
					var url = result.data;
					var content = formObj.getForm().findField("content").getValue();
					var width = formObj.getForm().findField("width").getValue();
					var height = formObj.getForm().findField("height").getValue();
					var values = {
						url : appBaseUri + ‘/static/img/upload/‘ + url,
						content : content,
						width : width,
						height : height
					};
					scope.insertImg(view, values);
					windowObj.close();// 关闭窗体
				},
				failure : function(response, options) {
					globalObject.errTip(options.result.msg);
				}
			});
		}
	},

	/**
	 * 保存远程的图片
	 */
	saveRemoteImg : function(btn, view) {
		var scope = this;
		var windowObj = btn.up(‘window‘);// 获取Window对象
		var formObj = btn.up(‘form‘);// 获取Form对象
		if (formObj.isValid()) {// 验证Form表单
			var values = formObj.getValues();// 获取Form表单的值
			scope.insertImg(view, values);
			windowObj.close();// 关闭窗体
		}
	},

	/**
	 * 插入图片
	 */
	insertImg : function(view, data) {
		var url = data.url;
		var content = data.content;
		var width = data.width;
		var height = data.height;
		var str = ‘<img src="‘ + url + ‘" border="0" ‘;
		if (content != undefined && content != null && content != ‘‘) {
			str += ‘ title="‘ + content + ‘" ‘;
		}
		if (width != undefined && width != null && width != 0) {
			str += ‘ width="‘ + width + ‘" ‘;
		}
		if (height != undefined && height != null && height != 0) {
			str += ‘ height="‘ + height + ‘" ‘;
		}
		str += ‘ />‘;
		view.insertAtCursor(str);
	}
});

2.2.2、ExtJS的图片文件上传插件Java后台代码如下。Spring MVC对文件上传已有直接处理,不用再自写文件上传组件。

	@RequestMapping(value = "/uploadAttachement", method = RequestMethod.POST)
	public void uploadAttachement(@RequestParam(value = "uploadAttachment", required = false) MultipartFile file, HttpServletRequest request, HttpServletResponse response) throws Exception {
		RequestContext requestContext = new RequestContext(request);
		JSONObject json = new JSONObject();
		if (!file.isEmpty()) {
			if (file.getSize() > 2097152) {
				json.put("msg", requestContext.getMessage("g_fileTooLarge"));
			} else {
				try {
					String originalFilename = file.getOriginalFilename();
					String fileName = sdf.format(new Date()) + ForestryUtils.getRandomString(3) + originalFilename.substring(originalFilename.lastIndexOf("."));
					File filePath = new File(getClass().getClassLoader().getResource("/").getPath().replace("/WEB-INF/classes/", "/static/img/upload/" + DateFormatUtils.format(new Date(), "yyyyMM")));
					if (!filePath.exists()) {
						filePath.mkdirs();
					}
					file.transferTo(new File(filePath.getAbsolutePath() + "\\" + fileName));
					json.put("success", true);
					json.put("data", DateFormatUtils.format(new Date(), "yyyyMM") + "/" + fileName);
					json.put("msg", requestContext.getMessage("g_uploadSuccess"));
				} catch (Exception e) {
					e.printStackTrace();
					json.put("msg", requestContext.getMessage("g_uploadFailure"));
				}
			}
		} else {
			json.put("msg", requestContext.getMessage("g_uploadNotExists"));
		}
		writeJSON(response, json.toString());
	}

3、继承Ext.grid.Panel重写列表组件,在toolbar上定义全局通用的“添加”、“导入”、“删除”等功能点,减少了代码冗余。

Ext.define(‘Ext.ux.custom.GlobalGridPanel‘, {
	extend : ‘Ext.grid.Panel‘,
	alias : ‘widget.globalgrid‘,
	xtype : ‘cell-editing‘,
	initComponent : function() {
		var me = this;
		var singleId;

		var uniqueID = me.cName + (me.cId ? me.cId : ‘‘) + (me.myId ? me.myId : ‘‘);

		this.cellEditing = Ext.create(‘Ext.grid.plugin.CellEditing‘, {
			clicksToEdit : 2
		});

		var tbarMenus = new Array();
		if (globalObject.haveActionMenu(me.cButtons, ‘Add‘)) {
			tbarMenus.push({
				xtype : ‘button‘,
				itemId : ‘btnAdd‘,
				iconCls : ‘icon-add‘,
				text : ‘添加‘,
				scope : this,
				handler : me.onAddClick
			});
		}
		if (globalObject.haveActionMenu(me.cButtons, ‘Import‘)) {
			tbarMenus.push({
				xtype : ‘button‘,
				itemId : ‘btnImport‘,
				iconCls : ‘icon-excel‘,
				text : ‘导入‘,
				scope : this,
				handler : me.onImportClick
			});
		}
		if (globalObject.haveActionMenu(me.cButtons, ‘Delete‘)) {
			tbarMenus.push({
				xtype : ‘button‘,
				itemId : ‘btnDelete‘,
				iconCls : ‘icon-delete‘,
				text : ‘删除‘,
				scope : this,
				disabled : true,
				handler : me.onDeleteClick
			});
		}
		if (globalObject.haveActionMenu(me.cButtons, ‘Export‘)) {
			tbarMenus.push({
				xtype : ‘splitbutton‘,
				itemId : ‘btnImport‘,
				text : ‘导出‘,
				scope : this,
				handler : function() {
					me.onExportClick(false);
				},
				menu : [ {
					text : ‘导出(包括隐藏列)‘,
					handler : function() {
						me.onExportClick(true);
					}
				}, {
					text : ‘导出选中数据‘,
					handler : function() {
						me.onExportClick(false, true);
					}
				}, {
					text : ‘导出选中数据(包括隐藏列)‘,
					handler : function() {
						me.onExportClick(true, true);
					}
				} ]
			});
		}

		if (tbarMenus.length == 0)
			me.hideTBar = true;
		this.ttoolbar = Ext.create(‘Ext.toolbar.Toolbar‘, {
			hidden : me.hideTBar || false,
			items : tbarMenus
		});

		Ext.apply(this, {
			stateful : me.cName ? true : false,
			stateId : me.cName ? (uniqueID + ‘gird‘) : null,
			enableColumnMove : me.cName ? true : false,
			plugins : this.plugins,
			selModel : Ext.create(‘Ext.selection.CheckboxModel‘),
			border : false,
			tbar : this.ttoolbar,
			bbar : me.hideBBar ? null : Ext.create(‘Ext.PagingToolbar‘, {
				store : me.getStore(),
				displayInfo : true
			}),
			listeners : {
				itemdblclick : function(dataview, record, item, index, e) {
					me.onViewClick();
				}
			}
		});
		this.getSelectionModel().on(‘selectionchange‘, function(sm, records) {
			if (me.down(‘#btnDelete‘))
				me.down(‘#btnDelete‘).setDisabled(sm.getCount() == 0);
		});

		this.callParent(arguments);
	},
	createStore : function(config) {
		Ext.applyIf(this, config);

		return Ext.create(‘Ext.data.Store‘, {
			model : config.modelName,
			// autoDestroy: true,
			// autoLoad: true,
			remoteSort : true,
			pageSize : globalPageSize,
			proxy : {
				type : ‘ajax‘,
				url : config.proxyUrl,
				extraParams : config.extraParams || null,
				reader : {
					type : ‘json‘,
					root : ‘data‘,
					totalProperty : ‘totalRecord‘,
					successProperty : "success"
				}
			},
			sorters : [ {
				property : config.sortProperty || ‘id‘,
				direction : config.sortDirection || ‘DESC‘
			} ]
		});
	},
	getTabId : function() {
		return this.up(‘panel‘).getId();
	},
	onAddClick : function() {
	},
	onEditClick : function() {
	},
	onImportClick : function() {
	},
	onViewClick : function() {
	},
	onDeleteClick : function() {
		var me = this;
		globalObject.confirmTip(‘删除的记录不可恢复,继续吗?‘, function(btn) {
			if (btn == ‘yes‘) {
				var s = me.getSelectionModel().getSelection();
				var ids = [];
				var idProperty = me.idProperty || ‘id‘;
				for (var i = 0, r; r = s[i]; i++) {
					ids.push(r.get(idProperty));
				}
				Ext.Ajax.request({
					url : me.proxyDeleteUrl,
					params : {
						ids : ids.join(‘,‘) || singleId
					},
					success : function(response) {
						if (response.responseText != ‘‘) {
							var res = Ext.JSON.decode(response.responseText);
							if (res.success) {
								globalObject.msgTip(‘操作成功!‘);
								// Ext.example.msg(‘系统信息‘, ‘{0}‘, "操作成功!");
								me.getStore().reload();
							} else {
								globalObject.errTip(‘操作失败!‘ + res.msg);
							}
						}
					}
				});
			}
		});
	},
	onExportClick : function(importHideColumn, onlySelected) {
		globalObject.exportToExcel(this, importHideColumn, onlySelected);
	}
});

4、开发Excel数据导入模块,同时支持xls和xlsx文件,在Java后台代码对导入过程中各种条件判断和异常有严格的处理。

4.1、Excel数据导入模块的界面如下。

4.2、Excel数据导入模块的Java后台代码如下。

	private static SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS");

	@RequestMapping(value = "/importForestryFile", method = RequestMethod.POST)
	public void importForestryFile(@RequestParam(value = "importedFile", required = false) MultipartFile file, HttpServletRequest request, HttpServletResponse response) throws Exception {
		RequestContext requestContext = new RequestContext(request);
		JSONObject json = new JSONObject();
		if (!file.isEmpty()) {
			if (file.getSize() > 2097152) {
				json.put("msg", requestContext.getMessage("g_fileTooLarge"));
			} else {
				try {
					String originalFilename = file.getOriginalFilename();
					String fileName = sdf.format(new Date()) + ForestryUtils.getRandomString(3) + originalFilename.substring(originalFilename.lastIndexOf("."));
					File filePath = new File(getClass().getClassLoader().getResource("/").getPath().replace("/WEB-INF/classes/", "/static/download/attachment/" + DateFormatUtils.format(new Date(), "yyyyMM")));
					if (!filePath.exists()) {
						filePath.mkdirs();
					}
					String serverFile = filePath.getAbsolutePath() + "\\" + fileName;
					file.transferTo(new File(serverFile));

					String fileType = fileName.substring(fileName.lastIndexOf(".") + 1);
					if (!fileType.equalsIgnoreCase("xls") && !fileType.equalsIgnoreCase("xlsx")) {
						json.put("success", false);
						json.put("msg", requestContext.getMessage("g_notValidExcel"));
						writeJSON(response, json.toString());
						return;
					}
					int count = 0;
					StringBuilder stringBuilder = new StringBuilder();
					InputStream xls = new FileInputStream(serverFile);
					Workbook wb = null;
					Sheet sheet = null;
					Row currentRow = null;
					Row headRow = null;
					Cell currentCell = null;
					if (fileType.equals("xls")) {
						wb = new HSSFWorkbook(xls);
					} else if (fileType.equals("xlsx")) {
						wb = new XSSFWorkbook(xls);
					}
					sheet = wb.getSheetAt(0);// excel中至少会存在一个sheet页
					int rowNum = sheet.getPhysicalNumberOfRows();// 物理有效行数
					Object[] rowValues = null;// excel中一行树木信息
					List<Object[]> models = new ArrayList<Object[]>();// excel中全部树木信息
					if (rowNum > 1) {
						headRow = sheet.getRow(0);
						columns: for (int i = 1; i < rowNum; i++) {
							currentRow = sheet.getRow(i);
							if (currentRow != null) {
								rowValues = new Object[5];
								// int cellNum = currentRow.getLastCellNum();// 总单元格数目
								for (short j = 0; j < 5; j++) {
									try {
										currentCell = currentRow.getCell(j);
										Object obj = null;
										if (currentCell == null) {
											obj = "";
										} else {
											switch (currentCell.getCellType()) {
												case Cell.CELL_TYPE_BLANK:
													obj = "";
													break;
												case Cell.CELL_TYPE_STRING:
													obj = currentCell.getRichStringCellValue();
													break;
												case Cell.CELL_TYPE_NUMERIC:
													if (HSSFDateUtil.isCellDateFormatted(currentCell)) {
														double d = currentCell.getNumericCellValue();
														Date date = HSSFDateUtil.getJavaDate(d);
														obj = sdfDate.format(date);
													} else {
														NumberFormat nf = NumberFormat.getInstance();
														nf.setGroupingUsed(false);//true时的格式:1,234,567,890
														obj = nf.format(currentCell.getNumericCellValue());
													}
													break;
												default:
													obj = "";
													break;
											}
										}
										String cellVal = obj.toString();
										rowValues[j] = cellVal;
									} catch (IllegalStateException e) {
										rowValues = null;
										stringBuilder.append("第" + i + "行," + headRow.getCell(j).getRichStringCellValue() + "列输入了非法值,未导入成功!");
										continue columns;
									} catch (NullPointerException e) {
										rowValues = null;
										stringBuilder.append("第" + i + "行," + headRow.getCell(j).getRichStringCellValue() + "列输入了空值,未导入成功!");
										continue columns;
									} catch (Exception e) {
										rowValues = null;
										stringBuilder.append(e.getMessage());
										continue columns;
									}
								}
								if (rowValues != null) {
									models.add(rowValues);
								}
							}
						}
					} else if (rowNum <= 1 && rowNum > 0) {// 表示模版中只存在头部信息
						json.put("success", false);
						json.put("msg", "Excel表格中没有需要导入 的内容!");
						writeJSON(response, json.toString());
						return;
					} else if (rowNum <= 0) {// 表示这是一个空sheet页
						json.put("success", false);
						json.put("msg", "所导入文件格式不正确,请下载模板!");
						writeJSON(response, json.toString());
						return;
					}
					List<Forestry> list = objectToForestry(models);// Object-->Forestry
					for (int i = 0; i < list.size(); i++) {
						if (StringUtils.isBlank(list.get(i).getEpcId()) || StringUtils.isBlank(list.get(i).getName())) {
							stringBuilder.append("第" + (i + 1) + "行记录的必填项有空值,导入失败。");
							continue;
						}
						Forestry checkForestryEpcId = forestryService.getByProerties("epcId", list.get(i).getEpcId());
						if (checkForestryEpcId != null) {
							stringBuilder.append("第" + (i + 1) + "行记录的epc编码已存在,导入失败。");
							continue;
						}
						if (list.get(i).getForestryType() == null) {
							stringBuilder.append("第" + (i + 1) + "行记录的种类为空或不存在,导入失败。");
							continue;
						}
						forestryService.persist(list.get(i));
						count++;
					}

					json.put("success", true);
					json.put("msg", count + "条记录导入完成。" + stringBuilder.toString());
				} catch (Exception e) {
					e.printStackTrace();
					json.put("success", false);
					json.put("msg", requestContext.getMessage("g_operateFailure"));
					writeJSON(response, json.toString());
				}
			}
		} else {
			json.put("success", false);
			json.put("msg", requestContext.getMessage("g_uploadNotExists"));
		}
		writeJSON(response, json.toString());
	}

	private List<Forestry> objectToForestry(List<Object[]> models) {
		List<Forestry> forestryList = new ArrayList<Forestry>();
		Forestry forestry = null;
		for (int i = 0; i < models.size(); i++) {
			try {
				forestry = new Forestry();
				forestry.setEpcId(models.get(i)[0].toString());
				forestry.setName(models.get(i)[1].toString());
				if (StringUtils.isBlank(models.get(i)[2].toString())) {
					forestry.setPlantTime(null);
				} else {
					forestry.setPlantTime(sdfDate.parse(models.get(i)[2].toString()));
				}
				if (StringUtils.isBlank(models.get(i)[3].toString())) {
					forestry.setEntryTime(null);
				} else {
					forestry.setEntryTime(sdfDate.parse(models.get(i)[3].toString()));
				}
				ForestryType forestryType = forestryTypeService.getByProerties("name", models.get(i)[4].toString());
				forestry.setForestryType(forestryType);
				forestryList.add(forestry);
			} catch (Exception e) {
				e.printStackTrace();
				continue;
			}
		}
		return forestryList;
	}

5、开发权限管理。不仅可以管理功能模块的权限,也可以管理功能模块里面各个按钮的权限。

5.1、权限管理的界面如下。

5.2、权限管理的代码如下。

// 权限管理
Ext.define(‘Forestry.app.systemManage.AuthorizationManagement‘, {
	extend : ‘Ext.panel.Panel‘,
	initComponent : function() {
		var me = this;
		Ext.apply(this, {
			layout : ‘border‘,
			items : [ Ext.create(‘Forestry.app.systemManage.AuthorizationManagement.SysUserGrid‘, {
				cButtons : me.cButtons,
				cName : me.cName
			}), Ext.create(‘Forestry.app.systemManage.AuthorizationManagement.MenuTree‘) ]
		});
		this.callParent(arguments);
	}
});

// 角色列表
Ext.define(‘Forestry.app.systemManage.AuthorizationManagement.SysUserGrid‘, {
	extend : ‘Ext.grid.Panel‘,
	id : ‘authorizationmanagement-sysusergrid‘,
	region : ‘west‘,
	width : ‘18%‘,
	initComponent : function() {
		var me = this;
		Ext.define(‘SysUserRoleList‘, {
			extend : ‘Ext.data.Model‘,
			idProperty : ‘role‘,
			fields : [ {
				name : ‘role‘,
				type : ‘short‘
			}, ‘roleName‘ ]
		});
		var sysusergridstore = Ext.create(‘Ext.data.Store‘, {
			model : ‘SysUserRoleList‘,
			// autoDestroy: true,
			autoLoad : true,
			remoteSort : true,
			pageSize : globalPageSize,
			proxy : {
				type : ‘ajax‘,
				url : appBaseUri + ‘/sys/sysuser/getRoleNameList‘,
				extraParams : me.extraParams || null,
				reader : {
					type : ‘json‘,
					root : ‘data‘,
					totalProperty : ‘totalRecord‘,
					successProperty : "success"
				}
			}
		});
		var sysusergridcolumns = [ {
			text : "roleId",
			dataIndex : ‘role‘,
			hidden : true,
			sortable : false,
			editor : {
				allowBlank : false
			}
		}, {
			text : "角色",
			dataIndex : ‘roleName‘,
			sortable : false,
			width : ‘85%‘,
			editor : {
				allowBlank : false
			}
		} ];
		Ext.apply(this, {
			store : sysusergridstore,
			selModel : Ext.create(‘Ext.selection.CheckboxModel‘),
			columns : sysusergridcolumns,
			listeners : {
				‘itemclick‘ : function(item, record) {
					me.currentRole = record.get(‘role‘);
					Ext.getCmp(‘authorizationmanagement-rolemenu‘).getStore().load({
						params : {
							‘role‘ : me.currentRole
						}
					});
				}
			}
		});
		this.callParent(arguments);
	}
});

// 树形菜单
Ext.define(‘Forestry.app.systemManage.AuthorizationManagement.MenuTree‘, {
	extend : ‘Ext.tree.Panel‘,
	id : ‘authorizationmanagement-rolemenu‘,
	plain : true,
	border : true,
	region : ‘center‘,
	autoScroll : true,
	initComponent : function() {
		var me = this;
		var menutreestore = Ext.create(‘Ext.data.TreeStore‘, {
			autoLoad : true,
			proxy : {
				type : ‘ajax‘,
				url : appBaseUri + ‘/sys/authority/getAuthorizationList‘,
				reader : {
					type : ‘json‘,
					root : ‘children‘
				}
			}
		});
		Ext.apply(this, {
			// title : ‘菜单权限‘,
			store : menutreestore,
			rootVisible : false,
			tbar : [ {
				xtype : ‘button‘,
				iconCls : ‘icon-save‘,
				text : ‘保存菜单权限‘,
				scope : this,
				handler : me.saveMenuPermission
			} ]
		});
		this.callParent(arguments);
	},
	saveMenuPermission : function() {
		var me = this;
		var roleId = Ext.getCmp(‘authorizationmanagement-sysusergrid‘).currentRole;
		if (!roleId) {
			globalObject.infoTip(‘请先选择角色!‘);
			return;
		};
		var s = me.getChecked();
		var ids = [];
		for (var i = 0, r; r = s[i]; i++) {
			if (r.get(‘id‘) != ‘root‘)
				ids.push(r.get(‘id‘));
		}
		me.setLoading(‘权限保存中...‘);
		Ext.Ajax.request({
			url : appBaseUri + ‘/sys/roleauthority/saveRoleAuthority‘,
			params : {
				ids : ids.join(‘,‘),
				role : roleId
			},
			success : function(response) {
				me.setLoading(false);
				var res = Ext.JSON.decode(response.responseText);
				if (res && !res.success) {
					Ext.Msg.alert(‘出错信息‘, res.msg);
				} else {
					globalObject.msgTip(‘保存成功!‘);
				}
			},
			failure : function(response, opts) {
				me.setLoading(false);
				Ext.Msg.alert(‘出错信息‘, ‘操作失败!‘);
			}
		});
	}
});

源码有50多M(包括Jar包和SQL文件),点此获取

基于ExtJS 4.2.1 + Hibernate 4.1.7 + Spring MVC 3.2.8 的通用后台管理系统

时间: 2024-10-27 09:21:48

基于ExtJS 4.2.1 + Hibernate 4.1.7 + Spring MVC 3.2.8 的通用后台管理系统的相关文章

基于Hibernate 4.3.8 + Spring MVC 4.0.9 的通用后台管理系统

获取[下载地址]   QQ: 313596790A 代码生成器(开发利器);     增删改查的处理类,service层,mybatis的xml,SQL( mysql   和oracle)脚本,   jsp页面 都生成   就不用写搬砖的代码了,生成的放到项目里,可以直接运行B 阿里巴巴数据库连接池druid;  数据库连接池  阿里巴巴的 druid.Druid在监控.可扩展性.稳定性和性能方面都有明显的优势C 安全权限框架shiro ;  Shiro 是一个用 Java 语言实现的框架,通过

通用后台管理系统(ExtJS 4.2 + Spring MVC 3.2 + Hibernate)

通用后台管理系统(ExtJS 4.2 +Spring MVC 3.2 + Hibernate) 开发语言JAVA 成品成品 前端技术extjs 数据库mysql,sql server,oracle 系统可作为OA.网站.电子政务.ERP.CRM.APP后台等基于B/S架构的应用软件系统的快速开发框架. 详细信息 原文:http://www.yctxkj.com/product/showproduct.php?lang=cn&id=16 系统可作为OA.网站.电子政务.ERP.CRM.APP后台等

分享基于EF+MVC+Bootstrap的通用后台管理系统及架构(转)

http://www.cnblogs.com/guozili/p/3496265.html 基于EF+MVC+Bootstrap构建通用后台管理系统,集成轻量级的缓存模块.日志模块.上传缩略图模块.通用配置及服务调用, 提供了OA.CRM.CMS的原型实例,适合快速构建中小型互联网及行业Web系统,且能作为代码实践及参考,欢迎提出意见. Demo预览 点击在线预览 admin/111111 请勿删数据 Framework 业务无关的底层通用机制及功能 Model基类:提供数据传输和底层的最基本的

分享基于EF+MVC+Bootstrap的通用后台管理系统及架构

原文来源:http://www.cnblogs.com/guozili/p/3496265.html 基于EF+MVC+Bootstrap构建通用后台管理系统,集成轻量级的缓存模块.日志模块.上传缩略图模块.通用配置及服务调用, 提供了OA.CRM.CMS的原型实例,适合快速构建中小型互联网及行业Web系统,且能作为代码实践及参考,欢迎提出意见. Demo预览 点击在线预览 admin/111111 请勿删数据 Framework 业务无关的底层通用机制及功能 Model基类:提供数据传输和底层

Java企业通用平台框架:Bootstrap、HTML5、jQuery、Spring MVC、Mybatis、Hibernate、高性能、高并发

1.适配所有设备(PC.平板.手机等),兼容所有浏览器(Chrome.Firefox.Opera.Safari.IE6~IE11等),适用所有项目(MIS管理信息系统.OA办公系统.ERP企业资源规划系统.CRM客户关系管理系统.网站等). 2.快速开发,敏捷的数据持久层解决方案. 2.1.事务自动处理. 2.2.O/R Mapping基于注解,零配置XML,便于维护,学习成本低. 2.3.接口和实现分离,不需写数据持久层代码,只需写接口,自动生成添加.修改.删除.排序.分页.各种条件的查询等S

Spring MVC、Mybatis、Hibernate、Bootstrap、HTML5、jQuery、Spring Security安全权限、Lucene全文检索、Ehcache分布式缓存 、高性能、高并发【Java企业通用开发平台框架】

功能特点: 1.适配所有设备(PC.平板.手机等),兼容所有浏览器(Chrome.Firefox.Opera.Safari.IE6~IE11等),适用所有项目(MIS管理信息系统.OA办公系统.ERP企业资源规划系统.CRM客户关系管理系统.网站.管理后台等). 2.快速开发,敏捷的数据持久层解决方案. 2.1.事务自动处理. 2.2.O/R Mapping基于注解,零配置XML,便于维护,学习成本低. 2.3.接口和实现分离,不需写数据持久层代码,只需写接口,自动生成添加.修改.删除.排序.分

基于spring mvc的图片验证码实现

基于spring mvc的图片验证码实现 标签: springmvcspring mvc验证码验证码验证 2016-01-28 10:49 8015人阅读 评论(4) 收藏 举报  分类: 表单处理 版权声明:本文为博主原创文章,未经博主允许不得转载. 本文实现基于spring mvc的图片验证码,分后台代码和前端页面的展现以及验证码的验证. 首看后台实现代码: @RequestMapping({"authCode"}) public void getAuthCode(HttpServ

TIMO后台管理系统-基于SpringBoot开发

项目介绍 TIMO后台管理系统,基于SpringBoot2.0 + Spring Data Jpa + Thymeleaf + Shiro 开发的后台管理系统,采用分模块的方式便于开发和维护,支持前后台模块分别部署,目前支持的功能有:权限管理.部门管理.字典管理.日志记录.文件上传.代码生成等,为快速开发后台系统而生的脚手架! 开源地址:https://gitee.com/aun/Timo 技术选型 后端技术:SpringBoot + Spring Data Jpa + Thymeleaf +

SpringMVC学习系列(12) 完结篇 之 基于Hibernate+Spring+Spring MVC+Bootstrap的管理系统实现

到这里已经写到第12篇了,前11篇基本上把Spring MVC主要的内容都讲了,现在就直接上一个项目吧,希望能对有需要的朋友有一些帮助. 一.首先看一下项目结构: InfrastructureProjects:是抽取出的基础项目,主要封装了一些通用的操作. SpringMVC3Demo:就是管理系统所在的项目. WeiXinAPI:是之前做微信管理平台测试时封装一些操作,如果不需要把该项目移除即可. 注:项目的前端UI框架用的是国外的一个基于Bootstrap框架的开发的Demo,如不需要替换为