SpringMVC之RESTful实现CRUD

RESTRUL_CRUD_需求

显示所有员工信息

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

添加员工信息

  • 显示添加页面:

  • URI:emp

  • 请求方式:GET

  • 显示效果

  • 添加员工信息:

  • URI:emp

  • 请求方式:POST

  • 显示效果:完成添加,重定向到 list 页面。

删除操作

  • URL:emp/{id}
  • 请求方式:DELETE
  • 删除后效果:对应记录从数据表中删除

修改操作:lastName 不可修改!

  1. 显示修改页面
    • URI:emp/{id}
    • 请求方式:GET
    • 显示效果:回显表单。
  2. 修改员工信息
  • URI:emp
  • 请求方式:PUT
  • 显示效果:完成修改,重定向到 list 页面。

相关的类

  • 省略了Service层
  • 实体类:Employee、Department
  • Controller:EmployeeController
  • Dao:EmployeeDao、DepartmentDao

相关页面

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

RESTRUL_CRUD_显示所有员工信息

搭建开发环境

  1. 导包

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    com.springsource.net.sf.cglib-2.2.0.jar
    com.springsource.org.aopalliance-1.0.0.jar
    com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
    spring-aop-4.0.0.RELEASE.jar
    spring-aspects-4.0.0.RELEASE.jar
    commons-logging-1.1.3.jar
    spring-beans-4.0.0.RELEASE.jar
    spring-context-4.0.0.RELEASE.jar
    spring-core-4.0.0.RELEASE.jar
    spring-expression-4.0.0.RELEASE.jar
    spring-jdbc-4.0.0.RELEASE.jar
    spring-orm-4.0.0.RELEASE.jar
    spring-tx-4.0.0.RELEASE.jar
    spring-web-4.0.0.RELEASE.jar
    spring-webmvc-4.0.0.RELEASE.jar
  2. 创建配置文件:springmvc.xml 增加context,mvc,beans名称空间。

  3. 配置核心控制器

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    <servlet>
    <servlet-name>springDispatcherServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:springmvc.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
    </servlet>

    <!-- Map all requests to the DispatcherServlet for handling -->
    <servlet-mapping>
    <servlet-name>springDispatcherServlet</servlet-name>
    <url-pattern>/</url-pattern>
    </servlet-mapping>
  4. 将 POST 请求转换为 PUT 或 DELETE 请求以及字符过滤器

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    <filter>
    <filter-name>CharacterEncodingFilter</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <init-param>
    <param-name>encoding</param-name>
    <param-value>utf-8</param-value>
    </init-param>
    <init-param>
    <param-name>forceEncoding</param-name>
    <param-value>true</param-value>
    </init-param>
    </filter>
    <filter-mapping>
    <filter-name>CharacterEncodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
    </filter-mapping>
  5. 创建相关页面

    1
    2
    /WEB-INF/views/list.jsp
    index.jsp
  6. 增加实体类

  7. 增加Dao

    1. EmployeeDao
      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
      package xyz.lyhcc.dao;

      import java.util.Collection;
      import java.util.HashMap;
      import java.util.Map;
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.stereotype.Repository;

      import xyz.lyhcc.bean.Department;
      import xyz.lyhcc.bean.Employee;


      @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);
      }
      }
    2. DeaprtmentDao
      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
      package xyz.lyhcc.bean;

      public class Department {
      private Integer id;
      private String departmentName;



      public Department() {
      super();
      }

      public Department(Integer id, String departmentName) {
      super();
      this.id = id;
      this.departmentName = departmentName;
      }

      public Integer getId() {
      return id;
      }

      public void setId(Integer id) {
      this.id = id;
      }

      public String getDepartmentName() {
      return departmentName;
      }

      public void setDepartmentName(String departmentName) {
      this.departmentName = departmentName;
      }


      }

