一、系统介绍
1、基于最新的ExtJS 5.1免费无限制版本 开发。
2、支持MySQL、SQL Server、Oracle、DB2等关系数据库。
3、本系统可作为OA、网站、电子政务、ERP、CRM等基于B/S架构的应用软件系统的快速开发框架 。
源码有50多M(包括Jar包和SQL文件),点此获取。咨询QQ:1345523590(咨询和技术支持)
二、特色功能 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、开发工具:Eclipse、MyEclipse等IDE。 2、采用ExtJS 5.1无限制免费版本 ,放心用于网站开发。 3、采用Spring MVC 4.0.9。 4、采用Hibernate 4.3.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);
}
public GetHttpServletRequestWrapper(HttpServletRequest request, String charset) {
super (request);
this .charset = charset;
}
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 : '* ' ,
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' ,
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 : '* ' ,
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' );
var formObj = btn.up( 'form' );
if (formObj.isValid()) {
formObj.form.doAction('submit' , {
url : appBaseUri + '/sys/forestrytype/uploadAttachement' ,
method : 'POST' ,
submitEmptyText : false ,
waitMsg : '正在上传图片,请稍候...' ,
timeout : 60000,
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' );
var formObj = btn.up( 'form' );
if (formObj.isValid()) {
var values = formObj.getValues();
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 = ' + 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,
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('操作成功!' );
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 );
int rowNum = sheet.getPhysicalNumberOfRows();
Object[] rowValues = null ;
List models = new ArrayList();
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 ];
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 );
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 ) {
json.put("success" , false );
json.put("msg" , "所导入文件格式不正确,请下载模板!" );
writeJSON(response, json.toString());
return ;
}
List list = objectToForestry(models);
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 objectToForestry(List models) {
List forestryList = new ArrayList();
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' ,
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 , {
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文件)