1. 程式人生 > >SpringMVC 學習筆記(五) 基於RESTful的CRUD

SpringMVC 學習筆記(五) 基於RESTful的CRUD

super() ger select bsp ber ota his version pub

1.1. 概述

當提交的表單帶有_method字段時,通過HiddenHttpMethodFilter POST 請求轉換成 DELETEPUT請求,加上@PathVariable註解從而實現 RESTful 風格的CRUD

技術分享

1.2. 配置信息

Web.xml

<?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_3_0.xsd" version="3.0" > <!-- The front controller of this Spring Web application, responsible for handling all application requests --> <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:spring-mvc.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> <!--配置 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> </web-app>

1.3. 效果

① 通過POST 請求添加員工信息

② 通過PUT 請求改動員工信息

③ 通過DELETE 請求刪除員工信息

④ 通過GET 請求 獲取全部的 員工信息

技術分享
技術分享

技術分享

1.4. 代碼

Employee.java

package com.ibigsea.springmvc.model;

public class Employee {
	
	private Integer id;
	private String name;
	private String email;
	private int sex;
	
	private Department department;
	
	public Employee(Integer id, String name, String email, int sex,
			Department department) {
		super();
		this.id = id;
		this.name = name;
		this.email = email;
		this.sex = sex;
		this.department = department;
	}
	
	public Employee() {
		super();
	}

	public Integer getId() {
		return id;
	}

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

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getEmail() {
		return email;
	}

	public void setEmail(String email) {
		this.email = email;
	}

	public int getSex() {
		return sex;
	}

	public void setSex(int sex) {
		this.sex = sex;
	}

	public Department getDepartment() {
		return department;
	}

	public void setDepartment(Department department) {
		this.department = department;
	}

	@Override
	public String toString() {
		return "Employee [id=" + id + ", name=" + name + ", email=" + email
				+ ", sex=" + sex + ", department=" + department + "]";
	}
	
}

Department.java

package com.ibigsea.springmvc.model;

import java.io.Serializable;

public class Department implements Serializable {

	private static final long serialVersionUID = 6881984318733090395L;
	
	private Integer id;
	private String name;

	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}

	@Override
	public String toString() {
		return "Department [id=" + id + ", name=" + name + "]";
	}
	
}

RestfulController.java

package com.ibigsea.springmvc.rest;

import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

import com.ibigsea.springmvc.dao.DepartmentDao;
import com.ibigsea.springmvc.dao.EmployeeDao;
import com.ibigsea.springmvc.model.Employee;

/**
 * 基於Restful風格的增刪改查
 * @author bigsea
 */
@Controller
@RequestMapping("/restful")
public class RestfulController {
	
	@Autowired
	private EmployeeDao employeeDao;
	
	@Autowired
	private DepartmentDao departmentDao;
	
	/**
	 * 由於改動的時候不能改動員工姓名,
	 * 所以通過 @ModelAttribute 註解,
	 * 表示在運行目標方法時,先獲取該員工對象
	 * 將員工對象存入 implicitMode 中
	 * @param id 員工ID
	 * @param map 實際傳入的是implicitMode
	 */
	@ModelAttribute
	public void getEmployee(@RequestParam(value="id",required=false) Integer id,Map<String,Object> map){
		if (id != null) {
			map.put("employee", employeeDao.getEmpById(id));
		}
	}
	
	/**
	 * 查看全部的員工信息
	 * @param map
	 * @return
	 */
	@RequestMapping("/list")
	public String list(Map<String, Object> map){
		map.put("emps", employeeDao.getAll());
		return "list";
	}
	
	/**
	 * 跳轉到員工加入頁面
	 * @param map
	 * @return
	 */
	@RequestMapping(value="/add",method=RequestMethod.GET)
	public String add(Map<String, Object> map){
		map.put("depts", departmentDao.getAll());
		map.put("action", "add");
		return "emp";
	}
	
