[TOC]

Restful开发风格

传统Web应用的问题
在传统模式下,客户端必定是支持html的浏览器,比如IE,Chorme等。目前互联网呈多元化的发展,处理浏览器,还有微信小程序,APP等应用客户端,这些客户端是不支持HTML的。我们希望这些客户端也可以通过HTML向后端进行通信,那该怎么办呢?这时,一种新的开发理念就产生了,那就是Restful开发。

image.png
REST与RESTful:

  • Rest - 表现层状态转移

资源(比如图片/CSS文件)在网络中以某种表现形式(URL)进行状态转移

  • RESTful是基于REST理念的一套开发风格,是具体的开发规则

只要符合RESTful开发规范,就可以认为是RESTful应用

RESTful传输数据:
image.png
RESTful开发规范:

  • 使用URL作为用户交互入口
  • 明确的语义规范(GET/POST/PUT/DELETE)

我们一般不怎么看到PUT/DELETE,这是因为在Web环境下,不支持PUT/DELETE请求
#GET:查询操作,POST:新增操作,PUT:更新操作,DELETE:删除操作

  • 只返回数据(JSON|XML),不包含任何表现

RESTful命名要求:
image.png

Restful基本使用

RestController注解与路径变量

  • RestController注解:简化开发(不用每个函数上写ResponseBody注解),表示返回数据而不是页面跳转
  • 路径变量:获取路径中的变量值 ```java package com.imooc.restful.controller;

import com.imooc.restful.entity.Person; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.*;

import java.util.ArrayList; import java.util.Date; import java.util.List;

@RestController @RequestMapping(“/restful”) //@CrossOrigin(origins = {“http://localhost:8080","http://www.imooc.com"}) //@CrossOrigin(origins = “*”,maxAge = 3600) public class RestfulController { @GetMapping(“/request”) //@ResponseBody public String doGetRequest(){ return “{\”message\”:\”返回查询结果\”}”; }

// POST /article/1
// POST /restful/request/100
@PostMapping("/request/{rid}")
//@ResponseBody
public String doPostRequest(@PathVariable("rid") Integer requestId, Person person){
    System.out.println(person.getName() + ":" + person.getAge());
    return "{\"message\":\"数据新建成功\",\"id\":" + requestId + "}";
}

@PutMapping("/request")
//@ResponseBody
public String doPutRequest(Person person){
    System.out.println(person.getName() + ":" + person.getAge());
    return "{\"message\":\"数据更新成功\"}";
}

@DeleteMapping("/request")
//@ResponseBody
public String doDeleteRequest(){
    return "{\"message\":\"数据删除成功\"}";
}

@GetMapping("/person")
public Person findByPersonId(Integer id){
    Person p = new Person();
    if(id==1){
        p.setName("lily");
        p.setAge(23);
    }else if(id==2){
        p.setName("smith");
        p.setAge(22);
    }
    return p;
}

@GetMapping("/persons")
public List<Person> findPersons(){
    List list = new ArrayList();
    Person p1 = new Person();
    p1.setName("lily");
    p1.setAge(23);
    p1.setBirthday(new Date());

    Person p2 = new Person();
    p2.setName("smith");
    p2.setAge(22);
    p2.setBirthday(new Date());
    list.add(p1);
    list.add(p2);
    return list;
}

}

#@RestController注解相当于@ResponseBody + @Controller
<a name="YDfro"></a>
### 简单请求和非简单请求

- 简单请求是指标准结构的HTTP请求,对应GET/POST请求
- 非简单请求是复杂要求的HTTP请求,指PUT/DELETE,扩展标准请求
- 两者最大区别是非简单请求发送前需要发送**预检请求**

最早的Spring MVC,是为网页服务的,默认网页在表单提交的时候,只支持GET/POST请求,对于PUT/DELETE请求是不支持的。随着技术的演进,PUT/DELETE是SpringMVC必须要考虑的,但是有不能把PUT/DELETE的处理方式强塞进原有的代码中,所以SpringMVC做了一个折中的方案,即用“表单内容过滤器”对PUT/DELETE进行额外处理。

src/main/webapp/WEB-INF/web.xml
```java

    <filter>
        <filter-name>formContentFilter</filter-name>
        <filter-class>org.springframework.web.filter.FormContentFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>formContentFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

JSON序列化

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.imooc</groupId>
    <artifactId>restful</artifactId>
    <version>1.0-SNAPSHOT</version>

    <repositories>
        <repository>
            <id>aliyun</id>
            <name>aliyun</name>
            <url>https://maven.aliyun.com/repository/public</url>
        </repository>
    </repositories>
    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.1.9.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-core</artifactId>
            <version>2.9.9</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.9.9</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-annotations</artifactId>
            <version>2.9.9</version>
        </dependency>
    </dependencies>
</project>

RestfulController.java
#直接返回对象

    @GetMapping("/person")
    public Person findByPersonId(Integer id){
        Person p = new Person();
        if(id==1){
            p.setName("lily");
            p.setAge(23);
        }else if(id==2){
            p.setName("smith");
            p.setAge(22);
        }
        return p;
    }

entity/Person.java
#使用JsonFormat注解格式化时间
#本来的值是new Date(),不格式化显示时间戳,格式化之后会显示XXXX年XX月XX日 XX时:XX分:XX秒

package com.imooc.restful.entity;

import com.fasterxml.jackson.annotation.JsonFormat;
import org.springframework.format.annotation.DateTimeFormat;

import java.util.Date;

public class Person {
    private String name;
    private Integer age;
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss" , timezone = "GMT+8")
    private Date birthday;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }
}

RestfulController.java

    @GetMapping("/persons")
    public List<Person> findPersons(){
        List list = new ArrayList();
        Person p1 = new Person();
        p1.setName("lily");
        p1.setAge(23);
        p1.setBirthday(new Date());

        Person p2 = new Person();
        p2.setName("smith");
        p2.setAge(22);
        p2.setBirthday(new Date());
        list.add(p1);
        list.add(p2);
        return list;
    }

跨域问题

  • 同源策略阻止从一个域加载的脚本去获取另一个域上的资源
  • 只要协议,域名,端口有任何一个不同,都被当做是不同的域
  • 浏览器Console看到Access-Control-Allow-Origin就代表跨域了

image.png
HTML中允许跨域的标签:
Restful风格的应用 - 图5 - 显示远程图片