需求说明
某公司有几个部门,每个部门有若干个员工。要求实现添加员工信息,删除员工信息,修改员工信息(lastName字段不可修改),删除员工信息。要求采用REST风格。
准备工作
1.把 hello-world例子实现,确保环境搭建好了;
2.写bean:
public class Department {
private Integer id;
private String departmentName;
public class Employee {
private Integer id;
//@NotEmpty
private String lastName;
//@Email
private String email;
//1 male, 0 female
private Integer gender;
private Department department;
}
3.写dao,模拟持久层
package com.csu.dao;
//2016年12月26日AdministratorDepartmentDao.java
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.stereotype.Repository;
import com.csu.bean.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);
}
}
package com.csu.dao;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import com.csu.bean.Department;
import com.csu.bean.Employee;
//2016年12月26日AdministratorEmployeeDao.java
@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"), null, null));
employees.put(1002, new Employee(1002, "E-BB", "bb@163.com", 1, new Department(102, "D-BB"), null, null));
employees.put(1003, new Employee(1003, "E-CC", "cc@163.com", 0, new Department(103, "D-CC"), null, null));
employees.put(1004, new Employee(1004, "E-DD", "dd@163.com", 0, new Department(104, "D-DD"), null, null));
employees.put(1005, new Employee(1005, "E-EE", "ee@163.com", 1, new Department(105, "D-EE"), null, null));
}
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);
}
}
显示所有员工的信息
1.做页面
做一个表格用来显示。
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>
这里的javascript是为了后面要将POST转PUT用的 ,可以先不要
<script type="text/javascript" src="scripts/jquery-1.9.1.min.js"></script>
<script type="text/javascript">
$(function(){
$(".delete").click(function(){
//alert("click!");
var href = $(this).attr("href");
alert(href);
$("form").attr("action", href).submit();
return false;
});
})
</script>
</head>
<body>
<form action="", method="POST">
<input type="hidden" name="_method" value="DELETE">
</form>
<!-- <a href="helloworld">test hello</a> -->
<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>
<a href="emp">Add New Employee</a>
</body>
</html>
index.jsp
<a href="showList">showList</a>
2.写Handler
EmployeeHandler.class
@RequestMapping("/showList")
public ModelAndView showList() {
ModelAndView modelAndView = new ModelAndView("list");
//添加模型数据到 ModelAndView 中.
modelAndView.addObject("employees", employeeDao.getAll());
//return "list";
return modelAndView;
}
效果
新增一个员工
1.做页面
通过 SpringMVC 的表单标签可以实现将模型数据 中的属性和 HTML 表单元素相绑定,以实现表单数据更便捷编辑和表单值的回显。
1. WHY 使用 form 标签呢 ?
可以更快速的开发出表单页面, 而且可以更方便的进行表单值的回显
2. 注意:
可以通过 modelAttribute 属性指定绑定的模型属性,
若没有指定该属性,则默认从 request 域对象中读取 command 的表单 bean
如果该属性值也不存在,则会发生错误。
报错: Neither BindingResult nor plain target object for bean name 'command' available as request attribute。
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" %>
<%@ 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>
pageContext:${pageContext.request.contextPath }
<form:form action="${pageContext.request.contextPath }/emp" method="POST" **modelAttribute="employee"**>
<c:if test="${employee.id == null }">
lastName: <form:input path="lastName"/><br><br>
</c:if>
<c:if test="${employee.id != null }">
not empty!
<form:hidden path="id"/>
<input type="hidden" name="_method" value="PUT">
</c:if>
email: <form:input path="email"/>
<%
Map<String, String> genders = new HashMap();
genders.put("1", "Male");
genders.put("0", "Female");
request.setAttribute("genders", genders);
%><br><br>
**自动绑定**
Gender:<form:radiobuttons path="gender" items="${genders }" value=""/><br><br>
**因为要显示所有部门供选择,座椅点击新增链接时不能直接到页面,必须由handler获取所有部门之后再转向页面。**
Department:<form:select path="department.id" items="${departments }" itemLabel="departmentName" itemValue="id">
</form:select><br><br>
<%-- Birth: <form:input path="birth"/><br><br>
<br>
Salary: <form:input path="salary"/><br><br>
<br> --%>
<input type="submit" value="Submit"/>
</form:form>
</body>
</html>
2.写handler
@RequestMapping(value="/emp",method=RequestMethod.PUT)
public String save(Employee employee) {
System.out.println(employee);
employeeDao.save(employee);
**一般情况下,控制器方法返回字符串类型的值会被当成逻辑视图名处理,如果返回的字符串中带 forward: 或 redirect: 前缀时,SpringMVC 会对他们进行特殊处理:将 forward: 和
redirect: 当成指示符,其后的字符串作为 URL 来处理
redirect:success.jsp:会完成一个到 success.jsp 的重定向的操作 –forward:success.jsp:会完成一个到 success.jsp 的转发操作**
return "redirect:/showList";
}
修改员工信息
1.回显至编辑页面
<td><a href="emp/${emp.id}">Edit</a></td>
体现rest风格,以前的做法是用问号带参数
@RequestMapping(value="/emp/{id}",method=RequestMethod.GET)
public String input(**@PathVariable("id") Integer id**, Map<String,Object> map) {
System.out.println(id);
Employee employee=employeeDao.get(id);
System.out.println(employee);
map.put("employee", employee);
map.put("departments", departmentDao.getDepartments());
return "input";
}
2.提交修改
可以看到 下面这个方法和新增时用的一毛一样的,但是,新增时用的可是PUT,此处用的POST,另外一个区别,save方法里面可是有区分的哦。
@RequestMapping(value="/emp",method=RequestMethod.POST)
public String save(Employee employee) {
System.out.println(employee);
employeeDao.save(employee);
return "redirect:/showList";
}
public void save(Employee employee){
if(employee.getId() == null){
employee.setId(initId++);
}
employee.setDepartment(departmentDao.getDepartment(employee.getDepartment().getId()));
employees.put(employee.getId(), employee);
}
由于lastName 字段不可修改,所以在修改时页面上没有lastName的框,那么提交到handler的时候,employee的lastaName是空的,如果不做任何处理,直接替换原来那个employee,那么以后这个employee的lastName字段将一直是空的。
解决方案是,先从数据库里根据ID把employee值给满上,模型数据在这个基础上进行填充。
此处可用@ModelAttribute实现,在Handler中加入方法:
@ModelAttribute
public void getEmployee(@RequestParam(value="id",required=false) Integer id, Map<String, Object> map) {
if (id!=null) {
map.put("employee", employeeDao.get(id));
}
}
在请求任何其他handler方法时,都会先执行一下这个方法。
可以看到,该方法传了个id,如果没有写 required=false,并且请求的方法不带id的话,那么会报错。
这样就不担心什么字段是空的了。
删除员工信息
1.需要把GET转POST,POST再转DELETE。(为了优雅的rest 牺牲巨大~)
为实现POST转PUT或者DELETE,必须在web.xml配置:
<!-- 配置 HiddenHttpMethodFilter: 把 POST 请求转为 DELETE、PUT 请求 -->
<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>
<td><a class="delete" href="emp/${emp.id}">Delete</a></td>
<form action="", method="POST">
<input type="hidden" name="_method" value="DELETE">
</form>
<script type="text/javascript">
$(function(){
$(".delete").click(function(){
//alert("click!");
var href = $(this).attr("href");
alert(href);
$("form").attr("action", href).submit();
return false;
});
})
</script>
以上javascript代码需要引用jquery:
<script type="text/javascript" src="scripts/jquery-1.9.1.min.js"></script>
这个库文件属于静态资源,当客户端请求访问该静态资源辅助实现功能时,遇到web.xml里的
<!-- Map all requests to the DispatcherServlet for handling -->
<servlet-mapping>
<servlet-name>springDispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
显然系统把请求静态资源也误以为是请求某一个handler方法,而实际上并没有对应jquery的handler方法,所以会报错。
优雅的 REST 风格的资源URL 不希望带 .html 或 .do 等后缀 •
若将 DispatcherServlet 请求映射配置为 /,则 Spring MVC 将捕获 •
WEB 容器的所有请求,包括静态资源的请求, SpringMVC 会将他
们当成一个普通请求处理,因找不到对应处理器将导致错误。
可以在 SpringMVC 的配置文件中配置
<mvc:annotation-driven></mvc:annotation-driven>
如果不加这一句,静态资源是没问题,但是普通的请求会被玩坏。原因尚不明,待研究。