• Springboot整合ShardingJdbc实现分库分表方案


    一、创建库表

    1、创建两个数据库

    1. CREATE SCHEMA `shard_db_0` DEFAULT CHARACTER SET utf8 ;
    2. CREATE SCHEMA `shard_db_1` DEFAULT CHARACTER SET utf8 ;

    2、在每个数据库各创建三个分表

    1. CREATE TABLE `tb_order_0` (
    2.   `order_id` bigint(20) NOT NULL,
    3.   `buyer_id` bigint(20) not null comment '买家ID',
    4.   `seller_id` bigint(20) not null comment '卖家ID',
    5.   `order_name` varchar(64) not NULL COMMENT '商品名称',
    6.   `price` decimal(10,2) DEFAULT NULL COMMENT '商品价格',
    7.   PRIMARY KEY (`order_id`)
    8. ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
    1. CREATE TABLE `tb_order_1` (
    2.   `order_id` bigint(20) NOT NULL,
    3.   `buyer_id` bigint(20) not null comment '买家ID',
    4.   `seller_id` bigint(20) not null comment '卖家ID',
    5.   `order_name` varchar(64) not NULL COMMENT '商品名称',
    6.   `price` decimal(10,2) DEFAULT NULL COMMENT '商品价格',
    7.   PRIMARY KEY (`order_id`)
    8. ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
    1. CREATE TABLE `tb_order_2` (
    2.   `order_id` bigint(20) NOT NULL,
    3.   `buyer_id` bigint(20) not null comment '买家ID',
    4.   `seller_id` bigint(20) not null comment '卖家ID',
    5.   `order_name` varchar(64) not NULL COMMENT '商品名称',
    6.   `price` decimal(10,2) DEFAULT NULL COMMENT '商品价格',
    7.   PRIMARY KEY (`order_id`)
    8. ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

    2、创建工程

    1、引入maven依赖

    1. <?xml version="1.0" encoding="UTF-8"?>
    2. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    3. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    4. <modelVersion>4.0.0</modelVersion>
    5. <parent>
    6. <groupId>org.springframework.boot</groupId>
    7. <artifactId>spring-boot-starter-parent</artifactId>
    8. <version>3.3.1</version>
    9. <relativePath/> <!-- lookup parent from repository -->
    10. </parent>
    11. <groupId>com.example</groupId>
    12. <artifactId>sharding-sphere-demo</artifactId>
    13. <version>0.0.1-SNAPSHOT</version>
    14. <name>sharding-sphere-demo</name>
    15. <description>sharding-sphere-demo</description>
    16. <url/>
    17. <licenses>
    18. <license/>
    19. </licenses>
    20. <developers>
    21. <developer/>
    22. </developers>
    23. <scm>
    24. <connection/>
    25. <developerConnection/>
    26. <tag/>
    27. <url/>
    28. </scm>
    29. <properties>
    30. <java.version>17</java.version>
    31. </properties>
    32. <dependencies>
    33. <dependency>
    34. <groupId>org.springframework.boot</groupId>
    35. <artifactId>spring-boot-starter-web</artifactId>
    36. </dependency>
    37. <dependency>
    38. <groupId>org.projectlombok</groupId>
    39. <artifactId>lombok</artifactId>
    40. <optional>true</optional>
    41. </dependency>
    42. <dependency>
    43. <groupId>org.springframework.boot</groupId>
    44. <artifactId>spring-boot-starter-test</artifactId>
    45. <scope>test</scope>
    46. </dependency>
    47. <dependency>
    48. <groupId>mysql</groupId>
    49. <artifactId>mysql-connector-java</artifactId>
    50. <version>8.0.15</version>
    51. </dependency>
    52. <!-- MyBatis-Plus -->
    53. <dependency>
    54. <groupId>com.baomidou</groupId>
    55. <artifactId>mybatis-plus-spring-boot3-starter</artifactId>
    56. <version>3.5.7</version>
    57. </dependency>
    58. <!-- https://mvnrepository.com/artifact/org.apache.shardingsphere/shardingsphere-jdbc-core-spring-boot-starter -->
    59. <dependency>
    60. <groupId>org.apache.shardingsphere</groupId>
    61. <artifactId>shardingsphere-jdbc-core-spring-boot-starter</artifactId>
    62. <version>5.2.1</version>
    63. </dependency>
    64. <dependency>
    65. <groupId>org.apache.commons</groupId>
    66. <artifactId>commons-lang3</artifactId>
    67. </dependency>
    68. <dependency>
    69. <groupId>cn.hutool</groupId>
    70. <artifactId>hutool-all</artifactId>
    71. <version>5.3.1</version>
    72. </dependency>
    73. <dependency>
    74. <groupId>junit</groupId>
    75. <artifactId>junit</artifactId>
    76. <scope>test</scope>
    77. </dependency>
    78. </dependencies>
    79. <build>
    80. <plugins>
    81. <plugin>
    82. <groupId>org.springframework.boot</groupId>
    83. <artifactId>spring-boot-maven-plugin</artifactId>
    84. <configuration>
    85. <excludes>
    86. <exclude>
    87. <groupId>org.projectlombok</groupId>
    88. <artifactId>lombok</artifactId>
    89. </exclude>
    90. </excludes>
    91. </configuration>
    92. </plugin>
    93. </plugins>
    94. </build>
    95. </project>

    2、创建po

    1. @Builder
    2. @Data
    3. @TableName("tb_buyer")
    4. public class TbBuyer {
    5. @TableId
    6. private Long buyerId;
    7. private String buyerName;
    8. private Boolean sex;
    9. private Integer age;
    10. }
    1. @Builder
    2. @Data
    3. @TableName("tb_order")
    4. public class TbOrder {
    5. @TableId
    6. private Long orderId;
    7. private Long buyerId;
    8. private Long sellerId;
    9. private String orderName;
    10. private BigDecimal price;
    11. }
    1. @Builder
    2. @Data
    3. @TableName("tb_seller")
    4. public class TbSeller {
    5. @TableId
    6. private Long sellerId;
    7. private String sellerName;
    8. private Boolean sex;
    9. private Integer age;
    10. }

    3、创建mapper

    1. package com.example.shardingsphere.mapper;
    2. import com.baomidou.mybatisplus.core.mapper.BaseMapper;
    3. import com.example.shardingsphere.po.TbBuyer;
    4. import org.apache.ibatis.annotations.Mapper;
    5. @Mapper
    6. public interface TbBuyerMapper extends BaseMapper<TbBuyer> {
    7. // 可以在这里定义自定义方法
    8. }
    1. package com.example.shardingsphere.mapper;
    2. import com.baomidou.mybatisplus.core.mapper.BaseMapper;
    3. import com.example.shardingsphere.po.TbOrder;
    4. import org.apache.ibatis.annotations.Mapper;
    5. @Mapper
    6. public interface TbOrderMapper extends BaseMapper<TbOrder> {
    7. // 可以在这里定义自定义方法
    8. }
    1. package com.example.shardingsphere.mapper;
    2. import com.baomidou.mybatisplus.core.mapper.BaseMapper;
    3. import com.example.shardingsphere.po.TbSeller;
    4. import org.apache.ibatis.annotations.Mapper;
    5. @Mapper
    6. public interface TbSellerMapper extends BaseMapper<TbSeller> {
    7. // 可以在这里定义自定义方法
    8. }

    4、创建controller控制器

    1. package com.example.shardingsphere.web;
    2. import com.example.shardingsphere.mapper.TbBuyerMapper;
    3. import com.example.shardingsphere.mapper.TbOrderMapper;
    4. import com.example.shardingsphere.mapper.TbSellerMapper;
    5. import com.example.shardingsphere.po.TbOrder;
    6. import jakarta.annotation.Resource;
    7. import org.springframework.web.bind.annotation.GetMapping;
    8. import org.springframework.web.bind.annotation.PathVariable;
    9. import org.springframework.web.bind.annotation.RestController;
    10. import java.util.HashMap;
    11. import java.util.Map;
    12. @RestController
    13. public class OrderController {
    14. @Resource
    15. private TbBuyerMapper tbBuyerMapper ;
    16. @Resource
    17. private TbSellerMapper tbSellerMapper ;
    18. @Resource
    19. private TbOrderMapper tbOrderMapper ;
    20. /**
    21. * 查询订单详情
    22. */
    23. @GetMapping("/order/info/{orderId}")
    24. public Map orderInfo (@PathVariable Long orderId){
    25. Map orderMap = new HashMap<>() ;
    26. TbOrder order = tbOrderMapper.selectById(orderId) ;
    27. if (order != null){
    28. orderMap.put("order",order) ;
    29. orderMap.put("buyer",tbBuyerMapper.selectById(order.getBuyerId())) ;
    30. orderMap.put("seller",tbSellerMapper.selectById(order.getSellerId())) ;
    31. }
    32. return orderMap ;
    33. }
    34. }

    5、用到的工具类(雪花算法生成关联表主键ID,测试用,无特殊意义)

    1. package com.example.shardingsphere.provider;
    2. import cn.hutool.core.lang.Snowflake;
    3. import cn.hutool.core.util.IdUtil;
    4. import cn.hutool.core.util.RandomUtil;
    5. import lombok.extern.slf4j.Slf4j;
    6. import org.apache.commons.lang3.StringUtils;
    7. import org.apache.commons.lang3.SystemUtils;
    8. import org.springframework.boot.ApplicationArguments;
    9. import org.springframework.boot.ApplicationRunner;
    10. import org.springframework.stereotype.Component;
    11. import java.net.Inet4Address;
    12. import java.net.InetAddress;
    13. import java.net.UnknownHostException;
    14. /**
    15. * 雪花算法
    16. *
    17. */
    18. @Slf4j
    19. @Component
    20. public class SnowFlakeProvider implements ApplicationRunner {
    21. private long workerId;
    22. private Snowflake snowFlake;
    23. private long datacenterId;
    24. /**
    25. * 初始化方法,用于在类实例化后进行必要的设置。
    26. * 本方法主要用于确定WorkerId,这是一个在分布式系统中唯一标识当前节点的ID。
    27. * 它通过获取本地主机名或IP并转换为long值来实现。
    28. * 如果无法获取本地主机名或IP,或者转换过程中发生异常,将不设置workerId,可能导致后续ID生成失败。
    29. */
    30. @Override
    31. public void run(ApplicationArguments args) throws Exception {
    32. //初始化workId
    33. initWorkId();
    34. initDataCenterId();
    35. //初始化SnowflakeID生成器
    36. createSnowFlake(workerId, datacenterId);
    37. }
    38. /**
    39. * 根据IP Address 生成workId
    40. *
    41. * @return
    42. */
    43. private void initWorkId() {
    44. try {
    45. String hostAddress = Inet4Address.getLocalHost().getHostAddress();
    46. log.info("hostAddress========={}", hostAddress);
    47. int[] ints = StringUtils.toCodePoints(hostAddress);
    48. int sums = 0;
    49. for (int b : ints) {
    50. sums += b;
    51. }
    52. workerId= (long) (sums % 32);
    53. } catch (UnknownHostException e) {
    54. log.error("根据IP获取workId失败。", e);
    55. // 如果获取失败,则使用随机数备用
    56. workerId = RandomUtil.randomLong(0, 31);
    57. }
    58. }
    59. /**
    60. * 根据HostName 生成dataCenterId
    61. * @return
    62. */
    63. private void initDataCenterId() {
    64. String hostName = getHostName();
    65. log.info("hostName========={}", hostName);
    66. int[] ints = StringUtils.toCodePoints(hostName);
    67. int sums = 0;
    68. for (int i : ints) {
    69. sums += i;
    70. }
    71. datacenterId = (long) (sums % 32);
    72. }
    73. /**
    74. * 获取 hostName
    75. * SystemUtils.getHostName() 在mac系统为空处理
    76. * @return
    77. */
    78. public static String getHostName() {
    79. //获取当前操作系统名称,例如:windows xp,linux 等
    80. String osName = System.getProperty("os.name");
    81. String hostName = null;
    82. if(!StringUtils.startsWithIgnoreCase(osName,"mac")){
    83. hostName = SystemUtils.getHostName();
    84. }else{
    85. try {
    86. hostName = InetAddress.getLocalHost().getHostName().toUpperCase();
    87. } catch (UnknownHostException e) {
    88. hostName = "N/A";
    89. log.error("获取 hostName错误:", e);
    90. }
    91. }
    92. return hostName;
    93. }
    94. /**
    95. * 初始化SnowflakeID生成器。
    96. * 使用指定的workerId和datacenterId创建SnowflakeID生成器实例。如果创建失败,将抛出异常。
    97. *
    98. * @param workerId 工作节点ID,用于标识当前节点。
    99. * @param datacenterId 数据中心ID,用于标识数据中心。
    100. * @throws IllegalArgumentException 如果Snowflake实例创建失败,则抛出此异常。
    101. * @throws RuntimeException 如果Snowflake实例创建过程中发生其他异常,则抛出此异常。
    102. */
    103. private Snowflake createSnowFlake(long workerId, long datacenterId) {
    104. try {
    105. this.snowFlake = IdUtil.createSnowflake(workerId, datacenterId);
    106. // 参数合法性检查
    107. if (null == snowFlake) {
    108. throw new IllegalArgumentException("Failed to create Snowflake instance. Check workerId and datacenterId.");
    109. }
    110. return snowFlake;
    111. } catch (Exception e) {
    112. log.error("创建Snowflake实例失败,异常:{}", e.getMessage());
    113. throw new RuntimeException("Initialization failed for Snowflake ID generator.", e);
    114. }
    115. }
    116. /**
    117. * 获取一个唯一的雪花ID。使用Snowflake算法生成ID,该算法由Twitter开源。
    118. * 具体来说,这个方法调用了Snowflake实例的nextId方法来获取一个唯一的长整型ID。
    119. * 使用synchronized关键字确保了这个方法在多线程环境下的线程安全,
    120. * 保证了ID的生成不会因为并发而产生重复或错乱。
    121. *
    122. * @return 生成的唯一长整型ID。
    123. */
    124. public synchronized long snowflakeId() {
    125. // 调用Snowflake实例的nextId方法获取唯一ID
    126. return this.snowFlake.nextId();
    127. }
    128. /**
    129. * 生成基于Snowflake算法的唯一ID。
    130. *

    131. * 使用Snowflake算法生成唯一的分布式ID。该算法由Twitter提出,通过组合时间戳、工作机器ID和序列号来生成全局唯一的ID。
    132. * 具体结构如下:
    133. * - 1位符号位,用于区分正负,由于ID只能是正数,所以这个位始终为0。
    134. * - 41位时间戳,精确到毫秒,可以使用约69年。
    135. * - 10位工作机器ID,可以部署在1024个节点,包括5位数据中心ID和5位工作机器ID。
    136. * - 12位序列号,用于同一毫秒内生成的ID去重,每个节点每毫秒可以生成4096个ID。
    137. *

    138. * 参数:
    139. * workerId - 工作机器ID,用于标识不同的工作机器或进程。
    140. * datacenterId - 数据中心ID,用于标识不同的数据中心。
    141. *

    142. * 返回:
    143. * 一个长整型的唯一ID,根据Snowflake算法生成。
    144. */
    145. public synchronized long snowflakeId(long workerId, long datacenterId) {
    146. return createSnowFlake(workerId, datacenterId).nextId();
    147. }
    148. }

    6、测试用例

    1. package com.example.shardingsphere;
    2. import cn.hutool.core.util.RandomUtil;
    3. import cn.hutool.json.JSONUtil;
    4. import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
    5. import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
    6. import com.example.shardingsphere.mapper.TbOrderMapper;
    7. import com.example.shardingsphere.po.TbOrder;
    8. import com.example.shardingsphere.provider.SnowFlakeProvider;
    9. import lombok.extern.slf4j.Slf4j;
    10. import org.junit.Assert;
    11. import org.junit.Test;
    12. import org.springframework.beans.factory.annotation.Autowired;
    13. import java.math.BigDecimal;
    14. import java.util.ArrayList;
    15. import java.util.List;
    16. @Slf4j
    17. public class ShardTest extends ShardingSphereDemoApplicationTests{
    18. @Autowired
    19. private SnowFlakeProvider snowFlakeProvider;
    20. @Autowired
    21. private TbOrderMapper tbOrderMapper ;
    22. /**
    23. * 写入100条数据
    24. */
    25. @Test
    26. public void testOrderInsert (){
    27. List<TbOrder> list = new ArrayList<>();
    28. for (int i=1 ; i<= 10 ; i++){
    29. TbOrder order = TbOrder.builder()
    30. // .orderId(snowFlakeProvider.snowflakeId())
    31. .buyerId(snowFlakeProvider.snowflakeId())
    32. .sellerId(snowFlakeProvider.snowflakeId())
    33. .orderName("订单"+ RandomUtil.randomInt(6))
    34. .price(RandomUtil.randomBigDecimal().setScale(2, BigDecimal.ROUND_HALF_UP))
    35. .build();
    36. list.add(order);
    37. }
    38. tbOrderMapper.insert(list);
    39. }
    40. @Test
    41. public void testOrderQuery (){
    42. TbOrder order = tbOrderMapper.selectById(5) ;
    43. Assert.assertNotNull(order);
    44. log.info("查询结果:"+ JSONUtil.toJsonStr(order));
    45. }
    46. @Test
    47. public void testOrderUpdate (){
    48. TbOrder order = tbOrderMapper.selectById(3) ;
    49. Assert.assertNotNull(order);
    50. order.setBuyerId(1l);
    51. order.setSellerId(3l);
    52. int count = tbOrderMapper.updateById(order) ;
    53. log.info("更新记录数:"+count);
    54. }
    55. @Test
    56. public void testOrderPage (){
    57. //分页参数
    58. Page<TbOrder> rowPage = new Page<>(1, 2);
    59. //queryWrapper组装查询where条件
    60. LambdaQueryWrapper<TbOrder> queryWrapper = new LambdaQueryWrapper<>();
    61. Page<TbOrder> page = tbOrderMapper.selectPage(rowPage, queryWrapper);
    62. log.info("分页查询结果:"+ JSONUtil.toJsonStr(page));
    63. }
    64. }

    7、yml配置

    1. server:
    2. port: 8095
    3. spring:
    4. application:
    5. name: dynamic-datasource-spring-boot-starter
    6. shardingsphere:
    7. mode:
    8. type: Standalone
    9. repository:
    10. type: JDBC
    11. database:
    12. name: db0
    13. # 数据源配置
    14. datasource:
    15. # 数据源名称,多数据源以逗号分隔
    16. names: db0,db1
    17. db0:
    18. type: com.zaxxer.hikari.HikariDataSource
    19. driver-class-name: com.mysql.cj.jdbc.Driver
    20. jdbc-url: jdbc:mysql://xx:3306/shard_db_0?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
    21. username: xx
    22. password: xx
    23. db1:
    24. type: com.zaxxer.hikari.HikariDataSource
    25. driver-class-name: com.mysql.cj.jdbc.Driver
    26. jdbc-url: jdbc:mysql://xx:3306/shard_db_1?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
    27. username: xx
    28. password: xx
    29. # 分片规则配置
    30. rules:
    31. sharding:
    32. # 分片算法配置
    33. sharding-algorithms:
    34. database-inline:
    35. # 分片算法类型
    36. type: INLINE
    37. props:
    38. # 分片算法的行表达式(算法自行定义,此处为方便演示效果)
    39. algorithm-expression: db${order_id % 2}
    40. table-inline:
    41. # 分片算法类型
    42. type: INLINE
    43. props:
    44. # 分片算法的行表达式
    45. algorithm-expression: tb_order_${order_id % 3}
    46. tables:
    47. # 逻辑表名称
    48. tb_order:
    49. # 行表达式标识符可以使用 ${...} 或 $->{...},但前者与 Spring 本身的属性文件占位符冲突,因此在 Spring 环境中使用行表达式标识符建议使用 $->{...}
    50. actual-data-nodes: db${0..1}.tb_order_${0..2}
    51. # 分库策略
    52. database-strategy:
    53. standard:
    54. # 分片列名称
    55. sharding-column: order_id
    56. # 分片算法名称
    57. sharding-algorithm-name: database-inline
    58. # 分表策略
    59. table-strategy:
    60. standard:
    61. # 分片列名称
    62. sharding-column: order_id
    63. # 分片算法名称
    64. sharding-algorithm-name: table-inline
    65. # 属性配置
    66. props:
    67. # 展示修改以后的sql语句
    68. sql-show: true
    69. mybatis-plus:
    70. type-aliases-package: com.example.dynamic.po
    71. configuration:
    72. map-underscore-to-camel-case: true
    73. log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
    74. mapper-locations:
    75. - classpath:/mapper/*.xml

    至此,一个支持分库分表的工程搭建完成。

    ########################################################

    关于搭建过程中遇到的问题(shardingsphere-jdbc-core-spring-boot-starter 5.2.1)

    1、Caused by: java.lang.NoSuchMethodError: org.yaml.snakeyaml.representer.Representer: method 'void ()' not found

    解答:该问题是由于版本问题导致的,是个兼容性问题。

    shardingsphere-jdbc-core-spring-boot-starter 5.2.1中使用snakeyaml版本1.33 spring-boot-starter-web使用snakeyaml版本2.2 2.2中删除了Representer和SafeRepresenter的无参构造器,因此导致了该异常。

     可通过降低boot版本号从而降低其中snakeyaml版本号解决,但由于snakeyaml 1.x版本有安全问题,而shardingsphere-jdbc-core-spring-boot-starter已是当前最高版本,因此可通过重新jar中bean新增无参构造器去覆盖jar bean去解决。

    com.main.java下新增目录org.yaml.snakeyaml.representer

    目录下新建bean

    1. //
    2. // Source code recreated from a .class file by IntelliJ IDEA
    3. // (powered by FernFlower decompiler)
    4. //
    5. package org.yaml.snakeyaml.representer;
    6. import java.util.ArrayList;
    7. import java.util.Arrays;
    8. import java.util.Collection;
    9. import java.util.Collections;
    10. import java.util.HashMap;
    11. import java.util.Iterator;
    12. import java.util.List;
    13. import java.util.Map;
    14. import java.util.Set;
    15. import org.yaml.snakeyaml.DumperOptions;
    16. import org.yaml.snakeyaml.TypeDescription;
    17. import org.yaml.snakeyaml.DumperOptions.FlowStyle;
    18. import org.yaml.snakeyaml.introspector.Property;
    19. import org.yaml.snakeyaml.introspector.PropertyUtils;
    20. import org.yaml.snakeyaml.nodes.MappingNode;
    21. import org.yaml.snakeyaml.nodes.Node;
    22. import org.yaml.snakeyaml.nodes.NodeId;
    23. import org.yaml.snakeyaml.nodes.NodeTuple;
    24. import org.yaml.snakeyaml.nodes.ScalarNode;
    25. import org.yaml.snakeyaml.nodes.SequenceNode;
    26. import org.yaml.snakeyaml.nodes.Tag;
    27. public class Representer extends SafeRepresenter {
    28. protected Map<Class<? extends Object>, TypeDescription> typeDefinitions = Collections.emptyMap();
    29. public Representer() {
    30. this.representers.put(null, new RepresentJavaBean());
    31. }
    32. public Representer(DumperOptions options) {
    33. super(options);
    34. this.representers.put(null, new RepresentJavaBean());
    35. }
    36. public TypeDescription addTypeDescription(TypeDescription td) {
    37. if (Collections.EMPTY_MAP == this.typeDefinitions) {
    38. this.typeDefinitions = new HashMap();
    39. }
    40. if (td.getTag() != null) {
    41. this.addClassTag(td.getType(), td.getTag());
    42. }
    43. td.setPropertyUtils(this.getPropertyUtils());
    44. return (TypeDescription)this.typeDefinitions.put(td.getType(), td);
    45. }
    46. public void setPropertyUtils(PropertyUtils propertyUtils) {
    47. super.setPropertyUtils(propertyUtils);
    48. Collection<TypeDescription> tds = this.typeDefinitions.values();
    49. Iterator var3 = tds.iterator();
    50. while(var3.hasNext()) {
    51. TypeDescription typeDescription = (TypeDescription)var3.next();
    52. typeDescription.setPropertyUtils(propertyUtils);
    53. }
    54. }
    55. protected MappingNode representJavaBean(Set<Property> properties, Object javaBean) {
    56. List<NodeTuple> value = new ArrayList(properties.size());
    57. Tag customTag = (Tag)this.classTags.get(javaBean.getClass());
    58. Tag tag = customTag != null ? customTag : new Tag(javaBean.getClass());
    59. MappingNode node = new MappingNode(tag, value, FlowStyle.AUTO);
    60. this.representedObjects.put(javaBean, node);
    61. DumperOptions.FlowStyle bestStyle = FlowStyle.FLOW;
    62. Iterator var8 = properties.iterator();
    63. while(true) {
    64. NodeTuple tuple;
    65. do {
    66. if (!var8.hasNext()) {
    67. if (this.defaultFlowStyle != FlowStyle.AUTO) {
    68. node.setFlowStyle(this.defaultFlowStyle);
    69. } else {
    70. node.setFlowStyle(bestStyle);
    71. }
    72. return node;
    73. }
    74. Property property = (Property)var8.next();
    75. Object memberValue = property.get(javaBean);
    76. Tag customPropertyTag = memberValue == null ? null : (Tag)this.classTags.get(memberValue.getClass());
    77. tuple = this.representJavaBeanProperty(javaBean, property, memberValue, customPropertyTag);
    78. } while(tuple == null);
    79. if (!((ScalarNode)tuple.getKeyNode()).isPlain()) {
    80. bestStyle = FlowStyle.BLOCK;
    81. }
    82. Node nodeValue = tuple.getValueNode();
    83. if (!(nodeValue instanceof ScalarNode) || !((ScalarNode)nodeValue).isPlain()) {
    84. bestStyle = FlowStyle.BLOCK;
    85. }
    86. value.add(tuple);
    87. }
    88. }
    89. protected NodeTuple representJavaBeanProperty(Object javaBean, Property property, Object propertyValue, Tag customTag) {
    90. ScalarNode nodeKey = (ScalarNode)this.representData(property.getName());
    91. boolean hasAlias = this.representedObjects.containsKey(propertyValue);
    92. Node nodeValue = this.representData(propertyValue);
    93. if (propertyValue != null && !hasAlias) {
    94. NodeId nodeId = nodeValue.getNodeId();
    95. if (customTag == null) {
    96. if (nodeId == NodeId.scalar) {
    97. if (property.getType() != Enum.class && propertyValue instanceof Enum) {
    98. nodeValue.setTag(Tag.STR);
    99. }
    100. } else {
    101. if (nodeId == NodeId.mapping && property.getType() == propertyValue.getClass() && !(propertyValue instanceof Map) && !nodeValue.getTag().equals(Tag.SET)) {
    102. nodeValue.setTag(Tag.MAP);
    103. }
    104. this.checkGlobalTag(property, nodeValue, propertyValue);
    105. }
    106. }
    107. }
    108. return new NodeTuple(nodeKey, nodeValue);
    109. }
    110. protected void checkGlobalTag(Property property, Node node, Object object) {
    111. if (!object.getClass().isArray() || !object.getClass().getComponentType().isPrimitive()) {
    112. Class<?>[] arguments = property.getActualTypeArguments();
    113. if (arguments != null) {
    114. Class t;
    115. Iterator iter;
    116. Iterator var9;
    117. if (node.getNodeId() == NodeId.sequence) {
    118. t = arguments[0];
    119. SequenceNode snode = (SequenceNode)node;
    120. Iterable<Object> memberList = Collections.emptyList();
    121. if (object.getClass().isArray()) {
    122. memberList = Arrays.asList((Object[])object);
    123. } else if (object instanceof Iterable) {
    124. memberList = (Iterable)object;
    125. }
    126. iter = ((Iterable)memberList).iterator();
    127. if (iter.hasNext()) {
    128. var9 = snode.getValue().iterator();
    129. while(var9.hasNext()) {
    130. Node childNode = (Node)var9.next();
    131. Object member = iter.next();
    132. if (member != null && t.equals(member.getClass()) && childNode.getNodeId() == NodeId.mapping) {
    133. childNode.setTag(Tag.MAP);
    134. }
    135. }
    136. }
    137. } else if (object instanceof Set) {
    138. t = arguments[0];
    139. MappingNode mnode = (MappingNode)node;
    140. Iterator<NodeTuple> ite = mnode.getValue().iterator();
    141. Set<?> set = (Set)object;
    142. var9 = set.iterator();
    143. while(var9.hasNext()) {
    144. Object member = var9.next();
    145. NodeTuple tuple = (NodeTuple)ite.next();
    146. Node keyNode = tuple.getKeyNode();
    147. if (t.equals(member.getClass()) && keyNode.getNodeId() == NodeId.mapping) {
    148. keyNode.setTag(Tag.MAP);
    149. }
    150. }
    151. } else if (object instanceof Map) {
    152. t = arguments[0];
    153. Class<?> valueType = arguments[1];
    154. MappingNode mnode = (MappingNode)node;
    155. iter = mnode.getValue().iterator();
    156. while(iter.hasNext()) {
    157. NodeTuple tuple = (NodeTuple)iter.next();
    158. this.resetTag(t, tuple.getKeyNode());
    159. this.resetTag(valueType, tuple.getValueNode());
    160. }
    161. }
    162. }
    163. }
    164. }
    165. private void resetTag(Class<? extends Object> type, Node node) {
    166. Tag tag = node.getTag();
    167. if (tag.matches(type)) {
    168. if (Enum.class.isAssignableFrom(type)) {
    169. node.setTag(Tag.STR);
    170. } else {
    171. node.setTag(Tag.MAP);
    172. }
    173. }
    174. }
    175. protected Set<Property> getProperties(Class<? extends Object> type) {
    176. return this.typeDefinitions.containsKey(type) ? ((TypeDescription)this.typeDefinitions.get(type)).getProperties() : this.getPropertyUtils().getProperties(type);
    177. }
    178. protected class RepresentJavaBean implements Represent {
    179. protected RepresentJavaBean() {
    180. }
    181. public Node representData(Object data) {
    182. return Representer.this.representJavaBean(Representer.this.getProperties(data.getClass()), data);
    183. }
    184. }
    185. }
    1. //
    2. // Source code recreated from a .class file by IntelliJ IDEA
    3. // (powered by FernFlower decompiler)
    4. //
    5. package org.yaml.snakeyaml.representer;
    6. import java.math.BigInteger;
    7. import java.nio.charset.StandardCharsets;
    8. import java.util.ArrayList;
    9. import java.util.Arrays;
    10. import java.util.Calendar;
    11. import java.util.Date;
    12. import java.util.HashMap;
    13. import java.util.Iterator;
    14. import java.util.LinkedHashMap;
    15. import java.util.List;
    16. import java.util.Map;
    17. import java.util.Set;
    18. import java.util.TimeZone;
    19. import java.util.UUID;
    20. import java.util.regex.Pattern;
    21. import org.yaml.snakeyaml.DumperOptions;
    22. import org.yaml.snakeyaml.DumperOptions.FlowStyle;
    23. import org.yaml.snakeyaml.DumperOptions.NonPrintableStyle;
    24. import org.yaml.snakeyaml.DumperOptions.ScalarStyle;
    25. import org.yaml.snakeyaml.error.YAMLException;
    26. import org.yaml.snakeyaml.external.biz.base64Coder.Base64Coder;
    27. import org.yaml.snakeyaml.nodes.Node;
    28. import org.yaml.snakeyaml.nodes.Tag;
    29. import org.yaml.snakeyaml.reader.StreamReader;
    30. class SafeRepresenter extends BaseRepresenter {
    31. protected Map<Class<? extends Object>, Tag> classTags;
    32. protected TimeZone timeZone = null;
    33. protected DumperOptions.NonPrintableStyle nonPrintableStyle;
    34. private static final Pattern MULTILINE_PATTERN = Pattern.compile("\n|\u0085|\u2028|\u2029");
    35. public SafeRepresenter() {
    36. this(new DumperOptions());
    37. }
    38. public SafeRepresenter(DumperOptions options) {
    39. if (options == null) {
    40. throw new NullPointerException("DumperOptions must be provided.");
    41. } else {
    42. this.nullRepresenter = new RepresentNull();
    43. this.representers.put(String.class, new RepresentString());
    44. this.representers.put(Boolean.class, new RepresentBoolean());
    45. this.representers.put(Character.class, new RepresentString());
    46. this.representers.put(UUID.class, new RepresentUuid());
    47. this.representers.put(byte[].class, new RepresentByteArray());
    48. Represent primitiveArray = new RepresentPrimitiveArray();
    49. this.representers.put(short[].class, primitiveArray);
    50. this.representers.put(int[].class, primitiveArray);
    51. this.representers.put(long[].class, primitiveArray);
    52. this.representers.put(float[].class, primitiveArray);
    53. this.representers.put(double[].class, primitiveArray);
    54. this.representers.put(char[].class, primitiveArray);
    55. this.representers.put(boolean[].class, primitiveArray);
    56. this.multiRepresenters.put(Number.class, new RepresentNumber());
    57. this.multiRepresenters.put(List.class, new RepresentList());
    58. this.multiRepresenters.put(Map.class, new RepresentMap());
    59. this.multiRepresenters.put(Set.class, new RepresentSet());
    60. this.multiRepresenters.put(Iterator.class, new RepresentIterator());
    61. this.multiRepresenters.put((new Object[0]).getClass(), new RepresentArray());
    62. this.multiRepresenters.put(Date.class, new RepresentDate());
    63. this.multiRepresenters.put(Enum.class, new RepresentEnum());
    64. this.multiRepresenters.put(Calendar.class, new RepresentDate());
    65. this.classTags = new HashMap();
    66. this.nonPrintableStyle = options.getNonPrintableStyle();
    67. this.setDefaultScalarStyle(options.getDefaultScalarStyle());
    68. this.setDefaultFlowStyle(options.getDefaultFlowStyle());
    69. }
    70. }
    71. protected Tag getTag(Class<?> clazz, Tag defaultTag) {
    72. return this.classTags.containsKey(clazz) ? (Tag)this.classTags.get(clazz) : defaultTag;
    73. }
    74. public Tag addClassTag(Class<? extends Object> clazz, Tag tag) {
    75. if (tag == null) {
    76. throw new NullPointerException("Tag must be provided.");
    77. } else {
    78. return (Tag)this.classTags.put(clazz, tag);
    79. }
    80. }
    81. public TimeZone getTimeZone() {
    82. return this.timeZone;
    83. }
    84. public void setTimeZone(TimeZone timeZone) {
    85. this.timeZone = timeZone;
    86. }
    87. protected class RepresentUuid implements Represent {
    88. protected RepresentUuid() {
    89. }
    90. public Node representData(Object data) {
    91. return SafeRepresenter.this.representScalar(SafeRepresenter.this.getTag(data.getClass(), new Tag(UUID.class)), data.toString());
    92. }
    93. }
    94. protected class RepresentByteArray implements Represent {
    95. protected RepresentByteArray() {
    96. }
    97. public Node representData(Object data) {
    98. char[] binary = Base64Coder.encode((byte[])data);
    99. return SafeRepresenter.this.representScalar(Tag.BINARY, String.valueOf(binary), ScalarStyle.LITERAL);
    100. }
    101. }
    102. protected class RepresentEnum implements Represent {
    103. protected RepresentEnum() {
    104. }
    105. public Node representData(Object data) {
    106. Tag tag = new Tag(data.getClass());
    107. return SafeRepresenter.this.representScalar(SafeRepresenter.this.getTag(data.getClass(), tag), ((Enum)data).name());
    108. }
    109. }
    110. protected class RepresentDate implements Represent {
    111. protected RepresentDate() {
    112. }
    113. public Node representData(Object data) {
    114. Calendar calendar;
    115. if (data instanceof Calendar) {
    116. calendar = (Calendar)data;
    117. } else {
    118. calendar = Calendar.getInstance(SafeRepresenter.this.getTimeZone() == null ? TimeZone.getTimeZone("UTC") : SafeRepresenter.this.timeZone);
    119. calendar.setTime((Date)data);
    120. }
    121. int years = calendar.get(1);
    122. int months = calendar.get(2) + 1;
    123. int days = calendar.get(5);
    124. int hour24 = calendar.get(11);
    125. int minutes = calendar.get(12);
    126. int seconds = calendar.get(13);
    127. int millis = calendar.get(14);
    128. StringBuilder buffer = new StringBuilder(String.valueOf(years));
    129. while(buffer.length() < 4) {
    130. buffer.insert(0, "0");
    131. }
    132. buffer.append("-");
    133. if (months < 10) {
    134. buffer.append("0");
    135. }
    136. buffer.append(months);
    137. buffer.append("-");
    138. if (days < 10) {
    139. buffer.append("0");
    140. }
    141. buffer.append(days);
    142. buffer.append("T");
    143. if (hour24 < 10) {
    144. buffer.append("0");
    145. }
    146. buffer.append(hour24);
    147. buffer.append(":");
    148. if (minutes < 10) {
    149. buffer.append("0");
    150. }
    151. buffer.append(minutes);
    152. buffer.append(":");
    153. if (seconds < 10) {
    154. buffer.append("0");
    155. }
    156. buffer.append(seconds);
    157. if (millis > 0) {
    158. if (millis < 10) {
    159. buffer.append(".00");
    160. } else if (millis < 100) {
    161. buffer.append(".0");
    162. } else {
    163. buffer.append(".");
    164. }
    165. buffer.append(millis);
    166. }
    167. int gmtOffset = calendar.getTimeZone().getOffset(calendar.getTime().getTime());
    168. if (gmtOffset == 0) {
    169. buffer.append('Z');
    170. } else {
    171. if (gmtOffset < 0) {
    172. buffer.append('-');
    173. gmtOffset *= -1;
    174. } else {
    175. buffer.append('+');
    176. }
    177. int minutesOffset = gmtOffset / '\uea60';
    178. int hoursOffset = minutesOffset / 60;
    179. int partOfHour = minutesOffset % 60;
    180. if (hoursOffset < 10) {
    181. buffer.append('0');
    182. }
    183. buffer.append(hoursOffset);
    184. buffer.append(':');
    185. if (partOfHour < 10) {
    186. buffer.append('0');
    187. }
    188. buffer.append(partOfHour);
    189. }
    190. return SafeRepresenter.this.representScalar(SafeRepresenter.this.getTag(data.getClass(), Tag.TIMESTAMP), buffer.toString(), ScalarStyle.PLAIN);
    191. }
    192. }
    193. protected class RepresentSet implements Represent {
    194. protected RepresentSet() {
    195. }
    196. public Node representData(Object data) {
    197. Map<Object, Object> value = new LinkedHashMap();
    198. Set<Object> set = (Set)data;
    199. Iterator var4 = set.iterator();
    200. while(var4.hasNext()) {
    201. Object key = var4.next();
    202. value.put(key, (Object)null);
    203. }
    204. return SafeRepresenter.this.representMapping(SafeRepresenter.this.getTag(data.getClass(), Tag.SET), value, FlowStyle.AUTO);
    205. }
    206. }
    207. protected class RepresentMap implements Represent {
    208. protected RepresentMap() {
    209. }
    210. public Node representData(Object data) {
    211. return SafeRepresenter.this.representMapping(SafeRepresenter.this.getTag(data.getClass(), Tag.MAP), (Map)data, FlowStyle.AUTO);
    212. }
    213. }
    214. protected class RepresentPrimitiveArray implements Represent {
    215. protected RepresentPrimitiveArray() {
    216. }
    217. public Node representData(Object data) {
    218. Class<?> type = data.getClass().getComponentType();
    219. if (Byte.TYPE == type) {
    220. return SafeRepresenter.this.representSequence(Tag.SEQ, this.asByteList(data), FlowStyle.AUTO);
    221. } else if (Short.TYPE == type) {
    222. return SafeRepresenter.this.representSequence(Tag.SEQ, this.asShortList(data), FlowStyle.AUTO);
    223. } else if (Integer.TYPE == type) {
    224. return SafeRepresenter.this.representSequence(Tag.SEQ, this.asIntList(data), FlowStyle.AUTO);
    225. } else if (Long.TYPE == type) {
    226. return SafeRepresenter.this.representSequence(Tag.SEQ, this.asLongList(data), FlowStyle.AUTO);
    227. } else if (Float.TYPE == type) {
    228. return SafeRepresenter.this.representSequence(Tag.SEQ, this.asFloatList(data), FlowStyle.AUTO);
    229. } else if (Double.TYPE == type) {
    230. return SafeRepresenter.this.representSequence(Tag.SEQ, this.asDoubleList(data), FlowStyle.AUTO);
    231. } else if (Character.TYPE == type) {
    232. return SafeRepresenter.this.representSequence(Tag.SEQ, this.asCharList(data), FlowStyle.AUTO);
    233. } else if (Boolean.TYPE == type) {
    234. return SafeRepresenter.this.representSequence(Tag.SEQ, this.asBooleanList(data), FlowStyle.AUTO);
    235. } else {
    236. throw new YAMLException("Unexpected primitive '" + type.getCanonicalName() + "'");
    237. }
    238. }
    239. private List<Byte> asByteList(Object in) {
    240. byte[] array = (byte[])in;
    241. List<Byte> list = new ArrayList(array.length);
    242. for(int i = 0; i < array.length; ++i) {
    243. list.add(array[i]);
    244. }
    245. return list;
    246. }
    247. private List<Short> asShortList(Object in) {
    248. short[] array = (short[])in;
    249. List<Short> list = new ArrayList(array.length);
    250. for(int i = 0; i < array.length; ++i) {
    251. list.add(array[i]);
    252. }
    253. return list;
    254. }
    255. private List<Integer> asIntList(Object in) {
    256. int[] array = (int[])in;
    257. List<Integer> list = new ArrayList(array.length);
    258. for(int i = 0; i < array.length; ++i) {
    259. list.add(array[i]);
    260. }
    261. return list;
    262. }
    263. private List<Long> asLongList(Object in) {
    264. long[] array = (long[])in;
    265. List<Long> list = new ArrayList(array.length);
    266. for(int i = 0; i < array.length; ++i) {
    267. list.add(array[i]);
    268. }
    269. return list;
    270. }
    271. private List<Float> asFloatList(Object in) {
    272. float[] array = (float[])in;
    273. List<Float> list = new ArrayList(array.length);
    274. for(int i = 0; i < array.length; ++i) {
    275. list.add(array[i]);
    276. }
    277. return list;
    278. }
    279. private List<Double> asDoubleList(Object in) {
    280. double[] array = (double[])in;
    281. List<Double> list = new ArrayList(array.length);
    282. for(int i = 0; i < array.length; ++i) {
    283. list.add(array[i]);
    284. }
    285. return list;
    286. }
    287. private List<Character> asCharList(Object in) {
    288. char[] array = (char[])in;
    289. List<Character> list = new ArrayList(array.length);
    290. for(int i = 0; i < array.length; ++i) {
    291. list.add(array[i]);
    292. }
    293. return list;
    294. }
    295. private List<Boolean> asBooleanList(Object in) {
    296. boolean[] array = (boolean[])in;
    297. List<Boolean> list = new ArrayList(array.length);
    298. for(int i = 0; i < array.length; ++i) {
    299. list.add(array[i]);
    300. }
    301. return list;
    302. }
    303. }
    304. protected class RepresentArray implements Represent {
    305. protected RepresentArray() {
    306. }
    307. public Node representData(Object data) {
    308. Object[] array = (Object[])data;
    309. List<Object> list = Arrays.asList(array);
    310. return SafeRepresenter.this.representSequence(Tag.SEQ, list, FlowStyle.AUTO);
    311. }
    312. }
    313. private static class IteratorWrapper implements Iterable<Object> {
    314. private final Iterator<Object> iter;
    315. public IteratorWrapper(Iterator<Object> iter) {
    316. this.iter = iter;
    317. }
    318. public Iterator<Object> iterator() {
    319. return this.iter;
    320. }
    321. }
    322. protected class RepresentIterator implements Represent {
    323. protected RepresentIterator() {
    324. }
    325. public Node representData(Object data) {
    326. Iterator<Object> iter = (Iterator)data;
    327. return SafeRepresenter.this.representSequence(SafeRepresenter.this.getTag(data.getClass(), Tag.SEQ), new IteratorWrapper(iter), FlowStyle.AUTO);
    328. }
    329. }
    330. protected class RepresentList implements Represent {
    331. protected RepresentList() {
    332. }
    333. public Node representData(Object data) {
    334. return SafeRepresenter.this.representSequence(SafeRepresenter.this.getTag(data.getClass(), Tag.SEQ), (List)data, FlowStyle.AUTO);
    335. }
    336. }
    337. protected class RepresentNumber implements Represent {
    338. protected RepresentNumber() {
    339. }
    340. public Node representData(Object data) {
    341. Tag tag;
    342. String value;
    343. if (!(data instanceof Byte) && !(data instanceof Short) && !(data instanceof Integer) && !(data instanceof Long) && !(data instanceof BigInteger)) {
    344. Number number = (Number)data;
    345. tag = Tag.FLOAT;
    346. if (number.equals(Double.NaN)) {
    347. value = ".NaN";
    348. } else if (number.equals(Double.POSITIVE_INFINITY)) {
    349. value = ".inf";
    350. } else if (number.equals(Double.NEGATIVE_INFINITY)) {
    351. value = "-.inf";
    352. } else {
    353. value = number.toString();
    354. }
    355. } else {
    356. tag = Tag.INT;
    357. value = data.toString();
    358. }
    359. return SafeRepresenter.this.representScalar(SafeRepresenter.this.getTag(data.getClass(), tag), value);
    360. }
    361. }
    362. protected class RepresentBoolean implements Represent {
    363. protected RepresentBoolean() {
    364. }
    365. public Node representData(Object data) {
    366. String value;
    367. if (Boolean.TRUE.equals(data)) {
    368. value = "true";
    369. } else {
    370. value = "false";
    371. }
    372. return SafeRepresenter.this.representScalar(Tag.BOOL, value);
    373. }
    374. }
    375. protected class RepresentString implements Represent {
    376. protected RepresentString() {
    377. }
    378. public Node representData(Object data) {
    379. Tag tag = Tag.STR;
    380. DumperOptions.ScalarStyle style = SafeRepresenter.this.defaultScalarStyle;
    381. String value = data.toString();
    382. if (SafeRepresenter.this.nonPrintableStyle == NonPrintableStyle.BINARY && !StreamReader.isPrintable(value)) {
    383. tag = Tag.BINARY;
    384. byte[] bytes = value.getBytes(StandardCharsets.UTF_8);
    385. String checkValue = new String(bytes, StandardCharsets.UTF_8);
    386. if (!checkValue.equals(value)) {
    387. throw new YAMLException("invalid string value has occurred");
    388. }
    389. char[] binary = Base64Coder.encode(bytes);
    390. value = String.valueOf(binary);
    391. style = ScalarStyle.LITERAL;
    392. }
    393. if (SafeRepresenter.this.defaultScalarStyle == ScalarStyle.PLAIN && SafeRepresenter.MULTILINE_PATTERN.matcher(value).find()) {
    394. style = ScalarStyle.LITERAL;
    395. }
    396. return SafeRepresenter.this.representScalar(tag, value, style);
    397. }
    398. }
    399. protected class RepresentNull implements Represent {
    400. protected RepresentNull() {
    401. }
    402. public Node representData(Object data) {
    403. return SafeRepresenter.this.representScalar(Tag.NULL, "null");
    404. }
    405. }
    406. }

  • 相关阅读:
    算法金 | 不愧是腾讯,问基础巨细节 。。。
    基于Matlab在以地球为中心的场景中模拟和跟踪航路飞机仿真(附源码)
    tiup dm deploy
    系统开发系列 之java反射以及应用
    【CANN训练营笔记】OrangePI AIPro 体验手写体识别模型训练与推理
    【spring】初识spring基础
    Linux中常用数据库管理系统之MariaDB
    springboot整合redis-sentinel哨兵模式集群(二)
    react状态管理工具redux的使用
    Android 内核加载fw通用方法分析
  • 原文地址:https://blog.csdn.net/weixin_39195030/article/details/140429674