SSM框架CRUD实战第二天

该文档是:ssm整合教程

博客连接:https://www.loveuluo.cn

日期:2021-01-13

6. 新增功能

6.1 新增功能分析

image-20210113104717859

image-20210113104734342

6.2 创建新增员工的模态框

(1)给新增按钮增加一个id:

image-20210113105523365

(2)给新增按钮绑定单击事件可以弹出模态框:

// 给新增员工按钮绑定单击事件
$("#emp_add_modal_btn").click(function () {
    // 给模态框绑定 弹出模态框的方法,可以传入一些设置属性
    $("#empAddModal").modal({
        //打开后背景不删除属性
        backdrop:"static"
    });
})

(3)模态框详细设置:

<%--员工添加的模态框--%>
<div id="empAddModal" class="modal fade" tabindex="-1" role="dialog">
    <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">员工添加</h4>
            </div>
            <%--这里就是模态框的显示的体,可以放入表单--%>
            <div class="modal-body">
                <form class="form-horizontal">
                    <%--表单组对应名字文本框--%>
                    <div class="form-group">
                        <%--提示信息占两列--%>
                        <label class="col-sm-2 control-label">名称</label>
                        <%--输入框占10列--%>
                        <div class="col-sm-10">
                            <input type="text" class="form-control" id="empName_add_input" name="empName" placeholder="empName">
                        </div>
                    </div>
                    <%--表单组对应邮箱文本框--%>
                    <div class="form-group">
                        <label class="col-sm-2 control-label">邮箱</label>
                        <div class="col-sm-10">
                            <input type="text" class="form-control" id="email_add_input" name="email" placeholder="email@qq.com">
                        </div>
                    </div>
                    <%--表单组对应性别单选框--%>
                    <div class="form-group">
                        <label class="col-sm-2 control-label">性别</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">所在部门</label>
                            <%--下拉列表--%>
                            <div class="col-sm-4">
                                <%--部门提交部门id即可--%>
                                <select class="form-control" name="dId" id="dept_add_select">

                                </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">保存</button>
            </div>
        </div><!-- /.modal-content -->
    </div><!-- /.modal-dialog -->
</div><!-- /.modal -->

页面结果:

image-20210113121056988

6.3 AJAX显示部门

(1)创建用于处理部门有关请求的Controller控制器:

/**
 * 处理和部门有关的请求
 */
@Controller
public class DepartmentController {

    @Autowired
    private DepartmentService departmentService;

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

(2)Controller中用到的DepartmentService业务层:

@Service
public class DepartmentService {

    @Autowired
    private DepartmentMapper departmentMapper;

