Spring Boot多租户配置与实现

在现代应用程序中,多租户架构是一种非常流行的设计模式。多租户架构允许多个客户(租户)共享同一个应用程序实例,同时确保数据的隔离性和安全性。本文将详细介绍如何在Spring Boot应用程序中配置和实现多租户支持,并提供丰富的Java代码示例,帮助你更加深入地理解多租户架构的实现。

1. 什么是多租户架构?

多租户架构是一种软件架构模式,其中单个应用程序实例为多个租户(客户)提供服务。每个租户的数据和配置都是隔离的,确保不同租户之间的数据安全和隐私。多租户架构通常有三种实现方式:

  • 共享数据库,独立数据表:所有租户共享同一个数据库,但每个租户有独立的数据表。
  • 共享数据库,共享数据表:所有租户共享同一个数据库和数据表,通过区分租户标识来隔离数据。
  • 独立数据库:每个租户有独立的数据库实例。

本文将重点介绍共享数据库,共享数据表的多租户实现方式。

2. Spring Boot多租户配置

我们将使用Spring Boot和Hibernate来实现多租户支持。以下是实现步骤:

  1. 设置基本项目结构。
  2. 配置数据源和Hibernate拦截器。
  3. 创建租户解析器。
  4. 配置实体和存储库。
  5. 测试多租户实现。
3. 设置基本项目结构

首先,创建一个Spring Boot项目,并添加以下依赖:

<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>com.h2database</groupId><artifactId>h2</artifactId><scope>runtime</scope></dependency>
</dependencies>
4. 配置数据源和Hibernate拦截器

application.properties中配置数据源:

spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=password
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.H2Dialect
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=update

创建一个TenantInterceptor类,用于拦截数据库操作并添加租户上下文:

import org.hibernate.EmptyInterceptor;
import org.hibernate.type.Type;
import org.springframework.stereotype.Component;import java.io.Serializable;@Component
public class TenantInterceptor extends EmptyInterceptor {@Overridepublic boolean onSave(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) {// 在保存实体时添加租户标识for (int i = 0; i < propertyNames.length; i++) {if ("tenantId".equals(propertyNames[i])) {state[i] = TenantContext.getCurrentTenant();return true;}}return false;}@Overridepublic boolean onFlushDirty(Object entity, Serializable id, Object[] currentState, Object[] previousState, String[] propertyNames, Type[] types) {// 在更新实体时添加租户标识for (int i = 0; i < propertyNames.length; i++) {if ("tenantId".equals(propertyNames[i])) {currentState[i] = TenantContext.getCurrentTenant();return true;}}return false;}
}

配置TenantContext,用于保存当前租户标识:

public class TenantContext {private static final ThreadLocal<String> currentTenant = new ThreadLocal<>();public static void setCurrentTenant(String tenantId) {currentTenant.set(tenantId);}public static String getCurrentTenant() {return currentTenant.get();}public static void clear() {currentTenant.remove();}
}
5. 创建租户解析器

租户解析器用于从请求中提取租户标识,并设置到TenantContext中。我们可以通过Spring的过滤器来实现这一功能。

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;public class TenantFilter implements Filter {@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)throws IOException, ServletException {HttpServletRequest httpRequest = (HttpServletRequest) request;String tenantId = httpRequest.getHeader("X-TenantID");if (tenantId != null) {TenantContext.setCurrentTenant(tenantId);}try {chain.doFilter(request, response);} finally {TenantContext.clear();}}@Overridepublic void init(FilterConfig filterConfig) throws ServletException {}@Overridepublic void destroy() {}
}

在配置类中注册这个过滤器:

import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class TenantConfiguration {@Beanpublic FilterRegistrationBean<TenantFilter> tenantFilter() {FilterRegistrationBean<TenantFilter> registrationBean = new FilterRegistrationBean<>();registrationBean.setFilter(new TenantFilter());registrationBean.addUrlPatterns("/*");return registrationBean;}
}
6. 配置实体和存储库

创建一个示例实体,并在其中包含租户标识字段:

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;@Entity
public class Product {@Id@GeneratedValue(strategy = GenerationType.IDENTITY)private Long id;private String tenantId;private String name;private Double price;// Getter和Setter方法
}

创建一个Spring Data JPA存储库接口:

import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;public interface ProductRepository extends JpaRepository<Product, Long> {List<Product> findByTenantId(String tenantId);
}
7. 测试多租户实现

创建一个简单的控制器来测试多租户功能:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;import java.util.List;@RestController
@RequestMapping("/products")
public class ProductController {@Autowiredprivate ProductRepository productRepository;@PostMappingpublic Product createProduct(@RequestBody Product product) {return productRepository.save(product);}@GetMappingpublic List<Product> getProducts() {String tenantId = TenantContext.getCurrentTenant();return productRepository.findByTenantId(tenantId);}
}