	/**
	 * 加入員工
	 * @param emp
	 * @return
	 */
	@RequestMapping(value="/add",method=RequestMethod.POST)
	public String add(Employee emp){
		if (emp == null) {
			return "emp";
		}
		if (emp.getDepartment().getId() != null) {
			emp.setDepartment(departmentDao.getDepartmentById(emp.getDepartment().getId()));
		}
		employeeDao.save(emp);
		return "redirect:/restful/list";
	}

	/**
	 * 刪除員工信息
	 * @param id
	 * @return
	 */
	@RequestMapping(value="/delete/{id}",method=RequestMethod.DELETE)
	public String delete(@PathVariable("id") Integer id){
		employeeDao.delEmpById(id);
		return "redirect:/restful/list";
	}
	
	/**
	 * 由於先運行了 @ModelAttribute 註解的方法,
	 * 獲取了該員工ID所相應的員工信息
	 * 然後在將前臺獲取的員工數據存入獲取的員工信息中,
	 * 這樣就不用提交name屬性也能夠獲取到值
	 * @param emp
	 * @return
	 */
	@RequestMapping(value="/edit",method=RequestMethod.PUT)
	public String edit(Employee emp){
		if (emp == null) {
			return "emp";
		}
		if (emp.getDepartment().getId() != null) {
			emp.setDepartment(departmentDao.getDepartmentById(emp.getDepartment().getId()));
		}
		employeeDao.save(emp);
		return "redirect:/restful/list";
	}
	
	/**
	 * 跳轉到員工改動頁面
	 * @param id 員工ID
	 * @param map implicitMode
	 * @return 
	 */
	@RequestMapping(value="/edit/{id}",method=RequestMethod.GET)
	public String edit(@PathVariable("id") Integer id,Map<String, Object> map){
		map.put("emp", employeeDao.getEmpById(id));
		map.put("depts", departmentDao.getAll());
		map.put("action", "edit");
		return "emp";
	}
	
	
	
}

EmployeeDao.java

package com.ibigsea.springmvc.dao;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

import org.springframework.stereotype.Component;

import com.ibigsea.springmvc.model.Department;
import com.ibigsea.springmvc.model.Employee;

@Component
public class EmployeeDao {
	
	private static Map<Integer,Employee> emps = new HashMap<Integer, Employee>();
	
	/**
	 * 初始化員工信息
	 */
	static {
		emps.put(1001, new Employee(1001,"AA","[email protected]",0,new Department(101, "JAVA")));
		emps.put(1002, new Employee(1002,"BB","[email protected]",0,new Department(102, ".NET")));
		emps.put(1003, new Employee(1003,"CC","[email protected]",1,new Department(103, "PHP")));
		emps.put(1004, new Employee(1004,"DD","[email protected]",0,new Department(104, "C")));
	}
	
	private static int employeeId = 1005;
	
	/**
	 * 保存員工信息
	 * @param emp
	 */
	public void save(Employee emp){
		if (emp.getId() == null) {
			emp.setId(employeeId++);
		}
		emps.put(emp.getId(), emp);
	}
	
	/**
	 * 獲取全部的員工信息
	 * @return
	 */
	public Collection<Employee> getAll(){
		return emps.values();
	}
	
	/**
	 * 依據ID獲取員工信息
	 * @param id
	 * @return
	 */
	public Employee getEmpById(Integer id){
		return emps.get(id);
	}
	
	/**
	 * 依據ID刪除員工信息
	 * @param id
	 */
	public void delEmpById(Integer id){
		emps.remove(id);
	}
	
}

DepartmentDao.java

package com.ibigsea.springmvc.dao;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

import org.springframework.stereotype.Component;

import com.ibigsea.springmvc.model.Department;

@Component
public class DepartmentDao {

	public static Map<Integer, Department> depts = new HashMap<Integer, Department>();
	
	/**
	 * 初始化部門信息
	 */
	static {
		depts.put(101, new Department(101,"JAVA"));
		depts.put(102, new Department(102,".NET"));
		depts.put(103, new Department(103,"PHP"));
		depts.put(104, new Department(104,"C"));
	}
	
	/**
	 * 獲取全部的部門信息
	 * @return
	 */
	public Collection<Department> getAll(){
		return depts.values();
	}
	
