• 62、SpringBoot 使用RestTemplate 整合第三方 RESTful 服务


    这节的要点:
    就是弄两个项目 , 从 端口9090 这个项目,通过 restTemplate, 去访问 端口8080 的项目,并获取8080项目的数据。

    ★ RESTful服务包含两方面的含义

    1. 自己的应用要暴露一些功能供别人来调用。
       此时我们是服务端。
    
    2. 我们的应用要去整合第三方的RESTful服务
       此时我们就是客户端。
    
    • 1
    • 2
    • 3
    • 4
    • 5

    ★ RESTful客户端的两种方式

    - 应用基于传统的Spring MVC框架,此时考虑使用RestTemplate来整合第三方RESTful服务。
      RestTemplate就属于传统Spring Web的API。
    
    - 应用基于传统的Web Flux框架,此时考虑使用WebClient来整合第三方RESTful服务。
      WebClient本身就是属于WebFlux API
    
    • 1
    • 2
    • 3
    • 4
    • 5

    ★ RestTemplate整合第三方RESTful服务

    (1)调用RestTemplateBuilder来构建RestTemplate
    
         千万不要自己去创建RestTemplate对象,相当于你没有利用spring容器的依赖注入。
         就是不要这样-->  this.restTemplate = new RestTemplate();
    
    (2)调用RestTemplate的如下方法:
         delete | getForXxx | postForXxx | put 
    
         exchange(String url, HttpMethod method, HttpEntity requestEntity, Class responseType, Map uriVariables):
         delete | getForXxx | postForXxx | put 都是 exchange的快捷方式
    
         execute(String url, HttpMethod method, RequestCallback requestCallback, ResponseExtractor responseExtractor, Map uriVariables):原始
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    千万不要自己去创建RestTemplate对象,相当于你没有利用spring容器的依赖注入。如图
    就是注入这个RestTemplate 对象时,
    要用restTemplateBuilder.build();,
    不要去new RestTemplate();

    在这里插入图片描述

    代码演示

    RESTful_XML 8080 项目代表 restful 服务的 服务端,生成json响应的,
    MyRestTemPlate 9090 项目代表 restful 服务的 客户端,发起请求的

    这个 RESTful_XML 就是第三方RESTful 服务,MyRestTemPlate 项目通过RestTemplate 来整合它

    需求:两个项目 , 从 9090 这个项目,通过 restTemplate 去访问 8080 的项目,并获取数据。

    查看所有图书的方法。
    这个 rootUri 个人的ip是会变的,以后测试需要更改
    在这里插入图片描述
    效果:成功通过restTemplate,从项目9090 访问到项目8080的数据
    在这里插入图片描述
    其他的方法也一样
    根据id查看图书
    在这里插入图片描述

    根据id修改图书:两种方法,有返回值和没有返回值

    方式1: 用 put() 方法,restTemplate.put() 默认没有返回值

    在这里插入图片描述

    在这里插入图片描述

    方式2:用 exchange() 方法,restTemplate.exchange() 有返回值

    在这里插入图片描述

    在这里插入图片描述

    完整代码:

    MyRestTemPlate

    Book

    在这里插入图片描述

    package cn.ljh.app.domain;
    
    import lombok.Data;
    
    @Data
    public class Book
    {
        private Integer id;
        private String name;
        private double price;
        private String author;
    
        public Book(Integer id, String name, double price, String author)
        {
            this.id = id;
            this.name = name;
            this.price = price;
            this.author = author;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    ClientController

    package cn.ljh.app.controller;
    
    
    import cn.ljh.app.domain.Book;
    import org.springframework.boot.web.client.RestTemplateBuilder;
    import org.springframework.http.HttpEntity;
    import org.springframework.http.HttpMethod;
    import org.springframework.http.HttpStatus;
    import org.springframework.http.ResponseEntity;
    import org.springframework.web.bind.annotation.*;
    import org.springframework.web.client.RestTemplate;
    
    import java.util.Collection;
    import java.util.List;
    import java.util.Map;
    
    @RestController
    @RequestMapping("/mybooks")
    public class ClientController
    {
        private final RestTemplate restTemplate;
    
        public ClientController(RestTemplateBuilder restTemplateBuilder)
        {
            /*
             * 此处的 RestTemplateBuilder 是来自于Spring 容器的注入,
             * 因此它所构建的 RestTemplate 已经接收了spring 容器的默认设置
             * 如果直接创建 RestTemplate , 那就相当于完全没有利用Spring容器的依赖注入,
             * 因此完全不能接受spring容器的默认配置,这样后面所介绍的配置 RestTemplate 完全不可能实现配置了
             */
            this.restTemplate = restTemplateBuilder
                    .rootUri("http://192.168.0.108:8080/") //为整个RestTemplate 指定基路径
                    .build();
    
        }
    
        //查看所有图书
        @GetMapping("/viewBooks")
        public ResponseEntity<List<Book>> viewBooks()
        {
            List<Book> list = restTemplate.getForObject("/books/viewBooks", List.class);
            ResponseEntity<List<Book>> entity = new ResponseEntity<>(list, null, HttpStatus.OK);
            return entity;
        }
    
        //查看所有图书
        @GetMapping("/viewBooks2")
        public ResponseEntity<Collection> viewBooks2()
        {
            //参数3:代表为 URL 填充路径参数值 ,就是路径后面的参数
            Collection data = restTemplate.getForObject("/books/viewBooks2", Collection.class);
            ResponseEntity<Collection> entity = new ResponseEntity<>(data, null, HttpStatus.OK);
            return entity;
        }
    
    
        //根据id查看图书
        @GetMapping("/{id}")
        public ResponseEntity<Book> getBookById(@PathVariable Integer id)
        {
            Book book = restTemplate.getForObject("/books/{id}", Book.class, id);
            ResponseEntity<Book> entity = new ResponseEntity<>(book, null, HttpStatus.OK);
            return entity;
        }
    
        //根据id删除图书
        @DeleteMapping("/{id}")
        public ResponseEntity<Map<String, String>> deleteBookById(@PathVariable Integer id)
        {
            //restTemplate 的 delete 默认是没有返回值的
            restTemplate.delete("/books/{id}", id);
            ResponseEntity<Map<String, String>> tip = new ResponseEntity<>(Map.of("tip", "id为:" + id + " 的图书删除成功"), null, HttpStatus.OK);
            return tip;
        }
    
        //根据id修改图书, restTemplate 的 put修改 默认是没有返回值的
        @PutMapping("/{id}")
        public ResponseEntity<Map<String, String>> updateById(@PathVariable Integer id)
        {
            restTemplate.put("/books/{id}",
                    Map.of("name", "修改的图书", "price", 120, "author", "图书的作者"),
                    id);
            ResponseEntity<Map<String, String>> entity =
                    new ResponseEntity<>(Map.of("tip", "图书修改成功"), null, HttpStatus.OK);
            return entity;
        }
    
        //因为 restTemplate 默认的 put修改、delete 是没有返回值的,如果要返回值,可以用 exchange 方法
        //参数2:代表要修改的数据封装在这个 map 里面
        @PutMapping("/exchange/{id}")
        public ResponseEntity<Map> updateById(@PathVariable Integer id, @RequestBody Map map)
        {
            //把要修改的book对象传进这个 HttpEntity 对象里面
            HttpEntity<Map> entity = new HttpEntity<>(map);
            //参数1:访问服务端的路径  参数2:要执行的请求类型  参数3:请求的数据,就是要修改的对象的新数据
            //参数4:指定服务器响应的数据类型  参数5 :用于为 URL 的路径参数填充值
            ResponseEntity<Map> exchange = restTemplate.exchange("/books/{id}", HttpMethod.PUT, entity, Map.class, id);
    
            return exchange;
    
        }
    
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105

    application.properties

    在这里插入图片描述

    pom.xml

    pom文件没什么要改的

    <?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.4.5</version>
        </parent>
        <groupId>cn.ljh</groupId>
        <artifactId>my_resttemplate</artifactId>
        <version>1.0.0</version>
        <name>my_resttemplate</name>
        <properties>
            <java.version>11</java.version>
            <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        </properties>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-devtools</artifactId>
                <scope>runtime</scope>
                <optional>true</optional>
            </dependency>
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <optional>true</optional>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
            </dependency>
        </dependencies>
    
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                    <configuration>
                        <excludes>
                            <exclude>
                                <groupId>org.projectlombok</groupId>
                                <artifactId>lombok</artifactId>
                            </exclude>
                        </excludes>
                    </configuration>
                </plugin>
            </plugins>
        </build>
    
    </project>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60

    RESTful_XML

    Book

    在这里插入图片描述

    package cn.ljh.app.domain;
    
    import lombok.Data;
    
    @Data
    public class Book
    {
        private Integer id;
        private String name;
        private double price;
        private String author;
    
        public Book(Integer id, String name, double price, String author)
        {
            this.id = id;
            this.name = name;
            this.price = price;
            this.author = author;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    controller

    package cn.ljh.app.controller;
    
    
    import cn.ljh.app.domain.Book;
    import cn.ljh.app.service.BookService;
    import org.springframework.http.HttpStatus;
    import org.springframework.http.ResponseEntity;
    import org.springframework.web.bind.annotation.*;
    
    import java.util.Collection;
    import java.util.List;
    
    /*
     *     GET  /books/{id} - (获取数据) 获取指定id的图书
     *     GET  /books?参数  -(获取数据) 获取符合查询参数的图书
     *     GET  /books        -(获取数据) 获取所有图书
     *     POST /books        -(添加数据) 添加图书
     *     PUT  /books/{id}    -(更新数据) 更新指定ID的图书
     *     DELETE /books/{id}    -(删除数据) 删除指定ID的图书
     *     DELETE /books?参数    -(删除数据) 删除符合指定参数的图书
     *
     *  Restful处理方法的返回值通常都应该使用HttpEntity或ResponseEntity。
     *
     */
    
    @RequestMapping("/books")
    @RestController
    public class BookController
    {
        //有参构造器进行依赖注入
        private BookService bookService;
    
        public BookController(BookService bookService)
        {
            this.bookService = bookService;
        }
    
    
        //根据id查看图书
        @GetMapping("/{id}")
        public ResponseEntity<Book> viewBookById(@PathVariable Integer id)
        {
            Book book = bookService.getBookById(id);
    
            //参数1:响应数据体  参数2:需要添加的响应头,没有就给个null   参数3:响应码 , OK 代表 200
            return new ResponseEntity<>(book, null, HttpStatus.OK);
        }
    
        //查看所有图书----------------------方法1------------
        @GetMapping("viewBooks")
        public ResponseEntity<List<Book>> viewBooks()
        {
            List<Book> allBooks = bookService.getAllBooks();
    
            return new ResponseEntity<>(allBooks, null, HttpStatus.OK);
        }
    
        //查看所有图书------------------------方法2----------
        @GetMapping("/viewBooks2")
        public ResponseEntity<Collection<Book>> viewBooks2()
        {
            Collection<Book> allBooks2 = bookService.getAllBooks2();
    
            ResponseEntity<Collection<Book>> books = new ResponseEntity<>(allBooks2, null, HttpStatus.OK);
            return books;
        }
    
        //添加图书
        @PostMapping("")
        public ResponseEntity<Book> addBook(@RequestBody Book book)
        {
            Book b = bookService.addOrUpdateBook(book);
            //HttpStatus.CREATED 代表返回的状态码为 201
            return new ResponseEntity<>(b, null, HttpStatus.CREATED);
        }
    
        //根据id更新图书信息
        @PutMapping("/{id}")
        public ResponseEntity<Book> updateBookById(@PathVariable Integer id, @RequestBody Book book)
        {
            book.setId(id);
            Book b = bookService.addOrUpdateBook(book);
    
            return new ResponseEntity<>(b, null, HttpStatus.OK);
        }
    
        //根据id删除图书
        @DeleteMapping("/{id}")
        public ResponseEntity<Book> deleteBookById(@PathVariable Integer id)
        {
            Book book = bookService.deleteBookById(id);
            return new ResponseEntity<>(book, null, HttpStatus.OK);
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95

    BookService

    package cn.ljh.app.service;
    
    import cn.ljh.app.domain.Book;
    
    import java.util.Collection;
    import java.util.List;
    
    public interface BookService
    {
        //根据id查看图书
        Book getBookById(Integer id);
    
        //查看所有图书
        List<Book> getAllBooks();
    
        Collection<Book> getAllBooks2();
    
        //添加/修改图书
        Book addOrUpdateBook(Book book);
    
        //根据id删除图书
        Book deleteBookById(Integer id);
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    BookServiceImpl

    package cn.ljh.app.service.impl;
    
    import cn.ljh.app.domain.Book;
    import cn.ljh.app.service.BookService;
    import org.springframework.stereotype.Service;
    
    import java.util.*;
    import java.util.concurrent.ConcurrentHashMap;
    
    
    @Service
    public class BookServiceImpl implements BookService
    {
        //创建一个线程安全的map集合存数据,假设为数据库
        static Map<Integer, Book> bookDB = new ConcurrentHashMap<>();
        static int nextId = 1;
    
        //初始化数据库的数据
        static
        {
            bookDB.put(nextId, new Book(nextId++, "火影忍者", 120, "岸本"));
            bookDB.put(nextId, new Book(nextId++, "七龙珠", 121, "鸟山明"));
        }
    
    
        //根据id查看图书
        @Override
        public Book getBookById(Integer id)
        {
            if (id != null)
            {
                Book book = bookDB.get(id);
                if (book!=null){
                    return book;
                }
            }
            throw new RuntimeException("根据id查看图书失败!");
        }
    
        //查看所有图书
        @Override
        public List<Book> getAllBooks()
        {
            //获取map中的所有数据
            Collection<Book> mapBooks = bookDB.values();
            //强转
            List<Book> books = new ArrayList<>(mapBooks);
            return books;
        }
    
        @Override
        public Collection<Book> getAllBooks2()
        {
            //获取map中的所有数据
            Collection<Book> mapBooks = bookDB.values();
            return mapBooks;
        }
    
        //添加/修改图书
        @Override
        public Book addOrUpdateBook(Book book)
        {
            if (book.getId() != null){
                //修改
                //map的key是唯一的,所以map里面有这个key的话,直接把原来的value覆盖掉
                bookDB.put(book.getId(),book);
                return book;
            }else {
                //新增
                //为新增的图书设置id
                book.setId(nextId);
                //book添加完之后,这个id才会自增
                bookDB.put(nextId++,book);
                return book;
            }
        }
    
        //根据id删除图书
        @Override
        public Book deleteBookById(Integer id)
        {
            Book book = bookDB.remove(id);
            return book;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85

    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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.4.5</version>
        </parent>
        <groupId>cn.ljh</groupId>
        <artifactId>RESTful_XML</artifactId>
        <version>1.0.0</version>
        <name>RESTful_XML</name>
        <properties>
            <java.version>11</java.version>
            <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        </properties>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
    
            <!-- 添加 Jackson format XML , 用于对象与XML之间的转换 -->
            <dependency>
                <groupId>com.fasterxml.jackson.dataformat</groupId>
                <artifactId>jackson-dataformat-xml</artifactId>
            </dependency>
    
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-devtools</artifactId>
                <scope>runtime</scope>
                <optional>true</optional>
            </dependency>
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <optional>true</optional>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
            </dependency>
        </dependencies>
    
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                    <configuration>
                        <excludes>
                            <exclude>
                                <groupId>org.projectlombok</groupId>
                                <artifactId>lombok</artifactId>
                            </exclude>
                        </excludes>
                    </configuration>
                </plugin>
            </plugins>
        </build>
    
    </project>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
  • 相关阅读:
    Apache Sqoop_2
    深度学习之自监督模型汇总
    《倍增商业成功宝典》全新升级上线!炙夏新品,久等终至!
    Android Framework 常见解决方案(22)防应用被LowMemoryKillerDaemon(LMKD)杀掉
    Jmeter接口测试简易步骤
    PHP/Lerv通过经纬度计算距离获取附近商家
    优化算法 - 梯度下降
    MySQL-Redis进阶生成全局唯一ID
    uni-app引入海康威视h5player实现视频监控的播放
    MacOS系统Chrome开发者模式下载在线视频
  • 原文地址:https://blog.csdn.net/weixin_44411039/article/details/132812899