非常重要,一定要注意,在项目上一旦不判空出现了问题,属于事故
1.物料批 mt_material_lot 和 mt_eo表,这两张表的查询,一定不能用全表查询,sql层面一定要走 条件查询,同样java层面一定要 传参过去,传参时,一定要 先判空先
2.hap建索引的命名规范
唯一索引:table_U1,2,3…(索引名都是大写)
普通索引:table_N1,2,3…
主键索引:table_PK
3.oracle的中的 串类型的处理 有三种
varchar
clob(hap用的多 文本) 对应java类型 String
blob(二进制 图片) 对应java类型 byte[]
注意:
1.直接查询的话 对 clob类型不用做任何处理,映射到java类型 就是 String
2.如果是要在 PL/SQL看效果,那么直接查询,字段框内只显示一个 clob(因为太长了,PL/SQL 默认不显示)
解决办法:
1.select to_char(clob) 这样在 字段框就可以看到 字符串了
2.在 PL/SQL 点击弹框 弹出 字符串的内容
4.包名用_隔开,大多以 核心表命名(前提是有核心表)
5.开发时,大多模块都涉及一张核心表,你就看 更新插入时,是操作哪张表,或者看文档功能总结,就知道了,其他都是关联表
6.少数业务,是没有核心表的,存开发api ,那就是见名知意,用_隔开
7.方法命名,查询用 get 查询一个对象:getUserById() ,查询集合:UserList()
8.文档中的 api名不要改
9.list,字符串 的拼接,截取也是很常见的,
10.对象转list 数组转list 都是用 Arrays.asList();
11.去重的几种方式
12.oracle建表规范,建表,建seq,不建触发器,插入 mt_sys_sequence表 seq字段和初始值
13.导入导出的自定义,以及在哪做导入字段的校验??
标准导入导出按钮标签(没有自定义)
导入
<span class="btn btn-primary k-grid-excel" style="float:left;" onclick='Hap.importExcel("")' >
<i class="fa fa-arrow-circle-up" style="margin-right:3px;">
i><@spring.message "excel.import"/>
导出
<span class="btn btn-primary k-grid-excel" style="float:left;margin-right:5px;" data-bind="click:exportExcel"><i class="fa fa-file-excel-o" style="margin-right:3px;">i>导出span>
14.lov查询除了查id , code , 如果要带出name,还得查 name (lov不能查 date类型的,时间用 时间选择器组件input框)
15.注意,VO和resultmap一定要继承,不然数据没有值,你在也不知道
1.grid不可编辑:
{
field: "name",
title: '姓名',
width: 120,
headerAttributes: {style: "text-align:center"},
attributes: {style: "text-align:center"},
editor: function(container,options){
container.html(options.model.name);
container.removeClass('k-edit-cell');
}
},
2.form不可编辑? 不会
3.必输校验 ?不会
4.选定lov 后带出 name框的值(就是将lov查出的 name 也赋值给 viewModel ,这样 lov框选中值后,name也赋上值了,判断的name框的值也就达到了自动带出的效果了)
{
field: "employeeId",
title: '用户名',
width: 120,
headerAttributes: {style: "text-align:center"},
attributes: {style: "text-align:center"},
template: function (dataItem) {
return dataItem['employeeCode'] || ''; /* 数据列默认显示值 */
},
editor: function (container, options) {
$('<input required name="' + options.field + '" />').appendTo(container)
.kendoLov($.extend( <@lov"EMPLOYEE_LOV"/>, {
select: function (e) {
// 将选择后的属性更新到数据模型中以保存
options.model.set('employeeId', e.item.employeeId);
//重要的就是这个,带出name值,就是给name赋值
options.model.set('name',e.item.name);
},
//TODO 之前的toolCategoryCode
textField: 'employeeCode', /* 编辑器显示的值 */
model: options.model
}));
}
5.下拉框默认值(optionLabel: “是”)
editor: function (container, options) {
$('<input required name="' + options.field + '"/>')
.appendTo(container)
.kendoDropDownList({
dataTextField: "meaning", //显示的文本
dataValueField: "value", //实际的值
optionLabel: "是",//默认选项值
dataSource: YES_NO,
valuePrimitive: true
});
}
16.唯一性校验,一般在后台校验,比较麻烦
17.描述维护,就是 消息维护,{0}代表第一个参数
18.前端页面只要有不会的,可以考虑 借鉴其他页面的源码来修改,而不是直接百度 kendoui ,或者 hap
19.表里面的 cid 用的多,代表时间戳或者序号,和 主键一样,要创建 sequence,插入的时候,insert(主键 , cid) vaules(seq_s.nextvalue , seq_cid_s.nextvalue)创建的代码已经创建好了的
20.grid 和 他的 viewModel是 跟 接口打交道的 根本,而不是前面 表单,前面的所****有div ,都得绑定好
<script>kendo.bind($('#div 的 id'), viewModel);script>
这样保证,这些div 的script事件是,将 数据 绑定到 对应 grid的 viewModel
同样这些 div里面的 lov 下拉框,也要有对应的 script,这些script就是,首先调用对应的下拉框 或 lov 然后,将框里面的值,赋值给 viewModel 例如
<script>
$("#siteId").kendoLov($.extend(${lovProvider.getLov(base.contextPath, base.locale,
"LOV_SITE")}, {
select: function (e) {
viewModel.model.set("siteId", e.item.siteId);
}
}));
script>
21.
<script type="text/javascript">
var viewModel = Hap.createGridViewModel("#grid");
var viewModelLine = Hap.createGridViewModel("#gridLine")
script>
这个代表的是,grid里面的 viewModel也就是数据模型,这是 grid的根本,viewModel 不是说对应的 实体类的json或者 说 colums的json,他在创建的时候,就是一个 map 里面的 key value都是为null的,
var viewModel = Hap.createGridViewModel(“#grid”);
这句最先执行
然后在,访问接口之前,你可以给 viewModel赋值,后,最先访问 read接口,这时在parameterMap中,对viewModel初始化了一下
你可以随便put 键值对,但是,一般
parameterMap: function (options, type) {
if (type !== "read" && options.models) {
var datas = Hap.prepareSubmitParameter(options, type)
return kendo.stringify(datas);
} else if (type === "read") {
return Hap.prepareQueryParameter(viewModel.model.toJSON(), options)
}
}
这是 viewModel的初始化,代码,这话的意思其实很简单,就是 调用查询方法,将查询出来的 JSON 赋值给 viewModel,所以说,viewModel的初始 key 是和 查询出来的,json相对应的
至于,comlun字段 和 viewModel是有关系的,在不做特定改变的情况下(例如下拉框,lov等),默认 filed和 viewModel的 key相同的 就取 对应的 value值
总之,viewModel是 数据模型,是整个 grid取值的依据的命脉,也是 于接口打交道,给接口传参的命脉
一切的 值的保存 和 取值,都要考虑到 viewModel ,例如 条件查询框,在取值后,一定要记得 给 viewModel赋值,这样 在访问接口的时候,这个框里面的值,才能传过去。
22. $(“#grid”).kendoGrid({
dataSource: dataSource,
resizable: true,
scrollable: true,
navigatable: false,
selectable: ‘multiple, rowbox’,
autoBind: 代表 gird自动不自动加载
editable: false 代表 grid不可编辑
})
字段隐藏
{
field: "cid",
hidden: true
},
22:整个页面需要的关注点
1.各个div
2.grid
3.各个事件发生 绑定的 script ,各个div绑定的 script …(script)
4.viewModel
5.viewModel赋值,取值的几个位置,script里面,paramterMap viewMoel初始化的时候,头行,传值,赋值给 viewModel的时候
23.在 script里面是可以 定义 变量的
24.头行明细
1.第一步,定义 2个 grid的 viewModel
<script type="text/javascript">
var viewModel = Hap.createGridViewModel("#grid");
var viewModelLine = Hap.createGridViewModel("#gridLine")
script>
2.第二步,定义头的div 和 行的 div
头div
<div id="page-content">
<div class="pull-left" id="toolbar-btn" style="padding-bottom:10px;">
<span class="btn btn-primary k-grid-add" style="float:left;margin-right:5px;" data-bind="click:create"><@spring.message "hap.new"/>span>
<span class="btn btn-success k-grid-save-changes" data-bind="click:save" style="float:left;margin-right:5px;"><@spring.message "hap.save"/>span>
<span data-bind="click:remove" class="btn btn-danger" style="float:left;"><@spring.message "hap.delete"/>span>
div>
<script>kendo.bind($('#toolbar-btn'), viewModel);script>
<div class="pull-right" id="query-form" style="padding-bottom:10px;">
<input type="text" data-role="maskedtextbox" style="float:left;width:150px;margin-right:5px;" placeholder='<@spring.message "OdInspectionPlan.inspectionPlanCode"/>'
data-bind="value:model.inspectionPlanCode" class="k-textbox">
<input type="text" data-role="maskedtextbox" style="float:left;width:150px;margin-right:5px;" placeholder='<@spring.message "OdInspectionPlan.inspectionPlanName"/>'
data-bind="value:model.inspectionPlanName" class="k-textbox">
<input placeholder='<@spring.message "bom.sitecode"/>'
data-bind="value:model.siteId" id="siteId">
<script>
$("#siteId").kendoLov($.extend(${lovProvider.getLov(base.contextPath, base.locale,
"LOV_SITE")}, {
select: function (e) {
viewModel.model.set("siteId", e.item.siteId);
}
}));
script>
<input placeholder='<@spring.message "odinspectionplan.materialid"/>'
data-bind="value:model.materialId" id="materialId">
<script>
$("#materialId").kendoLov($.extend(${lovProvider.getLov(base.contextPath, base.locale,
"LOV_MATERIAL")}, {
select: function (e) {
viewModel.model.set("materialId", e.item.materialId);
}
}));
script>
<input placeholder='<@spring.message "odinspectionplan.status"/>'
data-bind="value:model.status" id="status">
<script>
$("#status").kendoComboBox({
dataTextField: "meaning",
dataValueField: "value",
valuePrimitive: true,
dataSource: STATUS
});
script>
<input placeholder='<@spring.message "odinspectionplan.identifycategory"/>'
data-bind="value:model.identifyCategory" id="identifyCategory">
<script>
$("#identifyCategory").kendoComboBox({
dataTextField: "meaning",
dataValueField: "value",
valuePrimitive: true,
dataSource: I_CATE
});
script>
<span class="btn btn-primary" style="float:left;width:70px" data-bind="click:query" type="submit"><@spring.message "hap.query"/>span>
div>
<script>kendo.bind($('#query-form'), viewModel);script>
<div id = "xxx" style="clear:both">
<div id="grid">div>
div>
<script>kendo.bind($('#xxx'), viewModel);script>
div>
行div
<div class="pull-left" id="toolbar-btn1" style="padding-bottom:10px;">
<span class="btn btn-primary k-grid-add" style="float:left;margin-right:5px;" data-bind="click:create"><@spring.message "hap.new"/>span>
<span class="btn btn-success k-grid-save-changes" data-bind="click:save" style="float:left;margin-right:5px;"><@spring.message "hap.save"/>span>
<span data-bind="click:remove" class="btn btn-danger" style="float:left;"><@spring.message "hap.delete"/>span>
div>
<script>kendo.bind($('#toolbar-btn1'), viewModelLine);script>
<div id="bottom-content" style="clear:both;margin: 10px 5px 5px;">
<div id="gridLine">div>
div>
<script>kendo.bind($('#bottom-content'), viewModelLine);script>
3.定义头和行的 script grid
头的grid
<script type="text/javascript">
<!--绑定前面的 html 内容 -->
Hap.initEnterQuery('#query-form', viewModel.query);
var BaseUrl = _basePath;
dataSource = new kendo.data.DataSource({
transport: {
read: {
url: BaseUrl + "/calb/od/inspection/plan/query",
type: "POST",
dataType: "json"
},
update: {
url: BaseUrl + "/calb/od/inspection/plan/submit",
type: "POST",
contentType: "application/json"
},
destroy: {
url: BaseUrl + "/calb/od/inspection/plan/remove",
type: "POST",
contentType: "application/json"
},
create: {
url: BaseUrl + "/calb/od/inspection/plan/submit",
type: "POST",
contentType: "application/json"
},
//这里比较重要,这里是初始化 viewModel的代码,如果是查询的话,那么viewModel初始值和查询的VO的json串一样
parameterMap: function (options, type) {
if (type !== "read" && options.models) {
var datas = Hap.prepareSubmitParameter(options, type)
return kendo.stringify(datas);
} else if (type === "read") {
return Hap.prepareQueryParameter(viewModel.model.toJSON(), options)
}
}
},
batch: true,
serverPaging: true,
pageSize: 10,
schema: {
data: 'rows',
total: 'total',
model: {
id: "inspectionPlanId",
fields: {}
}
}
});
$("#grid").kendoGrid({
dataSource: dataSource,
resizable: true,
scrollable: true,
navigatable: false,
selectable: 'multiple, rowbox',
dataBound: function () {
if (parent.autoResizeIframe) {
parent.autoResizeIframe('${RequestParameters.functionCode!}')
}
},
pageable: {
pageSizes: [5, 10, 20, 50],
refresh: true,
buttonCount: 5
},
columns: [
{}
],
editable: true
});
script>
行的grid
<script>
//判断数据是否为空 data 就是 点击的 那行的 grid的 viewModel的 一行的数据
function ifNotNull(data) {
if (data != null && data != "" && data != undefined) {
return true;
}
return false;
}
var BaseUrl = _basePath;
//头点击事件,这是头点击的核心代码,主要的作用就是,将data的 palnId赋值给 这个 viewModelLine
myGrid2 = $("#grid").data("kendoGrid");
$("#grid").on('click', 'td', function () {
$("#head-div table tr").css("background-color", "#fff");
var rowIndex = $(this).parent().index();
$(this).parent().css("backgroundColor", "#acb4af");
var data = myGrid2.dataSource.data()[rowIndex];
if (!ifNotNull(data)) {
} else {
var inspectionPlanId = data.inspectionPlanId;
//这两句本质没区别,两种写法
viewModelLine.model.inspectionPlanId = inspectionPlanId;
viewModelLine.model.set("inspectionPlanId",inspectionPlanId);
$('#gridLine').data('kendoGrid').dataSource.page(1);
}
});
dataSourceLine = new kendo.data.DataSource({
transport: {
read: {
url: BaseUrl + "/calb/od/inspection/rel/query",
type: "POST",
dataType: "json"
},
update: {
url: BaseUrl + "/calb/od/inspection/rel/submit",
type: "POST",
contentType: "application/json"
},
destroy: {
url: BaseUrl + "/calb/od/inspection/rel/remove",
type: "POST",
contentType: "application/json"
},
create: {
url: BaseUrl + "/calb/od/inspection/rel/submit",
type: "POST",
contentType: "application/json"
},
parameterMap: function (options, type) {
if (type !== "read" && options.models) {
var datas = Hap.prepareSubmitParameter(options, type)
return kendo.stringify(datas);
} else if (type === "read") {
return Hap.prepareQueryParameter(viewModelLine.model.toJSON(), options)
}
}
},
batch: true,
serverPaging: true,
pageSize: 10,
schema: {
data: 'rows',
total: 'total',
model: {
id: "inspectionRelId",
fields: {}
}
}
});
$("#gridLine").kendoGrid({
dataSource: dataSourceLine,
resizable: true,
scrollable: true,
autoBind: false, //代表只有点击过后 才加载grid这句话一定要加上
navigatable: false,
selectable: 'multiple, rowbox',
dataBound: function () {
if (parent.autoResizeIframe) {
parent.autoResizeIframe('${RequestParameters.functionCode!}')
}
},
pageable: {
pageSizes: [5, 10, 20, 50],
refresh: true,
buttonCount: 5
},
columns: [
{}
],
editable: true
});
script>
头行最重要的两点就是
1.头点击事件代码中 给 viewModel赋值 头id
2.行的 gird中的 autoBind 一定要是 false 即 不自动加载 要点击后在加载
明细
1.首先在 行的gird中要加一个框,这个框不代表任何 field,只是用作显示,和 超链接点击 弹出 dilog框并传参数 (根据业务看要把 根据哪个字段 查 明细表),
注意
{
title: '<@spring.message "odinspectionrel.detail"/>',
width: 120,
attributes: {style: "text-align:center"},
headerAttributes: {style: "text-align:center"},
//重要代码,在这个框内显示"明细两字",点击将 参数 传到对应 diolog框的对应函数中去
dialog框的函数,去请求到某个地址去
template: function (rowdata) {
return '<a style="text-decoration : underline; color :blue; cursor:pointer" onclick="savegridattr(\''+rowdata.inspectionGroupId+'\''+',\''+rowdata.itemHeaderId+'\')">'+ '明细'+ 'a>'
},
},
2.dialog框的定义(dialog框的定义不在 body内,他是其他页面的)
<div id="dialog11">
div>
<script>
$("#dialog11").kendoWindow({
width: "500px",
height: "400px",
title: '校验计划明细',
modal: true,
resizable: false,
visible: false,
iframe: true,
close: function (e) {
//$('#grid').data('kendoGrid').dataSource.page(1);
}
});
function savegridattr(key) {
var roleWin = $("#dialog11").data("kendoWindow");
//这句就是,弹框访问的 url,带了参数的
roleWin.refresh('http://localhost:8080/core_war_exploded/calb_od_inspection_assign/od_inspection_assign.html?inspectionGroupId='+key);
if (parent.autoResizeIframe) {
parent.autoResizeIframe('${RequestParameters.functionCode!}', 700, function () {
roleWin.center().open();
});
} else {
roleWin.center().open();
}
}
script>
3.在 url页面,即明细页面,需要接受 行传过来的,参数,并赋值给 明细的 viewModel
明细html
1.接受,参数
<script type="text/javascript">
var viewModel = Hap.createGridViewModel("#grid");
//这句话就是接受 行通过url 带来的参数
var inspectionGroupId = "${RequestParameters.inspectionGroupId!'0'}";
//这句也得加上,弹dialog框才会成功
function back(){
window.parent.$('#dialog11').data("kendoWindow").close();
}
script>
2.赋值给,viewModel
//在 viewModel初始化的时候赋值
parameterMap: function (options, type) {
if (type !== "read" && options.models) {
var datas = Hap.prepareSubmitParameter(options, type)
return kendo.stringify(datas);
} else if (type === "read") {
viewModel.model.set("inspectionGroupId",inspectionGroupId);
return Hap.prepareQueryParameter(viewModel.model.toJSON(), options)
}
}
最后注意
(这是 行和明细的新增没有完成)
在行script 和 明细script 的 parameterMap 的 插入时,一定要将,viewModel中插入对应的 头ID 和 明细ID 这样插入才算成功,不然下次 头点击 查询,或者查询明细的时候,还是查不到新插入的记录
parameterMap: function (options, type) {
if (type !== "read" && options.models) {
//想法是在 这里 给 viewModel的 planId赋值
//都是效果还是不显示
var datas = Hap.prepareSubmitParameter(options, type);
return kendo.stringify(datas);
} else if (type === "read") {
return Hap.prepareQueryParameter(viewModelLine.model.toJSON(), options)
}
}
25.后台 如果要返回错误,那么就抛 mtException就可以,
,主要是,消息code和message,底层会走 全局异常,全局异常方法回返回 R(里面最重要的就是 code , message ,),这时抛异常,在异常方法里面会 setSuccess = false的,对于code和message , 一般如果不要求消息编码,那只有message也可以,message的拿到,如果是有消息编码的话,那message也要通过api获取到。最终都是返回 R只是 R的 code,messge,suceess怎么封装的问题
26.对于 kendoui前后端交互得数据主要注意两个位置
1.input查询框(查询)
2.grid表格数据(删除,修改,更新)
对于查询出来得 viewModel (有 所有后台传过来得 json字段,不管 grid中有没有 filed接收)
对于insert,新的记录 只有 filed字段和主键,这要区分清楚
input框和grid框得 viewModel 要区分开
27.数据校验
hap得数据校验,在查询时没有校验,在更新和插入时才数据校验了,所以对于查询的 非空字段,一般只考虑 搜索框,的必输项(前端的校验),或者到后台去,拿着dto去判断 null,不能说直接 在后台 jrs303校验,那对于 全表查就有影响了,当然视情况而定,这里说的 hap通用条件查询,即生成的,是没有做jrs303数据校验的
28.重置框(重置input框)
<span class="btn btn-default" style="float:left;" data-bind="click:reset"
type="button"><i class="fa fa-eraser" style="margin-right:3px;">i>
<@spring.message "hap.reset"/>span>
29.时间lov(时间不能用lov,因为在lov中无法查 date数据类型)
<input id="start" type="text" style="width: 100%" data-role="datetimepicker"
class="k-datetimepicker" data-bind="value:model.start(自定义的,后台用String start接收),events: {change: onChange}">input>
<small class="help-block">开始时间small>
30.注意:因为很多表不能用作,全表查询,我们在后台常常要校验,哪些输入框的值 不能为 null 保证拼接sql的时候 一定会走 where 索引,但是有一个问题,就是我们进入页面的时候,一定是没有任何条件的,简单来说如果用 我们写的 查询接口,那 就会因为查询条件的里面的属性为null , 而报错直接返回前端错误信息(通常是 xxx 不能为null/ xxx必输项等),那么我们有解决办法,
我们现在的目的就是,当进入页面的 那个查询的时候,第一我们要查询,第二我们不能走全表查询
1.所以,我们创建一个 专门 进入页面的一页 调用的接口,这个接口只在进入页面的时候调用,而为了满足上面2个要求,那么我们可以自定义sql,就是我们自己写一段默认查询的数据,例如我们可以 写 sql是,where xxx = 一个具体的值,这样查出的数据 即走了索引,又做到了进页面有数据,只是说这个数据没啥用 不能代表什么,只是用作 解决 bug的
2.至于说 一个接口,将 进入页面,和 点击查询按钮而不带任何查询条件,将这两种条件分隔开,如果不在前端做 特别的设计,例如进入页面 我给后台带 特定的参数,代表我这是 进入页面的这种情况,那么 进入页面的 查询接口 和 无条件的 点击查询按钮的 查询接口时,前台传给后台的 参数没有任何区别,无法做任何判断,将这两种情况 隔离开
31.limit是不能解决 不走全表查询 而节省效率的,因为limit是 select筛选出记录后在limit的,所以不要想着 用limit来,解决因为不能走 where(即全表查询)情况下,用limit的限制 来 达到 少扫描记录达到 不走全表 的效果的
32.自定义数据类型 和 final 类的 比大小的区别 TODO
33.Json包 api 各种的情况 TODO
34.前后台除了业务外最头疼就是 TODO
1.controller 参数接收
2.Dao层 参数接收
3.前台传给后台数据的封装定义
4.前台接收后台返回的json的 解析处理以及使用
35.批量模糊查询
36.前端 查询框 传过来一个 用 ,隔开的String ,或传过来 一个 List 1.直接传String ,如果在业务层代码不用,这个查询字段说,非得转换成 List 37.怎么样处理,前端批量String 用 ,隔开,无论是中文还是英文的 ,后台都能够处理,将String 转换成 List,而不会因为用户输入 中文,而导致程序报错 TODO