软件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 操作到此就结束了,欢迎大家提问纠错。