新增模块

  • 点击新增按钮会弹出一个输入界面

实现思路

  • index.jsp页面点击”按钮”,弹出新增对话框
  • 去数据库查询部门列表,显示在对话框中
  • 用户输入数据并进行校验完成保存
    • jQuery前端校验+Ajax用户名重复校验+重要数据配上后端校验和数据库唯一约束
  • Restful风格URI:
    • /emp/{id} GET查询员工
    • /emp 发POST即保存员工
    • /emp/{id} PUT请求修改员工
    • /epm/{id} DELETE删除员工

模态框

  • 弹出来的界面可以使用Boostrap提供的JavaScript插件模态框实现
  • 修改index.jsp文件,新增模态框
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
<!-- 员工添加的模态框 -->
<div class="modal fade" id="empAddModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title" id="myModalLabel">员工添加</h4>
</div>
<div class="modal-body">
<form class="form-horizontal">
<div class="form-group">
<label class="col-sm-2 control-label">empName</label>
<div class="col-sm-10">
<input type="text" name="empName" class="form-control" id="empName_add_input" placeholder="empName">
<span class="help-block"></span>
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">email</label>
<div class="col-sm-10">
<input type="text" name="email" class="form-control" id="email_add_input" placeholder="email@atguigu.com">
<span class="help-block"></span>
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">gender</label>
<div class="col-sm-10">
<label class="radio-inline">
<input type="radio" name="gender" id="gender1_add_input" value="M" checked="checked">
</label>
<label class="radio-inline">
<input type="radio" name="gender" id="gender2_add_input" value="F">
</label>
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">deptName</label>
<div class="col-sm-4">
<!-- 部门提交部门id即可 -->
<select class="form-control" name="dId">
</select>
</div>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">关闭</button>
<button type="button" class="btn btn-primary" id="emp_save_btn">保存</button>
</div>
</div>
</div>
</div>
  • 给新增按钮绑定事件
1
2
3
4
5
6
7
//点击新增按钮弹出模态框。
$("#emp_add_modal_btn").click(function(){
//弹出模态框
$("#empAddModal").modal({
backdrop:"static"
});
});

发现Ajax请求

  • 模态框弹出之前应该发送Ajax请求,弹出部门信息显示在下拉列表中
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//清空表单样式及内容
function reset_form(ele){
$(ele)[0].reset();
//清空表单样式
$(ele).find("*").removeClass("has-error has-success");
$(ele).find(".help-block").text("");
}

//点击新增按钮弹出模态框。
$("#emp_add_modal_btn").click(function(){
//清除表单数据(表单完整重置(表单的数据,表单的样式))
reset_form("#empAddModal form");
//s$("")[0].reset();
//发送ajax请求,查出部门信息,显示在下拉列表中
getDepts("#empAddModal select");
//弹出模态框
$("#empAddModal").modal({
backdrop:"static"
});
});
  • 发送Ajax的方法getDepts()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//查出所有的部门信息并显示在下拉列表中
function getDepts(ele){
//清空之前下拉列表的值
$(ele).empty();
$.ajax({
//需要一个控制器处理请求
url:"${APP_PATH}/depts",
type:"GET",
success:function(result){
//{"code":100,"msg":"处理成功!",
//"extend":{"depts":[{"deptId":1,"deptName":"开发部"},{"deptId":2,"deptName":"测试部"}]}}
//console.log(result);
//显示部门信息在下拉列表中
//$("#empAddModal select").append("")
$.each(result.extend.depts,function(){
var optionEle = $("<option></option>").append(this.deptName).attr("value",this.deptId);
optionEle.appendTo(ele);
});
}
});

}

控制器处理请求

  • 先创建业务层DepartmentService
1
2
3
4
5
6
7
8
9
10
11
12
13
@Service
public class DepartmentService {

@Autowired
private DepartmentMapper departmentMapper;

public List<Department> getDepts() {
//查出的所有部门信息
List<Department> list = departmentMapper.selectByExample(null);

return list;
}
}
  • 创建一个控制器DepartmentController处理和部门有关的请求
1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Controller
public class DepartmentController {

@Autowired
private DepartmentService departmentService;

/*返回所有部门信息*/
@RequestMapping("/depts")
@ResponseBody
public Msg getDepts(){
List<Department> list = departmentService.getDepts();
return Msg.success().add("depts",list);
}
}

实现保存模块

控制器

  • 点击保存,模态框中填写的表单数据提交给服务器进行保存
  • 首先在EmployeeService中新增员工保存方法
1
2
3
4
5
6
7
8
9
10
11
@Service
public class EmployeeService {

@Autowired
EmployeeMapper employeeMapper;
//员工保存
public void saveEmp(Employee employee) {
// TODO Auto-generated method stub
employeeMapper.insertSelective(employee);
}
}
  • EmployeeController中新增员工保存的方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 员工保存
//1、支持JSR303校验
///2、导入Hibernate-Validator