测试多租户功能可以通过以下步骤进行:

  1. 启动Spring Boot应用程序。
  2. 使用不同的X-TenantID头发送请求来创建和获取产品。

例如,使用cURL命令创建和获取产品:

# 创建产品,租户ID为tenant1
curl -H "X-TenantID: tenant1" -X POST -d '{"name": "Product A", "price": 10.99}' -H "Content-Type: application/json" http://localhost:8080/products# 创建产品,租户ID为tenant2
curl -H "X-TenantID: tenant2" -X POST -d '{"name": "Product B", "price": 15.99}' -H "Content-Type: application/json" http://localhost:8080/products# 获取产品,租户ID为tenant1
curl -H "X-TenantID: tenant1" http://localhost:8080/products# 获取产品,租户ID为tenant2
curl -H "X-TenantID: tenant2" http://localhost:8080/products

通过以上步骤,你可以看到不同租户具有自己的产品列表,实现了数据隔离的多租户架构。

8. 结论

本文详细介绍了如何在Spring Boot应用程序中配置和实现多租户支持。通过使用Spring Boot、Hibernate拦截器和自定义过滤器,我们可以实现共享数据库、共享数据表的多租户架构。希望通过本文的详细解释和代码示例,能帮助你更好地理解和实现多租户支持的Spring Boot应用程序。

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

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

相关文章

《人工智能大语言模型技术发展研究报告(2024)》【下载】

《人工智能大语言模型技术发展研究报告&#xff08;2024&#xff09;》下载 自2023年起&#xff0c;大模型技术产品的快速迭代和升级&#xff0c;已经成为全球科技竞争的关键因素。由中国软件评测中心发布的《人工智能大语言模型技术发展研究报告&#xff08;2024&#xff09;》…

kafka详解及应用场景介绍

Kafka架构 Kafka架构&#xff0c;由多个组件组成&#xff0c;如下图所示&#xff1a; 主要会包含&#xff1a;Topic、生产者、消费者、消费组等组件。 服务代理&#xff08;Broker&#xff09; Broker是Kafka集群中的一个节点&#xff0c;每个节点都是一个独立的Kafka服务器…

反激Flyback从逆向到初步设计(UC2844)

一.Flyback基本拓扑 国标gb/t 12325-2008《电能质量供电电压偏差》规定&#xff1a;220v单向供电电压偏差为标称电压的-10%&#xff0c;7%。 对应220V的标称电压&#xff0c;其浮动范围是在198~235.4V。以下运算均基于此规定进行。 首先220V进入EMI模块&#xff0c;消除差模干扰…

【Docker】Windows11环境下的安装

前置依赖环境配置 确保虚拟化开启 搜索栏直接搜索如下功能 勾选下面两个选项&#xff0c;确定 重启电脑&#xff0c;以管理员身份打开PowerShell wsl --status wsl --update打开微软应用商店选择一个Ubuntu版本下载并打开 输入一个用户名和密码 然后就可以在Windows下使…

FlowUs与生成式AI结合的未来展望:智能助手问问AI chat与自主代理Agent的应用

生成式AI在对话系统&#xff08;Chat&#xff09;和自主代理&#xff08;Agent&#xff09;中的应用将会带来显著的技术进步和商业机会。 对话系统&#xff08;Chat&#xff09; 对话系统是一种人工智能软件&#xff0c;它能够模拟人类对话&#xff0c;通过自然语言处理&…

go-kratos 学习笔记(7) 服务发现服务间通信grpc调用

服务发现 Registry 接口分为两个&#xff0c;Registrar 为实例注册和反注册&#xff0c;Discovery 为服务实例列表获取 创建一个 Discoverer 服务间的通信使用的grpc&#xff0c;放到data层&#xff0c;实现的是从uses服务调用orders服务 app/users/internal/data.go 加入 New…

2024安全大模型技术与市场研究报告

大模型驱动的AIGC引发技术革命&#xff0c;国资委强调国企需加大AI投入。大模型解决网络安全行业攻防不对等问题&#xff0c;国内外企业纷纷推出基于大模型的网络安全产品&#xff0c;AI将改变网络安全产品格局。 自 2022 年底开始&#xff0c;以 LLM(大语言模型&#xff0c;简…

PHP基础语法-Part2

if-else语句、switch语句 与其他语言相同 循环结构 for循环while循环do-while循环foreach循环&#xff0c;搭配数组使用 foreach ($age as $avlue) //只输出值 {xxx; } foreach ($age as $key > $avlue) //键和值都输出 {xxx; }foreach ($age as $key >…