	/**
	 * 依據ID獲取部門信息
	 * @param id
	 * @return
	 */
	public Department getDepartmentById(Integer id){
		return depts.get(id);
	}
	
}

List.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!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>員工信息</title>
</head>
<body>

	<c:if test="${ empty emps }">
		沒有員工信息
	</c:if>
    <c:if test="${ !empty emps }">
    		<table border="1" bordercolor="black" cellspacing="0">
    			<tr>
    				<td width="40px">id</td>
    				<td width="30px">name</td>
    				<td width="80px">email</td>
    				<td width="30px">sex</td>
    				<td width="40px">編輯</td>
    				<td width="40px">刪除</td>
    			</tr>
		    	<c:forEach items="${emps }" var="emp">
		    		<tr>
		    			<td>${emp.id }</td>
		    			<td>${emp.name }</td>
		    			<td>${emp.email }</td>
		    			<td>${emp.sex == 0 ?

'男' : '女'}</td> <td><a href="${pageContext.request.contextPath}/restful/edit/${emp.id }">Edit</a></td> <td><form action="${pageContext.request.contextPath}/restful/delete/${emp.id }" method="post"> <input type="hidden" name="_method" value="DELETE"> <input type="submit" value="Delete"> </form> </td> </tr> </c:forEach> </table> </c:if> <br><br> <a href="${pageContext.request.contextPath}/restful/add">加入員工</a> </body> </html>


Emp.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!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>員工信息</title>
</head>
<body>
	<form action="${pageContext.request.contextPath}/restful/${action}" method="post">
		<c:if test="${!empty emp}">
			<input type="hidden" name="_method" value="PUT">
			<input type="hidden" name="id" value="${emp.id }"><br/><br/>
		</c:if>
		<c:if test="${empty emp}">name : <input type="text" name="name" value="${emp.name }"><br/><br/></c:if>
		email : <input type="text" name="email" value="${emp.email }"><br/><br/>
		sex :<input type="radio" name="sex" value="0" <c:if test="${emp.sex == 0}">checked</c:if>>男    
		<input type="radio" name="sex" value="1" <c:if test="${emp.sex == 1}">checked</c:if>>女<br/><br/>
		department :<select name="department.id">
			<c:forEach items="${depts }" var="dept">
				<option value="${dept.id }" <c:if test="${emp.department.id == dept.id}">selected</c:if>>${dept.name }</option>
			</c:forEach>
		</select>
		<br><br/>
		<input type="submit" value="提交">
	</form>
</body>
</html>

1.5. 靜態資源問題

由於配置了DispatcherServlet而且攔截了全部的請求,所以在加入靜態資源的時候會訪問不到靜態資源,springMVC.xml配置

mvc:default-servlet-handler

將在 SpringMVC 上下文中定義一個DefaultServletHttpRequestHandler。它會對進入 DispatcherServlet 的請求進行篩查。假設發現是沒有經過映射的請求,就將該請求交由 WEB應用server默認的 Servlet 處理,假設不是靜態資源的請求。才由DispatcherServlet 繼續處理

mvc:annotation-driven

會自己主動註冊

RequestMappingHandlerMapping

RequestMappingHandlerAdapter

ExceptionHandlerExceptionResolver 三個bean

就能訪問到靜態資源了

1.6. mvc:annotation-drivenmvc:default-servlet-handler

在配置SpringMVC配置文件時加入mvc:annotation-driven

<mvc:annotation-driven /> 會自己主動註冊三個Bean

2 RequestMappingHandlerMapping

2 RequestMappingHandlerAdapter

2 ExceptionHandlerExceptionResolver

還將提供下面支持:

– 支持使用 ConversionService 實例對表單參數進行類型轉換

– 支持使用 @NumberFormat @DateTimeFormat註解完畢數據類型的格式化

– 支持使用 @Valid 註解對 JavaBean 實例進行 JSR 303 驗證

– 支持使用 @RequestBody@ResponseBody 註解


技術分享









SpringMVC 學習筆記(五) 基於RESTful的CRUD