学习SpringMVC——你们要的REST风格的CRUD来了
来来来,让一下,客官,您要的REST清蒸CRUD来了,火候刚刚好,不油不腻,请慢用~~~
如果说前面是准备调料,洗菜,切菜,摆盘,那么今天就来完整的上道菜,主要说的是基于REST风格实现数据的增删改查(CRUD)操作。
用料
entity:Employee + Department
对于这样的实体类大家肯定很熟悉,一个Employee就是一个员工,一个Department就是一个部门,一个员工只属于一个部门,一个部门可以对应多个员工。
Employee.java
package com.jackie.springmvc.crud.entities; import java.util.Date;
import javax.validation.constraints.Past;
import org.hibernate.validator.constraints.Email;
import org.hibernate.validator.constraints.NotEmpty;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.format.annotation.NumberFormat; public class Employee { private Integer id;
@NotEmpty
private String lastName; @Email
private String email;
//1 male, 0 female
private Integer gender; private Department department; @Past
@DateTimeFormat(pattern="yyyy-MM-dd")
private Date birth; @NumberFormat(pattern="#,###,###.#")
private Float salary; public Integer getId() {
return id;
} public void setId(Integer id) {
this.id = id;
} public String getLastName() {
return lastName;
} public void setLastName(String lastName) {
this.lastName = lastName;
} public String getEmail() {
return email;
} public void setEmail(String email) {
this.email = email;
} public Integer getGender() {
return gender;
} public void setGender(Integer gender) {
this.gender = gender;
} public Department getDepartment() {
return department;
} public void setDepartment(Department department) {
this.department = department;
} public Date getBirth() {
return birth;
} public void setBirth(Date birth) {
this.birth = birth;
} public Float getSalary() {
return salary;
} public void setSalary(Float salary) {
this.salary = salary;
} @Override
public String toString() {
return "Employee [id=" + id + ", lastName=" + lastName + ", email="
+ email + ", gender=" + gender + ", department=" + department
+ ", birth=" + birth + ", salary=" + salary + "]";
} public Employee(Integer id, String lastName, String email, Integer gender,
Department department) {
super();
this.id = id;
this.lastName = lastName;
this.email = email;
this.gender = gender;
this.department = department;
} public Employee() {
// TODO Auto-generated constructor stub
}
}
Department.java
package com.jackie.springmvc.crud.entities; public class Department { private Integer id;
private String departmentName; public Department() {
// TODO Auto-generated constructor stub
} public Department(int i, String string) {
this.id = i;
this.departmentName = string;
} 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;
} @Override
public String toString() {
return "Department [id=" + id + ", departmentName=" + departmentName
+ "]";
} }
dao层:除了entity层,我们还需要有dao层,用于对于entity的增删改查的操作,这里对应的有EmployeeDao和DepartmentDao
EmployeeDao.java
package com.jackie.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.jackie.springmvc.crud.entities.Department;
import com.jackie.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);
}
}
该dao提供了:1. 添加保存一个employee——save方法
2. 获取所有员工信息——getAll方法
3. 根据指定员工id查找员工——get方法
4. 根据指定员工id删除员工——delete方法
DepartmentDao.java
package com.jackie.springmvc.crud.dao; import java.util.Collection;
import java.util.HashMap;
import java.util.Map; import org.springframework.stereotype.Repository; import com.jackie.springmvc.crud.entities.Department; @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);
} }
该dao提供了:1. 查找所有部门信息——getDepartments
2. 根据指定id查找相应的部门信息——getDepartment
另外这里需要用到的所有jar包都在这里
http://pan.baidu.com/s/1qXT180c 提取码:z7q2
用料齐活了, 就开始做菜了,要做的分别是REST清蒸C(添加记录)、REST油炸R(查询记录)、REST红烧U(更新记录)和REST水煮D(删除记录)。
1. 查询记录
这个很简单,跟前几篇介绍的套路差不多,新建一个index.jsp,放入一个用于查询的超链接
<a href="emps">list all employees</a><br/>
相应的在Handler中需要添加映射支持,这里新建一个EmployeeHandler类
package com.jackie.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 org.springframework.web.bind.annotation.RequestMethod;
import com.jackie.springmvc.crud.dao.EmployeeDao; @Controller
public class EmployeeHandler { @Autowired
private EmployeeDao employeeDao; @RequestMapping("/emps")
public String list(Map<String, Object> map){
map.put("employees", employeeDao.getAll());
return "list";
} }
注意:
这里RequestMapping中没有指明RequestMethod的请求类型,默认是GET方式。
最终我们需要将查询的数据解析出来放到页面上,这个页面就是list.jsp
<%@ 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.employees}">
没有员工信息
</c:if>
<c:if test="${!empty requestScope.employees }">
<table border="1" cellpadding="10" cellspacing="0">
<tr>
<th>ID</th>
<th>LastName</th>
<th>Email</th>
<th>Gender</th>
<th>Department</th>
<th>Edit</th>
<th>Delete</th>
</tr> <c:forEach items="${requestScope.employees }" var="emp">
<tr>
<td>${emp.id }</td>
<td>${emp.lastName }</td>
<td>${emp.email }</td>
<td>${emp.gender==0?'Female':'Male' }</td>
<td>${emp.department.departmentName }</td>
<td><a href="emp/${emp.id}">Edit</a></td>
<td><a class="delete" href="emp/${emp.id}">Delete</a></td>
</tr>
</c:forEach>
</table>
</c:if>
<br><br>
</body>
</html>
这里通过表格的方式显示,表格的每一行显示一个员工记录。
如果Handler层没有传入employee,则显示“没有员工信息”。
如果从Handler层传入查询到的employee的信息,则通过遍历的方式查询每条记录并显示在对应的表格中。
结果如下:
这里查询了所有的员工信息,为简便起见,这里的员工信息并不是从数据库中读取的,而是在EmployeeDao中通过静态模块声明构造的,将每个员工信息放入一个map集合中。
2. 添加记录
添加记录即在原有的数据集合基础上,再新建一个员工信息,我们需要为员工的每个属性填充值,所以我们需要一个页面来为这些字段赋值,这个页面就叫input.jsp。
添加员工信息的入口链接就放在list.jsp中
<a href = "emp">add new employee</a><br/>
同时在EmployeeHandler中添加映射
@RequestMapping(value="/emp", method=RequestMethod.GET)
public String input(Map<String, Object> map){
map.put("departments", departmentDao.getDepartments());
map.put("employee", new Employee());
return "input";
}
input.jsp
<%@page import="java.util.HashMap"%>
<%@page import="java.util.Map"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ 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>
<form:form action="emp" method="POST" modelAttribute="employee">
<!-- path 属性对应html表单标签的name属性 -->
LastName: <form:input path="lastName"></form:input><br>
Email:<form:input path="email"></form:input><br>
<%
Map<String, String> genders = new HashMap<String, String>();
genders.put("1", "male");
genders.put("0", "female");
request.setAttribute("genders", genders);
%>
Gender:<form:radiobuttons path="gender" items="${genders }"/><br>
Department:<form:select path="department.id" items="${departments }" itemLabel="departmentName" itemValue="id"></form:select><br>
<input type="submit" value="Submit"/>
</form:form> </body>
</html>
先不看代码,至此你就能看到这样的效果:
到这里还没完,我们还需要写一个保存的handler接口,在EmployeeHandler.java中
@RequestMapping(value="/emp", method=RequestMethod.POST)
public String save(Employee employee){
employeeDao.save(employee);
return "redirect:/emps";
}
主要实现将新建的员工记录保存到employee集合中。
这样我们就能够成功的添加一条记录了
注意:
这里有几个问题需要声明
(1). 为什么使用form标签:可以更快速开发表单页面,而且可以方便的进行表单值的回显
(2) 为什么要在EmployeeHandler类中添加map.put("employee", employee),并且在input.jsp页面的form:form标签中添加modelAttribute="employee"
如果没有这样的声明代码,在运行中会出现报错信息如下:
HTTP Status 500 - An exception occurred processing JSP page /WEB-INF/views/input.jsp at line 23
type Exception report
message An exception occurred processing JSP page /WEB-INF/views/input.jsp at line 23
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/input.jsp at line 23 20: -->
21: <form:form action="emp" method="POST">
22: <!-- path 灞炴�у搴攈tml琛ㄥ崟鏍囩鐨刵ame灞炴�� -->
23: LastName: <form:input path="lastName"></form:input><br>
24: Email:<form:input path="email"></form:input><br>
25: <%
26: Map<String, String> genders = new HashMap<String, String>(); Stacktrace:
org.apache.jasper.servlet.JspServletWrapper.handleJspException(JspServletWrapper.java:574)
org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:471)
org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:396)
org.apache.jasper.servlet.JspServlet.service(JspServlet.java:340)
javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
org.springframework.web.servlet.view.InternalResourceView.renderMergedOutputModel(InternalResourceView.java:209)
org.springframework.web.servlet.view.AbstractView.render(AbstractView.java:267)
org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1221)
org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:1005)
org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:952)
org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:870)
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:961)
org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:852)
javax.servlet.http.HttpServlet.service(HttpServlet.java:622)
org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:837)
javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:77)
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
root cause
java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'command' available as request attribute
org.springframework.web.servlet.support.BindStatus.<init>(BindStatus.java:144)
org.springframework.web.servlet.tags.form.AbstractDataBoundFormElementTag.getBindStatus(AbstractDataBoundFormElementTag.java:168)
org.springframework.web.servlet.tags.form.AbstractDataBoundFormElementTag.getPropertyPath(AbstractDataBoundFormElementTag.java:188)
org.springframework.web.servlet.tags.form.AbstractDataBoundFormElementTag.getName(AbstractDataBoundFormElementTag.java:154)
org.springframework.web.servlet.tags.form.AbstractDataBoundFormElementTag.autogenerateId(AbstractDataBoundFormElementTag.java:141)
org.springframework.web.servlet.tags.form.AbstractDataBoundFormElementTag.resolveId(AbstractDataBoundFormElementTag.java:132)
org.springframework.web.servlet.tags.form.AbstractDataBoundFormElementTag.writeDefaultAttributes(AbstractDataBoundFormElementTag.java:116)
org.springframework.web.servlet.tags.form.AbstractHtmlElementTag.writeDefaultAttributes(AbstractHtmlElementTag.java:422)
org.springframework.web.servlet.tags.form.InputTag.writeTagContent(InputTag.java:142)
org.springframework.web.servlet.tags.form.AbstractFormTag.doStartTagInternal(AbstractFormTag.java:84)
org.springframework.web.servlet.tags.RequestContextAwareTag.doStartTag(RequestContextAwareTag.java:80)
org.apache.jsp.WEB_002dINF.views.input_jsp._jspx_meth_form_005finput_005f0(input_jsp.java:244)
org.apache.jsp.WEB_002dINF.views.input_jsp._jspService(input_jsp.java:168)
org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)
javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:438)
org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:396)
org.apache.jasper.servlet.JspServlet.service(JspServlet.java:340)
javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
org.springframework.web.servlet.view.InternalResourceView.renderMergedOutputModel(InternalResourceView.java:209)
org.springframework.web.servlet.view.AbstractView.render(AbstractView.java:267)
org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1221)
org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:1005)
org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:952)
org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:870)
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:961)
org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:852)
javax.servlet.http.HttpServlet.service(HttpServlet.java:622)
org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:837)
javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:77)
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
note The full stack trace of the root cause is available in the Apache Tomcat/8.0.36 logs.
于是在handler中将employee放入map集合中,此时运行,仍然报错
HTTP Status 500 - java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'command' available as request attribute
type Exception report
message java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'command' available as request attribute
description The server encountered an internal error that prevented it from fulfilling this request.
exception
org.apache.jasper.JasperException: java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'command' available as request attribute
org.apache.jasper.servlet.JspServletWrapper.handleJspException(JspServletWrapper.java:555)
org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:471)
org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:396)
org.apache.jasper.servlet.JspServlet.service(JspServlet.java:340)
javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
org.springframework.web.servlet.view.InternalResourceView.renderMergedOutputModel(InternalResourceView.java:209)
org.springframework.web.servlet.view.AbstractView.render(AbstractView.java:267)
org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1221)
org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:1005)
org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:952)
org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:870)
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:961)
org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:852)
javax.servlet.http.HttpServlet.service(HttpServlet.java:622)
org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:837)
javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:77)
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
root cause
java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'command' available as request attribute
org.springframework.web.servlet.support.BindStatus.<init>(BindStatus.java:144)
org.springframework.web.servlet.tags.form.AbstractDataBoundFormElementTag.getBindStatus(AbstractDataBoundFormElementTag.java:168)
org.springframework.web.servlet.tags.form.AbstractDataBoundFormElementTag.getPropertyPath(AbstractDataBoundFormElementTag.java:188)
org.springframework.web.servlet.tags.form.AbstractDataBoundFormElementTag.getName(AbstractDataBoundFormElementTag.java:154)
org.springframework.web.servlet.tags.form.AbstractDataBoundFormElementTag.autogenerateId(AbstractDataBoundFormElementTag.java:141)
org.springframework.web.servlet.tags.form.AbstractDataBoundFormElementTag.resolveId(AbstractDataBoundFormElementTag.java:132)
org.springframework.web.servlet.tags.form.AbstractDataBoundFormElementTag.writeDefaultAttributes(AbstractDataBoundFormElementTag.java:116)
org.springframework.web.servlet.tags.form.AbstractHtmlElementTag.writeDefaultAttributes(AbstractHtmlElementTag.java:422)
org.springframework.web.servlet.tags.form.InputTag.writeTagContent(InputTag.java:142)
org.springframework.web.servlet.tags.form.AbstractFormTag.doStartTagInternal(AbstractFormTag.java:84)
org.springframework.web.servlet.tags.RequestContextAwareTag.doStartTag(RequestContextAwareTag.java:80)
org.apache.jsp.WEB_002dINF.views.input_jsp._jspx_meth_form_005finput_005f0(input_jsp.java:244)
org.apache.jsp.WEB_002dINF.views.input_jsp._jspService(input_jsp.java:168)
org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)
javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:438)
org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:396)
org.apache.jasper.servlet.JspServlet.service(JspServlet.java:340)
javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
org.springframework.web.servlet.view.InternalResourceView.renderMergedOutputModel(InternalResourceView.java:209)
org.springframework.web.servlet.view.AbstractView.render(AbstractView.java:267)
org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1221)
org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:1005)
org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:952)
org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:870)
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:961)
org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:852)
javax.servlet.http.HttpServlet.service(HttpServlet.java:622)
org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:837)
javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:77)
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
note The full stack trace of the root cause is available in the Apache Tomcat/8.0.36 logs.
这时候在form:form中加入modelAttribute="employee",再次运行,就能够成功添加记录了。
这是为什么呢,因为表单在显示的时候会做一个检查,如果表单的字段在request的bean中不能一一对应,就会无法显示并报错,说白了就是这里加上了employee这个bean后,这个对象中的各个属性如email、gender和表单上的字段都能够对应起来了,校验通过,就能正常添加保存了。
注意input.jsp中modelAttribute的值要和handler中放进map集合的key值一致,默认在页面上这个modelAttribute的值为command,所以你会看到报错信息中频繁的出现command。
(3). <form:radiobuttons>这个标签中有一下属性:
items:存放具体的数据集合,可以是String、Map或List类型
itemValue:指定radio的value值,可以使集合中bean的一个属性值
itemLabel:radio的label值
3. 删除记录
其实从前面的list.jsp的表格中已经看出来了,在每条记录后面都有一个DELETE选项,用于删除该项记录,那么具体怎么实现
这里首先要该Delete项对应的href,在list.jsp中
<td><a href="emp/${emp.id}">Delete</a></td>
我们将href的值赋值为一个请求路径,显然我们需要在handler中添加映射处理:
@RequestMapping(value="/emp/{id}", method=RequestMethod.DELETE)
public String delete(@PathVariable("id") Integer id){
employeeDao.delete(id);
return "redirect:/emps";
}
删除完记录后重定向到emps即list.jsp页面。
效果如下
注意:
(1). 这里要明白,实际上我们在页面上发送的是一个rest的delete请求,但是通过<a href>的超链接方式我们只能发送get请求,而且前面我们说过,对于form来说只能发get和post请求,如果要发delete和put,则需要伪装成post请求,再在handler处理类中进行解析处理。
对于这个问题,我们想到了jquery,于是引入jquery库到WebContent/scripts目录下,版本是1.9.1
首先需要一个form表单,因为无可厚非,只有表单才能提交post请求
<form action="" method="POST">
<input type="hidden" name="_method" value="DELETE"/>
</form>
在list.jsp中引入jquery库
<script type="text/javascript" src="scripts/jquery-1.9.1.min.js"></script>
在delete对应的<a>中加入class=“delete”,方便后面使用jquery进行元素定位
写入功能实现代码:
<script type="text/javascript">
$(function(){
$(".delete").click(function(){
var href = $(this).attr("href");
$("form").attr("action", href).submit();
return false;
});
})
</script>
这段代码的意思无非就是:找到delete删除元素,提取器href属性值,并将其赋给新添加的form表单中,当点击超链接后相当于提交form,并移交给定义好的hanlder接口。
(2). 又要啰嗦下,对于静态资源来说,因为我们在web.xml中声明spring是拦截了所有请求,所以对于静态资源我们也统统招收,拦截不误,但是显然我们没有与这个静态资源对应的映射,也就是说spring拦截下来了,却没有能力处理,这里介绍在springmvc.xml中添加两个标签就能解决问题
<mvc:default-servlet-handler/>
<mvc:annotation-driven></mvc:annotation-driven>
在前面的章节中有介绍过其他的方法,就是在web.xml中声明各种静态资源的支持,比较繁琐傻瓜点^^
(3). 为什么添加了这个<mvc:default-servlet-handler/>就能解决问题:
Default-servlet-handler将在SpringMVC上下文中定义一个DefaultServletHttpRequestHandler,它会对进入DispatcherServlet的请求进行筛查,如果发现是没有经过映射的请求,就将该请求交由WEB应用服务器默认的Servlet处理。如果不是静态资源的请求,才由DispatcherServlet继续处理。
一般WEB应用服务器默认的Servlet的名称都是default,若所使用的WEB服务器的默认Serlvet名称不是default,则需要通过default-servlet-name属性显示指定。
这里的小问题比较多,不知道你晕了没,但是到目前为止,好像一个简易的框架就有了,有了后台的java,还有模板jsp技术,以及对于dom操作的Jquery,当然我们还少了一个真正的数据库。
4. 更新记录
更新操作实际上是分为两步:查找要修改的记录 + 修改记录并保存
(1). 查找记录
通过get方式映射到emp/${id}
与delete选项类似,在list.jsp改为
<td><a href="emp/${emp.id}">Edit</a></td>
同时在Handler添加相应映射
@RequestMapping(value="/emp/{id}", method=RequestMethod.GET)
public String input(@PathVariable("id") Integer id, Map<String, Object> map){
map.put("employee", employeeDao.get(id));
map.put("departments", departmentDao.getDepartments());
return "input";
}
这样就可以定位到选中的employee对象上,并跳转到input.jsp界面上。
(2). 修改并保存
这里要说清楚,进入input.jsp页面会有两种情况,一种是添加一条Employee记录,二是修改一条Employee记录,而且我们从前面的界面可以看出我们并不修改LastName这个字段,那我们如果让input.jsp具有辨识是从添加记录那还是修改记录那跳转过来的呢,于是我们需要在input.jsp中加入判断
<c:if test="${employee.id == null }">
<!-- path 属性对应 html 表单标签的 name 属性值 -->
LastName: <form:input path="lastName" />
<form:errors path="lastName"></form:errors>
</c:if>
<c:if test="${employee.id != null }">
<form:hidden path="id" />
<input type="hidden" name="_method" value="PUT" />
</c:if>
如果传过来的employee中id存在,那说明是修改更新,如果为空,说明是新建一条记录。
同时,老套路,这里还是利用隐藏域hidden来发送一个put请求到handler
在EmployeeHandler中
@ModelAttribute
public void getEmployee(@RequestParam(value="id",required=false) Integer id,
Map<String, Object> map){
if(id != null){
map.put("employee", employeeDao.get(id));
}
} @RequestMapping(value="/emp", method=RequestMethod.PUT)
public String update(Employee employee){
employeeDao.save(employee);
return "redirect:/emps";
}
之所以这里有ModelAttribute前篇已经说过,如果没有话,更新完后这个LastName字段就会为空。
最终效果如下:
至此,我们学习了:
1. 基于REST风格查询记录
2. 基于REST风格添加记录
3. 基于REST风格删除记录
4. 基于REST风格更新记录
5. 引入JQuery改变请求方式
6. 明白了Request中bean必须要和请求表单中的属性对应
如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮,您的“推荐”将是我最大的写作动力!如果您想持续关注我的文章,请扫描二维码,关注JackieZheng的微信公众号,我会将我的文章推送给您,并和您一起分享我日常阅读过的优质文章。
学习SpringMVC——你们要的REST风格的CRUD来了的更多相关文章
- 学习SpringMVC——如何获取请求参数
@RequestParam,你一定见过:@PathVariable,你肯定也知道:@QueryParam,你怎么会不晓得?!还有你熟悉的他(@CookieValue)!她(@ModelAndView) ...
- SpringMVC(三)Restful风格及实例、参数的转换
个人博客网:https://wushaopei.github.io/ (你想要这里多有) 一.Restful风格 1.Restful风格的介绍 Restful 一种软件架构风格.设计风格,而不是 ...
- 8.springMVC中的RESTful架构风格
RESTful架构:是一种设计的风格,并不是标准,只是提供了一组设计原则和约束条件,也是目前比较流行的一种互联网软件架构.它结构清晰.符合标准.易于理解.扩展方便,所以正得到越来越多网站的采用. 关于 ...
- 2.学习SpringMVC注解入门篇
一.SpringMVC执行流程 . 二.创建项目学习SpringMVC注解 按照我之前的SpringMVC创建项目,首先创建一个项目springmvc01,配置好pom.xml,web.xml,spr ...
- 萌新学习SpringMVC
前言 只有光头才能变强. 文本已收录至我的GitHub精选文章,欢迎Star:https://github.com/ZhongFuCheng3y/3y 这篇SpringMVC被催了很久了,这阵子由于做 ...
- java框架之SpringBoot(6)-Restful风格的CRUD示例
准备 环境 IDE:Idea SpringBoot版本:1.5.19 UI:BootStrap 4 模板引擎:thymeleaf 3 效果:Restful 风格 CRUD 功能的 Demo 依赖 &l ...
- Elasticsearch7.X 入门学习第二课笔记----基本api操作和CRUD
原文:Elasticsearch7.X 入门学习第二课笔记----基本api操作和CRUD 版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链 ...
- 学习SpringMVC中优秀的代码编写风格
在org.springframework.web.servlet.FrameworkServlet 中有下面这段代码 private class ContextRefreshListener impl ...
- 3.学习SpringMVC注解深入
一.SpringMVC注解: 1.RequestParam注解: 其中required属性默认为true(必须得传而且传的名字一样),为false时可以不传. 编写jsp代码: <a href= ...
随机推荐
- 0-1背包问题蛮力法求解(java版本)
sloves: package BackPack; public class Solves { public int[] DecimaltoBinary(int n,int m) { int ...
- 4.Windows Server2012 R2里面部署 MVC 的网站
网站部署之~Windows Server | 本地部署:http://www.cnblogs.com/dunitian/p/4822808.html#iis 后期会在博客首发更新:http://dnt ...
- Android调用微信登陆、分享、支付
前言:用了微信sdk各种痛苦,感觉比qq sdk调用麻烦多了,回调过于麻烦,还必须要在指定包名下的actvity进行回调,所以我在这里写一篇博客,有这个需求的朋友可以借鉴一下,以后自己别的项目有用到也 ...
- 浅谈 LayoutInflater
浅谈 LayoutInflater 版权声明:本文为博主原创文章,未经博主允许不得转载. 微博:厉圣杰 源码:AndroidDemo/View 文中如有纰漏,欢迎大家留言指出. 在 Android 的 ...
- AbpZero--2.如何启动
1.直接启动 VS中直接启动 2.IIS站点 IIS中配置一个站点来启动(推荐) 3.登录 系统默认创建2个用户 默认用户名:admin 密码:123qwe 租户:Default 默认用户名:adm ...
- 免费公开课,讲解强大的文档集成组件Aspose,现在可报名
课程①:Aspose.Total公开课内容:讲解全能型文档管理工具Aspose.Total主要功能及应用领域时间:2016-11-24 14:30 (暂定)报名地址:http://training.e ...
- Android的Kotlin秘方(I):OnGlobalLayoutListener
春节后,又重新“开张”.各位高手请继续支持.谢谢! 原文标题:Kotlin recipes for Android (I): OnGlobalLayoutListener 原文链接:http://an ...
- 开源 iOS 项目分类索引大全 - 待整理
开源 iOS 项目分类索引大全 GitHub 上大概600个开源 iOS 项目的分类和介绍,对于你挑选和使用开源项目应该有帮助 系统基础库 Category/Util sstoolkit 一套Cate ...
- 跟着老男孩教育学Python开发【第四篇】:模块
双层装饰器示例 __author__ = 'Golden' #!/usr/bin/env python # -*- coding:utf-8 -*- USER_INFO = {} def ch ...
- Linux课堂笔记(一)
一.Linux应用领域及版本介绍. 1.服务器.嵌入式.桌面应用等. (1)在服务器领域中,需要安全和稳定,特别是越老的内核版本越安全.越稳定. (2)Linux主要分内核版和发行版. 内核版本2.6 ...