@RequestMapping(value="/emp",method=RequestMethod.POST)
@ResponseBody
public Msg saveEmp(@Valid Employee employee,BindingResult result){
if(result.hasErrors()){
//校验失败,应该返回失败,在模态框中显示校验失败的错误信息
Map<String, Object> map = new HashMap<>();
List<FieldError> errors = result.getFieldErrors();
for (FieldError fieldError : errors) {
System.out.println("错误的字段名:"+fieldError.getField());
System.out.println("错误信息:"+fieldError.getDefaultMessage());
map.put(fieldError.getField(), fieldError.getDefaultMessage());
}
return Msg.fail().add("errorFields", map);
}else{
employeeService.saveEmp(employee);
return Msg.success();
}
}

发送Ajax

  • 取得表单的值后发送Ajax给服务器,后端控制器处理请求,调用方法插入到数据库中
  • 服务器返回JSON结果,保存成功就关闭模态框并跳转到最后一页
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
//点击保存,保存员工。
$("#emp_save_btn").click(function(){
//1、模态框中填写的表单数据提交给服务器进行保存
//1、先对要提交给服务器的数据进行校验
if(!validate_add_form()){
return false;
};
//1、判断之前的ajax用户名校验是否成功。如果成功。
if($(this).attr("ajax-va")=="error"){
return false;
}

//2、发送ajax请求保存员工
$.ajax({
url:"${APP_PATH}/emp",
type:"POST",
//jQuery中拿取表单内容的方法
data:$("#empAddModal form").serialize(),
success:function(result){
//alert(result.msg);
if(result.code == 100){
//员工保存成功;
//1、关闭模态框
$("#empAddModal").modal('hide');

//2、来到最后一页,显示刚才保存的数据
//发送ajax请求显示最后一页数据即可
to_page(totalRecord);
}else{
//显示失败信息
//console.log(result);
//有哪个字段的错误信息就显示哪个字段的;
if(undefined != result.extend.errorFields.email){
//显示邮箱错误信息
show_validate_msg("#email_add_input", "error", result.extend.errorFields.email);
}
if(undefined != result.extend.errorFields.empName){
//显示员工名字的错误信息
show_validate_msg("#empName_add_input", "error", result.extend.errorFields.empName);
}
}
}
});
});

数据校验功能

  • 需要对提交保存的数据进行校验

表单校验

  • 校验表单数据
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
//校验表单数据
function validate_add_form(){
//1、拿到要校验的数据,使用正则表达式
var empName = $("#empName_add_input").val();
var regName = /(^[a-zA-Z0-9_-]{6,16}$)|(^[\u2E80-\u9FFF]{2,5})/;
if(!regName.test(empName)){
//alert("用户名可以是2-5位中文或者6-16位英文和数字的组合");
show_validate_msg("#empName_add_input", "error", "用户名可以是2-5位中文或者6-16位英文和数字的组合");
return false;
}else{
show_validate_msg("#empName_add_input", "success", "");
};

//2、校验邮箱信息
var email = $("#email_add_input").val();
var regEmail = /^([a-z0-9_\.-]+)@([\da-z\.-]+)\.([a-z\.]{2,6})$/;
if(!regEmail.test(email)){
//alert("邮箱格式不正确");
//应该清空这个元素之前的样式
show_validate_msg("#email_add_input", "error", "邮箱格式不正确");
/* $("#email_add_input").parent().addClass("has-error");
$("#email_add_input").next("span").text("邮箱格式不正确"); */
return false;
}else{
show_validate_msg("#email_add_input", "success", "");
}
return true;
}

提示信息

1
2
3
4
5
6
7
8
9
10
11
12
13
//显示校验结果的提示信息
function show_validate_msg(ele,status,msg){
//清除当前元素的校验状态
$(ele).parent().removeClass("has-success has-error");
$(ele).next("span").text("");
if("success"==status){
$(ele).parent().addClass("has-success");
$(ele).next("span").text(msg);
}else if("error" == status){
$(ele).parent().addClass("has-error");
$(ele).next("span").text(msg);
}
}

用户名校验

  • 需要异步校验用户名是否重复,当输入框改变就校验用户名

  • EmployeeService中新增方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@Service
