第二节:SpringMVC 的表单标签


一、Spring 的表单标签

  1、form 表单标签

    通过 SpringMVC 的表单标签可以实现将模型数据中的属性和 HTML 表单元素相绑定,以实现表单数据更便捷编辑和表单值的回显

  2、form 标签

  (1)一般情况下,通过 GET 请求获取表单页面,而通过 POST 请求提交表单页面,因此获取表单页面和提交表单页面的 URL 是相同的   (2)只要满足该最佳条件的契约, 标签就无需通过 action 属性指定表单提交的 URL   (3)可以通过 modelAttribute 属性指定绑定的模型属性,若没有指定该属性,则默认从 request 域对象中读取 command 的表单 bean,如果该属性值也不存在,则会发生错误  

  3、表单组件标签

  (1)SpringMVC 提供了多个表单组件标签,如 等,用以绑定表单字段的属性值,它们的共有属性如下:

path:表单字段,对应 html 元素的 name 属性,支持级联属性
htmlEscape:是否对表单值的 HTML 特殊字符进行转换,默认值为 true
cssClass:表单组件对应的 css 样式类名
cssErrorClass:表单组件的数据存在错误时,采取的 css 样式

  (2)常用标签

    ① form:input、form:password、form:hidden、form:textarea:对应 HTML 表单的 text、password、hidden、textare 标签。     ② form:radiobutton :单选框组件标签,当表单 bean 对应的属性值和 value 值相等时,单选框被选中;     ③ form:radiobuttons:单选框组标签,用于构造多个单选框
items:可以是一个 List、String[] 或 map
itemValue:指定 radio 的value 值,可以是集合中 bean 的一个属性值
itemLabel:指定 radio 的 label 值
delimiter:多个单选框可以通过 delimiter 指定分隔符
    ④ form:checkbox:复选框组件,用于构造单个复选框     ⑤ form:checkboxs:用于构造多个复选框,使用方式同 form:radiobuttons 标签     ⑥ form:select:用于构造下拉框组件,使用方式同 form:radiobutons 标签     ⑦ form:option:下拉框选项组件标签。使用方式同 form:radiobuttons 标签     ⑧ form:errors:显示表单组件或数据校验所对应的错误
 :显示表单所有的错误
 :显示所有以 user 为前缀的属性对应的错误
 :显示特定表单对象属性的错误

  4、使用 form 表单标签

<%@ taglib uri="http://www.springframework.org/tags/form"  prefix="form" %>

二、使用 form 标签重构添加页面

  1、去添加页面

ADD

  2、控制器方法

    /**
     * 去添加页面,把需要的部门信息放在请求域中带到页面
     * @param model
     * @return
     */
    @RequestMapping(value = "/toAddPage", method = RequestMethod.GET)
    public String toAddPage(Model model) {
        Collection depts = departmentDao.getDepartments();
        //默认放到 request 域中
        model.addAttribute("depts", depts);

        model.addAttribute("command", new Employee(null, "张三", "san@126.com", 0, departmentDao.getDepartment(101)));
        model.addAttribute("employee", new Employee());
        return "add";
    }

  3、添加页面

<%--
    form 表单标签
    通过 SpringMVC 的表单标签可以实现将模型数据中的属性和 HTML 表单元素相绑定,以实现表单数据更便捷编辑和表单值的回显

    1、SpringMVC 认为,表单数据中每一项最终都是要回显的;
            path 指定的是一个属性,这个属性是从隐含模型(请求域中取出的某个对象的属性);
            path 指定的每一个属性,请求域中必须有一个对象,拥有这个属性;
            这个对象就是请求域中的 command

            modelAttribute=""
            modelAttribute="employee"
            1、以前我们表单标签会从请求域中获取一个 command 对象,把这个对象中的每一个属性对应的显示出来;
            2、可以告诉SpringMVC 不要去取 command 的值,放了一个 modelAttribute 指定的值
                取对象用的key就用 modelAttribute 指定的;

--%>
<%
    pageContext.setAttribute("ctx", request.getContextPath());
%>
<form:form action="${ctx}/emp" modelAttribute="employee" method="POST">
    
    lastName:<form:input path="lastName" /><br/>
    email:<form:input path="email" /><br/>
    gender:<br><form:radiobutton path="gender" value="1"/><br/><form:radiobutton path="gender" value="0" /><br/>
    dept:
        
        <form:select path="department.id" items="${depts}" itemLabel="departmentName" itemValue="id">form:select>
    <br>
    <input type="submit" value="保存">
form:form>

  4、常见错误

  可以通过 modelAttribute 指定绑定的模型属性,若没有指定该属性,则默认从 request 域中查找 command 的表单 bean,如果该属性也不存在,则会发生错误。

  错误:

java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'command' available as request attribute
    org.springframework.web.servlet.support.BindStatus.(BindStatus.java:141)

  没有指定 command 属性。

三、使用 form 标签重构修改页面

  1、修改链接

UPDARE

  2、根据id查询员工

    /**
     * 根据id查询员工信息
     * @param id
     * @return
     */
    @RequestMapping(value = "/emp/{id}", method = RequestMethod.GET)
    public String getEmpById(@PathVariable("id") Integer id, Model model) {
        Employee employee = employeeDao.get(id);
        model.addAttribute("emp", employee);

        Collection depts = departmentDao.getDepartments();
        model.addAttribute("depts", depts);
        return "edit";
    }

  3、修改页面

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core"  prefix="c" %>
<%@ taglib uri="http://www.springframework.org/tags/form"  prefix="form" %>
<html>
<head>
    <title>员工修改页面title>
head>
<body>
<%
    pageContext.setAttribute("ctp", request.getContextPath());
%>
<%-- modelAttribute="emp" 这个表单的所有内容显示绑定的是请求域中 emp 的值 --%>
<form:form action="${ctp}/emp/${emp.id}" modelAttribute="emp" method="post">
    <input type="hidden" name="_method" value="PUT">
    <input type="hidden" name="id" value="${emp.id}">
    email:<form:input path="email" /><br/>
    gender:<br><form:radiobutton path="gender" value="1"/><br/><form:radiobutton path="gender" value="0" /><br/>
    dept:
    <form:select path="department.id" items="${depts}" itemLabel="departmentName" itemValue="id">form:select>
    <br>
    <input type="submit" value="保存">
form:form>

body>
html>

  4、修改控制器

    /**
     * 修改员工信息
     * @param id
     * @param employee
     * @return
     */
    @RequestMapping(value = "/emp/{id}", method = RequestMethod.PUT)
    public String updateEmpById(@PathVariable("id") Integer id, @ModelAttribute(value = "employee") Employee employee) {
        System.out.println("employee = " + employee);

        employeeDao.save(employee);
        return "redirect:/emps";
    }

    @ModelAttribute
    public void myModelAttribute(@RequestParam(value = "id", required = false)Integer id, Model model) {
        if (id != null) {
            Employee employee = employeeDao.get(id);
            System.out.println("查询出的类型:employee = " + employee);
            model.addAttribute("employee", employee);
        }
        System.out.println("ModelAttribute运行了");
    }