首页 > 代码库 > Telerik Kendo UI 那点事【3】
Telerik Kendo UI 那点事【3】
中文化之后,我们开始具体使用kendo ui组件。经常开发系统的我,通常从最常用的控件用起,那就是表格控件GridView!现在的软件系统基本上就是标签框、文本框、选择框、树、表格堆砌而成。因此接触任何一种UI组件的时候,我通常都最为关注GridView,表格控件。小小的表格控件,做的好,能够给前端呈现和使用带来很好的感受的同时,还能够大幅度降低开发的工作量。
Kendo UI在这方面让我十分满意,甚至是震惊。因为它的GridView不仅仅是能够简单的在呈现层进行数据的过滤、排序、分组,关键是还能通过简单的配置,让界面的过滤、排序、分组与后台直接联动。相当于只要是呈现的数据列,如果要查询,根本不必再在表格的上方做一堆标签选择区。当然这也是对软件开发模型的一大挑战,习惯了通过标签框、选择框等一堆控件指定条件,生成where条件,然后在点查询的时候,进行后台查询再呈现的开发方式,已经完全过时,不仅不够高效,而且开发起来浪费大量时间,用户使用时,也并不直观,对于条件对查询后果的影响,用户根本不清楚,有时因为设置大量查询条件,而导致没有查询结果时,还很恼火。
二、直接联动,无sql,无拼装,查询呈现。
kendo ui 的GridView控件,通过MVVM绑定数据源,通过REST-Full风格的URL来与spring mvc的后台进行通信,就使用简单的GridView,就能直接实现对后台数据的实时查询、修改、增加、删除。并且无需写什么sql或者hql,也不需要拼装什么nosql的条件。一切都是完美联动。界面的操作会生成条件对象,整个框架体系浑然一体,后端hibernate通过对前端对象反馈的条件数据进行自动拼装,查询得到结果。
说了这么多,很多人看的可能觉得头晕,不如代码来的爽。那么就让我们领教一下kendo UI的GridView之美吧!
页面的头部就忽略了,需要head的到前一篇文章看一下吧。body的部分,如下写,就可以使用GridView。
头部首先要增加REST-Full风格的CURD连接定义(个人习惯,便于工程管理,你也可以直接写到js里)
<c:url value=http://www.mamicode.com/"/kendo/test6.json" var="transportReadUrl" />>然后是body部分:
<div> <div id="grid" style="height:580px"></div> </div> <script> $(document).ready(function() { $("#grid").kendoGrid({ "columnMenu" : true, "dataSource" : { "schema" : { "total" : "total", "model" : { "id" : "objectId", "fields" : { "objectId" : { "type" : "number" }, "age" : { "type" : "number" }, "name" : { "type" : "string" }, "bdate" : { "type" : "date" } } }, "data" : "data", "groups" : "data" }, "serverFiltering" : true, "transport" : { "destroy" : { "dataType" : "json", "contentType" : "application/json", "type" : "POST", "url" : "${transportDestroyUrl}" }, "update" : { "dataType" : "json", "contentType" : "application/json", "type" : "POST", "url" : "${transportUpdateUrl}" }, "read" : { "dataType" : "json", "contentType" : "application/json", "type" : "POST", "url" : "${transportReadUrl}" }, "create" : { "dataType" : "json", "contentType" : "application/json", "type" : "POST", "url" : "${transportCreateUrl}" }, "parameterMap" : function(options) { return JSON.stringify(options); } }, "batch" : false, "serverSorting" : true, "pageSize" : 10.0, "serverPaging" : true, "serverGrouping" : true }, "toolbar" : [ { "text" : "新增记录", "name" : "create" } ], "reorderable" : true, "filterable" : true, "pageable" : { "input" : true, "buttonCount" : 5.0, "pageSize" : 10.0, "pageSizes" : [ 5, 10, 15, 20, 30 ], "refresh" : true }, "sortable" : true, "columns" : [ { "field" : "objectId", "title" : "编号", "hidden" : true }, { "field" : "name", "title" : "姓名" }, { "field" : "age", "title" : "年龄" }, { "field" : "bdate", "title" : "出生日期", "filterable" : { "ui" : "datetimepicker" }, "format" : "{0:yyyy-MM-dd HH:mm:ss}" }, { "title" : " ", "command" : [ { "text" : "编辑", "name" : "edit" }, { "text" : "删除", "name" : "destroy" } ] } ], "groupable" : true, "editable" : { "mode" : "inline" } }); }); </script>接下来,后台spring MVC控制层如下:
@Controller public class KendoControl { @Autowired private SessionFactory sessionFactory; @RequestMapping(value = http://www.mamicode.com/"/kendo/test6d", method = RequestMethod.POST)>各位肯定发现了,里面有个DataSourceRequest类,还有个DataSourceResult类,所有的查询都和Request相关,核心的实现已经形成了模式,并且通过模型完成了界面查询与后端查询的映射,因此界面选择过滤、分组、排序等等操作时,read url会被调用,参数会被传到spring的mvc控制层,并且反序列化为DataSourceRequest对象,对象即实现了所有的操作,不需要我们再去拼装什么sql!伟大而美丽吧!这两个类是从kendo ui for JSP的DEMO工程中直接cp过来使用的,其中由于日期格式化的问题,修改了DataSourceRequest类。下面给出他们的源代码!实体类TestObject:
import java.util.Date; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.Table; import javax.persistence.Temporal; import javax.persistence.TemporalType; /** * TestObject entity. @author MyEclipse Persistence Tools */ @Entity @Table(name="test_object") public class TestObject implements java.io.Serializable { // Fields private Long objectId; private String name; private Integer age; private Date bdate; // Constructors /** default constructor */ public TestObject() { } /** minimal constructor */ public TestObject(Long id) { this.objectId = id; } /** full constructor */ public TestObject(Long id, String name, Integer age) { this.objectId = id; this.name = name; this.age = age; } // Property accessors @Id @GeneratedValue(strategy = GenerationType.AUTO) @Column(name="id") public Long getObjectId() { return this.objectId; } public void setObjectId(Long id) { this.objectId = id; } @Column(name="name") public String getName() { return this.name; } public void setName(String name) { this.name = name; } @Column(name="age") public Integer getAge() { return this.age; } public void setAge(Integer age) { this.age = age; } @Temporal(TemporalType.TIMESTAMP) @Column(name="bdate", length = 11) public Date getBdate() { return bdate; } public void setBdate(Date bdate) { this.bdate = bdate; } @Override public String toString() { return "TestObject [objectId=" + objectId + ", name=" + name + ", age=" + age + ", bdate=" + bdate + "]"; } }
DataSourceRequest:
package com.kendoui.spring.models; import java.beans.IntrospectionException; import java.beans.PropertyDescriptor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import org.codehaus.jackson.annotate.JsonAnySetter; import org.hibernate.Criteria; import org.hibernate.HibernateException; import org.hibernate.Session; import org.hibernate.criterion.Criterion; import org.hibernate.criterion.Junction; import org.hibernate.criterion.MatchMode; import org.hibernate.criterion.Order; import org.hibernate.criterion.ProjectionList; import org.hibernate.criterion.Projections; import org.hibernate.criterion.Restrictions; import org.hibernate.criterion.SimpleExpression; import org.hibernate.transform.ResultTransformer; public class DataSourceRequest { private int page; private int pageSize; private int take; private int skip; private List<SortDescriptor> sort; private List<GroupDescriptor> group; private List<AggregateDescriptor> aggregate; private HashMap<String, Object> data; private FilterDescriptor filter; public DataSourceRequest() { filter = new FilterDescriptor(); data = http://www.mamicode.com/new HashMap();> DataSourceResult:
package com.kendoui.spring.models; import java.util.List; import java.util.Map; public class DataSourceResult { private long total; private List<?> data; private Map<String, Object> aggregates; public long getTotal() { return total; } public void setTotal(long total) { this.total = total; } public List<?> getData() { return data; } public void setData(List<?> data) { this.data = http://www.mamicode.com/data;>
怎么样,简介而美丽吧!这就是设计的力量。很多人,工作的同伴都无视设计,设计无用论很盛行,什么如果有设计的时间,我早就怎样怎样。我只能说,他们太勤快了,工作时不动脑,累的永远是自己。设计之美就在于能够让程序员完美的偷懒,懒到骨头里,懒惰是聪明的源泉,是设计的动力。这里要强调一些细节。主要是kendo ui GridView使用的细节,也是CSDN另位博主 引路蜂未说明的:
1、dataSource的transport成员的parameterMap方法,必须进行覆盖重写,这个与后台spring的mvc映射密切相关。重写parameterMap方法,才能对后台提交数据时提交json对象,参数才能正常反序列化!切记!
"parameterMap" : function(options) { return JSON.stringify(options); }2、dataSource的schema成员的model成员,必须定义id属性,指向实体的ID。否则控件自身的修改、删除、增加操作会混乱,无法正常工作。现象是增加记录会多出2条,修改记录也会多出记录。因为控件无法正常识别修改、增加的操作,到底针对的记录是什么情况。而取消按钮又会被识别成删除操作导致增加或修改过程中取消,记录被删除的问题。因此一定要注意model成员的id属性一定要指定对应的id,否则GridView只能进行查询操作,不能进行增、删、改。
"dataSource" : { "schema" : { "total" : "total", "model" : { "id" : "objectId", "fields" : { "objectId" : { "type" : "number" }, "age" : { "type" : "number" }, "name" : { "type" : "string" }, "bdate" : { "type" : "date" } } },3、注意设置GridView自身的下列属性,以确保开启服务端分页、服务端查询、服务端过滤、服务端分组,也就是我说的界面与后台的直接联动。而不是将数据查询到界面缓冲后,由界面再分页、过滤、分组!"serverSorting" : true, "serverPaging" : true, "serverGrouping" : true4、注意对日期字段的描述设置。通过如下代码的设置,日期字段的过滤器设置,将变为日历控件。便于操作!{ "field" : "bdate", "title" : "出生日期", "filterable" : { "ui" : "datetimepicker" }, "format" : "{0:yyyy-MM-dd HH:mm:ss}" }
5、注意对最后一列显示的按钮的设置。其中name字段的属性值是固定的,只有3种。text为外观显示的中文,如果不设置的话,会是英文。{ "title" : " ", "command" : [ { "text" : "编辑", "name" : "edit" }, { "text" : "删除", "name" : "destroy" } ] }
6、代码最后的部分。指定了是直接在行编辑,还是弹出窗口编辑。如果是弹出窗口将inline改成popup即可,个人提倡用popup,因为popup模式下,弹出窗口里的属性是所有属性,列表hidden设置为true的属性也会显示在弹出窗口中。这样可以达到列表显示简洁,编辑时又不缺字段属性的目的。"editable" : { "mode" : "inline" }7、如果你希望列宽能够被调整,那么要设置resizeable为true,但是如果你设置它为真,则必须给所有的列指定width属性,否则,没有指定width的列会有无法显示的情形。从hidden变为显示时,也会无法呈现!
8、GridView顶部的Toolbar工具条,设置与最后一列两个按钮的配置类似,需要自行指定中文。
"toolbar" : [ { "text" : "新增记录", "name" : "create" } ],
至于后台的两个关键类,它山之石可以攻玉,取来直接用即可!很好的模型封装,无需再改动什么。要动的是我们的后台设计实现。也许又有人说,我的查询是复杂查询,多表联合的,肯定必须写复杂的sql。我只想说,你是否能考虑把它做成一个通用的sql形成视图,将视图映射为hibernate实体,然后将视图实体直接绑定给GridView,不就可以省下很多事!事在人为!设计的力量就是可以让我们去多思考,用极少量的功耗,实现极美的效果!未完待续……
Telerik Kendo UI 那点事【3】