【Java开发】 Spring 09 :Spring Data REST 实现并访问简单的超媒体服务

news2024/11/20 6:36:14

Spring Data REST 是提供一个灵活和可配置的机制来编写可以通过HTTP公开的简单服务,简单来说,而且可以省去大部分controller和services的逻辑,因为Spring Data REST 已经为你都做好了,目前支持JPA、MongoDB、Neo4j、Solr、Cassandra 和 Gemfire,因此本文以 JPA 举例。

目录

1 Spring Data REST 介绍

1.1 RestFul

1.2 HATEOAS

1.3 Spring Data REST

2 项目初始化

2.1 通过 IDEA Spring Initializr 创建项目

2.2 添加 Spring Web 等依赖

2.3 连接数据库配置

2.4 编写数据库对应的实体类

2 REST 资源(超链接服务)的实现

2.1 添加 data-rest 依赖

2.2 编写 UserRepository 接口

2.3 REST 相关页面

① 根路径:http://localhost:8080/

 ② 分页查询:http://localhost:8080/user?page=1&size=2

③ 基路径:http://localhost:8080/user

④ 查询某个user :http://localhost:8080/user/1

⑤ 自定义方法展示:http://localhost:8080/user/search

2.4 对 REST 资源进行 Post 请求

① 新增--POST  http://127.0.0.1:8080/user

② 修改--PUT  http://127.0.0.1:8080/userses/2

3 使用 restTemplate 访问超链接服务

3.1 HAL 渲染配置

3.2 get 请求

① getLink 获取 Linkl

② 分页查询

③ 查询所有 User

④ 查询某个 User

3.2 post 请求


1 Spring Data REST 介绍

Spring Data REST 的发展是经历了好一些阶段的,主要包括以下概念 👇

1.1 RestFul

REST 这个词是2000 年 Roy Fielding 在其博士论文中创造出来的,它是一种架构风格,它包含了一个分布式超文本系统中对于组件、连接器和数据的约束。简单来说,REST 是对互联网资源接口的一种约束标准,类似于食品质量标准。

REST 是作为互联网自身架构的抽象而出现的,其关键在于所定义的架构上的各种约束。只有满足这些约束,才能称之为符合 REST 架构风格,即所谓的“RESTful”服务。

1.2 HATEOAS

HATEOAS(Hypermedia as the engine of application state)是 REST 架构风格中最复杂的约束,也是构建成熟 REST 服务的核心。它的重要性在于打破了客户端和服务器之间严格的契约,使得客户端可以更加智能和自适应,而 REST 服务本身的演化和更新也变得更加容易。

简单来说,这里的自适应,指得是服务器返回给客户端的信息中,会自动包含客户端能够进行的操作,这样二者之间就不用通过建立一份额外的文档来约定访问的格式了。

Spring Hateoas,是Spring的一个子项目,Spring HATEOAS 的主要功能在于提供了简单的机制来创建这些满足 HATEOAS 要求的链接,并与 Spring MVC 框架有很好的结合。不过在实践中,Spring Data REST 更为常用。

1.3 Spring Data REST

Spring Data Rest 也是 Spring 的一个子项目,它的主要功能就是把你的 Spring Data Repositories 以满足 HATEOAS 的格式暴露出去,因此你的 JPA 资源 Repository 可以用一种通用的 http 访问格式对你的 Respository 进行 CRUD ,而且可以省去大部分 controller 和 services 的逻辑,因为Spring Data REST 已经为你都做好了,你只需要保证你的http访问格式正确即可!

官方文档:Spring Data REST Reference Documentation

目前 Spring Data REST 支持以下各datasource的的 repository 自动转换成 REST 服务

  • Spring Data JPA
  • Spring Data MongoDB
  • Spring Data Neo4j
  • Spring Data GemFire

简单来说,Spring Data REST 把我们需要编写的大量 REST 模版接口做了自动化实现。

2 项目初始化

项目初始化前提是已构建实体类对应的数据库,关于数据库的初始化详见【Spring 06】的 2.1 小节,当然对初始化的步骤熟悉的同学可直接跳过,直接从第 3 章开始了解即可~

2.1 通过 IDEA Spring Initializr 创建项目

2.2 添加 Spring Web 等依赖

2.3 连接数据库配置

路径:src/main/resources/application.properties