显示所有员工信息

  1. 页面链接

    1
    <a href="empList">To Employee List</a>
  2. 增加处理器

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    @Controller
    public class MyController {

    @Autowired
    EmployeeDao employeeDao;

    @RequestMapping("/retrieveEmps")
    public String retrieveEmps(Map<String, Object> map) {
    map.put("empList", employeeDao.getAll());
    return "list";
    }
    }
  3. SpringMVC中没遍历的标签,需要使用jstl标签进行集合遍历增加jstl标签库jar包

    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
    <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?"女": "男" }</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>
    <a href="toaddpage">Add Employee</a>

使用 Spring的表单标签

  • 通过 SpringMVC 的表单标签可以实现将模型数据中的属性和 HTML 表单元素相绑定,以实现表单数据更便捷编辑和表单值的回显
  • form 标签
    • 一般情况下,通过 GET 请求获取表单页面,而通过 POST 请求提交表单页面,因此获取表单页面和提交表单页面的 URL 是相同的。
    • 只要满足该最佳条件的契约,form:form 标签就无需通过 action 属性指定表单提交的 URL
    • 可以通过 modelAttribute 属性指定绑定的模型属性,若没有指定该属性,则默认从 request 域对象中读取 command 的表单 bean,如果该属性值也不存在,则会发生错误。
  • SpringMVC 提供了多个表单组件标签,如 form:input/form:select/ 等,用以绑定表单字段的属性值,它们的共有属性如下:
    • 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:显示表单组件或数据校验所对应的错误
    • <form:errors path= “*” /> :显示表单所有的错误
    • <form:errors path= “user*” /> :显示所有以 user 为前缀的属性对应的错误
    • <form:errors path= “username” /> :显示特定表单对象属性的错误

RESTRUL_CRUD_添加操作&表单标签

  1. 在list.jsp上增加连接

    1
    <a href="empInput">Add Employee</a>
  2. 增加处理器方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    @RequestMapping(value="toaddpage")
    public String addEmpPage(Model model) {
    Collection<Department> departments = departmentDao.getDepartments();
    model.addAttribute("depts", departments);
    //增加一个属性
    return "add";
    }
    @RequestMapping(value="increaseEmp",method=RequestMethod.POST)
    public String increaseEmp(Employee employee, Map<String, Object>map) {

    employeeDao.save(employee);
    return "redirect:/retrieveEmps";
    }
  3. 显示添加页面

    1. 非SpringMVC的form标签
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      <% pageContext.setAttribute("ctp", request.getContextPath()); %>
      <form action="increaseEmp" method="POST">

      lastName: <input type="text" name="lastName" />
      email: <input type="text" name="email" />
      gender:
      男<input type="radio" name="gender" value="1"/>
      女<input type="radio" name="gender" value="0"/>
      <select name="department.id">
      <c:forEach items="${depts }" var="dept">
      <option value="${dept.id }">${dept.departmentName }</option>
      </c:forEach>
      </select>
      <input type="submit" value="提交" />
      </form>
      1. SpringMVC的form标签
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
                 	<form:form action="increaseEmp" method="POST" modelAttribute="employee">
        <!-- java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'command' available as request attribute -->
        LastName: <form:input path="lastName"/></br></br>
        Email: <form:input path="email"/></br></br>
        Gender: 男<form:radiobutton path="gender" value="1"/>
        女<form:radiobutton path="gender" value="0"/>
        <br/>
        <br/>
        Department:<form:select path="department.id" items="${depts }" itemLabel="departmentName" itemValue="id"></form:select>
        <br/>
        <input type="submit" value="提交" />
        </form:form>

注意: 注意modelAttribute的使用,这里没有在域中使用添加对应的属性会报错
ava.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name ‘command’ available as request attribute


RESTRUL_CRUD_删除操作&处理静态资源

  1. 页面链接

