【注】常见问题和需要重点注意的地方,已用红色高亮标出
1.flexigrid for JQuery的官方网站(http://flexigrid.info/)
2.Flexigrid百度给出的词条
Flexigrid是一个类似于Ext Gird,但基于jQuery开发的Grid。它具有的功能包括:可以调整列宽,合并列标题,分页,排序,显示/隐藏表格等。Flexigrid显示的数据能够通过Ajax获取或者从一个普通的表格转换。
3.SSH为Java进行web开发的Struts 2.x spring hibernate 三大框架的简称,这里同时还是用到了JSON数据格式来传递数据。
1. 我们最终想要实现的效果为下图所示:
图表1
我们可以看到实现的效果中,主要分操作工作区(这里指——增删改)、标题区(即显示数据的标题)、数据区(显示查询的数据)、搜索功能区(开始为隐藏,用来根据条件来搜索)、显示数据的控制功能区(控制每页显示信息条数、上一页、下一页、刷新数据、提示)。
2. 首先我们应该到相关的官网上下载我们需要的所有的包(JQuery、Flexigrid)。
3. 下载完成后,我们就可以开始向着我们需要的方向前进了,我们先编写一个html文档,格式大概为下面的内容:
<body> <divid="parent"><divalign="center"> </div><tableid="flexme"></table> </div> </body>
flexme就是指的要使用flexigrid的地方,之所以会有#parent,我想朋友们应该理解,因为我们需要控制整体的flexme,所以在外面再包一层。
当然我们不能忽略了引入包的问题,因为刚才我们已经下载JQuery和Flexigrid的包,都解压好以后,放到工程目录中。这里注意我们需要先引入JQuery,然后才引入flexigrid的javascript和css包。
4. 做完上面的一步,就代表我们需要在html文件中做的工作,已经做完了,剩下的就是开始在javascript文件中完成了。大家如果有疑惑,可以了解一下flexigrid官方网站上给出的例子,最好用chrome或者firefox看一下例子源码。
我在这里进行了小范围的二次开发,即函数封装,我们只需要按要求传入下面的所有的参数,而不需要关心具体的flexigrid的设置,可以多次调用。所以这里我新建一个util.js文件,文件中的具体内容如下:
//JavaScript Document /* * author: 小森(http://weibo.com/jingmoxiaosen) * 参数解释 * ajaxurl 对应下边的url,即获取初次数据的ajax的url * args 指要显示的列名,即要展示的数据的标头的名字,可组合成colModel的json格式 * title 指显示在表格上面的提示,对应下边的title * searchitems 指要设置可以用来搜索的部分,组合成json后对应下边的searchitems * delurl 对应要进行删除操作的url(SSH对应的一个action) * addurl 对应进行添加和编辑操作的url(对应jsp页面) * */ function initflexifrid(ajaxurl,args,title,searchitems,delurl,addurl){ /*根据传入的参数数组,封装成JSON格式,因为flexigrid使用的JSON格式的形式*/ var cols ="["; cols = cols + "{display:'" + args[0] + "', name: '" + args[0] +"', width: 40, sortable: true, align:'center'},"; for(var i = 1; i < args.length - 1; i++){ cols = cols + "{display:'" + args[i] + "', name: '" + args[i] +"', width: 200, sortable: true, align:'left'},"; } cols = cols + "{display:'" + args[args.length - 1] + "', name: '" + args[args.length - 1] +"', width:200, sortable: true, align: 'left'}]"; var cols = eval("("+cols+")");//转化成json格式 var items ="["; for (var i = 0; i < searchitems.length - 1; i++) { items = items + "{display:'" + searchitems[i] + "' , name: '"+searchitems[i] +"'},"; } items = items + "{display:'" + searchitems[searchitems.length - 1] +"' , name: '"+searchitems[searchitems.length - 1] +"', isdefault: true } ]"; var items = eval("("+ items +")");//转化成json格式 //初始化flexigrid插件 $('#flexme').flexigrid({//flexme就是刚才在html文件中创建的table的id url: ajaxurl, dataType: 'json', colModel : cols, buttons : [//操作功能区,onpress对应他们相应的js操作函数,下面有函数体 {name: '增加', bclass:'add',onpress:button}, {name: '删除', bclass:'delete',onpress:button}, {name: '编辑', bclass:'edit',onpress:button}, {separator: true} ], searchitems : items,//搜索功能区 sortname: "id",//默认使用id排序 sortorder: "asc",//默认排序方式为递增 procmsg: "正在加载...", pagestat: '显示 {total}中 {from} 到 {to} 的元素', nomsg: '没有数据', errormsg: '链接失败', usepager: true,//是否使用分页 title: title, useRp: true, rp: 10,//每页显示信息的条数 showTableToggleBtn: true,//是否显示上一页、下一页的按钮 width: 640, height: 300, }); //button的事件函数 function button(com,grid) { if (com=='删除') { if($('.trSelected',grid).length==0){ alert("请选择要删除的数据"); }else{ if(confirm('是否删除这 ' + $('.trSelected',grid).length +' 条记录吗?')) { var id = "mulid="; for(var i=0;i<$('.trSelected',grid).length;i++){ if(i==$('.trSelected',grid).length-1){ id += $('.trSelected',grid).find("td:first").eq(i).text(); } else { id += $('.trSelected',grid).find("td:first").eq(i).text()+","; } } window.location.href= delurl +"!delete.action?"+id; } } } elseif (com=='增加') { window.location.href= addurl; } elseif (com=='编辑') { if($(".trSelected").length==1){ var getargs ="?"; for(var i = 0; i < args.length - 1; i++){ getargs = getargs + args[i] +"="+$('.trSelected',grid).find("td").eq(i).text()+"&"; } getargs = getargs + args[args.length-1] +"=" + $('.trSelected',grid).find("td").eq(args.length-1).text(); window.location.href = addurl + getargs; }elseif($(".trSelected").length > 1){ alert("请选择一个修改,不能同时修改多个"); }elseif($(".trSelected").length==0){ alert("请选择一个您要修改的内容") } } } }
有几点我们需要注意:【1】将传递过来的数组参数组装成JSON格式时,我们需要在前后加上”[”、”]”,这是JSON的格式要求,同时,我们组装完成后,需要使用JS的函数eval来完成转换,具体看上面的例子;【2】dataType的值为’json’,这是我使用的方式,还可以选择’xml’格式。
5. 这样子以后,我们就已经把使用flexigrid的js操作封装好了,当然我们需要的是在刚才新建的那个html文件加载完成时,就执行现在我们完成的js,所以我们需要新建对应的html的js文件friendlink.js,内容如下:
// JavaScript Document $(document).ready(function() {//在html加载时,自动完成的操作 var ajaxurl ='/****/friendlinkAction!getAllFriendlink.action'; varargs= new Array(); args[0]='id'; args[1]='text'; args[2]='link'; title = '友情链接'; var searchitems =new Array(); searchitems[0] = 'link'; searchitems[1] = 'text'; delurl = '/****/friendlinkAction'; addurl = '/****/manager/friendlink/addfriendlink.jsp'; initflexifrid(ajaxurl,args,title,searchitems,delurl,addurl);//这里就是我们调用的封装的函数 });
然后我们引入把这些文件都引入到html中,如何引入不再赘述,但是要注意引入顺序:JQuery->flexigrid->util.js->friendlink.js
6. 至此,我们所有的前台的操作已经基本完成了,我们可以开始做后台的SSH操作了,我们需要做什么呢?
这里关于导入SSH包,hibernate反转sql就不做说明了。在此,我们假设你已经得到了DAO文件和其他相关的配置文件。
编编写编写后台的Action走起,我们新建一个class文件,然后我们需要做的就是理一下我们的思绪。因为我们要弄清楚,我们需要什么后台接受什么参数,前台需要从后台得到什么数据等问题。当我们开始看官方给出的例子时,我们发现,其实后台需要的参数还是蛮多的,因为我们需要分页显示、需要每一页具体显示多少条信息、需要删除那些行、按照什么方式排序、按什么排序、按什么方式搜索、按什么条件搜索等等,前台还需要共有多少数据等,所以我查看了一下官方的例子(因其前台的name都是自动生成),总结出需要的参数为当前页(page)、共有多少条数据(total)、每页显示信息条数(rp)、搜索条件(query)、搜索方式(qtype)、排序方式(sortorder)、排序条件(sortname),还需要返回给前台的JSON数据(List的对象rows)。当然我们需要操作删除操作,就必须要获取已经选中的数据的id,这里我以字符串的形式get方式传递的,以”,”进行分割(mulid),全部生成对应的getter和setter方法。
下面为具体代码:(参数对应上面所述参数传递说明)
@Controller("friendlinkAction") @Namespace("/") @Scope("prototype") public classFriendlinkAction { private List<Map> rows = new ArrayList(); private int page; private int total; private int rp; private List<Friendlink> list; private String mulid; private String query; private String qtype; private String sortname; private String sortorder; private Map map=new HashMap(); public Friendlink friendlink = newFriendlink(); @Autowired private FriendlinkService flService; @JSON(serialize=false) public String getAllFriendlink(){ if (query == null ||("").equals(query)){ total =GetPagedata.getCount("Friendlink"); if ((Integer)page == null || page< 1) page = 1; else if (page > (total/rp+1)){ page = total/rp; } int start = (page-1)*rp; list = GetPagedata.getData("Friendlink",start,rp,sortname,sortorder); for (Friendlink temp : list){ map = new HashMap(); map.put("cell",new Object[]{temp.getId(),temp.getText(),temp.getLink()}); rows.add(map); } }else{ total = GetPagedata.getCount("Friendlink",query,qtype); if ((Integer)page == null || page< 1) page = 1; else if (page > (total/rp+1)){ page = total/rp; } int start = (page-1)*rp; list =GetPagedata.getData("Friendlink",query,qtype,start,rp,sortname,sortorder); for (Friendlink temp : list){ map = new HashMap(); map.put("cell",new Object[]{temp.getId(),temp.getText(),temp.getLink()}); rows.add(map); } } return "success"; } public String delete(){ flService.delete(mulid); return "index"; } public String addormerge(){ flService.addormerge(friendlink); return "index"; }
我们还需要配置struts.xml文档,因为我们需要返回JSON格式的数据,具体配置如下:
<packagename="getjson"extends="json-default"namespace="/"> <actionname="friendlinkAction"class="friendlinkAction"> <resulttype="json"name="success"> <paramname="rows">rows</param> <paramname="page">page</param> <paramname="total">total</param> <paramname="rp">rp</param> </result> <resultname="index">/manager/friendlink/friendlink.html</result> </action> </package>
这里为我们需要返回给前台ajax的JSON格式数据和普通数据,当然如果有些数据我们不想要返回,我们需要在action中的get*()方法前面加上@JSON(serialize=false),这样数据就不会传递了,减小网络传输压力,也避免不必要的数据被用户看到。
7. 具体的操作截图和解释如下:
图表2—添加操作
图表3—添加成功
图表4—删除一条数据操作
图表5—删除多条数据操作
图表6—不可同时编辑多条数据
图表7—看到我们编辑成功(对比图表3)
图表8—设置每一页显示的信息条数
图表9—按照条件搜索
1. 我们在firefox中的firebug跟踪时,已经看到了传递过来的JSON数据,显示全是undefined。
解决方法:我们需要仔细查看一下firebug下的json数据格式(特别是rows),看看是不是符合格式,将获得数据list需要转化为如下格式的json数据:[{‘cell’:*,*,*}, {‘cell’:*,*,*}, {‘cell’:*,*,*}],代码操作应该为:
list =GetPagedata.getData("Friendlink",start,rp,sortname,sortorder); for (Friendlink temp :list){ map =newHashMap(); map.put("cell",new Object[]{temp.getId(),temp.getText(),temp.getLink()}); rows.add(map); }
2. 网上也有朋友写的好像是有些问题,其json格式为[{‘id’:*,’cell’: *,*},{‘id’:*,’cell’: *,*}],测试了一下,这样子好像不行,当然我也不能完全确定,就当给大家提醒一下吧,不妨试试。
3. 获取数据成功后,无法进行分页操作。
这里我们首先,应该查看一下,我们在设置#flexme时 usepager:true(单击链接查看),是否已经设置为了true。如果这里已经设置成功,那我们就要确定一下,是不是已经在后台获取了rp、page等参数,如果没有获取就按照java 的action(单击链接查看)中的设置的方式弄一下。
4. 无法获取数据,表格显示不出来。
这个问题的话,可能就是我上面说的可能没有在后台获取相关的参数,可以按照参数说明(单击链接查看)这里的方法自己捉摸一下。
5. 为什么在添加、删除、编辑的按钮上没有图片
这个问题我也没有弄明白,为什么官方给的例子上有图片,自己的却没有。后来查看了一下他给的css文档,发现根本没有设置。当然了,这里可以理解,毕竟它也不知道你要有哪些按钮,按钮的名字有叫什么,它也不能智能生成css,所以这里需要我们自己来设置,自己在它给的css中设置一下就好了。代码如下:
.flexigrid div.fbutton .add{background:url(images/add.png)no-repeatcenterleft} .flexigrid div.fbutton.delete{background:url(images/close.png)no-repeatcenterleft} .flexigrid div.fbutton .edit{background:url(images/edit.png)no-repeatcenterleft}
6. 这里额外说一些可能在结合使用SSH的过程中,查询数据可能遇到的问题
(1) hibernate中使用LIKE报错 unexception token: %
这里大致的解决方法,就是这样做:like ? 然后query.setParameter(0,"%"+q+"%");好像是因为hibernate不兼容的问题吧。
(2) hibernate中使用limit时报错 unexception token:limit
这里是因为hibernate不允许使用limit,但是它也提供了相应的方法:
query.setFirstResult(start); query.setMaxResults(rp);
可以设置第一个数据和最大偏移量,和limit效果一样的。
(3)hibernate我们进行merge操作后,无法立即刷新数据,但是数据库中已经是新的数据,重启服务器发现可以显示出来。
解决方法:因为可能使用的是query.list()的方法获取数据,但是merge之后在一级缓存中的还是旧的数据,但是id是一样的,所以它就不会重新获取数据,这里我们可以在merge之后,这样操作:
Session session =HibernateSessionFactory.getSession(); session.clear(); session.close();