第三章:REST
REST是什么
- REST即Representational State Transfer.(资源)表现层状态转换。是目前最流行的一种互联网软件架构,他结构清晰,符合标准,易于理解,扩展方便,所以正得到越来越多的网站的采用。
- 资源(resources):网络上的一个实体,或者说是网络上的一个具体信息。它可以是一段文本,一张图片,一首歌曲,一种服务,总之就是一个具体的存在。可以用一个URI(统一资源定位符)指向它,每种资源对应一个特定的URI。获取这个资源,访问它的URI就可以了,因此URI即为每一个资源的独一无二的识别符。
- 表现层(Representation):把资源具体呈现出来的形式,叫做他的表现层(Representation)。比如,文本可以用txt格式表现,也可以用HTML格式,XML格式,JSON格式表现,甚至可以采用二进制格式。
- 状态转换(State Transfer):每发出一个请求,就代表了客户端和服务器的一次交互过程。HTTP协议,是一个无状态协议,即所有状态都保存在服务器端。因此,如果客户端想要操作服务器,必须通过某种手段,让服务器端发生“状态转化”(State Transfer)而这种转化是建立在表现层之上的,所以就是“表现层状态转化”
- 具体说,就是HTTP协议里面,四个表示操作方式的动词:GET,POST,PUT,DELETE。他们分别对应四种基本操作:GET用来获取资源,POST用来新建资源,PUT用来更新资源,DELETE用来删除资源。
- URL风格:
※请求路径相同,根据请求方法确定使用哪个方法来处理请求。
以前实现CRUD(增删改查):
查询:findAll GET
插入:insertUser POST
更新:getUserById GET updateUser PUT
删除:deletUser GET
REST风格实现CRUD(增删改查):
操作 URL 请求方式
查询: /user/1001 GET
插入: /user/ POST
更新: 查询后再修改 /user/ PUT
删除: /user/1001 DELETE
♦虽然服务端可以处理PUT和DELETE,但是客户端form表单只有GET和POST两种方式向服务器端发送请求。那么请求方式PUT,DELETE的时候要怎么向服务器端发送请求呢??
思路:客户端都以POST的方式发送请求,同时带过去一个参数_method,然后对请求方式和参数进行判断:
POST&&_method=PUT:PUT
POST&&_method=DELETE:DELETE
POST&&_method=null:POST

