9.1 RESTRULCRUD需求

1) 显示所有员工信息

  • URI:emps
  • 请求方式:GET
  • 显示效果


image.png

2) 添加员工信息

  • 显示添加页面:
  • URI:emp
  • 请求方式:GET
  • 显示效果

image.png

  • 添加员工信息:
  • URI:emp
  • 显示效果:完成添加,重定向到 list 页面。

image.png

3) 删除操作

URL:emp/{id}

请求方式:DELETE

删除后效果:对应记录从数据表中删除

4) 修改操作:lastName 不可修改!

A. 显示修改页面

  • URI:emp/{id}
  • 请求方式:GET
  • 显示效果:回显表单。

B. 修改员工信息

  • URI:emp
  • 请求方式:PUT
  • 显示效果:完成修改,重定向到 list 页面。

image.png

5) 相关的类

省略了Service层,为了教学方便

  • 实体类:Employee、Department
  • Handler:EmployeeHandler
  • Dao:EmployeeDao、DepartmentDao

image.png

6) 相关的页面

  • list.jsp
  • input.jsp
  • edit.jsp

    9.2 RESTRULCRUD显示所有员工信息

    1) 搭建开发环境

    ① 拷贝jar包
    ②创建配置文件:applicationContext.xml ```xml <?xml version=”1.0” encoding=”UTF-8”?>

  1. ③配置核心控制器:web.xml
  2. ```xml
  3. <?xml version="1.0" encoding="UTF-8"?>
  4. <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
  5. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  6. xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
  7. version="4.0">
  8. <servlet>
  9. <servlet-name>dispatcherServlet</servlet-name>
  10. <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  11. <init-param>
  12. <param-name>contextConfigLocation</param-name>
  13. <param-value>classpath:META-INF/applicationContext.xml</param-value>
  14. </init-param>
  15. <load-on-startup>1</load-on-startup>
  16. <async-supported>true</async-supported>
  17. </servlet>
  18. <servlet-mapping>
  19. <servlet-name>dispatcherServlet</servlet-name>
  20. <url-pattern>/</url-pattern>
  21. </servlet-mapping>
  22. <!--使用SpringMVC前端控制器写完就直接写字符编码过滤器-->
  23. <filter>
  24. <filter-name>CharacterEncodingFilter</filter-name>
  25. <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
  26. <init-param>
  27. <!--encoding;解决请求乱码问题;request.setCharacterEncoding(this.encoding);-->
  28. <param-name>encoding</param-name>
  29. <param-value>UTF-8</param-value>
  30. </init-param>
  31. <init-param>
  32. <!--forceEncoding;解决响应乱码问题;response.setCharacterEncoding(this.encoding);-->
  33. <param-name>forceEncoding</param-name>
  34. <param-value>true</param-value>
  35. </init-param>
  36. </filter>
  37. <filter-mapping>
  38. <filter-name>CharacterEncodingFilter</filter-name>
  39. <url-pattern>/*</url-pattern>
  40. </filter-mapping>
  41. <!--支持REST风格的Filter-->
  42. <filter>
  43. <filter-name>HiddenHttpMethodFilter</filter-name>
  44. <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
  45. </filter>
  46. <filter-mapping>
  47. <filter-name>HiddenHttpMethodFilter</filter-name>
  48. <url-pattern>/*</url-pattern>
  49. </filter-mapping>
  50. </web-app>

⑤ 创建相关页面
/WEB-INF/pages/list.jsp
index.jsp
⑥增加实体类
image.png
⑦增加DAO类
EmployeeDao

@Repository
public class EmployeeDao {

    private static Map<Integer, Employee> employees = null;

    @Autowired
    private DepartmentDao departmentDao;

    static{
        employees = new HashMap<Integer, Employee>();

        employees.put(1001, new Employee(1001, "E-AA", "aa@163.com", 1, new Department(101, "D-AA")));
        employees.put(1002, new Employee(1002, "E-BB", "bb@163.com", 1, new Department(102, "D-BB")));
        employees.put(1003, new Employee(1003, "E-CC", "cc@163.com", 0, new Department(103, "D-CC")));
        employees.put(1004, new Employee(1004, "E-DD", "dd@163.com", 0, new Department(104, "D-DD")));
        employees.put(1005, new Employee(1005, "E-EE", "ee@163.com", 1, new Department(105, "D-EE")));
    }

    private static Integer initId = 1006;

    public void save(Employee employee){
        if(employee.getId() == null){
            employee.setId(initId++);
        }

        employee.setDepartment(departmentDao.getDepartment(employee.getDepartment().getId()));
        employees.put(employee.getId(), employee);
    }

    public Collection<Employee> getAll(){
        return employees.values();
    }

    public Employee get(Integer id){
        return employees.get(id);
    }

    public void delete(Integer id){
        employees.remove(id);
    }

}

DepartmentDao

@Repository
public class DepartmentDao {

    private static Map<Integer, Department> departments = null;

    static{
        departments = new HashMap<Integer, Department>();

        departments.put(101, new Department(101, "D-AA"));
        departments.put(102, new Department(102, "D-BB"));
        departments.put(103, new Department(103, "D-CC"));
        departments.put(104, new Department(104, "D-DD"));
        departments.put(105, new Department(105, "D-EE"));
    }

    public Collection<Department> getDepartments(){
        return departments.values();
    }

    public Department getDepartment(Integer id){
        return departments.get(id);
    }

}

2) 显示所有员工信息

①页面链接

<a href="/emps">To Employee List</a>

②处理器

//查询所有员工
@RequestMapping("/emps")
public String getEmps(Model model){
    Collection<Employee> all = employeeDao.getAll();
    model.addAttribute("emps",all);
    return "list";
}

③SpringMVC中没遍历的标签,需要使用jstl标签进行集合遍历增加jstl标签库jar包

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>    

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 
Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>

<c:if test="${empty requestScope.empList }">
对不起,没有找到任何员工!
</c:if>
<c:if test="${!empty requestScope.empList }">
<table border="1" cellpadding="10" cellspacing="0">                
    <tr>
        <td>EmpId</td>
        <td>LastName</td>
        <td>Gender</td>
        <td>Email</td>
        <td>DepartmentName</td>
        <td>Edit</td>
        <td>Delete</td>
    </tr>
        <c:forEach items="${requestScope.empList }" var="emp">
            <tr>
                <td>${emp.id }</td>
                <td>${emp.lastName }</td>
                <td>${emp.gender==0?"Female":"Male" }</td>
                <td>${emp.email }</td>
                <td>${emp.department.departmentName }</td>
                <td><a href="">Edit</a></td>
                <td><a href="">Delete</a></td>
            </tr>                
        </c:forEach>        
</table>
</c:if>

</body>
</html>

9.3 RESTRULCRUD添加操作&表单标签

①在list.jsp上增加连接

<a href="toAddPage">Add Employee</a>

②处理器方法

    //去员工添加页面,去页面之前需要查询所有部门信息进行展示
    @RequestMapping("/toAddPage")
    public String toAddPage(Model model){
        Collection<Department> departments = departmentDao.getDepartments();
        model.addAttribute("depts",departments);
        model.addAttribute("employee",new Employee());
        return "add";
    }

③添加add.jsp页面(使用Spring的表单标签)

<!--表单标签:
1、SpringMVC认为表单数据中的每一项最终都是要回显的;
path指定的是一个属性;这个属性是从隐含模型(请求域中取出某个对象的属性)
path指定的每一个属性,请求域中必须有一个对象,拥有这个属性;
    这个对象就是请求域中的command的值
    modelAttribute="";
        1)以前我们表单标签会从请求域中获取一个command对象的值;把这个对象中每一个属性都对应的显示出来
        2)可以告诉SpringMVC不要去取command的值,我放了一个modelAttribute指定的值;
        取对象用的key就用modelAttribute指定的。
-->
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<html>
<head>
    <title>员工添加</title>
</head>
<body>
    <h1>员工添加</h1>
    <%
        pageContext.setAttribute("ctp",request.getContextPath());
    %>
    <form:form action="http://localhost:8080/SpringMVC_6_crud/emp" modelAttribute="employee" method="post">
        <!--path属性:就是html标签-input的name项
            path作用:
                1、当做原生name项
                2、自动回显隐含模型中某个对象对应的这个属性的值
        -->
        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="2"/><br>
        dept:<br>
                <!--items属性:指定要遍历的集合;自动遍历;遍历出的每一个元素都是departments对象
                    itemValue属性:指定遍历出的对象的哪个属性是作为option标签体的值
                    itemLabel属性:指定历出的对象的哪个属性是作为要提交的信息
                -->
                <form:select path="department.id" items="${depts}"
                             itemValue="id"
                             itemLabel="departmentName"/><br>
        <input type="submit" value="提交">
    </form:form>



<%--    <form>--%>
<%--        lastName:<input name="lastName" type="text"><br>--%>
<%--        email:<input name="email" type="text"><br>--%>
<%--        gender:<br>--%>
<%--             男<input name="gender" type="radio" value="1"><br>--%>
<%--             女<input name="gender" type="radio" value="0"><br>--%>
<%--        dept:--%>
<%--            <select name="department.id">--%>
<%--                <c:forEach items="${departments}" var="depts">--%>
<%--                    <option value="${depts.id}">${depts.departmentName}</option>--%>
<%--                </c:forEach>--%>
<%--            </select>--%>
<%--        <input type="submit" value="提交">--%>
<%--    </form>--%>
</body>
</html>

添加完后,点击提交按钮转跳/emp

//保存员工
@RequestMapping(value = "/emp",method = RequestMethod.POST)
public String addEmp(@ModelAttribute("employee") Employee employee){
    System.out.println("要添加的员工: "+employee);
    employeeDao.save(employee);
    //重定向到查询所有员工请求
    return "forward:/emps";
}

/emp保存员工信息,并转发到/emps—/emps在上面已经列出会转发到/list查询出所有员工信息并展示到list.jsp页面

9.4 使用 Spring的表单标签

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

  • form 标签

    • 一般情况下,通过 GET 请求获取表单页面,而通过 POST 请求提交表单页面因此获取表单页面和提交表单页面的 URL 是相同的
    • 只要满足该最佳条件的契约 标签就无需通过 action 属性指定表单提交的 URL
    • 可以通过modelAttribute属性指定绑定的模型属性,若没有指定该属性,则默认从request 域对象中读取command的表单 bean,如果该属性值也不存在,则会发生错误。只要path属性跟modelAttribute绑定的对象的属性同名就会自动赋值实现回显效果
  • SpringMVC 提供了多个表单组件标签,如 等,用以绑定表单字段的属性值,它们的共有属性如下:

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

  • 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:radiobuttons 标签
  • form:option:下拉框选项组件标签。使用方式同 form:radiobuttons 标签
  • form:errors:显示表单组件或数据校验所对应的错误
    • :显示表单所有的错误
    • :显示所有以 user 为前缀的属性对应的错误
    • :显示特定表单对象属性的错误
<form:form action="${ctp }/emp" modelAttribute="employee" method="POST">

    lastName:<form:input path="lastName"/><form:errors path="lastName"></form:errors>-->${errorInfo.lastName }<br/>
    email:<form:input path="email"/><form:errors path="email"></form:errors>-->${errorInfo.email }<br/>
    gender:<br/>
        男:<form:radiobutton path="gender" value="1"/><br/>
        女:<form:radiobutton path="gender" value="0"/><br/>
    birth:<form:input path="birth"/><form:errors path="birth"></form:errors>-->${errorInfo.birth }<br/>
    dept:
        <form:select path="department.id" items="${depts }" itemLabel="departmentName" itemValue="id"></form:select>
    <input type="submit" value="提交"/> 
</form:form>

9.5 添加员工实验代码

① 表单

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8" import="java.util.*"%>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
 "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>

<!-- 
1.为什么使用SpringMVC的form标签
① 快速开发
② 表单回显
2.可以通过modelAttribute指定绑定的模型属性,
若没有指定该属性,则默认从request域中查找command的表单的bean
如果该属性也不存在,那么,则会发生错误。
 -->
 <form:form action="empAdd" method="POST" modelAttribute="employee">
         LastName : <form:input path="lastName" /><br><br>
         Email : <form:input path="email" /><br><br>
         <%
                 Map<String,String> map = new HashMap<String,String>();
                 map.put("1", "Male");
                 map.put("0","Female");
                 request.setAttribute("genders", map);
         %>
         Gender : <br><form:radiobuttons path="gender" items="${genders }" delimiter="<br>"/><br><br>
         DeptName : 
                 <form:select path="department.id" 
                                                 items="${deptList }" 
                                                 itemLabel="departmentName" 
                                                 itemValue="id"></form:select><br><br>
                 <input type="submit" value="Submit"><br><br>
 </form:form> 
</body>
</html>

对比普通的表单:

<%-- <form action=""> --%>
<!--     lastName:<input type="text" name="lastName"/><br/> -->
<!--     email:<input type="text" name="email"/><br/> -->
<!--     gender:<br/> -->
<!--         男:<input type="radio" name="gender" value="1"/><br/> -->
<!--         女:<input type="radio" name="gender" value="0"/><br/> -->
<!--     dept: -->
<!--         <select name="department.id"> -->
<%--             <c:forEach items="${depts }" var="deptItem"> --%>
<%--                 <option value="${deptItem.id }">${deptItem.departmentName }</option> --%>
<%--             </c:forEach> --%>
<!--         </select> -->
<!--     <input type="submit" value="提交"/> -->
<%-- </form>  --%>

②控制器方法

@Controller
public class EmployeeHandler {
@RequestMapping(value="/empAdd",method=RequestMethod.POST)
public String empAdd(Employee employee){
employeeDao.save(employee);
return "redirect:/empList";
}
}

9.6 RESTRULCRUD删除操作&处理静态资源

1) 删除实验代码

① 页面链接

<form action="${ctp}/emp/${emp.id}" method="post">
    <input name="_method" type="hidden" value="Delete">
    <input type="submit" value="删除">
</form>

② 控制器方法

//删除员工
@RequestMapping(value = "/emp/{id}",method = RequestMethod.DELETE)
public String deleteEmp(@PathVariable("id") Integer id){
    employeeDao.delete(id);
    return "redirect:/emps";
}

2) HiddenHttpMethodFilter过滤器

  • 发起请求,无法执行,因为delete请求必须通过post请求转换为delete请求,借助:HiddenHttpMethodFilter过滤器

    3) 需要使用jQuery来转换请求方式

    ① 加入jQuery库文件
    /scripts/jquery-1.9.1.min.js
    ② jQuery库文件不起作用
警告: No mapping found for HTTP request with URI [/SpringMVC_03_RESTFul_CRUD/scripts/jquery-1.9.1.min.js] in DispatcherServlet with name ‘springDispatcherServlet’

image.png

③解决办法,SpringMVC 处理静态资源
SpringMVC 处理静态资源:
a) 为什么会有这样的问题:
优雅的 REST 风格的资源URL 不希望带 .html 或 .do 等后缀
若将 DispatcherServlet 请求映射配置为 /,
则 Spring MVC 将捕获 WEB 容器的所有请求, 包括静态资源的请求, SpringMVC 会将他们当成一个普通请求处理,
因找不到对应处理器将导致错误。
b) 解决: 在 SpringMVC 的配置文件中配置
④配置后,原来的请求又不好使了
需要配置

4) 关于作用


5) 通过jQuery转换为DELETE请求

<td><a class="delete" href="empDelete/${emp.id }">Delete</a></td>
<form action="" method="post">
<input type="hidden" name="_method" value="DELETE"/>
</form>
<script type="text/javascript" src="scripts/jquery-1.9.1.min.js"></script>
<script type="text/javascript">
$(function(){
        $(".delete").click(function(){
            var href = $(this).attr("href");
            $("form").attr("action",href).submit();
            return false ;
        });
});
</script>

6) 删除操作流程图解

image.png

9.7 RESTRULCRUD修改操作

image.png

1) 根据id查询员工对象,表单回显

来到修改页面edit
①页面链接

<td>
    <a href="${ctp}/emp/${emp.id}" methods="GET">Edit</a>
</td>

②控制器方法

    //查询员工,来到修改页面回显
    @RequestMapping(value = "/emp/{id}",method = RequestMethod.GET)
    public String getEmp(@PathVariable("id") Integer id,Model model){
        Employee employeeId = employeeDao.get(id);
        model.addAttribute("empId",employeeId);
        Collection<Department> departments = departmentDao.getDepartments();
        model.addAttribute("depts",departments);
        return "edit";
    }

③修改页面

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8" import="java.util.*"%>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
 "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>

<!-- 
1.为什么使用SpringMVC的form标签
① 快速开发
② 表单回显
2.可以通过modelAttribute指定绑定的模型属性,
若没有指定该属性,则默认从request域中查找command的表单的bean
如果该属性也不存在,那么,则会发生错误。
修改功能需要增加绝对路径,相对路径会报错,路径不对
 -->
 <form:form action="${pageContext.request.contextPath }/empUpdate" 
method="POST" modelAttribute="employee">                        
<%--
         LastName : <form:input path="lastName" /><br><br>
          --%>
                 <form:hidden path="id"/>
                 <input type="hidden" name="_method" value="PUT">
                 <%-- 这里不要使用form:hidden标签,否则会报错。 
<form:hidden path="_method" value="PUT"/>
                         Spring的隐含标签,没有value属性,同时,path指定的值,在模型对象中也没有这个属性(_method),所以回显时会报错。
                         org.springframework.beans.NotReadablePropertyException: 
                         Invalid property '_method' of bean class [com.atguigu.springmvc.crud.entities.Employee]: 
                         Bean property '_method' is not readable or has an invalid getter method: 
                         Does the return type of the getter match the parameter type of the setter?
                  --%>

         Email : <form:input path="email" /><br><br>
         <%
                 Map<String,String> map = new HashMap<String,String>();
                 map.put("1", "Male");
                 map.put("0","Female");
                 request.setAttribute("genders", map);
         %>
         Gender : <br><form:radiobuttons path="gender" items="${genders }" delimiter="<br>"/><br><br>
         DeptName : 
                 <form:select path="department.id" 
                                                 items="${deptList }" 
                                                 itemLabel="departmentName" 
                                                 itemValue="id"></form:select><br><br>
                 <input type="submit" value="Submit"><br><br>
 </form:form>
</body>
</html>

2) 提交表单,修改数据

在修改页面edit,修改并重定向到/emps展示所有数据

//修改员工
@RequestMapping(value = "/emp/{id}",method = RequestMethod.PUT)
public String updateEmp(Employee employee){
    System.out.println("要修改的员工: "+employee);

    return "redirect:/emps";
}

如果有id值就获取,没有就拉倒

    @ModelAttribute
    public void myModelAttribute(@RequestParam(value = "id",required = false)Integer id,Model model){
        if (id !=null){
            Employee employee = employeeDao.get(id);
            model.addAttribute("employee",employee);
        }
    }