一、什么是 RESTful
RESTful 即 Representational State Transfer 的缩写,最初由 Roy T. Fielding(HTTP/1.1协议专家组负责人)在其2000年的博士学位论文中提出。RESTful 架构,就是目前最流行的一种互联网软件架构。它结构清晰、符合标准、易于理解、扩展方便,所以正得到越来越多网站的采用。
延伸阅读:
RESTful 架构风格概述 https://blog.igevin.info/posts/restful-architecture-in-general/
10个有关RESTful API良好设计的最佳实践 https://www.jdon.com/soa/10-best-practices-for-better-restful-api.html
二、Spring MVC 实现 RESTful
1. 配置前端控制器
在 web.xml 文件中配置前端控制器可配置多个,但注意 servlet-name
不能一样。
<servlet>
<servlet-name>SpringMVC-REST</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring/springmvc.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>SpringMVC-REST</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
2. 配置过滤器 HiddenHttpMethodFilter
配置 HiddenHttpMethodFilter 是为了将 POST 请求转为 PUT 或 DELETE 请求。这个也在 web.xml 中配置。
<filter>
<filter-name>hiddenHttpMethodFilter-REST</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>hiddenHttpMethodFilter-REST</filter-name>
<url-pattern>/</url-pattern>
</filter-mapping>
使用方法是在表单中增加隐藏内容<input type="hidden" name="_method" value="POST" />
即可,如果需要将 POST
请求转为 DELETE
请求,只需要将代码改为<input type="hidden" name="_method" value="DELETE" />
即可,当提交时就为一个 DELETE
请求,PUT
请求同理改为 value="PUT"
。
3. 配置对静态资源的解析
因为在配置前端控制器是是配置的对所有请求都进行拦截,所以它也会对静态资源,如 js、css、image 等进行拦截。所以需要使用框架提供的 mvc:resources
对静态资源进行过滤,防止获取不到静态资源。在 springmvc.xml 中配置,配置方式如下:
<!-- 对静态资源访问 -->
<mvc:resources location="/js/" mapping="/js/**"/>
<mvc:resources location="/css/" mapping="/css/**"/>
<mvc:resources location="/images/" mapping="/images/**"/>
4. 编写 Controller
编写一个测试的 Controller。
package com.ssm.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
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.ResponseBody;
import com.ssm.po.ItemsCustom;
import com.ssm.service.ItemService;
/**
* @Description 测试RESTful风格的url
* @author 欧阳
* @since 2018年12月16日 下午4:23:32
* @version V1.0
*/
@Controller
@RequestMapping("/rest")
public class TestRESTController {
@Autowired
private ItemService itemService;
//查询商品
@RequestMapping(value="/items/{id}",method=RequestMethod.GET)
public @ResponseBody ItemsCustom findItems(@PathVariable(value="id") Integer id)
throws Exception {
ItemsCustom itemsCustom = itemService.findItemsById(id);
System.out.println("执行了查询商品操作");
return itemsCustom;
}
//添加商品
@RequestMapping(value="/items",method=RequestMethod.POST)
public @ResponseBody ItemsCustom saveItems(ItemsCustom itemsCustom)
throws Exception {
System.out.println("执行了添加商品操作");
return itemsCustom;
}
//修改商品
@RequestMapping(value="/items",method=RequestMethod.PUT)
public @ResponseBody ItemsCustom updateItems(ItemsCustom itemsCustom)
throws Exception {
System.out.println("执行了修改商品操作");
return itemsCustom;
}
//删除商品
@RequestMapping(value="/items",method=RequestMethod.DELETE)
public @ResponseBody ItemsCustom deleteItems(Integer id)
throws Exception {
System.out.println("执行了删除商品操作");
//假定为删除商品 Service
ItemsCustom itemsCustom = itemService.findItemsById(id);
return itemsCustom;
}
}
在 Controller 中使用 @RequestMapping(value="/items/{id}") 注解,其中的 {xxx}
表示占位符,请求的URL可以是 /items/1
,/items/2
等等,然后通过在方法中使用 @PathVariable 注解获取 {×××}
中的 ×××
变量并注解的绑定到形参上。
@PathVariable
用于将请求 URL 中的模板变量映射到功能处理方法的参数上。
5. 编写 JSP 测试页面
JSP 测试页面代码:
<a href="${pageContext.request.contextPath }/rest/items/1">查询商品</a>
<hr>
添加商品信息:
<form action="${pageContext.request.contextPath }/rest/items"
method="post">
<input type="text" name="id" value="1" />
<table width="70%" border=1 cellpadding="0" cellspacing="0">
<tr>
<td>商品名称</td>
<td><input type="text" name="name" value="添加商品名称" /></td>
</tr>
<tr>
<td>商品价格</td>
<td><input type="text" name="price" value="999" /></td>
</tr>
<tr>
<td>商品生产日期</td>
<td><input type="text" name="createtime"
value="2018-12-12 10:10:10" /></td>
</tr>
<tr>
<td>商品简介</td>
<td><textarea rows="3" cols="30" name="detail">商品特级</textarea>
</td>
</tr>
<tr>
<td colspan="2" align="center"><input type="submit" value="提交" />
</td>
</tr>
</table>
</form>
<hr>
修改商品信息:
<form action="${pageContext.request.contextPath }/rest/items"
method="post">
<input type="hidden" name="_method" value="PUT" /> <input type="text"
name="id" value="1" />
<table width="70%" border=1 cellpadding="0" cellspacing="0">
<tr>
<td>商品名称</td>
<td><input type="text" name="name" value="修改商品名称" /></td>
</tr>
<tr>
<td>商品价格</td>
<td><input type="text" name="price" value="999" /></td>
</tr>
<tr>
<td>商品生产日期</td>
<td><input type="text" name="createtime"
value="2018-12-12 10:10:10" /></td>
</tr>
<tr>
<td>商品简介</td>
<td><textarea rows="3" cols="30" name="detail">商品特级</textarea>
</td>
</tr>
<tr>
<td colspan="2" align="center"><input type="submit" value="提交" />
</td>
</tr>
</table>
</form>
<hr>
删除商品:
<form action="${pageContext.request.contextPath }/rest/items"
method="post">
<input type="hidden" name="_method" value="DELETE" />
<input type="text" name="id" value="1" />
<input type="submit" value="提交" />
</form>
分别点击不同的操作按钮就会进入不能的操作方法中,而其中他们的 URL 都是一样的。