1. 环境搭建
<!--引入样式文件-->
<link rel="stylesheet" href="${pageContext.request.contextPath}/statics/boot/css/bootstrap.css" type="text/css">
<link rel="stylesheet" href="${pageContext.request.contextPath}/statics/jqgrid/css/trirand/ui.jqgrid-bootstrap.css" type="text/css">
<!--引入js功能文件-->
<script src="${pageContext.request.contextPath}/statics/boot/js/jquery-2.2.1.min.js" type="text/javascript"></script>
<script src="${pageContext.request.contextPath}/statics/boot/js/bootstrap.min.js" type="text/javascript"></script>
<script src="${pageContext.request.contextPath}/statics/jqgrid/js/trirand/i18n/grid.locale-cn.js" type="text/javascript"></script>
<script src="${pageContext.request.contextPath}/statics/jqgrid/js/trirand/jquery.jqGrid.min.js" type="text/javascript"></script>
2. 基础结构
<table id="user-table"></table>
<div id="user-pager"></div>
<script>
$(function () {
//展示供应商信息
$("#user-table").jqGrid({
// 整合使用bootstrap样式的属性
styleUI:'Bootstrap',
url:'${pageContext.request.contextPath}/user/findUserByPage',
editurl:'${pageContext.request.contextPath}/user/operUser',
caption : "用户详细信息",
datatype:'json',
colNames:['姓名','性别','年龄'],
// 开启表格编辑模式
cellEdit:true,
colModel:[
{name:'username',align:'center',editable:true},
{name:'sex',align:'center',editable:true},
{name:'age',align:'center',editable:true}
],
//添加分页
//使用分页工具栏
pager:'#user-pager',
rowList:[5,10,15],
rowNum:10,
page:1,
}).navGrid('#user-pager',{edit : true,add : true,del : true,search:true});
})
</script>
3. 常用初始化参数
参数(带常用值) | 作用 |
---|---|
url:‘项目名/user/findUserByPage’ | 获取数据的地址 |
editurl:‘项目名/user/operUser’ | 对数据进行增删改时的请求路径 |
styleUI:‘Bootstrap’ | 整合使用bootstrap样式的属性 |
caption : “用户详细信息” | 表格标题 |
datatype:‘json’ | 从服务器端返回的数据类型 |
colNames:[‘姓名’,‘性别’,‘年龄’] | 表头的列名 |
colModel:[{name:‘username’},{name:‘sex’},{name:‘age’}] | 每列各单元格名(下文详细介绍) |
cellEdit:true | 开启表格编辑模式(允许进行增删改查 |
autowidth:true | 数据表格是否自适应父容器的大小宽度 |
rownumbers:true | 显示行号 |
multiselect:true | 在第一列前加入复选框 |
multiselectWidth:20 | 当multiselect为true时设置multiselect列宽度 |
height:400 | 设置表格整体高度 |
pager:’#user-pager’ | 使用分页工具栏,写入指定div的id |
rowList:[5,10,15] | 设置每页显示条数的选项 |
rowNum:10 | 设置每页显示条数,必须从rowList中选择 |
page:1 | 设置初始的页码 |
viewrecords:true | 是否显示总条数 |
4. 常用colModel参数
参数(带常用值) | 作用 |
---|---|
name:‘username’ | 表格的列名 |
align:‘center’ | 设置表格内容居中显示 |
editable:true | 单元格是否可编辑 |
edittype:‘file’ | 单元格编辑时的类型,这里一般用作文件上传 |
edittype:‘select’ | 设置单元格编辑时为下拉列表(数据获取以下两种方式) |
editoptions:{value:“正常:正常;冻结:冻结”} | 设置下拉列表选项 |
editoptions:{dataUrl:‘项目名/guru/findAll’} | 动态从服务器端获取数据,如果为下拉列表,返回值为拼接的select、option字符串 |
hidden:true | 设置此列是否隐藏 |
editrules:{edithidden:true} | 该字段隐藏时, 此属性可以控制是否可编辑 |
formatter | 设置此列的最终展示结果 |
colModel的实际使用
a. 格式化日期
{
name:'createDate',
align:'center',
formatter:"date",
//srcformat为标准格式,newformat为最终显示格式
formatoptions: {srcformat:'Y-m-d H:i:s',newformat:'Y-m-d'}
}
b. 编辑时固定的下拉列表
{
name:'status',
align:'center',
edittype:"select",
//value中前者为发送至后台的数据,后者为前台展示的数据
editoptions:{value:"正常:正常;冻结:冻结"},
editable:true
}
c. 编辑时动态获取的的下拉列表(并设置表格显示内容)
{
name:'deptId',
align:'center',
editable:true,
edittype:'select',
editoptions:{dataUrl:'${pageContext.request.contextPath}/dept/findAll'},
formatter:function (value,options,row) {
/**
* value: 第一次(url)加载到的数据(deptId)
* options: 略
* row: 当前行(url)的所有数据
*/
return row.deptName;
}
}
editoptions:{dataUrl:‘项目名/dept/findAll’}:发送请求到后台,返回拼接的select、option字符串
formatter:设置初始化时该列的显示内容,function中有三个参数
- value: 第一次(url)加载到的数据(deptId),即与name对应的数据
- row: 当前行(url)的所有数据
前台返回的数据中有deptName属性,所以直接return row.deptName;即可
一定注意editoptions与formatter两者互不影响。editoptions设置编辑时 该列的展示形式与数据,formatter设置初始化后该列最终展示的数据!!!
d. 图片相关的展示与编辑
{
name:'cover',
align:'center',
editable:true,
edittype:'file',
formatter:function(value,options,row){
return '<img src="${pageContext.request.contextPath}/view/banner/image/'+row.cover+'" width="150px" height="60px"/>';
},
}
- edittype:‘file’ :设置该列编辑时类型,方便上传图片
- formatter中后台拿到的数据中cover为文件名,这里在src中手动拼接了一下文件路径,便于展示。
注:关于jqGrid的文件上传是使用ajaxfileupload.js插件用异步上传的方式实现的,具体内容见我的另一篇博文ajaxfileupload+Jqgrid实现异步文件上传
e. 隐藏该列,编辑时展示
{
name:'password',
align:'center',
editable:true,
hidden:true, //隐藏此列
editrules:{edithidden:true} //editrules:设置编辑字段的控件的规则
//edithidden: 该字段隐藏时, 此属性可以控制是否可编辑
}
5. 二级表格的使用
a. 效果展示
这里使用的是在当前行前加一个按钮,通过按钮来控制子表的展示与隐藏。
b. 使用步骤
- 使用二级表格首先要在初始化参数中开启subGrid :true
- 之后再使用subGridRowExpanded : function(subgrid_id, row_id) {}
function中的两个参数:
subgrid_id: 当前行子表的id
row_id: 父表当前行的id
之后的编码都在{}内完成 - 动态生成存放子表的table,存放子表工具栏的div并赋予id
//subgrid_id 子表id row_id父表当前行id
var subgrid_table_id, pager_id;
subgrid_table_id = subgrid_id + "_t"; //生成存放子表表格<table>的id
pager_id = "p_" + subgrid_table_id; //生成存放子表工具栏div的id
//生成table div
$("#" + subgrid_id).html(
"<table id='" + subgrid_table_id
+ "' class='scroll'></table><div id='"
+ pager_id + "' class='scroll'></div>");
- 获取该子表格table标签与工具栏div标签填充相应数据,与普通jqdrid填充数据相同。
c. 具体编码
subGrid : true,
subGridRowExpanded : function(subgrid_id, row_id) {
//subgrid_id 子表id row_id父表当前行id
var subgrid_table_id, pager_id;
subgrid_table_id = subgrid_id + "_t"; //生成存放子表表格<table>的id
pager_id = "p_" + subgrid_table_id; //生成存放子表工具栏div的id
//生成table div
$("#" + subgrid_id).html(
"<table id='" + subgrid_table_id
+ "' class='scroll'></table><div id='"
+ pager_id + "' class='scroll'></div>");
//填充内容
$("#" + subgrid_table_id).jqGrid(
{
// 整合使用bootstrap样式的属性
styleUI:'Bootstrap',
url:'${pageContext.request.contextPath}/chapter/findChapterByPage?aid='+row_id,
editurl:'${pageContext.request.contextPath}/chapter/operChapter?aid='+row_id,
caption : "章节详细信息",
datatype:'json',
colNames:['名称','大小(单位:M)','时长','创建时间','操作'],
// 开启表格编辑模式
cellEdit:true,
colModel:[
{name:'title',align:'center',editable:true},
{name:'size',align:'center'},
{name:'duration',align:'center'},
{
name:'createDate',
align:'center',
formatter:"date",
formatoptions: {srcformat:'Y-m-d H:i:s',newformat:'Y-m-d'}
},
{
name:'audio',
width:350,
formatter:function(value,options,row){
return '<audio controls loop>' +
'<source src="${pageContext.request.contextPath}/view/album/mp3/'+row.audio+'" type="audio/mpeg"/>' +
'</audio>';
},
align:'center',
editable:true,
edittype:'file',
},
],
//数据表格是否自适应父容器的大小宽度
autowidth:true,
//显示行号
rownumbers:true,
//在第一列前加入复选框
multiselect:true,
multiselectWidth:20,
//设置高度
height:200,
//添加分页
//使用分页工具栏
pager:"#"+pager_id,
rowList:[5,10,15],
rowNum:10,
page:1,
//显示总记录数
viewrecords:true
}).navGrid("#"+pager_id,{edit : true,add : true,del : true,search:true});
},
6. 关于jqGrid的一些其他实际应用
a. jqgrid的.navGrid()方法(执行完增删改后的一些操作);
.navGrid方法可对工具栏和编辑事件做一些设置。比如控制工具栏增、删、改、查操作是否显示。对修改、添加、删除操作做一些控制。
但注意它的顺序有严格要求。
.navGrid(“工具栏id”,{工具栏显示内容},{修改操作},{添加操作}),{删除操作}
示例:
.navGrid("#pager_id",{edit : true,add : true,del : true,search:true},
//=====控制修改操作=========
{
//修改后关闭
closeAfterEdit: true,
//提交后:
afterSubmit:function (response) {
//response为修改操作访问controller的返回值
//map集合可通过response.responseJSON.key取值
}
},
//=====控制添加操作=========
{
//添加后关闭
closeAfterAdd: true,
//提交后:
afterSubmit:function (response) {
//response为添加操作访问controller的返回值
//map集合可通过response.responseJSON.key取值
}
},
{
//控制删除操作 删除操作里没有afterSubmit
afterComplete: function () {
//在完成删除操作后可执行
}
}
);
b. 设置表头也居中(记得复选框)
在colMode中设置align:'center’可控制该列内容居中,但该表格的表头(第一行)还是靠左显示,这里可以通过css样式设置表头居中。对th标签进行控制。
<style>
th{
text-align:center;
}
</style>
注意:如果第一列加入了复选框,则该列复选框仍会有问题。没有找到很好的解决方法。这里选择使用设置复选框大小维持视觉上的居中。
jqGrid初始化参数中设置:
//在第一列前加入复选框
multiselect:true,
//当multiselect为true时设置multiselect列宽度
multiselectWidth:20,
c. 修改或添加后关闭模态框
在.navGrid方法中找到对应修改或添加操作的位置,加入:
修改:
//修改后关闭
closeAfterEdit: true,
添加:
//修改后关闭
closeAfterAdd: true,
删除的模态框执行操作后会自动关闭。
具体实例与代码参照上述 a
7. 一个带有二级表格完整代码
前台代码:
<%@page contentType="text/html; UTF-8" isELIgnored="false" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!--相关js文件在主页面已经引入->
<c:set value="${pageContext.request.contextPath}" var="app"/>
<ul class="nav nav-tabs">
<li role="presentation" class="active"><a href="#">专辑详情</a></li>
<li role="presentation"><a href="${app}/album/download">导出专辑信息</a></li>
</ul>
<table id="album-table"></table>
<div id="album-pager"></div>
<script>
$(function () {
//展示专辑信息
$("#album-table").jqGrid({
// 整合使用bootstrap样式的属性
styleUI:'Bootstrap',
url:'${app}/album/findAlbumByPage',
editurl:'${app}/album/operAlbum',
datatype:'json',
colNames:['名称','封面','作者','简介','播音','集数','上架时间','分数'],
// 开启表格编辑模式
cellEdit:true,
colModel:[
{name:'title',align:'center',editable:true},
{
name:'cover',
formatter:function(value,options,row){
return '<img src="${app}/view/album/image/'+row.cover+'" width="150px" height="60px"/>';
},
align:'center',
editable:true,
edittype:'file',
},
{name:'author',align:'center',editable:true},
{name:'detail',align:'center',editable:true},
{name:'broadcast',align:'center',editable:true},
{name:'count',align:'center'},
{
name:'createDate',
align:'center',
formatter:"date",
formatoptions: {srcformat:'Y-m-d H:i:s',newformat:'Y-m-d'}
},
{
name:'score',
align:'center',
edittype:"select",
editoptions:{value:"1:1;2:2;3:3;4:4;5:5"},
editable:true
},
],
//二级表格开始=========================================================
subGrid : true,
subGridRowExpanded : function(subgrid_id, row_id) {
//subgrid_id 子表id row_id父表当前行id
var subgrid_table_id, pager_id;
subgrid_table_id = subgrid_id + "_t"; //生成存放子表表格<table>的id
pager_id = "p_" + subgrid_table_id; //生成存放子表工具栏div的id
//生成table div
$("#" + subgrid_id).html(
"<table id='" + subgrid_table_id
+ "' class='scroll'></table><div id='"
+ pager_id + "' class='scroll'></div>");
//填充内容
$("#" + subgrid_table_id).jqGrid(
{
// 整合使用bootstrap样式的属性
styleUI:'Bootstrap',
url:'${app}/chapter/findChapterByPage?aid='+row_id,
editurl:'${app}/chapter/operChapter?aid='+row_id,
caption : "章节详细信息",
datatype:'json',
colNames:['名称','大小(单位:M)','时长','创建时间','操作'],
// 开启表格编辑模式
cellEdit:true,
colModel:[
{name:'title',align:'center',editable:true},
{name:'size',align:'center'},
{name:'duration',align:'center'},
{
name:'createDate',
align:'center',
formatter:"date",
formatoptions: {srcformat:'Y-m-d H:i:s',newformat:'Y-m-d'}
},
{
name:'audio',
width:350,
formatter:function(value,options,row){
return '<audio controls loop>' +
'<source src="${app}/view/album/mp3/'+row.audio+'" type="audio/mpeg"/>' +
'</audio>';
},
align:'center',
editable:true,
edittype:'file',
},
],
//数据表格是否自适应父容器的大小宽度
autowidth:true,
//显示行号
rownumbers:true,
//在第一列前加入复选框
multiselect:true,
multiselectWidth:20,
//设置高度
height:200,
//添加分页
//使用分页工具栏
pager:"#"+pager_id,
rowList:[5,10,15],
rowNum:10,
page:1,
//显示总记录数
viewrecords:true
}).navGrid("#"+pager_id,{edit : true,add : true,del : true,search:true},
//=====二级表格控制修改操作=========
{
//修改后关闭
closeAfterEdit: true,
//提交后:
afterSubmit:function (response) {
var id = response.responseJSON.data; //返回的id
var code = response.responseJSON.code; //返回的状态码
if(code==200) {
$.ajaxFileUpload({
fileElementId: "audio", //需要上传的文件域的ID,即<input type="file">的ID。
url: "${app}/chapter/upload", //后台方法的路径
type: 'post', //当要提交自定义参数时,这个参数要设置成post
data: {id: id}, //发送请求时传递的参数(数据)
// dataType: 'json', //服务器返回的数据类型。可以为xml,script,json,html。如果不填写,jQuery会自动判断。
// secureuri: false, //是否启用安全提交,默认为false。
// async : true, //是否是异步
success:function() {
$("#album-table").trigger("reloadGrid");
}
})
return "true";
}
}
},
//=====二级表格控制添加操作=========
{
//添加后关闭
closeAfterAdd: true,
//提交后:
afterSubmit:function (response) {
var id = response.responseJSON.data; //返回的id
var code = response.responseJSON.code; //返回的状态码
if(code==200) {
$.ajaxFileUpload({
fileElementId: "audio", //需要上传的文件域的ID,即<input type="file">的ID。
url: "${app}/chapter/upload", //后台方法的路径
type: 'post', //当要提交自定义参数时,这个参数要设置成post
data: {id: id}, //发送请求时传递的参数(数据)
success:function() {
$("#album-table").trigger("reloadGrid");
}
})
return "true";
}
}
},
{
//控制删除操作 添加操作里没有afterSubmit
afterComplete: function () {
//刷新父表(集数)
$("#album-table").trigger("reloadGrid");
}
}
);
},
//二级表格结束=========================================================
//数据表格是否自适应父容器的大小宽度
autowidth:true,
//显示行号
rownumbers:true,
//在第一列前加入复选框
multiselect:true,
multiselectWidth:20,
//设置高度
height:500,
//添加分页
//使用分页工具栏
pager:'#album-pager',
rowList:[5,10,15],
rowNum:10,
page:1,
//显示总记录数
viewrecords:true
}).navGrid('#album-pager',{edit : true,add : true,del : true,search:true},
//.navGrid("工具栏id",{显示内容},{修改操作},{添加操作}),{删除操作}
//=====控制修改操作====================================================================
{
//修改后关闭
closeAfterEdit:true,
//提交后:
afterSubmit:function (response) {
var id = response.responseJSON.data; //返回的id
var code = response.responseJSON.code; //返回的状态码
if(code==200) {
$.ajaxFileUpload({
fileElementId: "cover", //需要上传的文件域的ID,即<input type="file">的ID。
url: "${app}/album/upload", //后台方法的路径
type: 'post', //当要提交自定义参数时,这个参数要设置成post
data: {id: id}, //发送请求时传递的参数(数据)
// dataType: 'json', //服务器返回的数据类型。可以为xml,script,json,html。如果不填写,jQuery会自动判断。
// secureuri: false, //是否启用安全提交,默认为false。
// async : true, //是否是异步
success:function() {
$("#album-table").trigger("reloadGrid");
}
})
return "true";
}
}
},
//=====控制添加操作====================================================================
{
//添加后关闭
closeAfterAdd: true,
//提交后:
afterSubmit:function (response) {
var id = response.responseJSON.data; //返回的id
var code = response.responseJSON.code; //返回的状态码
if(code==200) {
$.ajaxFileUpload({
fileElementId: "cover", //需要上传的文件域的ID,即<input type="file">的ID。
url: "${app}/album/upload", //后台方法的路径
type: 'post', //当要提交自定义参数时,这个参数要设置成post
data: {id: id}, //发送请求时传递的参数(数据)
//dataType: 'json', //服务器返回的数据类型。可以为xml,script,json,html。如果不填写,jQuery会自动判断。
// secureuri: false, //是否启用安全提交,默认为false。
// async : true, //是否是异步
success:function() {
$("#album-table").trigger("reloadGrid");
}
})
return "true";
}
}
}
);
})
</script>
后台代码:
@RequestMapping("album")
@RestController
public class AlbumController extends BaseApiService{
@Autowired
private AlbumService albumService;
@Autowired
private AlbumDAO albumDAO;
@Autowired
private ChapterDAO chapterDAO;
@RequestMapping("findAlbumByPage")
/**
* page:查询页数
* rows:每页显示条数
* searchField: 查询条件
* searchString: 查询内容
* 加入分页工具栏后,远程响应json数据格式为:
* {"rows":[当前页结果(list)],"page":"当前页","total":"总页数","records":"总条数"}
*/
public Map<String,Object> findAlbumByPage(Integer page, Integer rows,
String searchField, String searchString){
//创建结果集
List<Album> albumList = null;
Integer records = 0;
HashMap<String, Object> map = new HashMap<>();
Integer total = 0;
//判断是否为模糊查询
if(searchField==null){
//查询集合
albumList = albumService.findAllByPage(page, rows);
//查询总条数
records = albumService.getCount();
//计算总页数
total = records%rows==0?records/rows:records/rows+1;
}else {
//查询集合
albumList = albumService.findAllByPageBySearch(page, rows,searchField,searchString);
//查询总条数
records = albumService.getCountBySearch(searchField,searchString);
//计算总页数
total = records%rows==0?records/rows:records/rows+1;
}
return setPageMap(albumList,page,total,records);
}
@RequestMapping("operAlbum")
public Map<String,Object> operAlbum(Album album,MultipartFile cover,String id,String oper) {
//添加
if("add".equals(oper)){
String i = albumService.add(album);
return setResultSuccessData(i);
}
//修改
if("edit".equals(oper)){
String i = albumService.update(album);
return setResultSuccessData(i);
}
//删除
if("del".equals(oper)){
String[] ids = id.split(",");
for (String i : ids) {
albumService.delete(i);
}
}
return null;
}
@RequestMapping("upload")
public String upload(MultipartFile cover, String id, HttpSession session) throws IOException {
System.out.println("id===="+id);
System.out.println("cover===="+cover.getOriginalFilename());
if ("".equals(cover.getOriginalFilename())) return null;
//获取文件上传路径
String realPath = session.getServletContext().getRealPath("/view/album/image");
//文件上传
cover.transferTo(new File(realPath,cover.getOriginalFilename()));
//修改数据库图片中的路径
Album album = new Album();
album.setId(id).setCover(cover.getOriginalFilename());
albumService.update(album);
return "success";
}
}
说明:
- BaseApiService:自己定义的一个工具类,更方便的设置返回值(map)
- return setResultSuccessData(i); 对应map数据:{“code”:200,“data”:i}