    //查询所有部门
    public List<Department> getDepts() {
        return departmentMapper.selectByExample(null);
    }
}

(3)index.jsp页面增加ajax获得所有部门:

//2.给新增员工按钮绑定单击事件
$("#emp_add_modal_btn").click(function () {
    // 防止部门数据叠加
    $("#dept_add_select").empty();
    // 发送ajax请求,查出部门信息,显示在下拉列表中
    getDepts();
    // 给模态框绑定 弹出模态框的方法,可以传入一些设置属性
    $("#empAddModal").modal({
        // 打开后背景不删除属性
        backdrop:"static"
    });
})

// ajax-查出所有部门的信息并显示在下拉列表中
function getDepts() {
    $.ajax({
        url:"${APP_PATH}/depts",
        type:"GET",
        success:function(result){
            console.log(result);
            // 显示部门信息在下拉列表中(index代表索引,dept代表遍历出来的每个对象)
            $.each(result.extend.depts,function (index,dept) {
                //定义一个<option></option>标签,两个中间添加的值是dept.deptName,用attr给这个option标签加一个value属性值是dept.deptId
                var optionEle = $("<option></option>").append(index+1+"."+dept.deptName).attr("value",dept.deptId);
                //把上边这玩意添加到下拉列表当中
                optionEle.appendTo($("#dept_add_select"));
            });
        }
    });
}

页面结果:

image-20210113130510624

6.4 点击保存添加员工

(1)给模态框中的保存按钮和表单增加id:

image-20210113131715665

image-20210113133543399

(2)EmployeeController增加一个保存用户的方法:

/**
 * 保存用户的方法
 * @return
 */
//必须是/emp且是post请求才能调用这个方法,rest风格uri
@RequestMapping(value = "/emp",method = RequestMethod.POST)
@ResponseBody
public Msg saveEmp(Employee employee){
    employeeService.saveEmp(employee);
    return Msg.success();
}

(3)Controller中用到的employeeService的saveEmp方法:

/**
 * 保存员工的方法
 * @param employee
 */
public void saveEmp(Employee employee) {
    //insertSelective是有选择的插入,里边有很多if判断,因为员工的id是自增的不需要插入,这里选用这个来插入
    employeeMapper.insertSelective(employee);
}

(3)index.jsp页面增加保存按钮的单击事件保存用户,保存后自动转到最后一页显示新增的数据:

为了保证能来到最后一页,定义一个总记录数(总记录数可以保证一定大于最大页数)的全局变量,然后直接跳转到总记录数的页数,而分页插件会自动把大于最大页数的变成最大页数:

image-20210113143122332

image-20210113143213392

index.jsp页面:

//3.单击模态框中的保存按钮,将表单数据提交给服务器进行保存
$("#emp_save_btn").click(function () {
    // serialize方法可以得到表单的数据并变成key=value& ...的形式
    // alert($("#form_add").serialize()); empName=Luo&email=Luo%40qq.com&gender=M&dId=1
    // 发送ajax请求保存员工
    $.ajax({
       url:"${APP_PATH}/emp",
       type:"POST",
       data:$("#form_add").serialize(),
       success:function (result) {
            // 员工保存成功:
            //(1)关闭模态框
            $("#empAddModal").modal('hide');
            //(2)来到最后一页显示刚才保存的数据
            //  为了保证能来到最后一页,定义一个总记录数的全局变量,然后直接跳转到总记录数的页数,而分页插件会自动把大于最大页数的变成最大页数。
            to_page(totalRecord);//调用自己定义的to_page方法
       }
    });
});

页面结果:

image-20210113143752953

image-20210113143757495

6.5 jQuery前端校验

(1)给两个输入框下边添加span,用于提示错误信息:

image-20210113150554571

(2)在保存按钮的单击事件中,在保存之前先对要提交给服务器的数据进行校验:

image-20210113154547653

(3)校验的逻辑:

// 校验表单数据的方法
function validate_add_from() {
    //(1)校验用户名
    // 拿到要校验的数据,使用正则表达式判断
    var empName = $("#empName_add_input").val();
    var regName = /(^[a-zA-Z0-9_-]{6,16}$)|(^[\u2E80-\u9FFF]{2,5})/;
    if (!regName.test(empName)) {
        // 调用显示校验信息的方法
        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)){
        // 调用显示校验信息的方法
        show_validate_msg("#email_add_input","error","邮箱格式不正确");
        return false;
    }else {
        // 调用显示校验信息的方法
        show_validate_msg("#email_add_input","success","")
    }
    return true;
}

// 显示校验信息的方法,可以传入要校验的元素、成功还是失败、要提示的信息
function show_validate_msg(ele,status,msg) {
    //(3)清除当前元素的校验状态
    $(ele).parent().removeClass("has-success has-error");
    $(ele).next("span").text("");
    //(1)如果是校验成功该怎么提示
    if ("success" == status){
        // 这里直接增加has-success属性的话,会增加在has-error之后,自然就不会生效,所以要清空样式
        $(ele).parent().addClass("has-success");
        $(ele).next("span").text(msg);
    //(2)如果是校验失败该怎么提示
    } else if ("error" == status){
        // 给input框的父元素添加has-error属性,会变成提示错误的样式
        $(ele).parent().addClass("has-error");
        // 给这个input紧邻的span的元素的文本值设置提示信息
        $(ele).next("span").text(msg);
    }
}

页面结果:

image-20210113154731764

image-20210113154748615

6.6 Ajax校验用户名是否重复

(1)EmployeeController增加一个校验用户名的方法:

/**
 * 根据用户名查询是否有相同名称用户方法
 * @param empName
 * @return
 */
@RequestMapping("/checkuse")
@ResponseBody
public Msg checkuse(String empName){
    boolean b = employeeService.checkUser(empName);
    //页面可以根据Msg中带上的状态判断是否成功
    if (b){
        return Msg.success();
    }else {
        return Msg.fail();
    }
}

(2)Controller中用到的employeeService的checkUser方法:

/**
 * 检验用户名是否可用
 * @param empName
 * @return true:代表当前姓名可用 false:不可用
 */
