一:简介
在前面DataGrid(3)的基础上添加后台的实现、本来是想只搭建前台页面的、后台不写、现在觉得还是都实现好点、从真实情况出发、后台用的ssh。
1、 新增冻结列功能。
2、 实现界面的添加、删除、修改、撤销编辑、撤销选中、清空datagrid记录的功能、在后台也对其实现。
3、 新增右键菜单功能。
4、 可根据右键菜单来对记录进行新增、修改、删除。
二:效果图
三:关键部分
1、新增冻结列功能:
a) 具体需求描述:
有时候表格的列数太多(这里在前面的补充中也说道过、datagrid的列较少的时候、可以把其一个属性fitColumn设为true、这样列平局充满表格、好看点)的时候、当用户想要参照某个列的数据查看其他数据的时候、比如根据某个人的名字查看他的具体信息、这时候就可以在拖动滚动条查看后面的记录的时候让名字那一列始终按固定大小显示在原来位置、
b) 效果图:
c) 关键代码:作为datagrid的一个属性、当然是在初始化的时候指定:具体的见user.jsp
frozenColumns : [[{//冻结列、不管数据列再多、拖动下方滚动条时、其中的列都不会滚动(这些列下方根本就没有滚动条)、参数与columns一样、注意:双中括号——[[{xxx},{xxx}]] title : '编号', field : 'id', width : 100,//必须要给 checkbox : true, }, { title : '姓名', field : 'userName', width : 100,//必须要给 editor : { type:'validatebox', options:{ required: true, } } } ]],
2、添加、修改
a) 具体业务描述:很常见的操作。
b) 通过datagrid的onAfterEditor事件来提交、这里我暂时只对一行进行操作、不进行批量添加、修改。如何区分是添加事件还是修改事件?
c) 添加、修改都有成功、失败。成功如何将数据持久化到数据库中和页面显示(即点击撤销按钮不会将添加、修改的内容取消显示)?失败如何将事物回滚到添加、删除之前?
d) 关键代码:对上面问题有很详细的注释、这也是注释有点多的原因、不再抽出来。。。
onAfterEdit : function(rowIndex, rowData, changes){ /* * 如何区别是添加、还是修改? */ //获取所有插入的行信息 var inserted = $('#datagrid').datagrid('getChanges','inserted'); //获取所有被修改的行信息 var updated = $('#datagrid').datagrid('getChanges','updated'); //传入后台的url、根据到底是添加、还是修改动态改变、即进入Action中不同的方法。 var url = ''; if(inserted.length > 0){ url='login_addUser.action'; } if(updated.length > 0){ url='login_updateUser.action'; } $.ajax({ url : url, data : rowData, dataType : 'json', success : function(r){ if(r.success && r){ //如果成功、则确定显示操作之后的行信息、即点击撤销的时候不会回滚事务(仅是前台、此时后台关于数据库的已经处理)。 $('#datagrid').datagrid('acceptChanges'); //给出提示、是通过后台传过来的一个json对象 $.messager.show({ title : '提示', msg : r.msg, }); }else{ //如果失败、则回滚事务(仅是前台、此时后台关于数据库的已经处理)。 $('#datagrid').datagrid('rejectChanges'); $.messager.alert('错误',r.msg,'error'); } editRow = undefined; $('#datagrid').datagrid('unselectAll'); } }); },
3、右键菜单:
a) 需求描述、用户就喜欢用鼠标右键菜单来操作。
b) 构建右键菜单
c) 如何将右键菜单动态的显示在鼠标单机右键的位置
d) 如何透过显示的右键菜单项操作数据、这里操作数据就是通过onclick事件触发函数、函数功能和datagrid上面的按钮功能几乎一样、代码中做了一个抽取。
e) 关键代码:
构造右键菜单div:
<%-- 通过指定class的方式、构造右键菜单--%> <div id="mm" class="easyui-menu" style="width:120px;display:none;"> <div onclick="addUser()" iconcls="icon-add">增加</div> <div onclick="delUsers()" iconcls="icon-remove">删除</div> <div onclick="updateUser()" iconcls="icon-edit">编辑</div> </div>
显示右键菜单div:
//显示右键菜单、并且设置显示位置就是触发鼠标右击的位置。 onRowContextMenu : function(e, rowIndex, rowData){ //1、阻止原来浏览器右键事件 e.preventDefault(); $(this).datagrid('unselectAll'); $(this).datagrid('selectRow', rowIndex); //显示自定义右键菜单 $('#mm').menu('show', { //动态显示右键菜单位置 left: e.pageX, top: e.pageY }); }
实现右键菜单功能:
/* * 右键菜单功能 */ //添加记录 function addUser(){ privateAddUser(); } //修改记录 function updateUser(){ privateUpdateUser(); } //删除记录 function delUsers(){ privateDelUsers(); }
四:源码
1、前台代码:
a) datagrid2.jsp:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <title>My JSP 'original.jsp' starting page</title> <link rel="stylesheet" type="text/css" href="css/easyui/default/easyui.css"> <link rel="stylesheet" type="text/css" href="css/easyui/icon.css"> <link rel="stylesheet" type="text/css" href="css/easyui/demo.css"> <script type="text/javascript" src="js/jquery.min.js"></script> <script type="text/javascript" src="js/jquery.easyui.min.js"></script> <script type="text/javascript" src="js/chyUtils.js"></script> <script type="text/javascript"> function userManage(id){ console.info(id); if("door" == id){ $('#tt').tabs('select', 0); } if("userManage" == id){ $('#tt').tabs('select', 1); } } </script> <div data-options="region:'north', split:false" style="height:100px;"></div> <div data-options="region:'east',title:'在线列表',split:true" style="width:160px;"></div> <div data-options="region:'west',title:'功能导航',split:true" style="width:160px;"> <div class="easyui-accordion" data-options="fit:true,border:false"> <div title="Title1" data-options=" iconCls:'icon-save'" style="padding:10px;"> content1 </div> <div title="Title2" data-options="fit:true,border:false,iconCls:'icon-reload',selected:true" style="padding:10px"> <ul> <li>门户 </li> <li>用户管理</li> </ul> </div> </div> </div> <div data-options="region:'center',title:'欢迎'," style="overflow: hidden;"> <div id="tt" class="easyui-tabs" data-options="fit:true,border:false,"> <div title="门户" data-options="closable:true"> 门户 </div> <div id="userManage" title="用户管理" data-options="href:'user.jsp',closable:true"> </div> </div> </div>
b) user.jsp:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <script type="text/javascript"> var editRow = undefined;//用于存放当前编辑行的index $(function() { $('#datagrid').datagrid({ url : 'login_getUserJson.action', title : '用户列表', iconCls : 'icon-save', pagination : true, pageSize : 10, pageList : [ 10, 20, 30, 40, 50, 60, 70, 80, 90, 100 ], fit : true,//使表格自适应 fitColumns : false,//当使用冻结列:frozenColumms的时候必须设置为false或者不写 nowrap : false,//表格中的文字可以换行、默认是false、不能换行、这样在文字很多的时候就看不到全部:使用真实的数据去测试 border : false, idFeild : 'id',//标识、会记录我们选中项的id、不一定是id、通常使用主键 sortName : 'id',//设置默认排序时的 字段(必须是field中的一个字段) sortOrder : 'asc',//是按照升序还是降序排序 但是仅仅添加这两个字段并不会自动排序、这样写的意义就是前台会自动的向后台传递两个参数:sort order,我们可以在后台查询记录的时候进行排序 frozenColumns : [[{//冻结列、不管数据列再多、拖动下方滚动条时、其中的列都不会滚动(这些列下方根本就没有滚动条)、参数与columns一样、注意:双中括号——[[{xxx},{xxx}]] title : '编号', field : 'id', width : 100,//必须要给 checkbox : true, }, { title : '姓名', field : 'userName', width : 100,//必须要给 editor : { type:'validatebox', options:{ required: true, } } } ]], columns : [ [ { title : '密码', field : 'passWord', width : 200,//必须要给 editor : { type:'validatebox', options:{ required: true, } } }, { title : '创建时间', field : 'createTime', width : 200,//必须要给 editor : { type:'datetimebox',//扩展的用于选择具体时间的类型 options:{ required: true, } } }, { title : '修改时间', field : 'updateTime', width : 200,//必须要给 editor : { type:'datetimebox',//扩展的用于选择具体时间的类型 options:{ required: true, } } } ] ], toolbar : [ { text : '增加', iconCls : 'icon-add', handler : function() { privateAddUser(); } }, '-', { text : '删除', iconCls : 'icon-remove', handler : function() { privateDelUsers(); } }, '-', { text : '修改', iconCls : 'icon-edit', handler : function() { privateUpdateUser(); } }, '-',{ text : '保存', iconCls : 'icon-save', handler : function() { $('#datagrid').datagrid('endEdit', editRow); } }, '-',{ text : '取消编辑', iconCls : 'icon-undo', handler : function() { //将事务回滚、取消选中的行 editRow = undefined; $('#datagrid').datagrid('rejectChanges'); $('#datagrid').datagrid('unselectAll'); } }, '-',{ text : '取消选中', iconCls : 'icon-undo', handler : function() { $('#datagrid').datagrid('unselectAll'); } }, '-',{ text : '清空显示', iconCls : 'icon-undo', handler : function() { $('#datagrid').datagrid('loadData', []); } }, '-',{ text : '还原显示', iconCls : 'icon-redo', handler : function() { $('#datagrid').datagrid('load'); } }, '-' ], onAfterEdit : function(rowIndex, rowData, changes){ /* * 如何区别是添加、还是修改? */ //获取所有插入的行信息 var inserted = $('#datagrid').datagrid('getChanges','inserted'); //获取所有被修改的行信息 var updated = $('#datagrid').datagrid('getChanges','updated'); //传入后台的url、根据到底是添加、还是修改动态改变、即进入Action中不同的方法。 var url = ''; if(inserted.length > 0){ url='login_addUser.action'; } if(updated.length > 0){ url='login_updateUser.action'; } $.ajax({ url : url, data : rowData, dataType : 'json', success : function(r){ if(r.success && r){ //如果成功、则确定显示操作之后的行信息、即点击撤销的时候不会回滚事务(仅是前台、此时后台关于数据库的已经处理)。 $('#datagrid').datagrid('acceptChanges'); //给出提示、是通过后台传过来的一个json对象 $.messager.show({ title : '提示', msg : r.msg, }); }else{ //如果失败、则回滚事务(仅是前台、此时后台关于数据库的已经处理)。 $('#datagrid').datagrid('rejectChanges'); $.messager.alert('错误',r.msg,'error'); } editRow = undefined; $('#datagrid').datagrid('unselectAll'); } }); }, //双击修改行 onDblClickRow : function(rowIndex, rowData){ changeUpdateEditor(); $('#datagrid').datagrid('unselectAll'); if(editRow != undefined){ $('#datagrid').datagrid('endEdit', editRow); editRow = undefined; } if(editRow == undefined){ $('#datagrid').datagrid('beginEdit',rowIndex); editRow = rowIndex; } }, //显示右键菜单、并且设置显示位置就是触发鼠标右击的位置。 onRowContextMenu : function(e, rowIndex, rowData){ //1、阻止原来浏览器右键事件 e.preventDefault(); $(this).datagrid('unselectAll'); $(this).datagrid('selectRow', rowIndex); //显示自定义右键菜单 $('#mm').menu('show', { //动态显示右键菜单位置 left: e.pageX, top: e.pageY }); } }); }); /* * 右键菜单功能 */ //添加记录 function addUser(){ privateAddUser(); } //修改记录 function updateUser(){ privateUpdateUser(); } //删除记录 function delUsers(){ privateDelUsers(); } function privateDelUsers(){ var rows = $('#datagrid').datagrid('getSelections'); if(rows.length > 0){ $.messager.confirm('请确认','您确定要删除当前选择的'+rows.length+'项吗?', function(option){ if(option){ //一般将id的一个集合传到后台删除 var ids = []; for(var i = 0; i< rows.length; i++){ ids.push(rows[i].id); } console.info(ids.join(',')); $.ajax({ url : 'login_delUsers.action', data : { ids : ids.join(',') }, dataType : 'json', success : function(r){ $('#datagrid').datagrid('load'); $('#datagrid').datagrid('unselectAll'); $.messager.show({ title : '提示', msg : '删除成功' }); } }); } }); }else{ $.messager.alert('提示', '请选择要删除的记录', 'error'); } } function privateUpdateUser(){ var rows = $('#datagrid').datagrid('getSelections'); if(rows.length ==1){ changeUpdateEditor(); if(editRow != undefined){ $('#datagrid').datagrid('endEdit', editRow); editRow = undefined; } if(editRow == undefined){ var rowIndex = $('#datagrid').datagrid('getRowIndex',rows[0]); $('#datagrid').datagrid('beginEdit',rowIndex); editRow = rowIndex; $('#datagrid').datagrid('unselectAll'); } }else if( rows.length == 0){ $.messager.alert('提示', '请选择一条修改记录!','info'); }else if(rows.length >= 1){ $.messager.alert('提示', '只能选择一条修改记录!','info'); } } function privateAddUser(){ if(editRow != undefined){ $('#datagrid').datagrid('endEdit', editRow); } if(editRow == undefined){ //新增的时候不让用户选择创建时间、应该用后台自动生成的当前的时间 changeAddEditor(); $('#datagrid').datagrid('insertRow', { index : 0, row : { userName:'请输入名称', passWord:'请输入密码' } }); editRow = 0; $('#datagrid').datagrid('beginEdit',0); } } //查询数据 function show() { $('#datagrid').datagrid('load', serializeObject($('#searchForm'))); } //清除查询条件、返回初始数据展示状态 function clean() { $('#datagrid').datagrid('load', {}); $('#searchForm').find('input').val(''); } //添加行时改变editor function changeAddEditor(){ $('#datagrid').datagrid('removeEditor', ['updateTime','createTime']); $('#datagrid').datagrid('addEditor', { field : 'passWord', editor : { type:'validatebox', options:{ required: true, } } }); } //修改行是改变editor function changeUpdateEditor(){ $('#datagrid').datagrid('removeEditor','passWord'); $('#datagrid').datagrid('addEditor', [{ field : 'createTime', editor : { type:'datetimebox',//扩展的用于选择具体时间的类型 options:{ required: true, } } },{ field : 'updateTime', editor : { type:'datetimebox',//扩展的用于选择具体时间的类型 options:{ required: true, } } }]); } </script> <div class="easyui-layout" data-options="fit:true,border:false,"> <div data-options="region:'north',border:false,title:'过滤'" style="height: 140px;overflow: hidden"> <form id="searchForm"> <table class="datagrid-toolbar" style="height:100%;width:100%"> <tbody><tr> <th>用户名</th> <td><input id="username" name="username" style="width: 320px"> </td> </tr> <tr> <th>创建时间</th> <td><input name="createTimeStart" editable="false" class="easyui-datetimebox" style="width:155px;"> 至 <input name="createTimeEnd" editable="false" class="easyui-datetimebox" style="width:155px;"></td> </tr> <tr> <th>修改时间</th> <td><input name="modifyTimeStart" editable="false" class="easyui-datetimebox" style="width:155px;"> 至 <input name="modifyTimeEnd" editable="false" class="easyui-datetimebox" style="width:155px;"> 查询 清空</td> </tr> </tbody></table> </form> </div> <div data-options="region:'center',border:false"> <table id="datagrid"></table> </div> <%-- 通过指定class的方式、构造右键菜单--%> <div id="mm" class="easyui-menu" style="width:120px;display:none;"> <div onclick="addUser()" iconcls="icon-add">增加</div> <div onclick="delUsers()" iconcls="icon-remove">删除</div> <div onclick="updateUser()" iconcls="icon-edit">编辑</div> </div> </div>
b) chyUtils.js:与前面一样、不再贴了。
2、后台代码
后台可以自己实现、不再一一贴出来、这里就贴个关键的action、一个处理返回数据的Json、一个UserDTO、源码有时间再上传到csdn上。
a) LoginAction:
private UserService userService; private int page; private int rows; private String sort; private String order; private String username; private String password; private int id; private String userName; private String passWord; private String createTime; private String updateTime; private String ids; public String login() throws IOException{ String result = null; if("admin".equals(username) && "123".equals(password)){ result = "success"; }else{ result = "faile"; } pwObj(result); return null; } public String regist() throws IOException{ pwObj("success"); return null; } /** * 添加用户 */ public String addUser() throws JsonGenerationException, JsonMappingException, IOException{ Json j = new Json(); UserDTO u = new UserDTO(); BeanUtils.copyProperties(this, u); u.setCreateTime(getCurrentTime()); u.setUpdateTime(getCurrentTime()); boolean addStatu = userService.addUser(u); if(addStatu){ j.setMsg("Add User [" + u.getUserName() + "] Success !"); j.setSuccess(addStatu); }else{ j.setMsg("Add User [" + u.getUserName() + "] fail !"); j.setSuccess(addStatu); } pwObj(getJson(j)); return null; } /** * 更新用户信息 */ public String updateUser() throws JsonGenerationException, JsonMappingException, IOException{ Json j = new Json(); UserDTO u = new UserDTO(); BeanUtils.copyProperties(this, u); u.setCreateTime(createTime); u.setUpdateTime(updateTime); boolean addStatu = userService.updateUser(u); if(addStatu){ j.setMsg("Update User [" + u.getUserName() + "] Success !"); j.setSuccess(addStatu); }else{ j.setMsg("Update User [" + u.getUserName() + "] fail !"); j.setSuccess(addStatu); } pwObj(getJson(j)); return null; } /** * 删除用户信息 */ public String delUsers() throws JsonGenerationException, JsonMappingException, IOException{ Json j = new Json(); try { j.setMsg("Delete users success !"); j.setSuccess(true); userService.delUsers(ids); } catch (Exception e) { j.setMsg("Delete users fail !"); e.printStackTrace(); } pwObj(getJson(j)); return null; } /** * 初始化datagrid */ public String getUserJson() throws IOException{ List<userdto> userList = userService.getUsers(page, rows); int total = userService.getCountUsers(); Map<string, object=""> m = new HashMap<string, object="">(); m.put("total", total); m.put("rows", userList); pwObj(getJson(m)); return null; } private String getCurrentTime(){ SimpleDateFormat sDateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); return sDateFormat.format(new java.util.Date()); } private String getJson(Object o) throws IOException, JsonGenerationException, JsonMappingException { ObjectMapper om = new ObjectMapper(); StringWriter sw = new StringWriter(); JsonGenerator jg = new JsonFactory().createJsonGenerator(sw); om.writeValue(jg, o); jg.close(); return sw.toString(); } private void pwObj(Object obj) throws IOException { PrintWriter pw = ServletActionContext.getResponse().getWriter(); pw.print(obj); pw.flush(); pw.close(); }</string,></string,></userdto>
b) 使用到的Json工具类:
package com.chy.ssh.utils; public class Json { private boolean success = false; //操作是否成功 private String msg; //提示信息 private Object o; //其他信息 public boolean isSuccess() { return success; } public void setSuccess(boolean success) { this.success = success; } public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } public Object getO() { return o; } public void setO(Object o) { this.o = o; } }
c) UserDTO:
package com.chy.ssh.business.bean; import java.io.Serializable; @SuppressWarnings("serial") public class UserDTO implements Serializable{ private int id; private String userName; private String passWord; private String createTime; private String updateTime; public UserDTO() { super(); } public String getCreateTime() { return createTime; } public void setCreateTime(String createTime) { this.createTime = createTime; } public String getUpdateTime() { return updateTime; } public void setUpdateTime(String updateTime) { this.updateTime = updateTime; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getPassWord() { return passWord; } public void setPassWord(String passWord) { this.passWord = passWord; } public int getId() { return id; } public void setId(int id) { this.id = id; } }
五:补充说明
后面的内容会越来越多、老想着把东西全贴出来不现实、可能只会贴关键的想说的地方、有时间将源码上传到csdn上、也可以留个邮箱、共同进步。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· 展开说说关于C#中ORM框架的用法!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
2010-01-18 [设计模式整理笔记 八] 单例模式(Singleton)
2010-01-18 [设计模式整理笔记 七] 原型模式(ProtoType)