#数据库连接配置
spring.datasource.username=root
spring.datasource.password=root
#mysql5~8 驱动不同driver-class-name     8需要增加时区的配置serverTimezone=UTC,放在url最后
#useSSL=false 安全连接
spring.datasource.url=jdbc:mysql://localhost:3306/mybatis_plus?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

2.4 编写数据库对应的实体类

@Entity 注释比较关键,没了它不行

路径:src/main/java/com/restdemo/pojo/User.java

package com.restdemo.pojo;

import lombok.*;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import java.io.Serializable;

@Entity
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class User implements Serializable {

    @javax.persistence.Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;
    private Integer age;
    private String email;

}

以上准备工作准备完毕,不需要像 MVC 项目那样编写 Service层、Controller层等内容~

2 REST 资源(超链接服务)的实现

2.1 添加 data-rest 依赖

路径:pom.xml

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-rest</artifactId>
        </dependency>

2.2 编写 UserRepository 接口

路径:src/main/java/com/restdemo/repository/UserRepository.java

package com.restdemo.repository;

import com.restdemo.pojo.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.repository.query.Param;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;

import java.util.List;

@RepositoryRestResource( path = "user") //指定基路径
public interface UserRepository extends JpaRepository<User,Long> {

    //自定义方法,JpaRepository提供了很多供使用
    User findUserByName(@Param("name") String name);//参数可以用 @Param 自定义注解

    //根据name查询,查询到的结果根据Id排序
    List<User> findByNameInOrderById(List<String> list);
}

2.3 REST 相关页面

① 根路径:http://localhost:8080/

 ② 分页查询:http://localhost:8080/user?page=1&size=2

③ 基路径:http://localhost:8080/user

返回所有的 user 记录

④ 查询某个user :http://localhost:8080/user/1

查询 id 为 1 的 user

⑤ 自定义方法展示:http://localhost:8080/user/search

展示自定义的方法~

使用其中的第二个方法 👇

2.4 对 REST 资源进行 Post 请求

此时用到辅助工具 Apifox(类似Postman)👇,请求参数与属性名相同自动填充到 user 对象中

① 新增--POST  http://127.0.0.1:8080/user

 返回内容 👇

数据库新增成功 👇

② 修改--PUT  http://127.0.0.1:8080/userses/2

返回内容 👇

数据库修改成功 👇

3 使用 restTemplate 访问超链接服务

注意由于是请求本地项目的 web 资源,因此需要在先启动项目 👇,然后再对测试类进行测试

关于 restTemplate 的简单教学在该链接:Spring 08 :访问 Web 资源,首先浅浅地用下 restTemplate 👇

package com.restdemo;

@SpringBootTest
class RestdemoApplicationTests {

    //new 一个RestTemplate ,后面也会用到
    RestTemplate restTemplate = new RestTemplate();

    @Test
    public void queryOneUser(){
        //构建 uri
        URI uri = UriComponentsBuilder
                .fromUriString("http://localhost:8080/user")
                .build()
                .toUri();
        //执行rest请求,ResponseEntity封装了返回信息,若将getForEntity 替换成 getForObject,则不需要 ResponseEntity
        ResponseEntity<Object> user = restTemplate.getForEntity(uri,Object.class);
        //打印返回信息
        System.out.printf("Response Status: {%s}"+"\n"+"Response Headers: {%s}"+"\n", user.getStatusCode(), user.getHeaders().toString());
        System.out.printf("Users: {%s}", user.getBody());
    }
}

此时返回是不带任何处理的,所有的记录及 links 都混在一起,那么就需要其他办法处理分析返回的数据!

3.1 HAL 渲染配置

路径:src/main/java/com/restdemo/RestdemoApplication.java

package com.restdemo;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.hateoas.config.EnableHypermediaSupport;
import org.springframework.hateoas.mediatype.hal.Jackson2HalModule;
import org.springframework.http.MediaType;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.client.RestTemplate;

import java.util.Collections;

@SpringBootApplication
@EnableHypermediaSupport(type = {EnableHypermediaSupport.HypermediaType.HAL}) //注入HAL渲染
public class RestdemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(RestdemoApplication.class, args);
    }

    //注册Jackson2HalModule 开启Jackson JSON对HAL的支持
    @Bean
    public Jackson2HalModule jackson2HalModule() {
        return new Jackson2HalModule();
    }

    @Bean
    public RestTemplate restTemplate() {
        final ObjectMapper mapper = new ObjectMapper();
        mapper.registerModule(new Jackson2HalModule());

        final MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
        converter.setSupportedMediaTypes(MediaType.parseMediaTypes("application/hal+json"));
        converter.setObjectMapper(mapper);

        return new RestTemplate(Collections.<HttpMessageConverter<?>>singletonList(converter));
    }
}

