一、Rest 和 RESTful
REST 是 Representational State Transfer 的缩写,简单翻译便是表述性状态转移,是由 Roy Thomas Fielding 博士于2000年提出的概念。
其实,REST是Web服务的一种架构风格,再言之,是一种设计风格,也就是一种思想,而并非一种标准。
通常,REST基于使用 HTTP, URI 和 XML, JSON 以及 HTML 这些现有的广泛流行的协议和标准。
而 RESTful,可以简陋翻译成 REST 式,RESTful Web Service是一种常见的REST的应用,是遵守了 REST 风格的 Web 服务,并且是 ROA (面向资源的架构)。
REST 架构之中有一条很重要的原则就是:网络上的所有事物都可以被抽象为资源,理解这一点很关键。
二、资源操作
当我们欲对一个 User 资源进行 CRUD 操作的时候,最常见的便是直接在 URL 内体现透彻,并且发出的都是 GET 或 POST 请求,如:
http://127.0.0.1/user/query/1 GET 查询
http://127.0.0.1/user/save POST 新增
http://127.0.0.1/user/update POST 修改
http://127.0.0.1/user/delete GET/POST 删除
而采用 RESTful 进行编写的时候就会情不自禁采用如下方式:
http://127.0.0.1/user/1 GET 查询
http://127.0.0.1/user POST 新增
http://127.0.0.1/user PUT 修改
http://127.0.0.1/user DELETE 删除
转变点在于,我们的 URI 清晰明朗,所有的请求都围绕着我们的 user 资源,而具体的操作则体现在请求方式和参数上面,后面会详细说明。
另外,响应的设计上面也会有所变动,但是围绕不变的原则点是:
Content body 仅仅用来传输数据,此举在于保证数据拿来即用的原则,而并不需要进行“拆箱”
描述数据或者请求的元数据放在 Hearder 中,如 X-Restful-Fields
响应示例: 错误: { "status": 200, "data": { "user_id": 777, "user_name": "Fitz" } } 正确: Response Headers: Status: 200 Response Body: { "user_id": 777, "user_name": "Fitz" }
三、http 响应状态码
四、SpringMVC 实现 RESTful Web Service
其实简言之就是,将 URI 和 HTTP 请求方法映射到 Java 处理方法,并将 Java 方法处理结果返回给HTTP请求者。
前面提过只需加以简单注解即可,主要涉及到以下三个注解:
@RequestMapping
最重要的一个注解,用于处理HTTP请求地址映射,可用于类或方法上,用于类上时表示类中的所有响应请求的方法都是以该地址作为父路径,在Spring中,一般一个Controller类处理一种资源,所以每个Controller类都会加@RequestMapping注解。常用属性:value:指定请求的地址method:指定请求的 method 类型, GET、POST、PUT、DELETE 等params:指定 request 中必须包含某些参数,如果有,才让该方法处理
@PathVariable
映射 URL 路径里面的参数
@ResponseBody 和 @ResponseBody
将请求或者响应 body 中的数据(一般常用的为 json)与我们的 Java 对象的互相转换
五、代码体现
保存商品
/** * 说明:商品操作相关controller * / @Controller @RequestMapping("item") public class ItemController { // 注入service @Autowired private ItemService itemService; /** * 说明:保存商品 * * @param item * @param desc * @return * @author CKK */ @RequestMapping(method = RequestMethod.POST) public ResponseEntity<Void> saveItem(Item item, @RequestParam(value = "desc") String desc, @RequestParam(value = "itemParams") String itemParams) { try { if (StringUtils.isBlank(item.getTitle())) { // 400 参数不符 return ResponseEntity.badRequest().build(); // TODO 参数校验待完善 } Boolean saveResult = itemService.saveItem(item, desc, itemParams); if (saveResult) { // 201 添加成功 return ResponseEntity.status(HttpStatus.CREATED).build(); } else { // 500 发送异常 return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); } } catch (Exception e) { e.printStackTrace(); } // 500 发送异常 return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); } }
修改商品
/** * 说明:修改商品 * @param item * @param desc * @return * @author CKK */ @RequestMapping(method = RequestMethod.PUT) public ResponseEntity<Void> updateItem(Item item, @RequestParam(value = "desc") String desc, @RequestParam(value = "itemParams") String itemParams) { try { if (StringUtils.isBlank(item.getTitle())) { // 400 参数不符 return ResponseEntity.badRequest().build(); // TODO 参数校验待完善 } Boolean saveResult = itemService.updateItem(item, desc, itemParams); if (saveResult) { // 204 添加成功 return ResponseEntity.status(HttpStatus.NO_CONTENT).build(); } else { // 500 发送异常 return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); } } catch (Exception e) { e.printStackTrace(); } // 500 发送异常 return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); }
但是默认情况下,PUT 请求是无法提交表单数据的,所以我们需要在 web.xml 中添加过滤器来解决,配置如下:
<!-- 解决PUT请求无法提交表单数据的问题 --> <filter> <filter-name>HttpMethodFilter</filter-name> <filter-class>org.springframework.web.filter.HttpPutFormContentFilter</filter-class> </filter> <filter-mapping> <filter-name>HttpMethodFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
删除资源
删除资源操作其实大同小异,需要使用 @RequestMapping(method = RequestMethod.DELETE)
但是还有一点需要注意,DELETE 请求同样是无法提交表单数据的,所以需要在 web.xml 中添加过滤器解决,配置如下:
<!-- 将POST请求转化为DELETE或者是PUT 要用_method指定真正的请求参数 --> <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>
当然,测试的时候也有小技巧:
文章评论