SpringMVC——使用REST风格实现RESTRUL_CRUD

一、RESTRUL_CRUD_需求

1.1 效果页面介绍

  1. 显示所有员工信息

    URI:emps
    请求方式:GET
    显示效果:
    在这里插入图片描述

  2. 添加员工信息

    • 显示添加页面:
      URI:emp
      请求方式:GET
      显示效果:
      在这里插入图片描述
    • 添加员工信息:
      URI:emp
      显示效果:完成添加,重定向到 list 页面。
      在这里插入图片描述
  3. 删除操作

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

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

    • 显示修改页面
      URI:emp/{id}
      请求方式:GET
      显示效果:回显表单。
    • 修改员工信息
      URI:emp
      请求方式:PUT
      显示效果:完成修改,重定向到 list 页面。
      在这里插入图片描述

2.2 CRUD分析

  1. 项目结构: 在这里插入图片描述

  2. 相关的类:(省略了Service层,为了教学方便)

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

    EmployeeDao:

    /**
     * 操作员工的Dao
     */
    @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", "[email protected]", 1, new Department(101, "D-AA")));
    		employees.put(1002, new Employee(1002, "E-BB", "[email protected]", 1, new Department(102, "D-BB")));
    		employees.put(1003, new Employee(1003, "E-CC", "[email protected]", 0, new Department(103, "D-CC")));
    		employees.put(1004, new Employee(1004, "E-DD", "[email protected]", 0, new Department(104, "D-DD")));
    		employees.put(1005, new Employee(1005, "E-EE", "[email protected]", 1, new Department(105, "D-EE")));
    	}
    	
    	private static Integer initId = 1006;
    	
    	/**
    	 * 员工保存/更新二合一方法
    	 * @param employee
    	 */
    	public void save(Employee employee){
          
          
    		if(employee.getId() == null){
          
          
    			employee.setId(initId++);
    		}
    		
    		employee.setDepartment(departmentDao.getDepartment(employee.getDepartment().getId()));
    		employees.put(employee.getId(), employee);
    	}
    	
    	/**
    	 * 查询所有员工
    	 * @return
    	 */
    	public Collection<Employee> getAll(){
          
          
    		return employees.values();
    	}
    	
    	/**
    	 * 按照id查询某个员工
    	 * @param id
    	 * @return
    	 */
    	public Employee get(Integer id){
          
          
    		return employees.get(id);
    	}
    	
    	/**
    	 * 删除员工
    	 * @param id
    	 */
    	public void delete(Integer id){
          
          
    		employees.remove(id);
    	}
    }
    

    DepartmentDao:

    /**
     * 操作部门的dao
     */
    @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"));
    	}
    	
    	/**
    	 * 返回所有的部门
    	 * @return
    	 */
    	public Collection<Department> getDepartments(){
          
          
    		return departments.values();
    	}
    	
    	/**
    	 * 按照部门id查询部门
    	 * @param id
    	 * @return
    	 */
    	public Department getDepartment(Integer id){
          
          
    		return departments.get(id);
    	}
    }
    

    web.xml配置(前端控制器、字符编码过滤器和HiddenHttpMethodFilter过滤器)

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
      <display-name>06_SpringMVC_crud</display-name>
      
      	<!-- 配置前端控制器 -->
    	<servlet>
    		<servlet-name>springmvc</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>springmvc</servlet-name>
    		<url-pattern>/</url-pattern>
    	</servlet-mapping>
    	
    	<!-- 配置字符编码过滤器 -->
    	<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>
    	
    	<!-- 支持Rest风格转换的filter -->
    	<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-app>
    
  3. URUD地址分析:

     增删改查的URL地址;       /资源名/资源标识
     /emp/1          GET:查询id为1的员工
     /emp/1          PUT:更新id为1的员工
     /emp/1          DELETE:删除id为1的员工
     /emp             POST:新增员工;
     /emps           GET:查询所有员工
    

二、RESTRUL_CRUD_显示所有员工信息

  • 显示所有员工信息流程:

    访问index.jsp----直接发送/emps------控制器查询所有员工------放在请求域中-----转发到list页面展示

index.jsp页面:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
    
<!-- 访问项目就要展示员工列表页面 -->
<jsp:forward page="/emps"></jsp:forward>

控制器方法:

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

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>
<%
	pageContext.setAttribute("ctp", request.getContextPath());
%>


<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>员工列表页面</title>
<script type="text/javascript" src="${ctp }/script/jquery-1.7.2.js"></script>
</head>
<body>
<h1>员工列表</h1>
<table border="1" cellpadding="5" 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.emps }" var="emp">
		<tr>
			<td>${emp.id }</td>
			<td>${emp.lastName }</td>
			<td>${emp.email }</td>
			<td>${emp.gender==1?'Male':'Female' }</td>
			<td>${emp.department.departmentName }</td>
			<td><a href="${ctp }/emp/${emp.id}">Edit</a></td>
			<td><!-- 为删除按钮添加点击事件 -->
				<a href="${ctp }/emp/${emp.id}" class="deleteBtn">DELETE</a>
			</td>
		</tr>
	</c:forEach>