public boolean checkUser(String empName) {
    //根据给定的条件,判断是表中是否有这个条件的数据,没有就返回,一条就返回1,两条就返回2...
    EmployeeExample employeeExample=new EmployeeExample();
    //条件对象
    EmployeeExample.Criteria criteria = employeeExample.createCriteria();
    //条件就是名字必须等于empName
    criteria.andEmpNameEqualTo(empName);

    long count = employeeMapper.countByExample(employeeExample);
    return count==0;
}

(3)定义一个全局变量,把用户名是否存在的ajax请求的结果保存起来:

image-20210113164038415

(4)index.jsp页面增加事件 当用户名文本输入框改变时发送ajax请求校验用户名是否已经存在:

//4.当用户名文本输入框改变时发送ajax请求校验用户名是否已经存在
$("#empName_add_input").change(function () {
    var empName = $("#empName_add_input").val();
    $.ajax({
        url:"${APP_PATH}/checkuse",
        type:"POST",
        data:"empName="+empName,
        success:function (result) {
            if (result.code==100){
                show_validate_msg("#empName_add_input","success","用户名未重复");
                // 对全局属性赋值,用来在下边判断是否要执行下去
                ajaxNameResult = "success";
            } else {
                show_validate_msg("#empName_add_input","error","用户名已存在");
                 // 对全局属性赋值,用来在下边判断是否要执行下去
                ajaxNameResult = "error";
            }
        }
    });
});

(5)在保存用户的按钮单击事件中再添加一道判断:

image-20210113165037503

页面结果:

image-20210113165514081

6.7 校验用户名的细节处理

(1)小问题,名称输入例如:aaa的时候,此时用户名未重复,提示用户名未重复。但是点击保存的时候会显示用户名违法,因为设置了验证正则表达式:

image-20210113165705668

image-20210113165718543

(2)解决方案,用户名在后台校验的时候,也给他按照正则表达式的规则先校验,正则通过后再按照用户名是否存在校验:

EmployeeController后台修改:

/**
 * 根据用户名查询是否有相同名称用户方法
 * @param empName
 * @return
 */
@RequestMapping("/checkuse")
@ResponseBody
public Msg checkuse(String empName){
    //先判断用户名是否是合法的表达式
    String regx = "(^[a-zA-Z0-9_-]{6,16}$)|(^[\\u2E80-\\u9FFF]{2,5})";
    boolean matches = empName.matches(regx);
    //如果匹配失败
    if (!matches){
        return Msg.fail().add("va_msg","用户名必须是2-5位中文或者6-16位英文和数字的组合");
    }
    //数据库用户名重复校验
    boolean b = employeeService.checkUser(empName);
    if (b){
        return Msg.success();
    }else {
        return Msg.fail().add("va_msg","用户名已存在");
    }
}

前台的change事件的错误信息动态获取:

image-20210113170650900

页面效果:

image-20210113170842870

6.8 后端JSR303校验

(1)导入jar依赖:

<!--JSR303数据校验支持;tomcat7及以上的服务器直接可以用了,
tomcat7以下的服务器:el表达式不是新的标准。需要额外给服务器的lib包中替换新的标准的el
-->
<!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-validator -->
<dependency>
  <groupId>org.hibernate</groupId>
  <artifactId>hibernate-validator</artifactId>
  <version>5.4.1.Final</version>
</dependency>

(2)修改要校验的bean:

