RESTRUL_CRUD
- RESTRUL_CRUD_需求
- 显示所有员工信息
- URI:emps
- 请求方式:GET
- 显示效果
- 添加员工信息
- 显示添加页面:
- URI:emp
- 请求方式:GET
- 显示效果
- 添加员工信息:
- URI:emp
- 请求方式:POST
- 显示效果:完成添加,重定向到 list 页面。
- 删除操作
- URL:emp/{id}
- 请求方式:DELETE
- 删除后效果:对应记录从数据表中删除
- 修改操作:lastName 不可修改!
- 显示修改页面
- URI:emp/{id}
- 请求方式:GET
- 显示效果:回显表单。
- 修改员工信息
- URI:emp
- 请求方式:PUT
- 显示效果:完成修改,重定向到 list 页面。
- 相关的类
省略了Service层,为了教学方便
- 实体类:Employee、Department
- Handler:EmployeeHandler
- Dao:EmployeeDao、DepartmentDao
- 相关的页面
- list.jsp
- input.jsp
- edit.jsp
- RESTRUL_CRUD_显示所有员工信息
- 搭建开发环境
- 拷贝jar包
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 |
-
- 创建配置文件:springmvc.xml 增加context,mvc,beans名称空间。
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<!-- 配置扫描的包:com.sirius.springmvc.crud --> <context:component-scan base-package="com.sirius.springmvc"/>
<!-- 配置视图解析器:默认采用转发 --> <bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/views/"/> <property name="suffix" value=".jsp"></property> </bean> </beans> |
-
- 配置核心控制器:web.xml
<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> <servlet-mapping> <servlet-name>springDispatcherServlet</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> |
-
- 将 POST 请求转换为 PUT 或 DELETE 请求
<filter> <filter-name>HiddenHttpMethodFilter</filter-name> <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class> </filter> <filter-mapping> <filter-name>HiddenHttpMethodFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> |
-
- 创建相关页面
/WEB-INF/views/list.jsp
index.jsp
-
- 增加实体类
|
|
-
- 增加DAO类
package com.sirius.springmvc.crud.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 com.sirius.springmvc.crud.entities.Department; import com.sirius.springmvc.crud.entities.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); } } | package com.sirius.springmvc.crud.dao;
import java.util.Collection; import java.util.HashMap; import java.util.Map;
import org.springframework.stereotype.Repository;
import com.sirius.springmvc.crud.entities.Department;
@Repository public class DepartmentDao {
private static Map<Integer, Department> departments = null;
static{ departments = new LinkedHashMap<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); }
} |
- 显示所有员工信息
- 增加页面链接
<a href="empList">To Employee List</a> |
-
- 增加处理器
package com.sirius.springmvc.crud.handlers;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping;
import com.sirius.springmvc.crud.dao.EmployeeDao;
@Controller public class EmployeeHandler {
@Autowired private EmployeeDao employeeDao ;
@RequestMapping("/empList") public String empList(Map<String,Object> map){ map.put("empList", employeeDao.getAll()); //默认存放到request域中 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> |
- RESTRUL_CRUD_添加操作&表单标签
- 在list.jsp上增加连接
<a href="empInput">Add Employee</a> |
- 增加处理器方法
@RequestMapping(value="/empInput",method=RequestMethod.GET) public String empInput(Map<String,Object> map){ map.put("deptList", departmentDao.getDepartments()); //解决错误:java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'command' available as request attribute Employee employee = new Employee(); //map.put("command", employee); map.put("employee", employee); return "add"; } |
- 显示添加页面
<%@ 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> |
- 显示表单信息时,会报错:
HTTP Status 500 -
type Exception report message description The server encountered an internal error () that prevented it from fulfilling this request. exception org.apache.jasper.JasperException: An exception occurred processing JSP page /WEB-INF/views/add.jsp at line 18 15: ② 表单回显 Stacktrace: root cause java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'command' available as request attribute |
- 使用 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” /> :显示特定表单对象属性的错误
- 添加员工实验代码
- 表单
<%@ 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> |
- 控制器方法
@Controller public class EmployeeHandler { @RequestMapping(value="/empAdd",method=RequestMethod.POST) public String empAdd(Employee employee){ employeeDao.save(employee); return "redirect:/empList"; } } |
- RESTRUL_CRUD_删除操作&处理静态资源
- 删除实验代码
- 页面链接
<td><a href="/empDelete/${emp.id }">Delete</a></td> |
- 控制器方法
@RequestMapping(value="/empDelete/{id}" ,method=RequestMethod.DELETE) public String empDelete(@PathVariable("id") Integer id){ employeeDao.delete(id); return "redirect:/empList"; } |
- HiddenHttpMethodFilter过滤器
- 发起请求,无法执行,因为delete请求必须通过post请求转换为delete请求,借助:HiddenHttpMethodFilter过滤器
- 需要使用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' |
|
- 解决办法,SpringMVC 处理静态资源
SpringMVC 处理静态资源:
-
- 为什么会有这样的问题:
优雅的 REST 风格的资源URL 不希望带 .html 或 .do 等后缀
若将 DispatcherServlet 请求映射配置为 /,
则 Spring MVC 将捕获 WEB 容器的所有请求, 包括静态资源的请求, SpringMVC 会将他们当成一个普通请求处理,
因找不到对应处理器将导致错误。
-
- 解决: 在 SpringMVC 的配置文件中配置 <mvc:default-servlet-handler/>
- 配置后,原来的请求又不好使了
需要配置<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 <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/> --> <mvc:default-servlet-handler default-servlet-name="default"/> |
- 通过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> |
- 删除操作流程图解
- RESTRUL_CRUD_修改操作
- 根据id查询员工对象,表单回显
- 页面链接
<td><a href="empEdit/${emp.id }">Edit</a></td> |
- 控制器方法
//修改员工 - 表单回显 @RequestMapping(value="/empEdit/{id}",method=RequestMethod.GET) public String empEdit(@PathVariable("id") Integer id,Map<String,Object> map){ map.put("employee", employeeDao.get(id)); map.put("deptList",departmentDao.getDepartments()); 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.sirius.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> |
- 提交表单,修改数据
- 控制器方法
@RequestMapping(value="/empUpdate",method=RequestMethod.PUT) public String empUpdate(Employee employee){ employeeDao.save(employee); //用户名称不需要修改,会被置空 return "redirect:/empList"; } @ModelAttribute public void getEmployee( @RequestParam(value="id",required=false) Integer id,Map<String,Object> map){ if(id!=null){ map.put("employee", employeeDao.get(id)); } } |