</table>
<form id="deleteForm" action="${ctp }/emp/${emp.id}" method="POST">
	<input type="hidden" name="_method" value="DELETE"/>
</form>
<script type="text/javascript">
	$(function(){
     
     
		$(".deleteBtn").click(function(){
     
     
			//1、改变表单的action指向
			$("#deleteForm").attr("action",this.href);
			//2、提交表单
			$("#deleteForm").submit();
			return false;
		}); 
	});
</script>

<a href="${ctp }/toAddpage" >添加员工</a>

</body>
</html>

三、RESTRUL_CRUD_添加操作(使用Spring的表单标签)(重点)

3.1 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” /> :显示特定表单对象属性的错误

3.2 添加操作

  • 员工添加流程:

    在list页面点击“”员工添加“”----(查询出所有的部门信息要展示在页面)----来到添加页面(add.jsp)--------输入员工数据--------点击保存(/emp )------处理器收到员工保存请求(保存员工)--------保存完成以后还是来到列表页面;

  1. 在list.jsp上增加连接

    <a href="toAddPage">Add Employee</a>
    
  2. 处理器方法:

    /**
     * 去员工添加页面,去页面之前需要查出所有部门信息,进行展示
     * @return
     */
    @RequestMapping("/toAddpage")
    public String toAddPage(Model model){
          
          
    	//查询所有部门信息
    	Collection<Department> departments = departmentDao.getDepartments();
    	model.addAttribute("deps", departments);
    	//向请求域中传入一个employee对象,SpringMVC的表单标签会从请求域中读取该对象。(默认读取叫command对象)
    	model.addAttribute("employee", new Employee());
    //		model.addAttribute("command", new Employee(1009,"zhangsan","[email protected]",1,null));
    	return "add";
    }
    
  3. 添加add.jsp页面(使用Spring的表单标签)

    要使用Spring MVC提供的表单标签,首先需要在视图页面添加:

    <%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
    

    add.jsp页面:

    <%@ page language="java" contentType="text/html; charset=UTF-8"
        pageEncoding="UTF-8"%>
    <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
    <%@ 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>
    	<h1>员工添加</h1>
    <!-- 
    表单标签; 
    	通过 SpringMVC的表单标签可以实现将模型数据中的属性和 HTML 表单元素相绑定,
    	以实现表单数据更便捷编辑和表单值的回显
    	1)、SpringMVC认为,表单数据中的每一项最终都是要回显的;
    		path指定的是一个属性;这个属性是从隐含模型(请求域中取出的某个对象中的属性);
    		path指定的每一个属性,请求域中必须有一个对象,拥有这个属性;
    				这个对象就是请求域中的command;
    -->
    <!-- 
    	2.可以通过modelAttribute指定绑定的模型属性,
    	若没有指定该属性,则默认从request域中查找command的表单的bean
    	如果该属性也不存在,那么,则会发生错误。
     -->
    <%
    	pageContext.setAttribute("ctp", request.getContextPath());//使用绝对路径
    %>
    <form:form action="${ctp }/emp" method="post" modelAttribute="employee">
    	<!-- path就是原来html-input的name项:需要写 
    		path:
    			1)、当做原生的name项
    			2)、自动回显隐含模型中某个对象对应的这个属性的值
    	-->
    	lastName:<form:input path="lastName"/><br/>
    	email:<form:input path="email"/><br/>
    	gender:
    		<form:radiobutton path="gender" value="1"/>Male
    		<form:radiobutton path="gender" value="0"/>FeMale<br/>
    	department:
    		<!-- 
    			items="":指定要遍历的集合 ;自动遍历;遍历出的每一个元素是一个department对象
    			itemLabel="属性名":指定遍历出的这个对象的哪个属性是作为option标签体的值
    			itemValue="属性名":指定刚才遍历出来的这个对象的哪个属性是作为要提交 的value值
    		 -->
    		<form:select path="department.id" 
    		items="${requestScope.deps }" 
    		itemLabel="departmentName" 
    		itemValue="id"></form:select><br/>
    	<input type="submit" value="Submit"/>
    </form:form>
    	
    	
    	
    <%-- 使用原始的表单标签
    <form action="emp" method="post">
    	LastName:<input type="text" name="lastName"/><br/>
    	Email:<input type="text" name="email"/><br/>
    	Gender:<input type="radio" name="gender" value="1"/>Male<input type="radio" name="gender" value="0"/>Female<br/>
    	Department:
    	<select name="department.id">
    		<c:forEach items="#{requestScope.deps }" var="dep">
    			<option value="${dep.id }">${dep.departmentName}</option>
    		</c:forEach>
    	</select><br/>
    	<input type="submit" value="Submit"/>
    </form> 
    --%>
    </body>
    </html>
    

注意:
用了表单标签的页面可能会报这个错误,请求域中没有一个command类型的对象,所以来到页面之前一定要给请求域中放这个对象。
在这里插入图片描述