3.2 get 请求

路径:src/test/java/com/restdemo/RestdemoApplicationTests.java

① getLink 获取 Linkl

对 getLink 方法进行测试,主要是获取对应的 Link 供后边使用~

@SpringBootTest
class RestdemoApplicationTests {

    @Autowired
    private RestTemplate restTemplate;

    //构建 URI
    private static final URI ROOT_URI = URI.create("http://localhost:8080");
    //输出的links:{<http://localhost:8080/user{?page,size,sort}>;rel="users",<http://localhost:8080/profile>;rel="profile"}
    private static final URI SEARCH_URI = URI.create("http://localhost:8080/user/search");
    //输出的links:{<http://localhost:8080/user/search/findByNameInOrderById{?list}>;rel="findByNameInOrderById",<http://localhost:8080/user/search/findUserByName{?name}>;rel="findUserByName",<http://localhost:8080/user/search>;rel="self"}

    @Test
    public void mainTest(){
        Link link = getLink(ROOT_URI,"users");
    }

    //我们根据 ROOT_URI or SEARCH_URI 返回的 Links 进行相应的请求或处理
    public Link getLink(URI uri, String rel){
        //返回 link 的包装数据
        ResponseEntity<CollectionModel<Links>> rootResp =
                restTemplate.exchange(uri, HttpMethod.GET, null,
                        new ParameterizedTypeReference<CollectionModel<Links>>() {});
        //从包装数据中提取对应的 link
        Link link = rootResp.getBody().getRequiredLink(rel);
        System.out.printf("根据{%s},查找到 Link:{%s}", rel,link);
        return link;
    }

输出如下 👇,获取到预期的 Link

② 分页查询

此处就要用到 getLink 方法了!

    @Test
    public void queryPage(){
        //获取 link 模板
        Link link = getLink(ROOT_URI,"users");
        //page=1,size=2,sort="id",进行分页查询
        ResponseEntity<CollectionModel<Object>> usersResp =
                restTemplate.exchange(link.getTemplate().expand(1,2,"id"), HttpMethod.GET, null,
                        new ParameterizedTypeReference<CollectionModel<Object>>() {});
        //打印返回信息
        System.out.printf("\n"+"分页查询结果: {%s}", usersResp.getBody().getContent());
    }

输出成功 👇

③ 查询所有 User

    @Test
    public void queryAllUsers(){
        //基路径
        URI ROOT_URI1 = URI.create("http://localhost:8080/user");
        //执行 get 请求
        ResponseEntity<CollectionModel<User>> rootResp =
                restTemplate.exchange(ROOT_URI1, HttpMethod.GET, null,
                        new ParameterizedTypeReference<CollectionModel<User>>() {});
        //打印返回信息,若User实体放里边,返回会带id且为null,个人认为不是很美观,所以后边均为Object
        System.out.printf("All users: {%s}", rootResp.getBody().getContent());
    }

输出成功 👇

④ 查询某个 User

    @Test
    public void queryOneUser(){
        //获取 link 模板
        Link link = getLink(SEARCH_URI,"findUserByName");
        //执行 get 请求
        ResponseEntity<EntityModel<Object>> usersResp =
                restTemplate.exchange(link.getTemplate().expand("yinyu"), HttpMethod.GET, null,
                        new ParameterizedTypeReference<EntityModel<Object>>() {});
        //打印返回信息
        System.out.printf("\n"+"The user: : {%s}", usersResp.getBody());
    }

输出成功 👇

3.2 post 请求

