(一 )第三天主要实现的功能
实现对员工信息的增删改
准备:
在jsp页面中的from表单内的添加、修改、删除、查询的空间中添加自定义属性
data-method="add" data-method="edit" data-method="remove" data-method="save"
js代码中为jsp页面上所有的data-method内的属性添加事件
/*为页面上所有data-method内的属性添加事件*/
$("*[data-method]").click(function () {
lzj[$(this).data("method")]();
/*两种调用方式: lzj.add() lzj["add"]() */
});
lzj = {
add(){},
edit(){ },
remove(){ },
search(){},
save(){ }
}
(二)删除细节
- 前端js代码逻辑思路
① 获取选中行(下面只考虑选中,没有选中直接弹出消息框,提示用户即可)
② 弹出消息框,确认是否删除
③ 使用ajax发送get请求,传入id进行删除
④ 删除成功之后刷新页面
⑤ 删除失败,弹出消息框提示用户,并告诉失败原因 - 后台java代码逻辑思路
注意此处的删除的路径只能是delete,因为后期权限处理设置的此路径
① 删除方法添加路径注解和json格式注解 @RequestMapping("/delete")
@ResponseBody
② 创建一个JsonResult对象,目的用于返回错误消息对象,使用的是json格式
③ 通过注入的业务层调用SpringDataJpa的删除方法
④ 返回返回jsonResult对象
(三)添加细节
- 前台jsp代码思路
① 创建一个对话框,放入一个表单
② 对话框默认关闭,在data-options属性中设置:closed:true
③ 对话框设置为模态框,在data-options属性中设置:modal:true
④ 对话框中新增确认和取消按钮在data-options属性中设置:buttons:’#dialogBtns’
因为textbox的验证功能比较少,所以此处使用validatebox的验证功能
⑤ 简单验证:年龄:validType:‘integerRange[18,70]’,required:true、邮箱:equired:true,validType:‘email’
⑥ 密码验证:需引入插件
⑦ 用户名唯一验证—>前台通过ajax传入输入的用户名给后台,后台根据用户名在数据库中进行查询
js代码中自定义验证规则
注意
1)ajax默认发送的是异步的请求,需要修改为同步请求:async: false。否则会导致检验失败
2)同步请求返回的值是字符串,需要将其和字符串true进行绝对相等比较
//自定义验证: 验证用户名的唯一性
$.extend($.fn.validatebox.defaults.rules, {
checkUserName: {
/** 用户名唯一的验证功能
* @param value 前台用户在表单内输入的用户名
* @param param 为数组,是调用验证功能时,输入的参数(此处不使用,因为从后台进行获取)
* @returns {boolean}
*/
validator: function(value, param){
console.debug(param)
/**
* 通过ajax发送请求,访问后台方法
* 注意此时传的参数必须和后台方法内的参数名一致username
* ajax访问是异步的,需要修改为同步的访问,不能使用$.get的方法
*/
var empId = $("#employeeId").val(); //修改信息的时候,需要id
var result= $.ajax({
url: "/employee/checkUsername",
data:{username:value,id: empId},
async: false //同步请求
}).responseText;
console.debug(result)
//返回false,表示验证失败,在数据库中已经存在了一个相同的用户名
return result==="true";
},
//不符合验证时,给以用户提示信息
message: '亲~ ,此用户名已经被占用了,请换一个试试'
}
});
仓库层将根据用户名进行查询用户名是否存在
"select count(o) from Employee o where username = ?1"
业务层判断仓库层是否有查询到数据
public boolean checkName(String username) {
Long count = employeeRepository.findCountByUsername(username);
//count>0,代表在数据库中能查询到此用户,用户名已存在
return !(count>0);
}
web层将数据库的用户名和前台传入的用户名进行判断
public boolean checkUsername(Long id ,String username) {
if(id!=null){
//1.根据id到数据库中获到数据
Employee dbEmp = employeeService.findOne(id);
//2.判断数据库的员工名称和传过来的是否相等
if(dbEmp.getUsername().equals(username)){
//3.如果相等,代表这个用户名是可以使用的
return true;
}
}
return employeeService.checkName(username);
}
- 前台js代码
① 将新增的表单的会话框设置在页面中心
② 将自定义的show属性的控件展示并激活
③ 添加前清空表单
add(){
//打开添加或修改的表单,并将表单放置在页面的中心
employeeDialog.dialog("open").dialog("center");
//将密码和确认密码显示出来,即带有data-show属性的打开
$("*[data-show]").show();
//将data-show属性内的input控件激活,可以使用
$("*[data-show] input").validatebox("enable");
//每次添加数据的时候都清空表单内的数据,保证添加时,表单内不会回显之前编辑的数据
employeeForm.form("clear");
},
(四)修改细节
- 编辑的回显
① 将自定义属性(即密码和确认密码)进行禁用和隐藏
//将密码和确认密码显示出来,即带有data-show属性的打开
$("*[data-show]").hide();
//将input组件禁用,避免在修改保存数据的时候,确认密码控件导致数据无法保存
$("*[data-show] input").validatebox("disable");
② 清除多余的内容,即确认密码的内容清空
employeeForm.form("clear");
③ 部门额的回显需要转换
(因为回显需要字段"department.id" row中存放的是department.id)
if(selectRow.department){
selectRow["department.id"] = selectRow.department.id;
}
④ 将选中的数据放入表单内(因为此时选中的数据,已经存放在了rows内,所以直接将rows中的数据,加载进form内即可)
employeeForm.form("load",selectRow);
(五)保存细节
添加数据和修改数据都需要进行保存
- 前台js代码逻辑
① 判断是修改保存还是编辑保存,
编辑保存多传入一个参数,后台进行核对
url = "/employee/save";
var id = $("#employeeId").val();
if(id){
//在编辑保存的时候,避免数据丢失,使用SpringMVC的注解只对更新方法,进行数据进行查询,于是添加cmd(名字随意)条件,后台进行判断
url = "/employee/update?cmd=update";
}
② 提交表单之前先进行验证
onSubmit: function(){
//当前from,提交保存信息之前,判断验证
return $(this).form('validate');
},
③ 保存成功之后的回调函数,返回的是一个字符串,需要转为json格式
④ 保存成功:刷新页面并关闭对话窗口
⑤ 失败,则弹出消息框,提示用户
employeeForm.form({
url:url,
onSubmit: function(){
//当前from,提交保存信息之前,判断验证
return $(this).form('validate');
},
//保存成功后的回调函数,返回的是一个字符串,需要转换为一个JSON对象
success:function(data){
/*console.debug(data);*///data是一个字符串
/*var result = eval("("+data+")");*/
var result = JSON.parse(data);
//操作成功
if (result.success) {
//刷新页面
employeeGrids.datagrid("reload");
//关闭窗口
employeeDialog.dialog("close");
}else{
//5、获取后台返回结果:{susscee:true/false,msg:"失败原因"},并提示给用户
$.messager.alert('提示',`删除失败,,原因是:${result.msg}`,'error');
}
}
});
employeeForm.submit();
====
技术点①:修改和添加的保存方法是一致的,但为了后期的权限处理,添加和修改的保存路径不能一致,所以在web层抽取一个私有的保存方法,然后以供调用,前台传入不同的参数进行兼容判断
数据丢失问题
技术点②:修改数据出现的数据丢失问题
分析:
解决方案:
① 使用隐藏域,将隐藏域中的值传入到后台(不推荐,因为安全性太低且麻烦,隐藏域内的值,易被不法分子进行数据抓包)
② 使用SpringMVC的注解@Column(updateble=false),在domain对象上对应的字段上贴此注解,告诉SpringDataJpa,修改的时候不对此字段进行操作(不推荐,因为如果需要对此字段进行操作时,很麻烦,并且扩展性太低)
③避免使用反射,在web层,直接通过id获取此对象,将传入的值进行set修改,前台没有传入则不会进行set设置(不推荐因为前台修改,后台也必须跟着进行修改,耦合度高)
④ 使用SpringMVC的 @ModelAttribute注解,贴在查询方法上
此注解认识:
1)在执行任何一个路径之前,都会先执行被贴的方法
2)此时update中的查询的对象,已经是从数据库中查询出来的对象,并且SpringMVC已经对齐进行了修改操作
修改部门出现n-to-no异常
技术点③
错误分析:
因为find方法获取的员工对象是持久化对象,员工的部门是懒加载数据,传入的是department.id,SpringMVC只要发现输入的字符串有".",它就会把这个字符串进行拆分,前面都是get属性,最后一个“.”就是set属性,而懒加载获取的对象的id被修改,就会出现脏数据更新,从而导致n-to-no错误
解决方案:在find查询获取了员工对象之后,将员工的部设置为null,因为部门为空,SpringMVC就会新创建一个部门对象,此时就不是持久化对象,可以修改成功
即凡是传入的关联对象,都需要设置为null,否则就会出现n-to-n