public class Employee {
    private Integer empId;
    //@Pattern代表自定义规则(regexp = 正则表达式,message = 错误提示的消息)
    @Pattern(regexp = "(^[a-zA-Z0-9_-]{6,16}$)|(^[\\u2E80-\\u9FFF]{2,5})",
            message = "用户名必须是2-5位中文或者6-16位英文和数字的组合")
    private String empName;
    private String gender;
    //@Email自带的email规则
    @Email(message = "邮箱格式不正确")
    private String email;
    private Integer dId;
    private Department department;

(3)Controller在要进行校验的参数前加上注解:

/**
 * 保存用户的方法
 * @return
 */
//必须是/emp且是post请求才能调用这个方法,rest风格uri
@RequestMapping(value = "/emp",method = RequestMethod.POST)
@ResponseBody
//@Valid:代表我们封装对象以后,这里边的数据要进行校验
//BindingResult result:封装校验的结果
public Msg saveEmp(@Valid Employee employee, BindingResult result){
    if (result.hasErrors()){
        //用于存放错误字段和信息
        Map<String,Object> errorMap= new HashMap<>();
        //校验失败,应该返回失败,在模态框中显示校验失败的错误信息
        List<FieldError> fieldErrors = result.getFieldErrors();
        //遍历 拿到的所有的有错误的对象
        for (FieldError fieldError : fieldErrors) {
            System.out.println("错误的字段名:"+fieldError.getField());
            System.out.println("错误的信息:"+fieldError.getDefaultMessage());
            errorMap.put(fieldError.getField(),fieldError.getDefaultMessage());
        }
        return Msg.fail().add("errorFields",errorMap);
    }else {
        employeeService.saveEmp(employee);
        return Msg.success();
    }
}

可以把数据返回前端去显示,这里演示越过前端验证直接访问后端验证控制台的打印输出:

image-20210113192318727

image-20210113192327384

7. 修改功能

7.1 修改功能分析

image-20210113192503249

7.2 创建员工修改的模态框

(1)构建表格的方法中给删除和修改按键都添加class标识:

image-20210113193112245

(2)修改查出所有部门信息并且显示在下拉列表的方法,改为传参的形式:

image-20210113194532463

之前调用这个方法的新增员工也要修改:

image-20210113194628198

(3)员工修改的模态框:

修改的模态框,名字是不能修改的所以改为静态样式,只有别的可以修改。

<%--员工修改的模态框--%>
<div id="empUpdateModal" class="modal fade" tabindex="-1" role="dialog">
    <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">员工修改</h4>
            </div>
            <%--这里就是模态框的显示的体,可以放入表单--%>
            <div class="modal-body">
                <form class="form-horizontal" id="form_update">
                    <%--表单组对应名字文本框--%>
                    <div class="form-group">
                        <%--提示信息占两列--%>
                        <label class="col-sm-2 control-label">名称</label>
                        <%--输入框占10列--%>
                        <div class="col-sm-10">
                            <p class="form-control-static" id="empName_update_static"></p>
                        </div>
                    </div>
                    <%--表单组对应邮箱文本框--%>
                    <div class="form-group">
                        <label class="col-sm-2 control-label">邮箱</label>
                        <div class="col-sm-10">
                            <input type="text" class="form-control" id="email_update_input" name="email" placeholder="email@qq.com">
                            <span class="help-block"></span>
                        </div>
                    </div>
                    <%--表单组对应性别单选框--%>
                    <div class="form-group">
                        <label class="col-sm-2 control-label">性别</label>
                        <%--单选框--%>
                        <div class="col-sm-10">
                            <label class="radio-inline">
                                <input type="radio" name="gender" id="gender1_update_input" value="M" checked="checked"> 男
                            </label>
                            <label class="radio-inline">
                                <input type="radio" name="gender" id="gender2_update_input" value="F"> 女
                            </label>
                        </div>
                    </div>
                    <%--表单组对应部门下拉列表--%>
                    <div class="form-group">
                        <label class="col-sm-2 control-label">所在部门</label>
                        <%--下拉列表--%>
                        <div class="col-sm-4">
                            <%--部门提交部门id即可--%>
                            <select class="form-control" name="dId" id="dept_update_select">