RESTRUL_CRUD_修改操作

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

  1. 页面链接

    1
    <td><a href="empEdit/${emp.id }">Edit</a></td>
  2. 控制器方法

    1
    2
    3
    4
    5
    6
       @RequestMapping(value="empEdit/{id}", method=RequestMethod.GET)
    public String editEmp(@PathVariable(value="id") Integer id, Map<String, Object>map) {
    map.put("employee", employeeDao.get(id));
    map.put("depts", departmentDao.getDepartments());
    return "edit";
    }
  3. 修改页面

    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
    <%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
    <%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
    <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="UTF-8">
    <title>员工信息修改界面</title>
    </head>
    <body>
    <form:form action="${pageContext.request.contextPath }/empUpdate"
    method="POST" modelAttribute="employee">
    <input type="hidden" name="id" value="${employee.id }" />
    <input type="hidden" name="_method" value="PUT">
    Email : <form:input path="email" />
    <br>
    <br>
    Gender: 男<form:radiobutton path="gender" value="1"/>
    女<form:radiobutton path="gender" value="0"/>
    <br/>
    <br/>
    DeptName :
    <form:select path="department.id" items="${depts }" itemLabel="departmentName" itemValue="id"></form:select>
    <br>
    <br>
    <input type="submit" value="Submit"><br><br>
    </form:form>

    </body>
    </html>

提交表单,修改数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@RequestMapping(value="empUpdate",method=RequestMethod.PUT)
public String updateEmp(Employee employee) {

System.out.println(employee);
employeeDao.save(employee);
return "redirect:/retrieveEmps";
}

@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);
}

}

RESTRUL_CRUD_删除操作&处理静态资源

删除实验代码

  1. 页面链接

    1
    <td><a href="/empDelete/${emp.id }">Delete</a></td>
  2. 控制器方法

    1
    2
    3
    4
    5
    @RequestMapping(value="delEmp/{id}", method=RequestMethod.DELETE)
    public String delEmp(@PathVariable(value="id") Integer id) {
    employeeDao.delete(id);
    return "redirect:/retrieveEmps";
    }

HiddenHttpMethodFilter过滤器

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

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

  1. 加入jQuery库文件
    1
    /scripts/jquery-1.9.1.min.js
  2. jQuery库文件不起作用
    1
    警告: No mapping found for HTTP request with URI [/SpringMVC_03_RESTFul_CRUD/scripts/jquery-1.9.1.min.js] in DispatcherServlet with name 'springDispatcherServlet'
  3. 解决方法,SpringMVC 处理静态资源

    SpringMVC 处理静态资源:

    a)为什么会有这样的问题:

    优雅的 REST 风格的资源URL 不希望带 .html 或 .do 等后缀  
    若将 DispatcherServlet 请求映射配置为 /, 
    则 Spring MVC 将捕获 WEB 容器的所有请求, 包括静态资源的请求, SpringMVC 会将他们当成一个普通请求处理, 
    因找不到对应处理器将导致错误。

    b)解决: 在 SpringMVC 的配置文件中配置 mvc:default-servlet-handler/

  4. 配置后,原来的请求又不好使了
    1
    2
    <!-- 在前端控制器对应的配置文件,增加 -->
    <mvc:annotation-driven />

    关于mvc:default-servlet-handler/作用

mvc:default-servlet-handler/ 将在 SpringMVC 上下文中定义一个 DefaultServletHttpRequestHandler,
它会对进入 DispatcherServlet 的请求进行筛查,如果发现是没有经过映射的请求,
就将该请求交由 WEB 应用服务器默认的 Servlet 处理,如果不是静态资源的请求,才由 DispatcherServlet 继续处理
一般 WEB 应用服务器默认的 Servlet 的名称都是 default。
若所使用的 WEB 服务器的默认 Servlet 名称不是 default,则需要通过 default-servlet-name 属性显式指定
参考:CATALINA_HOME/config/web.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
<servlet>
<servlet-name>default</servlet-name>
<servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
<init-param>
<param-name>debug</param-name>
<param-value>0</param-value>
</init-param>
<init-param>
<param-name>listings</param-name>
<param-value>false</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>

该标签属性default-servlet-name默认值是”default”,可以省略。
mvc:default-servlet-handler/

1
<mvc:default-servlet-handler default-servlet-name="default"/>

通过jQuery转换为DELETE请求

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<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>

Comments

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×