    @Test
    public void postAddUser(){
        //构建uri
        URI uri = URI.create("http://localhost:8080/user");
        //请求数据包装
        User user = User.builder().name("yinyu222").age(18).email("yinyu@163.com").build();
        RequestEntity<User> req = RequestEntity.post(uri).body(user);
        //post请求执行
        ResponseEntity<EntityModel<Object>> resp =
                restTemplate.exchange(req,
                        new ParameterizedTypeReference<EntityModel<Object>>() {});
        //打印返回信息
        System.out.printf("Response messae: : {%s}", resp.getBody());
    }

返回成功 👇

 


参考文章

SpringBoot实战之使用 Spring Data REST 实现简单的超媒体服务 | 码农家园

Spring Data REST - 慕尘 - 博客园

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/72023.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Ribbon负载均衡

Ribbon负载均衡 Ribbon是微服务架构中&#xff0c;可以作为负载均衡的技术实现&#xff0c;如下图所示 Ribbon负载均衡 1、消费者发起请求2、被负载均衡拦截器拦截3、将请求信息交给RibbonLoadBanlancerClient4、获取url的服务id5、DynamicServerListLoadBalancer拿到id去eur…

java基础巩固-宇宙第一AiYWM:为了维持生计,架构知识+分布式微服务+高并发高可用高性能知识序幕就此拉开(二:网关balabala)~整起

上集&#xff0c;在架构知识分布式微服务高并发高可用高性能知识序幕就此拉开&#xff08;一&#xff1a;总览篇&#xff09;中&#xff0c;说到了 当用户请求过来时&#xff0c;这个请求或者说URL先到服务调用端【咱们之前的项目中的Controller其实就算是一个服务调用方&#…

VMware ESXi 8.0 SLIC Unlocker 集成网卡驱动和 NVMe 驱动 (集成驱动版)

发布 ESXi 8.0 集成驱动版&#xff0c;在个人电脑上运行企业级工作负载 请访问原文链接&#xff1a;VMware ESXi 8.0 SLIC & Unlocker 集成网卡驱动和 NVMe 驱动 (集成驱动版)&#xff0c;查看最新版。原创作品&#xff0c;转载请保留出处。 作者主页&#xff1a;www.sysi…

【Pytorch】第 3 章 :进行数值估计的蒙特卡洛方法

&#x1f50e;大家好&#xff0c;我是Sonhhxg_柒&#xff0c;希望你看完之后&#xff0c;能对你有所帮助&#xff0c;不足请指正&#xff01;共同学习交流&#x1f50e; &#x1f4dd;个人主页&#xff0d;Sonhhxg_柒的博客_CSDN博客 &#x1f4c3; &#x1f381;欢迎各位→点赞…

Java ssh框架 mysql实现的进销存管理系统源码+运行教程+文档

今天给大家演示一下一款由sshmysql实现的进销存管理系统&#xff0c;其中struts版本是struts2&#xff0c;这个系统的功能非常完善&#xff0c;简直可以说是牛逼&#xff0c;到了可以用于企业直接商用的地步&#xff0c;此外该项目还带有完整的论文&#xff0c;是Java学习者及广…

Spark 初识

文章目录Spark 初识Spark是什么Apache Spark演变为什么使用Spark全快Spark组件Spark CoreSpark SQLSpark StreamingSpark MLlibSpark GraphXSparkRpySparkspark 在数仓的应用总结Spark 初识 从今天开始我们进入数据仓库的查询引擎篇了&#xff0c;前面我们已经写了大量的文章介…

三分钟了解LAP编程框架

针对Java开发者的灵魂拷问&#xff1a; 1、梳理的流程&#xff0c;关键逻辑是否有遗漏&#xff0c;理解一致吗&#xff1f; 2、设计时&#xff0c;如何更方便的与产品沟通&#xff1f;原有的设计是否有不合理的&#xff1f;绘制的流程图大家都能理解吗&#xff1f; 3、测试时&a…

316页11万字AI赋能智慧水利大数据信息化平台建设和运营解决方案

第一章 系统综述 1.1 项目背景 1.2 系统概述 1.3 需求分析 1.3.1 中心管控需求 1.3.2 前端监测需求 1.4 建设目标 1.5 设计原则 1.6 设计依据 第二章 系统总体设计 2.1 总体设计思路 2.2 架构设计 2.2.1 逻辑架构 2.2.2 系统架构 2.3 关键技术应用 2.4 系统特色…

代码随想录刷题|LeetCode 647. 回文子串 516.最长回文子序列

647. 回文子串 题目链接&#xff1a;https://leetcode.cn/problems/palindromic-substrings/ 思路 动态规划思路 1、确定dp数组 布尔类型的dp[i][j]&#xff1a;表示区间范围[i,j] &#xff08;注意是左闭右闭&#xff09;的子串是否是回文子串&#xff0c;如果是dp[i][j]为tr…

【真的?】用 ChatGPT 写一篇 Python 翻译库博客,可以打 9 分

今天来个大的实践项目&#xff0c;用 ChatGPT 写一篇博客&#xff0c;冲击一下热榜&#xff01; 从零开始玩 ChatGPT⛳️ ChatGPT 亮点⛳️ 账号篇⛳️ 第一次使用⛳️ 用 Python 实现一个英汉互译的小程序⛳️ googletrans 库核心用法⛳️ 再补充一些知识点⛳️ googletrans 和…

功率放大电路和电压放大电路的区别是什么意思

功率放大电路和电压放大电路都属于模拟电路&#xff0c;是工程师日常经常用到的比较常见的模拟电路&#xff0c;很多小白工程师对于功率放大电路和电压放大电路的区别都很好奇&#xff0c;下面就来看看区别有哪些。 图&#xff1a;功率放大电路与电压放大电路对比 1、功能和基本…

docker之网络配置

目录一、网络模式1.bridge模式(默认模式)2.host模式3.初识网络模式二、bridge模式三、host模式四、自定义网络一、网络模式 Docker在创建容器时有四种网络模式&#xff1a;bridge/host/container/none&#xff0c;bridge为默认不需要用–net去指定&#xff0c;其他三种模式需要…

微服务框架 SpringCloud微服务架构 19 文档操作 19.2 修改文档

微服务框架 【SpringCloudRabbitMQDockerRedis搜索分布式&#xff0c;系统详解springcloud微服务技术栈课程|黑马程序员Java微服务】 SpringCloud微服务架构 文章目录微服务框架SpringCloud微服务架构19 文档操作19.2 修改文档19.2.1 修改文档19.2.2 总结19 文档操作 19.2 修…

推荐一款超级好用的工具:uTools详解使用

介绍 uTools 是什么&#xff1f;下载并安装uTools 能做什么&#xff1f;一切皆插件超级面板 uTools 是什么&#xff1f; uTools 是一个极简、插件化、跨平台的现代桌面软件。通过自由选配丰富的插件&#xff0c;打造你得心应手的工具集合。 通过快捷键&#xff08;默认 alt…

红队隧道应用篇之CS正反向连接突破内网(二)

正向连接 环境拓扑图 操作步骤 在CS客户端新建一个TCP协议的监听, 监听端口为4444 创建无状态木马(Windows Executable(S)), 选择上述建立的TCP监听器, 随后将无状态木马放到不出网的内网主机中去运行, 运行后内网主机就会监听本机的4444端口 在web服务器的beacon命令行输入:…

EMQX安装与使用

EMQX文档&#xff1a;https://www.emqx.io/docs/zh/v5.0/ 1.安装 https://www.emqx.io/zh/downloads 找到自己合适的平台和版本安装 ①&#xff1a;后台启动 emqx start启动成功后可以使用 emqx ping 命令检测节点运行状态&#xff0c;返回 pong 则表示正常运行&#xff1a; …

pmp 证书到底有什么用处?

PMP 证书最重要的两个用处&#xff1a;一个是岗位招聘要求&#xff0c;一个是项目招标要求。 一、PMP证书的应用 1、PMP 证书的敲门砖作用 前面说的&#xff0c;PMP 作为项目管理领域的一个权威公认证书&#xff0c;很多行业要求项目管理岗位人才都会加一条"具备PMP 等证…

Redis vs MongoDB

Redis vs MongoDB 通常情况下&#xff0c;应用系统的技术选型&#xff0c;对于如何选择非关系型数据库&#xff0c;是一个不小的挑战。这不仅考验架构师在技术上的广度和深度&#xff0c;同时也考究对业务细节了解和熟悉程度。只有将业务场景、业务特点、数据特征跟具体的技术…

数据挖掘与机器学习课程总结

2022.11月 文章目录一、引言1.1 数据中的知识发现包括哪几个步骤&#xff1f;(Knowledge Discovery from Data, KDD)1.2 数据挖掘应用二、学习的可行性2.1 Hoeffding 不等式&#xff08;Hoeffding’s Inequality&#xff09;2.2 用 Hoeffding 不等式说明学习的可行性三、数据和…

浅学Linux内核MMU

1 MMU基本知识 1.1 什么是MMU MMU是 MemoryManagementUnit 的缩写即&#xff0c;内存管理单元. 针对各种CPU, MMU是个可选的配件. MMU负责的是虚拟地址与物理地址的转换. 提供硬件机制的内存访问授权.&#xff08;现代 CPU 的应用中&#xff0c;基本上都选择了使用 MMU&#…