                            </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_update_btn">更新</button>
            </div>
        </div><!-- /.modal-content -->
    </div><!-- /.modal-dialog -->
</div><!-- /.modal -->

(4)给修改按钮绑定单击事件弹出模态框:

注意点:我们是按钮创建之前就绑定了click,所以绑定不上。方法一:可以在创建按钮的时候绑定。 方法二:绑定点击.on()可以为后添加的元素也绑定

//5.给修改按钮用on绑定单机事件,on可以为后加的元素也绑定
$(document).on("click",".edit_btn",function(){
    // 查出员工信息,显示员工信息

    // -防止部门数据叠加
    $("#dept_update_select").empty();
    // 查出部门信息,并显示部门列表
    getDepts("#dept_update_select");
    // 弹出模态框
    $("#empUpdateModal").modal({
        backdrop:"static"
    });
});

页面结果:

image-20210113195743742

7.3 修改模态框回显员工信息

(1)构建表格的方法中为编辑按钮添加一个自定义属性:

image-20210113202743356

(2)查询单个员工的方法:

// ajax-查询单个员工信息的方法
function getEmp(id) {
    $.ajax({
        url:"${APP_PATH}/emp/"+id,
        type:"GET",
        success:function (result) {
            var empData = result.extend.emp;
            $("#empName_update_static").text(empData.empName);
            $("#email_update_input").val(empData.email);
            $("#empUpdateModal input[name=gender]").val([empData.gender]);
            $("#empUpdateModal select").val([empData.dId]);
        }
    })
}

(3)单击编辑按钮查出员工信息,显示员工信息:

//5.给修改按钮用on绑定单机事件,on可以为后加的元素也绑定
$(document).on("click",".edit_btn",function(){
    // -防止部门数据叠加
    $("#dept_update_select").empty();
    // 查出部门信息,并显示部门列表
    getDepts("#dept_update_select");
    // 查出员工信息,显示员工信息
    getEmp($(this).attr("edit-id"));//$(this).attr("edit-id") = 获取当前对象的edit-id属性的值
    // 弹出模态框
    $("#empUpdateModal").modal({
        backdrop:"static"
    });
});

页面结果:

image-20210113203442429

image-20210113203449282

7.4 点击更新更新员工信息

(1)把员工的id传递给模态框的更新按钮:

image-20210113204633364

(2)定义一个全局当前页数据,并在构建分页信息的方法中给它赋值:

image-20210113212349259

image-20210113212454753

(3)EmployeeController类增加一个根据id更新员工的方法:

/**
 * 根据id更新员工
 * @param employee
 * @return
 */
@ResponseBody
//{empId}占位符的值会自动封装进Employee对象中属性名是empId的
@RequestMapping(value = "/emp/{empId}",method = RequestMethod.PUT)
public Msg saveEmp(Employee employee){
    employeeService.updateEmp(employee);
    return Msg.success();
}

(4)EmployeeController中所需要的employeeService的updateEmp方法编写:

/**
 * 更新员工
 * @param employee
 */
public void updateEmp(Employee employee) {
    //有选择的根据主键进行更新,因为我们传过来的对象是没有名字的,名字固定了不能改
    employeeMapper.updateByPrimaryKeySelective(employee);
}

(5)index.jsp页面点击更新按钮单击事件更新员工:

//6.点击更新,更新员工信息
$("#emp_update_btn").click(function () {
    // 验证邮箱是否合法
    var email=$("#email_update_input").val();
    var regEmail = /^([a-z0-9_\.-]+)@([\da-z\.-]+)\.([a-z\.]{2,6})$/;
    if (!regEmail.test(email)){
        show_validate_msg("#email_update_input","error","邮箱格式不正确");
        return false;
    }else {
        show_validate_msg("#email_update_input","success","")
    }

    // 发送ajax请求保存更新的员工数据
    $.ajax({
        url:"${APP_PATH}/emp/"+$(this).attr("edit-id"),
        type:"POST",
        data:$("#empUpdateModal form").serialize()+"&_method=PUT",//&_method=PUT = 指定请求方式为PUT
        success:function (result) {
            // 关闭模态框
            $("#empUpdateModal").modal("hide");
            // 回到页面
            to_page(currentPage);
        }
    })
});

页面结果:

image-20210113212858971

image-20210113212913904

image-20210113212932192

8. 删除功能

8.1 删除功能分析

image-20210113213028389

image-20210113213024090

8.2 删除单一员工

(1)在构建表格的时候为删除按钮添加一个属性:

image-20210113214939952

(2)EmployeeController类增加一个根据id删除员工的方法:

/**
 * 员工删除
 * @param id
 * @return
 */
@ResponseBody
@RequestMapping(value = "/emp/{id}",method = RequestMethod.DELETE)
public Msg deleteEmpById(@PathVariable("id")Integer id){
    employeeService.deleteEmp(id);
    return Msg.success();
}

(3)EmployeeController中所需要的employeeService的deleteEmp方法编写:

/**
 * 员工删除
 * @param id
 */
public void deleteEmp(Integer id) {
    employeeMapper.deleteByPrimaryKey(id);
}

(4)index.jsp页面点击删除按钮单击事件删除员工:

//7.点击删除(单个删除)
$(document).on("click",".delete_btn",function() {
    // 弹出是否确认删除对话框
   var empId=$(this).attr("del-id");
   var empName = $(this).parents("tr").find("td:eq(0)").text();//得到当前员工的姓名
    if (confirm("确认删除【"+empName+"】吗?")){
        // 确认,发送ajax请求删除即可
        $.ajax({
            url:"${APP_PATH}/emp/"+empId,
            type:"POST",
            data:"_method=DELETE",
            success:function (result) {
                //回到本页
                to_page(currentPage);
            }
        })
    }

});

页面结果:

image-20210113221454324

image-20210113221459311

image-20210113221503839

9. 总结

image-20210113221931302

最后修改:2021 年 01 月 21 日 04 : 37 PM
如果觉得我的文章对你有用,请随意赞赏