030开发日志(创建ManyToMany的column5)
现在对于这个字段来说,还剩最后一个功能了,那就是可以修改ManyToMany的值了。在grid的inline操作里面,是可以直接删除已有值,但是如果要新增的话,就必须要有一个新的界面了。下面来看看开发修改ManyToMany字段所需要的步骤。
1、创建一个修改窗口,在里面创建一个可check的树;
2?到后台请求数据,读取当前记录的所有的ManyToMany的可选项,并把已经选中的打勾;
3?根据读取到的数据更新树;
4?用户操作check 和 uncheck;
5?保存修改,使用ajax 将修改过后的ManyToMany中打勾的选项发送到后台,执行保存功能;
6?刷新当前记录,显示正确的ManyToMany值。
在以上的步骤中可以看出,对于所有的ManyToMany字段的修改都是用这一个办法。上面步骤中比较难的就是如何根据前台的请求生成模块该记录的ManyToMany的所有选项并把已经选中的打勾,以及保存修改过后的值。对于本系统而言,所有的方法尽量都是通用的,因此有些功能的开发比较困难。
在进行第2步操作时,前台应传给后台的参数应该有:当前模块名称,当前记录id,ManyToMany的模块名称,中间模块的名称。
同样在进行第5步操作的时候,也要传给后台第2步的参数,并加上当前所有选中ManyToMany的值。
接着前一节的ManyToManyColumn.js,来修改一下当用户单击修改按钮的时候要进行的操作。
processEvent : function(type, view, cell, recordIndex, cellIndex, e, record, row) { var me = this; if (type === 'click') { var module = this.up('modulegrid').module; if (e.getTarget().className === 'manyToManyContext') { app.modules.showModuleRecord(this.manyToManyModuleName, e .getTarget().getAttribute('_id')); } else if (Ext.String.startsWith(e.getTarget().className, 'manyToManyContextClose')) { // 点击了删除按钮,先找到前面一个节点,里面包含了要删除的信息 var target = e.getTarget().previousElementSibling; var text = module.tf_title + ' ' + record.getTitleTpl() + ' 的 ' + this.manyToManyModuleTitle + '【' + target.innerHTML + '】'; Ext.MessageBox.confirm('确定删除', '确定要删除' + text + '吗?', function( btn) { if (btn == 'yes') { // 使用module里面批量删除的ajax Ext.Ajax.request({ url : 'rest/module/removerecords.do', params : { moduleName : me.fieldDefine.tf_joinTable, ids : target.getAttribute('_joinid'), titles : target.innerHTML }, success : function(response) { var info = Ext.decode(response.responseText, true); if (info.resultCode == 0) { Ext.toastInfo(text + ' 已成功被删除。'); // 删除记录后,刷新当前记录 me.up('modulegrid').refreshSelectedRecord(); } else { Ext.MessageBox.show({ title : '删除结果', msg : text + '删除失败:<br/><br/>' + info.errorMessageList, buttons : Ext.MessageBox.OK, icon : Ext.MessageBox.ERROR }); } }, failure : function() { window.alert('删除时,服务器返回返回错误'); } }) } }); } else if (Ext.String.startsWith(e.getTarget().className, 'manyToManyEdit')) { //编辑当前记录的manyToMany字段; Ext.widget( 'manytomanyeditwindow', { grid : me.up('modulegrid'), title : module.tf_title + '【' + record.getTitleTpl() + '】的' + this.manyToManyModuleTitle, moduleName : module.tf_moduleName, idvalue : record.getIdValue(), manyToManyModuleName : me.manyToManyModuleName, linkModuleName : me.fieldDefine.tf_joinTable }).show(); } } }
在上面的代码中可以看出,如果单击了修改按钮,会去创建一个manytomanyeditwindow。在这个window中完成上面的6步操作。
/** * 修改记录的manyToMany字段的窗口,在窗口中完成选择操作,并可保存。 */ Ext.define('app.module.widget.window.ManyToManyEditWindow', { extend : 'Ext.window.Window', alias : 'widget.manytomanyeditwindow', requires : [ 'app.lib.CheckTreePanel' ], width : 450, height : 600, modal : true, maximizable : true, layout : 'fit', buttons : [ '->', { text : '保存', iconCls : 'fa fa-save', handler : function(button) { var window = button.up('window'); var tree = window.down('treepanel'); var selected = [] tree.getRootNode().cascadeBy(function(node) { // 所有选中的 ManyToMany 的值 if (node.data.checked == true && node.data.leaf == true) { selected.push(node.data.fieldvalue); } }); // 提交ajax请求后台修改 Ext.Ajax.request({ url : 'modulemanytomany/setmanytomanydetail.do', params : { moduleName : window.moduleName, id : window.idvalue, manyToManyModuleName : window.manyToManyModuleName, linkModuleName : window.linkModuleName, selected : selected.join(',') }, success : function(response) { var info = Ext.decode(response.responseText, true); if (info.success) { Ext.toastInfo(window.titlemess + ' 已保存。'); window.grid.refreshSelectedRecord(); window.close(); } else Ext.toastError(window.titlemess + ' 保存失败。<br>' + '原因:' + info.msg); } }) } }, { text : '关闭', iconCls : 'fa fa-close', handler : function(button) { button.up('window').close(); } }, '->' ], initComponent : function() { var me = this; this.titlemess = this.title; this.title = '设置 ' + this.titlemess; this.items = [ { xtype : 'checktreepanel', autoLoad : false, rootVisible : false, root : {}, store : Ext.create('Ext.data.TreeStore', { proxy : { type : 'ajax', url : 'modulemanytomany/getmanytomanydetail.do', extraParams : { moduleName : me.moduleName, id : me.idvalue, manyToManyModuleName : me.manyToManyModuleName, linkModuleName : me.linkModuleName } } }) } ]; this.callParent(arguments); } })
这是前台的界面操作的代码,那么后台要处理上面所述的第2,第5步。需要新增一个Controller类来接收ajax请求。下面这个是控制类:
package com.jfok.cfcmms.controller; import java.util.List; import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import com.jfok.cfcmms.service.ModuleManyToManyService; import com.jfok.cfcmms.share.TreeNodeRecordChecked; import com.jfok.cfcmms.util.ActionResult; /** * 用来管理模块的ManyToMany数据的读取和修改的保存 * * @author jiangfeng * * 2016-01-11 * */ @Controller @RequestMapping("/modulemanytomany") public class ModuleManyToManyController { @Resource private ModuleManyToManyService moduleManyToManyService; /** * * @param request * @param moduleName * 当前模块名称 * @param id * 当前记录id * @param manyToManyModuleName * manyToMany的模块名称 * @param linkModuleName * 中间模块名称 * @return 返回所有manyToManyModuleName的记录数据,并把当前记录已有的manyToMany值的checked置为true */ @RequestMapping("/getmanytomanydetail.do") public @ResponseBody List<TreeNodeRecordChecked> genManyToManyDetail(HttpServletRequest request, String moduleName, String id, String manyToManyModuleName, String linkModuleName) { return moduleManyToManyService.getManyToManyDetail(request, moduleName, id, manyToManyModuleName, linkModuleName); } /** * * @param request * @param moduleName * 当前模块名称 * @param id * 当前记录id * @param manyToManyModuleName * manyToMany的模块名称 * @param linkModuleName * 中间模块名称 * @param selected * 所有选中的值,以逗号分隔 * @return 返回所有manyToManyModuleName的记录数据,并把当前记录已有的manyToMany值的checked置为true */ @RequestMapping("/setmanytomanydetail.do") public @ResponseBody ActionResult setManyToManyDetail(HttpServletRequest request, String moduleName, String id, String manyToManyModuleName, String linkModuleName, String selected) { return moduleManyToManyService.setManyToManyDetail(request, moduleName, id, manyToManyModuleName, linkModuleName, selected.split(",")); } }
最后一个就是用来处理请求的Service类了,这个类也是这个功能的关键。由他来完成系统中所有的类似的ManyToMany字段读取和修改的操作。
package com.jfok.cfcmms.service; import java.util.ArrayList; import java.util.List; import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; import com.jfok.cfcmms.DAO.ModuleDAO; import com.jfok.cfcmms.DAO.SystemBaseDAO; import com.jfok.cfcmms.core.module.SqlGenerator; import com.jfok.cfcmms.core.module.SqlModuleFilter; import com.jfok.cfcmms.hibernate.system.module._Module; import com.jfok.cfcmms.share.TreeNodeRecord; import com.jfok.cfcmms.share.TreeNodeRecordChecked; import com.jfok.cfcmms.share.ValueText; import com.jfok.cfcmms.util.ActionResult; import net.sf.json.JSONArray; import net.sf.json.JSONObject; @Service public class ModuleManyToManyService { @Resource private SystemBaseDAO systemBaseDAO; @Resource private ModuleDAO moduleDAO; @Resource private ModuleService moduleService; /** * * @param request * @param moduleName * 当前模块名称 * @param id * 当前记录id * @param manyToManyModuleName * manyToMany的模块名称 * @param linkModuleName * 中间模块名称 * @return 返回所有manyToManyModuleName的记录数据,并把当前记录已有的manyToMany值的checked置为true */ @Transactional(propagation = Propagation.REQUIRED, readOnly = true) public List<TreeNodeRecordChecked> getManyToManyDetail(HttpServletRequest request, String moduleName, String id, String manyToManyModuleName, String linkModuleName) { _Module module = SystemAndLoginInfoService.getModuleWithName(moduleName); _Module manyToManyModule = SystemAndLoginInfoService.getModuleWithName(manyToManyModuleName); List<TreeNodeRecord> result = new ArrayList<TreeNodeRecord>(); // 首先读取manyToManyModuleName中的所有权限可视范围之内的数据 List<ValueText> allTreeItems = moduleDAO.getModuleWithComboDataWithQuery(manyToManyModuleName, null, request); for (ValueText vt : allTreeItems) { TreeNodeRecordChecked record = new TreeNodeRecordChecked(); record.setFieldvalue(vt.getValue()); record.setText(vt.getText()); record.setLeaf(true); result.add(record); } // 在linkModuleName中读取当前id的manyToMany的值,在数据可视涠之内 List<SqlModuleFilter> filters = new ArrayList<SqlModuleFilter>(); SqlModuleFilter moduleIdFilter = new SqlModuleFilter(); moduleIdFilter.setModuleName(module.getTf_moduleName()); moduleIdFilter.setTableAsName(module.getTableAsName()); moduleIdFilter.setPrimarykey(module.getTf_primaryKey()); moduleIdFilter.setEqualsValue(id); filters.add(moduleIdFilter); SqlGenerator generator = new SqlGenerator(linkModuleName, request); generator.setModuleFilters(filters); JSONArray dataArray = moduleDAO.getData(generator, -1, 0); // 生成TreeNodeRecordChecked,并加入checked标志 for (int i = 0; i < dataArray.size(); i++) { String manytomanyid = dataArray.getJSONObject(i).getString( manyToManyModule.getTableAsName() + "___" + manyToManyModule.getTf_primaryKey()); for (TreeNodeRecord record : result) { if (record.getFieldvalue().equals(manytomanyid)) ((TreeNodeRecordChecked) record).setChecked(true); } } // 返回结果 List<TreeNodeRecordChecked> root = new ArrayList<TreeNodeRecordChecked>(); TreeNodeRecordChecked rootrecord = new TreeNodeRecordChecked(); rootrecord.setText(manyToManyModule.getTf_title()); rootrecord.setChildren(result); rootrecord.setExpanded(true); root.add(rootrecord); return root; } public ActionResult setManyToManyDetail(HttpServletRequest request, String moduleName, String id, String manyToManyModuleName, String linkModuleName, String[] selected) { _Module module = SystemAndLoginInfoService.getModuleWithName(moduleName); _Module manyToManyModule = SystemAndLoginInfoService.getModuleWithName(manyToManyModuleName); _Module linkedModule = SystemAndLoginInfoService.getModuleWithName(linkModuleName); // 在linkModuleName中读取当前id的manyToMany的值,在数据可视涠之内 List<SqlModuleFilter> filters = new ArrayList<SqlModuleFilter>(); SqlModuleFilter moduleIdFilter = new SqlModuleFilter(); moduleIdFilter.setModuleName(module.getTf_moduleName()); moduleIdFilter.setTableAsName(module.getTableAsName()); moduleIdFilter.setPrimarykey(module.getTf_primaryKey()); moduleIdFilter.setEqualsValue(id); filters.add(moduleIdFilter); SqlGenerator generator = new SqlGenerator(linkModuleName, request); generator.setModuleFilters(filters); JSONArray dataArray = moduleDAO.getData(generator, -1, 0); // 如果原来有,现在selected里面没有了,那么就要删除了 for (int i = 0; i < dataArray.size(); i++) { String manytomanyid = dataArray.getJSONObject(i).getString( manyToManyModule.getTableAsName() + "___" + manyToManyModule.getTf_primaryKey()); boolean isfound = false; for (String selectedid : selected) { if (manytomanyid.equals(selectedid)) { isfound = true; break; } } if (!isfound) { // 需要删除这个manyTomany,调用系统Service的remove,会判断能否删除的逻辑,会记入日志 // 尚未做出错处理 moduleService.remove(linkModuleName, dataArray.getJSONObject(i).getString(linkedModule.getTf_primaryKey()), request); } } // 如果原来没有,现在selected里面有了,那么就要增加进去 for (String selectedid : selected) { if (selectedid.length() > 0) { boolean isfound = false; for (int i = 0; i < dataArray.size(); i++) { String manytomanyid = dataArray.getJSONObject(i).getString( manyToManyModule.getTableAsName() + "___" + manyToManyModule.getTf_primaryKey()); if (manytomanyid.equals(selectedid)) { isfound = true; break; } } if (!isfound) { JSONObject object = new JSONObject(); object.put( manyToManyModule.getTableAsName() + "___" + manyToManyModule.getTf_primaryKey(), selectedid); object.put(module.getTableAsName() + "___" + module.getTf_primaryKey(), id); // 需要新增这个manyTomany,调用系统Service的add ,会判断是否能新增等逻辑,会记入日志 // 尚未做出错处理 moduleService.add(linkModuleName, object.toString(), request); } } } ActionResult result = new ActionResult(); return result; } }
经过以上代码的协同工作,我们可以打开人员的设置权限的窗口来进行权限设置了。
修改一些用户操作角色,然后保存。
至此用户的ManyToMany字段操作角色的修改即可完成。
对于操作角色来说,用户也是一个ManyToMany字段,同样也适用于这样操作。
至此ManyToMany字段的定义、显示、操作都基本完成。
进阶设想:
对于选择tree的改进。在我现在的系统里,在用户模块中,有一个设置权限的按钮,其实就是完成了ManyToMany字段的选择与保存,有了这个字段功能之后,这个设置权限的按钮就可以不要了。但是有一点是不一样的,看看下面的截图:
在上图的选择角色的窗口的tree中,角色是按照角色分组来进行分类的,这样在选择的时候可以更直观。以后的ManyToMany字段的选择树也要做成可以配置成这样的结构。这里我大体先写一下思路:
1?在模块配置中新增一个配置字段:ManyToMany选择时候的树形模块路径;
2?在某个模块被当作ManyToMany字段来选择的时候,读取其模块路径,然后把当前模块的值都加在相应的节点之下。
比如对于角色来选择人员来说,可以把部门作为人员的模块路径,这样在选择树中,先是部门的值,然后人员会挂在相应的部门之下来进行选择。
(这个功能以后有时间再做了)