public class EmployeeService {

@Autowired
EmployeeMapper employeeMapper;
/**
* 检验用户名是否可用
*
* @param empName
* @return true:代表当前姓名可用 fasle:不可用
*/
public boolean checkUser(String empName) {
// TODO Auto-generated method stub
EmployeeExample example = new EmployeeExample();
//查询条件
EmployeeExample.Criteria criteria = example.createCriteria();
//拼装条件
criteria.andEmpNameEqualTo(empName);
//返回查到的记录数
long count = employeeMapper.countByExample(example);
return count == 0; //为0表示没有记录,当前用户名可用
}
  • 修改EmployeeController新增用户名校验的方法,记得和前端的校验规则统一起来
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@ResponseBody
@RequestMapping("/checkuser")
public Msg checkuser(@RequestParam("empName")String empName){
//先判断用户名是否是合法的表达式;
String regx = "(^[a-zA-Z0-9_-]{6,16}$)|(^[\u2E80-\u9FFF]{2,5})";
if(!empName.matches(regx)){
return Msg.fail().add("va_msg", "用户名必须是6-16位数字和字母的组合或者2-5位中文");
}

//数据库用户名重复校验
boolean b = employeeService.checkUser(empName);
if(b){
return Msg.success(); //可用
}else{
return Msg.fail().add("va_msg", "用户名不可用"); //返回提示信息
}
}
  • 发送Ajax请求校验用户名是否可用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//校验用户名是否可用
$("#empName_add_input").change(function(){
//发送ajax请求校验用户名是否可用
var empName = this.value;
$.ajax({
url:"${APP_PATH}/checkuser",
data:"empName="+empName,
type:"POST",
success:function(result){
if(result.code==100){
show_validate_msg("#empName_add_input","success","用户名可用");
$("#emp_save_btn").attr("ajax-va","success");
}else{
show_validate_msg("#empName_add_input","error",result.extend.va_msg);
$("#emp_save_btn").attr("ajax-va","error");
}
}
});
});

因为用户名是监听表单内容发生改变时调用,当如果表单内容不变时会出错,所以需要打开模态框就对表单进行清空

1
2
3
4
5
6
7
8
9
10
11
12
13
//清空表单样式及内容
function reset_form(ele){
$(ele)[0].reset();
//清空表单样式
$(ele).find("*").removeClass("has-error has-success");
$(ele).find(".help-block").text("");
}

//点击新增按钮弹出模态框。
$("#emp_add_modal_btn").click(function(){
//清除表单数据(表单完整重置(表单的数据,表单的样式))
reset_form("#empAddModal form");
}

后端校验

  • 前端校验很容易被人改动,不够安全。最完整的校验应该是前端校验+后端校验+数据库约束
  • 可以使用JSR303进行校验,需要导入Hibernate-Validator包,在实体类员工Employee上给每一个字段加上相应要求
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class Employee {
private Integer empId;

@Pattern(regexp="(^[a-zA-Z0-9_-]{6,16}$)|(^[\u2E80-\u9FFF]{2,5})"
,message="用户名必须是2-5位中文或者6-16位英文和数字的组合")
private String empName;

private String gender;


//@Email
@Pattern(regexp="^([a-z0-9_\\.-]+)@([\\da-z\\.-]+)\\.([a-z\\.]{2,6})$",
message="邮箱格式不正确")
private String email;

private Integer dId;

//希望查询员工的时候把部门信息也查询出来
private Department department;
//getter,setter,无参和有参构造
}
  • 修改控制器EmployeeController中的员工保存方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

/**
* 员工保存
* 1、支持JSR303校验
* 2、导入Hibernate-Validator
*/
@RequestMapping(value="/emp",method=RequestMethod.POST)
@ResponseBody
public Msg saveEmp(@Valid Employee employee,BindingResult result){
if(result.hasErrors()){
//校验失败,应该返回失败,在模态框中显示校验失败的错误信息
Map<String, Object> map = new HashMap<>();
List<FieldError> errors = result.getFieldErrors();
for (FieldError fieldError : errors) {
System.out.println("错误的字段名:"+fieldError.getField());
System.out.println("错误信息:"+fieldError.getDefaultMessage());
map.put(fieldError.getField(), fieldError.getDefaultMessage());
}
return Msg.fail().add("errorFields", map);
}else{
employeeService.saveEmp(employee);
return Msg.success();
}

}
  • 前端保存事件修改
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
//点击保存,保存员工。
$("#emp_save_btn").click(function(){
//1、模态框中填写的表单数据提交给服务器进行保存
//1、先对要提交给服务器的数据进行校验
if(!validate_add_form()){
return false;
};
//1、判断之前的ajax用户名校验是否成功。如果成功。
if($(this).attr("ajax-va")=="error"){
return false;
}

//2、发送ajax请求保存员工
$.ajax({
url:"${APP_PATH}/emp",
type:"POST",
//jQuery中拿取表单内容的方法
data:$("#empAddModal form").serialize(),
success:function(result){
//alert(result.msg);
if(result.code == 100){
//员工保存成功;
//1、关闭模态框
$("#empAddModal").modal('hide');

//2、来到最后一页,显示刚才保存的数据
//发送ajax请求显示最后一页数据即可
to_page(totalRecord);
}else{
//显示失败信息
//console.log(result);
//有哪个字段的错误信息就显示哪个字段的;
if(undefined != result.extend.errorFields.email){
//显示邮箱错误信息
show_validate_msg("#email_add_input", "error", result.extend.errorFields.email);
}
if(undefined != result.extend.errorFields.empName){
//显示员工名字的错误信息
show_validate_msg("#empName_add_input", "error", result.extend.errorFields.empName);
}
}
}
});
});