四、RESTRUL_CRUD_修改操作

  • 员工修改修改流程:
    在这里插入图片描述

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

  1. 修改连接:

    <td>
        <a href="${ctp}/emp/${emp.id}" methods="GET">Edit</a>
    </td>
    
  2. 控制器方法,根据id查询员工信息,再转发到修改页面

    /**
     * 根据id查询员工信息,再转发到修改页面
     * @param id
     * @param model
     * @return
     */
    @RequestMapping(value="/emp/{id}",method=RequestMethod.GET)
    public String getEmp(@PathVariable("id")Integer id,Model model){
          
          
    	//1、查询员工信息
    	Employee employee = employeeDao.get(id);
    	//2、放到请求域中
    	model.addAttribute("employee", employee);
    	//3、继续查出部门信息放在隐含模型中
    	model.addAttribute("deps", departmentDao.getDepartments());
    	return "edit";
    }
    
  3. edit.jsp,修改页面上显示待修改的信息

    <h1>员工修改页面</h1>
    <!-- modelAttribute:这个表单的所有内容显示绑定的是请求域中 employee的值-->
    <form:form action="${ctp }/emp/${employee.id }" method="post" modelAttribute="employee">
    	<input type="hidden" name="_method" value="PUT"/>
    	<input type="hidden" name="id" value="${employee.id }"/>
    	lastName:${employee.lastName }<br/>
    	email:<form:input path="email"/><br/>
    	gender:
    		<form:radiobutton path="gender" value="1"/>Male
    		<form:radiobutton path="gender" value="0"/>Female<br/>
    	department:
    		<form:select path="department.id" 
    		items="${requestScope.deps }" 
    		itemLabel="departmentName" 
    		itemValue="id"></form:select><br/>
    	<input type="submit" value="Submit"/>
    </form:form>
    

4.2 提交表单,修改数据

控制器方法:ModelAttribute提前从数据库中查询员工信息。再重定向到列表页面

/**
 * ModelAttribute方法提前查询员工信息
 * @param id
 * @param model
 */
@ModelAttribute
public void beforeUpdateEmp(@RequestParam(value="id",required=false)Integer id,Model model){
    
    
	//从隐藏域中获取id
	if(id != null){
    
    
		Employee employee = employeeDao.get(id);
		System.out.println("修改员工之前的信息"+employee);
		model.addAttribute("employee", employee);
	}
}

/**
 * 修改员工信息
 * @param employee
 * @return
 */
@RequestMapping(value="/emp/{id}",method=RequestMethod.PUT)
public String updateEmp(@PathVariable("id")Integer id,@ModelAttribute("employee")Employee employee){
    
    
	System.out.println("修改的员工信息为"+employee);
	employeeDao.save(employee);
	return "redirect:/emps";
}

五、RESTRUL_CRUD_删除操作

  • 员工删除流程:
    在这里插入图片描述
  1. 由于超链接无法发送DELETE请求,所以需要给超链接添加单击事件,通过jQuery提交form表单发送请求。

    <td>
    	<!-- 为删除按钮添加点击事件 -->
    	<a href="${ctp }/emp/${emp.id}" class="deleteBtn">DELETE</a>
    </td>
    
    <form id="deleteForm" action="${ctp }/emp/${emp.id}" method="POST">
    	<input type="hidden" name="_method" value="DELETE"/>
    </form>
    <script type="text/javascript">
    	$(function(){
           
           
    		<!-- 为删除按钮添加点击事件 -->
    		$(".deleteBtn").click(function(){
           
           
    			//1、改变表单的action指向
    			$("#deleteForm").attr("action",this.href);
    			//2、提交表单
    			$("#deleteForm").submit();
    			return false;
    		}); 
    	});
    </script>
    
  2. 控制器方法

    /**
     * 接收DELETE请求,删除员工信息
     * @param id
     * @return
     */
    @RequestMapping(value="/emp/{id}",method=RequestMethod.DELETE)
    public String deleteEmp(@PathVariable("id")Integer id){
          
          
    	employeeDao.delete(id);
    	//重定向到查询员工的页面
    	return "redirect:/emps";
    }
    

六、关于静态资源加载(注意)

默认前端控制器是拦截所有资源(除过jsp),js文件就404了

<!-- 默认前端控制器是拦截所有资源(除过jsp),js文件就404了;要js文件的请求是交给tomcat处理的
http://localhost:8080/7.SpringMVC_crud/scripts/jquery-1.9.1.min.js -->
<!-- 告诉SpringMVC,自己映射的请求就自己处理,不能处理的请求直接交给tomcat -->
<!-- 静态资源能访问,动态映射的请求就不能 -->
<mvc:default-servlet-handler/>
<!-- springmvc可以保证动态请求和静态请求都能访问 -->
<mvc:annotation-driven></mvc:annotation-driven>

猜你喜欢

转载自blog.csdn.net/weixin_44630656/article/details/115217025