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直接实现