軟件152 余建強
源碼下載:http://download.csdn.net/detail/qq_35318576/9826210
1 使用框架
SpringMVC、Maven、Ajax、JSTL、JSR303數據校驗
2 什么是 RESTful 架構
(1)簡而言之,我們總結一下什么是RESTful架構:
1)每一個URI代表一種資源;
2)客戶端和服務器之間,傳遞這種資源的某種表現層;
3)客戶端通過四個HTTP動詞,對服務器端資源進行操作,實現"表現層狀態轉化"。
(2)四個表示操作方式的動詞:GET、POST、PUT、DELETE。
它們分別對應四種基本操作:GET用來獲取資源,POST用來新建資源(也可以用於更新資源),PUT用來更新資源,DELETE用來刪除資源。
3 實現步驟
(1)Maven 需要導入的 jar 包,pom.xml 部分配置
<dependencies> <!-- Servlet API --> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> <scope>provided</scope> <!-- 編譯時用到servlet-api和jsp-api,但在打包的時候不用這兩個依賴 --> </dependency> <!-- JSP API --> <dependency> <groupId>javax.servlet.jsp</groupId> <artifactId>jsp-api</artifactId> <version>2.2</version> <scope>provided</scope> <!-- 編譯時用到servlet-api和jsp-api,但在打包的時候不用這兩個依賴 --> </dependency> <!-- JUnit --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> <scope>test</scope> </dependency> <!-- jstl --> <dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> <version>1.2</version> </dependency> <!-- standard --> <dependency> <groupId>taglibs</groupId> <artifactId>standard</artifactId> <version>1.1.2</version> </dependency> <!-- spring-context --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>4.1.6.RELEASE</version> </dependency> <!-- spring-web --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>4.1.6.RELEASE</version> </dependency> <!-- spring-webmvc --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>4.1.6.RELEASE</version> </dependency> <!-- hibernate-validator-annotation-processor --> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-validator-annotation-processor</artifactId> <version>5.0.3.Final</version> </dependency> <!-- hibernate-validator --> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-validator</artifactId> <version>5.0.3.Final</version> </dependency> </dependencies>
(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" id="WebApp_ID" version="3.0"> <display-name>SpringMVC_170422_I18N_JSTLView</display-name> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> <!-- Spring 解決中文亂碼問題 --> <filter> <filter-name>encodingFilter</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> </filter> <filter-mapping> <filter-name>encodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!-- 配置 org.springframework.web.filter.HiddenHttpMethodFilter: 可以把 POST 請求轉換為 DELETE 或 POST 請求 --> <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> <!-- 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> <!-- 配置 DispatcherServlet 的一個初始化參數:配置 SpringMVC 配置文件的位置和名稱 --> <!-- 默認的配置文件格式:/WEB-INF/<servlet-name>-servlet.xml --> <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> </web-app>
(3)spring-mvc.xml 文件內容如下
<?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:aop="http://www.springframework.org/schema/aop" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="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.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd"> <!-- 配置自定義掃描包 --> <context:component-scan base-package="com.cqvie" /> <!-- 配置視圖解析器:如何把 handler 方法返回值解析為實際的物理視圖 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/views/"></property> <property name="suffix" value=".jsp"></property> </bean> <!-- 加載靜態資源 --> <!-- default-servlet-handler 將在 SpringMVC 上下文中定義一個 DefaultServletHttpRequestHandler, 它會對進入 DispatcherServlet 的請求進行篩查, 如果發現是沒有經過映射的請求, 就將該請求交由 WEB 應用服務器默認的 Servlet 處理. 如果不是靜態資源的請求,才由 DispatcherServlet 繼續處理 一般 WEB 應用服務器默認的 Servlet 的名稱都是 default. 若所使用的 WEB 服務器的默認 Servlet 名稱不是 default,則需要通過 default-servlet-name 屬性顯式指定 --> <mvc:default-servlet-handler /> <!-- 避免不能正常訪問@RequestMapping鏈接,通常配置 mvc:annotation-driven 標簽 --> <mvc:annotation-driven></mvc:annotation-driven> <!-- 配置國際化資源文件 --> <bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource"> <property name="basename" value="i18n"></property> </bean> </beans>
(4)實體類 Department.java 和 Employee.java

package com.cqvie.model; public class Department { private Integer id; private String departmentName; public Department() {} //不能省略此無參構造方法 public Department(Integer id, String departmentName) { this.id = id; this.departmentName = departmentName; } 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; } }

package com.cqvie.model; 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; private int gender; @Past //日期必須小於當前日期 @DateTimeFormat(pattern = "yyyy-MM-dd") //日期格式 private Date birthday; @NumberFormat(pattern = "#,###,##.#")//eg:8,456,89.2 輸入數字格式 private Float num; private Department department; public Employee(Integer id, String lastName, String email, int gender, Department department) { this.id = id; this.lastName = lastName; this.email = email; this.gender = gender; this.department = department; } public Employee() { } 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 int getGender() { return gender; } public void setGender(int gender) { this.gender = gender; } public Department getDepartment() { return department; } public void setDepartment(Department department) { this.department = department; } public Date getBirthday() { return birthday; } public void setBirthday(Date birthday) { this.birthday = birthday; } public Float getNum() { return num; } public void setNum(Float num) { this.num = num; } @Override public String toString() { return "Employee [id=" + id + ", lastName=" + lastName + ", email=" + email + ", gender=" + gender + ", birthday=" + birthday + ", num=" + num + ", department=" + department + "]"; } }
(5)Dao 類,本實例屬於簡單模擬數據庫操作,並非實際數據庫操作

package com.cqvie.dao; import java.util.Collection; import java.util.HashMap; import java.util.Map; import org.springframework.stereotype.Repository; import com.cqvie.model.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")); } /** * 獲得全部部門信息 * @return */ public Collection<Department> getDepartments() { return departments.values(); } /** * 根據ID獲取部門 * @param id * @return */ public Department getDepartment(Integer id) { return departments.get(id); } }

package com.cqvie.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.cqvie.model.Department; import com.cqvie.model.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; /** * 保存信息 * @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獲取信息 */ public Employee get(Integer id) { return employees.get(id); } /** * 根據ID刪除該信息 * @param id */ public void delete(Integer id) { employees.remove(id); } }
(6)Handler 及控制層代碼 EmployeeHandler.java
package com.cqvie.handler; import java.util.Map; import javax.validation.Valid; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.validation.Errors; import org.springframework.validation.FieldError; 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.cqvie.dao.DepartmentDao; import com.cqvie.dao.EmployeeDao; import com.cqvie.model.Employee; @Controller public class EmployeeHandler { @Autowired private EmployeeDao employeeDao; @Autowired private DepartmentDao departmentDao; /** * 顯示所有用戶 * @param map * @return */ @RequestMapping("/emps") public String list(Map<String, Object> map) { map.put("employees", employeeDao.getAll()); System.out.println("****list*****"); return "list"; } /** * 輸入信息頁面 * @param map * @return */ @RequestMapping(value = "/emp") public String input(Map<String, Object> map) { map.put("dapartments", departmentDao.getDepartments()); map.put("employee", new Employee());// employee 和 input.jsp 頁面的 modelAttribute="employee" 值一致 System.out.println("****input*****"); return "input"; } /** * 保存用戶 * @param employee * @param result * @param map * @return */ @RequestMapping(value = "/emp-save", method = {RequestMethod.POST}) public String save(@Valid Employee employee, Errors result, Map<String, Object> map) { if(result.getErrorCount() > 0) { System.err.println("*********************出錯了!*********************"); for(FieldError error: result.getFieldErrors()) { System.err.println(error.getField() + ":" + error.getDefaultMessage()); } map.put("dapartments", departmentDao.getDepartments()); return "input"; } employeeDao.save(employee); System.out.println("****save*****"); System.out.println(employee); return "redirect:/emps"; } /** * 刪除用戶 * @param id * @return */ @RequestMapping(value = "/emp-del/{id}", method = RequestMethod.DELETE) public String delete(@PathVariable("id") Integer id) { employeeDao.delete(id); System.out.println("*****delete******"); return "redirect:/emps"; } /** * 修改用戶頁面 * @param id * @param map * @return */ @RequestMapping(value = "/emp-update-input/{id}", method = RequestMethod.GET) public String inputUpdate(@PathVariable("id") Integer id, Map<String, Object> map) { map.put("employee", employeeDao.get(id));// employee 和 input.jsp 頁面的 modelAttribute="employee" 值一致 map.put("dapartments", departmentDao.getDepartments()); return "input"; } /** * 修改用戶 * @param employee * @return */ @RequestMapping(value = "emp-save", method = RequestMethod.PUT) public String update(Employee employee) { employeeDao.save(employee); System.out.println("*****update******"); return "redirect:/emps"; } @ModelAttribute public void getEmployee(@RequestParam(value = "id", required = false) Integer id, Map<String, Object> map) { if(id != null) { map.put("employee", employeeDao.get(id)); } } }
(7)顯示界面 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> <!-- SpringMVC 處理靜態資源: 1. 為什么會有這樣的問題: 優雅的 REST 風格的資源URL 不希望帶 .html 或 .do 等后綴 若將 DispatcherServlet 請求映射配置為 /, 則 Spring MVC 將捕獲 WEB 容器的所有請求, 包括靜態資源的請求, SpringMVC 會將他們當成一個普通請求處理, 因找不到對應處理器將導致錯誤。 2. 解決: 在 SpringMVC 的配置文件中配置 <mvc:default-servlet-handler/> --> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>首頁</title> <script type="text/javascript" src="js/jquery.js"></script> <script type="text/javascript"> $(function() { $(".delete").click(function() { var name = $(this).next(":input").val(); var result = confirm("確認要刪除 " + name + " 的信息嗎?"); if(result == true) { var href = $(this).attr("href"); $("form").attr("action", href).submit(); } return false; }); }); </script> </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>E-mail</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-update-input/${emp.id}">Edit</a> </td> <td> <a class="delete" href="emp-del/${emp.id}">Delete</a> <input type="hidden" value="${emp.lastName}" /> </td> </tr> </c:forEach> </table> </c:if> <hr> <a href="emp">Add New Employee</a> <form action="" method="post"> <input type="hidden" name="_method" value="DELETE"> </form> </body> </html>
(8)增加用戶和修改用戶界面 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" %> <% Map<String, Object> genders = new HashMap<String, Object>(); genders.put("1", "Male"); genders.put("0", "Female"); request.setAttribute("genders", genders); %> <!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> <!-- 可以通過 modelAttribute 屬性指定綁定的模型屬性, 若沒有指定該屬性,則默認從 request 域對象中讀取 command 的表單 bean, 如果該屬性值也不存在,則會發生錯誤 --> <form:form action="${pageContext.request.contextPath}/emp-save" method="post" modelAttribute="employee"> <form:errors path="*"></form:errors><br> <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> <br> Email:<form:input path="email"/> <form:errors path="email"></form:errors> <br> Gender:<form:radiobuttons path="gender" items="${genders}"/> <br> Birthday:<form:input path="birthday"/> <form:errors path="birthday"></form:errors> <br> Number:<form:input path="num"/> <br> Department:<form:select path="department.id" items="${dapartments}" itemLabel="departmentName" itemValue="id"></form:select><br> <input type="submit" value="Submit"> </form:form> </body> </html>
(9)國際化資源文件 i18n.properties 配置,本例用戶 JSR303 數據校驗自定義提示錯誤語言
NotEmpty.employee.lastName = LastName \u4E0D\u80FD\u4E3A\u7A7A Email.employee.email = Email \u4E0D\u662F\u5408\u6CD5\u90AE\u7BB1 Past.employee.birthday = Birthday \u4E0D\u80FD\u662F\u4E00\u4E2A\u5C06\u6765\u7684\u65F6\u95F4 typeMismatch.employee.birthday = Birthday \u4E0D\u662F\u4E00\u4E2A\u5408\u6CD5\u7684\u65E5\u671F
使用SpringMVC RESTful 架構實現簡單的 CRUD 操作到此就結束了,歡迎大家提問糾錯。