上面的处理要在客户端发送请求后DispatcherServelet前处理,这样的处理可以用监听(listener)或过滤器(filter)
web.xml中个组件的顺序:listener>>filter>>servlet
当然spring MVC已经给我们想好了,提供了一个filter:HiddenHttpMethodFilter
源码:
HiddenHttpMethodFilter.java
1 package org.springframework.web.filter; 2 3 import java.io.IOException; 4 import java.util.Locale; 5 import javax.servlet.FilterChain; 6 import javax.servlet.ServletException; 7 import javax.servlet.ServletRequest; 8 import javax.servlet.http.HttpServletRequest; 9 import javax.servlet.http.HttpServletRequestWrapper; 10 import javax.servlet.http.HttpServletResponse; 11 import org.springframework.util.Assert; 12 import org.springframework.util.StringUtils; 13 14 public class HiddenHttpMethodFilter extends OncePerRequestFilter { 15 public static final String DEFAULT_METHOD_PARAM = "_method"; 16 private String methodParam = "_method"; 17 18 public HiddenHttpMethodFilter() { 19 } 20 21 public void setMethodParam(String methodParam) { 22 Assert.hasText(methodParam, "'methodParam' must not be empty"); 23 this.methodParam = methodParam; 24 } 25 26 protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { 27 HttpServletRequest requestToUse = request; 28 if ("POST".equals(request.getMethod()) && request.getAttribute("javax.servlet.error.exception") == null) { 29 String paramValue = request.getParameter(this.methodParam); 30 if (StringUtils.hasLength(paramValue)) { 31 requestToUse = new HiddenHttpMethodFilter.HttpMethodRequestWrapper(request, paramValue); 32 } 33 } 34 35 filterChain.doFilter((ServletRequest)requestToUse, response); 36 } 37 38 private static class HttpMethodRequestWrapper extends HttpServletRequestWrapper { 39 private final String method; 40 41 public HttpMethodRequestWrapper(HttpServletRequest request, String method) { 42 super(request); 43 this.method = method.toUpperCase(Locale.ENGLISH); 44 } 45 46 public String getMethod() { 47 return this.method; 48 } 49 } 50 }
REST CRUD
web.xml
1 <?xml version="1.0" encoding="UTF-8"?> 2 <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" 5 version="4.0"> 6 <filter> 7 <filter-name>HiddenHttpMethodFilter</filter-name> 8 <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class> 9 </filter> 10 <filter-mapping> 11 <filter-name>HiddenHttpMethodFilter</filter-name> 12 <url-pattern>/*</url-pattern> 13 </filter-mapping> 14 <servlet> 15 <servlet-name>springMVC</servlet-name> 16 <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> 17 </servlet> 18 <servlet-mapping> 19 <servlet-name>springMVC</servlet-name> 20 <url-pattern>/</url-pattern> 21 </servlet-mapping> 22 </web-app>
springMVC-servlet.xml
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xmlns:context="http://www.springframework.org/schema/context" 5 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"> 6 7 <context:component-scan base-package="com.iwakan.controller"/> 8 <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> 9 <!-- 10 /WEB-INF下的东西不能直接访问,只能通过转发进行访问。 11 转发和重定向的区别在于,地址发布发生变化,重定向地址发生变化, 12 如果用重定向访问的化话,又相当于直接访问WEB-INF下的页面了 13 --> 14 <property name="prefix" value="/WEB-INF/view/"/> 15 <property name="suffix" value=".jsp"></property> 16 </bean> 17 </beans>
rest.jsp
1 <%@ page contentType="text/html;charset=UTF-8" language="java" %> 2 <html> 3 <head> 4 <title>Rest</title> 5 </head> 6 <body> 7 <a href="/testREST/1001">测试GET</a> 8 <br> 9 <br> 10 <form action="/testREST" method="post"> 11 <input type="submit" value="测试POST"> 12 </form> 13 <br> 14 <form action="/testREST" method="post"> 15 <input type="hidden" name="_method" value="PUT"> 16 <input type="submit" value="测试PUT"> 17 </form> 18 <br> 19 <form action="/testREST/1001" method="post"> 20 <input type="hidden" name="_method" value="DELETE"> 21 <input type="submit" value="测试DELETE"> 22 </form> 23 </body> 24 </html>
RestController.java
1 package com.iwakan.controller; 2 3 import org.springframework.stereotype.Controller; 4 import org.springframework.web.bind.annotation.PathVariable; 5 import org.springframework.web.bind.annotation.RequestMapping; 6 import org.springframework.web.bind.annotation.RequestMethod; 7 8 @Controller 9 public class RestController { 10 11 @RequestMapping(value = "/testREST/{id}", method = RequestMethod.GET) 12 public String getUserById(@PathVariable("id") Integer id) { 13 System.out.println("GET:id==" + id); 14 return "success"; 15 } 16 17 @RequestMapping(value = "/testREST" ,method = RequestMethod.POST) 18 public String insertUser() { 19 System.out.println("POST"); 20 return "success"; 21 } 22 23 @RequestMapping(value = "/testREST",method = RequestMethod.PUT) 24 public String UpdateUser(){ 25 System.out.println("PUT"); 26 return "success"; 27 } 28 29 @RequestMapping(value = "/testREST/{id}",method = RequestMethod.DELETE) 30 public String deleteUser(@PathVariable("id") Integer id){ 31 System.out.println("DELETE:id=="+id); 32 return "success"; 33 } 34 }
success.jsp
1 <%@ page contentType="text/html;charset=UTF-8" language="java" %> 2 <html> 3 <head> 4 <title>成功</title> 5 </head> 6 <body> 7 <h2>成功</h2> 8 </body> 9 </html>

当点击上面连个按钮时报错:

解决办法:
三种简单处理的办法!
第一:tomcat换到7.0以及以下版本
第二:请求先转给一个Controller,再返回jsp页面
第三种:在你的success页面头部文件将
<%@ page language=”java” contentType=”text/html; charset=UTF-8”
pageEncoding=”UTF-8” isErrorPage=”true”%>
success.jsp
1 <%@ page contentType="text/html;charset=UTF-8" pageEncoding="utf-8" isErrorPage="true" language="java" %> 2 <html> 3 <head> 4 <title>成功</title> 5 </head> 6 <body> 7 <h2>成功</h2> 8 </body> 9 </html>
修改完成后,在点击就成功了。
用Ajax也可以实现REST风格。
※ form表单只有GET和POST两种请求,只能通过HiddenHttpMethodFilter来实现。然而,AJax有八种请求方式,所以可以在不通过HiddenHttpMethodFilter直接实现

浙公网安备 33010602011771号