k8s核心知识总结

写在前面 时间一下子到了7月份尾&#xff1b;整个7月份都乱糟糟的&#xff0c;不管怎么样&#xff0c;日子还是得过啊&#xff0c; 1、7月份核心了解个关于k8s&#xff0c;iceberg等相关技术&#xff0c;了解了相关的基础逻辑&#xff0c;虽然和数开主线有点偏&#xff0c;但是…

系统架构设计师②:操作系统

系统架构设计师②&#xff1a;操作系统 操作系统作用 ①管理系统的硬件、软件、数据资源 ②控制程序运行 ③人机之间的接口 ④应用软件与硬件之间的接口 进程管理 进程是程序在一个数据集合上运行的过程&#xff0c;它是系统进行资源分配和调度的一个独立单位。它由程序块、…

qt表格模型视图

Qt 提供了一套强大的模型/视图框架&#xff0c;允许你以一种非常灵活和高效的方式显示和处理数据。在 Qt 中&#xff0c;表格视图&#xff08;TableView&#xff09;和模型&#xff08;TableModel&#xff09;是这种框架的一部分&#xff0c;常用于显示和编辑表格数据。 以下是…

利用Java调用银行卡二要素接口

一、什么是银行卡二要素&#xff1f; 银行卡二要素验证接口是一种 API 接口&#xff0c;主要用于验证用户提供的银行卡号与姓名这两个要素是否一致。 二、银行卡二要素作用及场景有哪些&#xff1f; 其作用是通过核验用户的身份信息&#xff0c;判断是否为目标用户本人操作&…

Apache Spark:深度解析

文章目录 引言Apache Spark 官网链接Spark 的原理1. 核心组件2. 弹性分布式数据集&#xff08;RDD&#xff09;3. 执行模型 基础使用1. 环境搭建2. 示例代码 高级功能1. DataFrame 和 Dataset2. 机器学习3. 流处理 优缺点优点缺点 结论 引言 Apache Spark 是一个快速、通用、可…

[Github] Github网络错误,与VPN代理相关

报错类型&#xff1a; OpenSSL SSL_connect: Connection was reset in connection to http://github.com:443 前提&#xff1a;计算机已经开了VPN代理&#xff0c;造成无法正常通过github完成push/pull等操作 解决方法&#xff1a; 在终端中输入&#xff1a; git config -…

Lua 复数计算器

Lua复数计算器 主要包括复数的加减乘除操作&#xff0c;以及打印 编写复数类 -- ***** 元类 ***** Complex {real 0, imag 0}-- 构造函数 function Complex:new(real, imag)local o o or {}o.real real or 0o.imag imag or 0setmetatable(o, self)self.__index selfr…

【初阶数据结构】8.二叉树(3)

文章目录 4.实现链式结构二叉树4.1 前中后序遍历4.1.1 遍历规则4.1.2 代码实现 4.2 结点个数以及高度等4.3 层序遍历4.4 判断是否为完全二叉树4.5层序遍历和判断是否为完全二叉树完整代码 4.实现链式结构二叉树 用链表来表示一棵二叉树&#xff0c;即用链来指示元素的逻辑关系…

space desk设备屏幕拓展软件

在正常开发的时候一般采用多个屏幕的方式来提高效率&#xff0c;这时就采用hdmi和vga拓展的形式&#xff0c;前提是屏幕但往往有电源以及续航不够的问题&#xff0c;不太方便出门在外的话 这时我就推荐大家使用软件无线连接的形式 进行软件下载下图为投影端可以在pc端下载 我…

如何保护您的 WordPress 不被黑?

明月可以说是见到过太多 WordPress 网站被黑的示例了&#xff0c;加上平时明月也会接一些 WordPress 疑难杂症的解决服务订单&#xff0c;所以这方面绝对是专业对口了。作为一个资深 WordPress 博客站长&#xff0c;谁都有被黑过的经历&#xff0c;都是一步步走过来的&#xff…

【数据结构】搜索二叉树

二叉搜索树 二叉树的博客 在之前的数据结构的文章中已经基本对二叉树有一定的了解&#xff0c;二叉搜索树也是一种数据结构&#xff0c;下面将对二叉搜索树进行讲解。 二叉搜索树的概念 二叉搜索树又称为二叉排序树&#xff0c;它或者是一棵空树&#xff0c;或者是具有下面性…

ObservableCollection新增数据前判断数据是否存在

public class MyDataModel {public int Id { get; set; }public string Name { get; set; }}public static void Main(){// 创建 ObservableCollectionObservableCollection<MyDataModel> myDataCollection new ObservableCollection<MyDataModel>{new MyDataMode…