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

一、创建库表

1、创建两个数据库

CREATE SCHEMA `shard_db_0` DEFAULT CHARACTER SET utf8 ;
CREATE SCHEMA `shard_db_1` DEFAULT CHARACTER SET utf8 ;

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

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

2、创建工程

1、引入maven依赖

<?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>3.3.1</version><relativePath/> <!-- lookup parent from repository --></parent><groupId>com.example</groupId><artifactId>sharding-sphere-demo</artifactId><version>0.0.1-SNAPSHOT</version><name>sharding-sphere-demo</name><description>sharding-sphere-demo</description><url/><licenses><license/></licenses><developers><developer/></developers><scm><connection/><developerConnection/><tag/><url/></scm><properties><java.version>17</java.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></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><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.15</version></dependency><!-- MyBatis-Plus --><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-spring-boot3-starter</artifactId><version>3.5.7</version></dependency><!-- https://mvnrepository.com/artifact/org.apache.shardingsphere/shardingsphere-jdbc-core-spring-boot-starter --><dependency><groupId>org.apache.shardingsphere</groupId><artifactId>shardingsphere-jdbc-core-spring-boot-starter</artifactId><version>5.2.1</version></dependency><dependency><groupId>org.apache.commons</groupId><artifactId>commons-lang3</artifactId></dependency><dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.3.1</version></dependency><dependency><groupId>junit</groupId><artifactId>junit</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>

2、创建po

@Builder
@Data
@TableName("tb_buyer")
public class TbBuyer {@TableIdprivate Long buyerId;private String buyerName;private Boolean sex;private Integer age;}
@Builder
@Data
@TableName("tb_order")
public class TbOrder {@TableIdprivate Long orderId;private Long buyerId;private Long sellerId;private String orderName;private BigDecimal price;}
@Builder
@Data
@TableName("tb_seller")
public class TbSeller {@TableIdprivate Long sellerId;private String sellerName;private Boolean sex;private Integer age;}

3、创建mapper

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

4、创建controller控制器

package com.example.shardingsphere.web;import com.example.shardingsphere.mapper.TbBuyerMapper;
import com.example.shardingsphere.mapper.TbOrderMapper;
import com.example.shardingsphere.mapper.TbSellerMapper;
import com.example.shardingsphere.po.TbOrder;
import jakarta.annotation.Resource;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;import java.util.HashMap;
import java.util.Map;@RestController
public class OrderController {@Resourceprivate TbBuyerMapper tbBuyerMapper ;@Resourceprivate TbSellerMapper tbSellerMapper ;@Resourceprivate TbOrderMapper tbOrderMapper ;/*** 查询订单详情*/@GetMapping("/order/info/{orderId}")public Map<String,Object> orderInfo (@PathVariable Long orderId){Map<String,Object> orderMap = new HashMap<>() ;TbOrder order = tbOrderMapper.selectById(orderId) ;if (order != null){orderMap.put("order",order) ;orderMap.put("buyer",tbBuyerMapper.selectById(order.getBuyerId())) ;orderMap.put("seller",tbSellerMapper.selectById(order.getSellerId())) ;}return orderMap ;}
}

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

package com.example.shardingsphere.provider;import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.RandomUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.SystemUtils;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.UnknownHostException;/*** 雪花算法**/
@Slf4j
@Component
public class SnowFlakeProvider implements ApplicationRunner {private long workerId;private Snowflake snowFlake;private long datacenterId;/*** 初始化方法,用于在类实例化后进行必要的设置。* 本方法主要用于确定WorkerId,这是一个在分布式系统中唯一标识当前节点的ID。* 它通过获取本地主机名或IP并转换为long值来实现。* 如果无法获取本地主机名或IP,或者转换过程中发生异常,将不设置workerId,可能导致后续ID生成失败。*/@Overridepublic void run(ApplicationArguments args) throws Exception {//初始化workIdinitWorkId();initDataCenterId();//初始化SnowflakeID生成器createSnowFlake(workerId, datacenterId);}/*** 根据IP Address 生成workId** @return*/private void initWorkId() {try {String hostAddress = Inet4Address.getLocalHost().getHostAddress();log.info("hostAddress========={}", hostAddress);int[] ints = StringUtils.toCodePoints(hostAddress);int sums = 0;for (int b : ints) {sums += b;}workerId= (long) (sums % 32);} catch (UnknownHostException e) {log.error("根据IP获取workId失败。", e);// 如果获取失败,则使用随机数备用workerId = RandomUtil.randomLong(0, 31);}}/*** 根据HostName 生成dataCenterId* @return*/private void initDataCenterId() {String hostName = getHostName();log.info("hostName========={}", hostName);int[] ints = StringUtils.toCodePoints(hostName);int sums = 0;for (int i : ints) {sums += i;}datacenterId = (long) (sums % 32);}/*** 获取 hostName*   SystemUtils.getHostName() 在mac系统为空处理* @return*/public static String getHostName() {//获取当前操作系统名称,例如:windows xp,linux 等String osName = System.getProperty("os.name");String hostName = null;if(!StringUtils.startsWithIgnoreCase(osName,"mac")){hostName = SystemUtils.getHostName();}else{try {hostName = InetAddress.getLocalHost().getHostName().toUpperCase();} catch (UnknownHostException e) {hostName = "N/A";log.error("获取 hostName错误:", e);}}return hostName;}/*** 初始化SnowflakeID生成器。* 使用指定的workerId和datacenterId创建SnowflakeID生成器实例。如果创建失败,将抛出异常。** @param workerId 工作节点ID,用于标识当前节点。* @param datacenterId 数据中心ID,用于标识数据中心。* @throws IllegalArgumentException 如果Snowflake实例创建失败,则抛出此异常。* @throws RuntimeException 如果Snowflake实例创建过程中发生其他异常,则抛出此异常。*/private Snowflake createSnowFlake(long workerId, long datacenterId) {try {this.snowFlake = IdUtil.createSnowflake(workerId, datacenterId);// 参数合法性检查if (null == snowFlake) {throw new IllegalArgumentException("Failed to create Snowflake instance. Check workerId and datacenterId.");}return snowFlake;} catch (Exception e) {log.error("创建Snowflake实例失败,异常:{}", e.getMessage());throw new RuntimeException("Initialization failed for Snowflake ID generator.", e);}}/*** 获取一个唯一的雪花ID。使用Snowflake算法生成ID,该算法由Twitter开源。* 具体来说,这个方法调用了Snowflake实例的nextId方法来获取一个唯一的长整型ID。* 使用synchronized关键字确保了这个方法在多线程环境下的线程安全,* 保证了ID的生成不会因为并发而产生重复或错乱。** @return 生成的唯一长整型ID。*/public synchronized long snowflakeId() {// 调用Snowflake实例的nextId方法获取唯一IDreturn this.snowFlake.nextId();}/*** 生成基于Snowflake算法的唯一ID。* <p>* 使用Snowflake算法生成唯一的分布式ID。该算法由Twitter提出,通过组合时间戳、工作机器ID和序列号来生成全局唯一的ID。* 具体结构如下:* - 1位符号位,用于区分正负,由于ID只能是正数,所以这个位始终为0。* - 41位时间戳,精确到毫秒,可以使用约69年。* - 10位工作机器ID,可以部署在1024个节点,包括5位数据中心ID和5位工作机器ID。* - 12位序列号,用于同一毫秒内生成的ID去重,每个节点每毫秒可以生成4096个ID。* <p>* 参数:* workerId - 工作机器ID,用于标识不同的工作机器或进程。* datacenterId - 数据中心ID,用于标识不同的数据中心。* <p>* 返回:* 一个长整型的唯一ID,根据Snowflake算法生成。*/public synchronized long snowflakeId(long workerId, long datacenterId) {return createSnowFlake(workerId, datacenterId).nextId();}}

6、测试用例

package com.example.shardingsphere;import cn.hutool.core.util.RandomUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.shardingsphere.mapper.TbOrderMapper;
import com.example.shardingsphere.po.TbOrder;
import com.example.shardingsphere.provider.SnowFlakeProvider;
import lombok.extern.slf4j.Slf4j;
import org.junit.Assert;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;@Slf4j
public class ShardTest extends ShardingSphereDemoApplicationTests{@Autowiredprivate SnowFlakeProvider snowFlakeProvider;@Autowiredprivate TbOrderMapper tbOrderMapper ;/*** 写入100条数据*/@Testpublic void testOrderInsert (){List<TbOrder> list = new ArrayList<>();for (int i=1 ; i<= 10 ; i++){TbOrder order = TbOrder.builder()
//                    .orderId(snowFlakeProvider.snowflakeId()).buyerId(snowFlakeProvider.snowflakeId()).sellerId(snowFlakeProvider.snowflakeId()).orderName("订单"+ RandomUtil.randomInt(6)).price(RandomUtil.randomBigDecimal().setScale(2, BigDecimal.ROUND_HALF_UP)).build();list.add(order);}tbOrderMapper.insert(list);}@Testpublic void testOrderQuery (){TbOrder order = tbOrderMapper.selectById(5) ;Assert.assertNotNull(order);log.info("查询结果:"+ JSONUtil.toJsonStr(order));}@Testpublic void testOrderUpdate (){TbOrder order = tbOrderMapper.selectById(3) ;Assert.assertNotNull(order);order.setBuyerId(1l);order.setSellerId(3l);int count = tbOrderMapper.updateById(order) ;log.info("更新记录数:"+count);}@Testpublic void testOrderPage (){//分页参数Page<TbOrder> rowPage = new Page<>(1, 2);//queryWrapper组装查询where条件LambdaQueryWrapper<TbOrder> queryWrapper = new LambdaQueryWrapper<>();Page<TbOrder> page = tbOrderMapper.selectPage(rowPage, queryWrapper);log.info("分页查询结果:"+ JSONUtil.toJsonStr(page));}}

7、yml配置

server:port: 8095spring:application:name: dynamic-datasource-spring-boot-startershardingsphere:mode:type: Standalonerepository:type: JDBCdatabase:name: db0# 数据源配置datasource:# 数据源名称,多数据源以逗号分隔names: db0,db1db0:type: com.zaxxer.hikari.HikariDataSourcedriver-class-name: com.mysql.cj.jdbc.Driverjdbc-url: jdbc:mysql://xx:3306/shard_db_0?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=trueusername: xxpassword: xxdb1:type: com.zaxxer.hikari.HikariDataSourcedriver-class-name: com.mysql.cj.jdbc.Driverjdbc-url: jdbc:mysql://xx:3306/shard_db_1?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=trueusername: xxpassword: xx# 分片规则配置rules:sharding:# 分片算法配置sharding-algorithms:database-inline:# 分片算法类型type: INLINEprops:# 分片算法的行表达式(算法自行定义,此处为方便演示效果)algorithm-expression: db${order_id % 2}table-inline:# 分片算法类型type: INLINEprops:# 分片算法的行表达式algorithm-expression: tb_order_${order_id % 3}tables:# 逻辑表名称tb_order:# 行表达式标识符可以使用 ${...} 或 $->{...},但前者与 Spring 本身的属性文件占位符冲突,因此在 Spring 环境中使用行表达式标识符建议使用 $->{...}actual-data-nodes: db${0..1}.tb_order_${0..2}# 分库策略database-strategy:standard:# 分片列名称sharding-column: order_id# 分片算法名称sharding-algorithm-name: database-inline# 分表策略table-strategy:standard:# 分片列名称sharding-column: order_id# 分片算法名称sharding-algorithm-name: table-inline# 属性配置props:# 展示修改以后的sql语句sql-show: truemybatis-plus:type-aliases-package: com.example.dynamic.poconfiguration:map-underscore-to-camel-case: truelog-impl: org.apache.ibatis.logging.stdout.StdOutImplmapper-locations:- 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 <init>()' 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

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//package org.yaml.snakeyaml.representer;import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.yaml.snakeyaml.DumperOptions;
import org.yaml.snakeyaml.TypeDescription;
import org.yaml.snakeyaml.DumperOptions.FlowStyle;
import org.yaml.snakeyaml.introspector.Property;
import org.yaml.snakeyaml.introspector.PropertyUtils;
import org.yaml.snakeyaml.nodes.MappingNode;
import org.yaml.snakeyaml.nodes.Node;
import org.yaml.snakeyaml.nodes.NodeId;
import org.yaml.snakeyaml.nodes.NodeTuple;
import org.yaml.snakeyaml.nodes.ScalarNode;
import org.yaml.snakeyaml.nodes.SequenceNode;
import org.yaml.snakeyaml.nodes.Tag;public class Representer extends SafeRepresenter {protected Map<Class<? extends Object>, TypeDescription> typeDefinitions = Collections.emptyMap();public Representer() {this.representers.put(null, new RepresentJavaBean());}public Representer(DumperOptions options) {super(options);this.representers.put(null, new RepresentJavaBean());}public TypeDescription addTypeDescription(TypeDescription td) {if (Collections.EMPTY_MAP == this.typeDefinitions) {this.typeDefinitions = new HashMap();}if (td.getTag() != null) {this.addClassTag(td.getType(), td.getTag());}td.setPropertyUtils(this.getPropertyUtils());return (TypeDescription)this.typeDefinitions.put(td.getType(), td);}public void setPropertyUtils(PropertyUtils propertyUtils) {super.setPropertyUtils(propertyUtils);Collection<TypeDescription> tds = this.typeDefinitions.values();Iterator var3 = tds.iterator();while(var3.hasNext()) {TypeDescription typeDescription = (TypeDescription)var3.next();typeDescription.setPropertyUtils(propertyUtils);}}protected MappingNode representJavaBean(Set<Property> properties, Object javaBean) {List<NodeTuple> value = new ArrayList(properties.size());Tag customTag = (Tag)this.classTags.get(javaBean.getClass());Tag tag = customTag != null ? customTag : new Tag(javaBean.getClass());MappingNode node = new MappingNode(tag, value, FlowStyle.AUTO);this.representedObjects.put(javaBean, node);DumperOptions.FlowStyle bestStyle = FlowStyle.FLOW;Iterator var8 = properties.iterator();while(true) {NodeTuple tuple;do {if (!var8.hasNext()) {if (this.defaultFlowStyle != FlowStyle.AUTO) {node.setFlowStyle(this.defaultFlowStyle);} else {node.setFlowStyle(bestStyle);}return node;}Property property = (Property)var8.next();Object memberValue = property.get(javaBean);Tag customPropertyTag = memberValue == null ? null : (Tag)this.classTags.get(memberValue.getClass());tuple = this.representJavaBeanProperty(javaBean, property, memberValue, customPropertyTag);} while(tuple == null);if (!((ScalarNode)tuple.getKeyNode()).isPlain()) {bestStyle = FlowStyle.BLOCK;}Node nodeValue = tuple.getValueNode();if (!(nodeValue instanceof ScalarNode) || !((ScalarNode)nodeValue).isPlain()) {bestStyle = FlowStyle.BLOCK;}value.add(tuple);}}protected NodeTuple representJavaBeanProperty(Object javaBean, Property property, Object propertyValue, Tag customTag) {ScalarNode nodeKey = (ScalarNode)this.representData(property.getName());boolean hasAlias = this.representedObjects.containsKey(propertyValue);Node nodeValue = this.representData(propertyValue);if (propertyValue != null && !hasAlias) {NodeId nodeId = nodeValue.getNodeId();if (customTag == null) {if (nodeId == NodeId.scalar) {if (property.getType() != Enum.class && propertyValue instanceof Enum) {nodeValue.setTag(Tag.STR);}} else {if (nodeId == NodeId.mapping && property.getType() == propertyValue.getClass() && !(propertyValue instanceof Map) && !nodeValue.getTag().equals(Tag.SET)) {nodeValue.setTag(Tag.MAP);}this.checkGlobalTag(property, nodeValue, propertyValue);}}}return new NodeTuple(nodeKey, nodeValue);}protected void checkGlobalTag(Property property, Node node, Object object) {if (!object.getClass().isArray() || !object.getClass().getComponentType().isPrimitive()) {Class<?>[] arguments = property.getActualTypeArguments();if (arguments != null) {Class t;Iterator iter;Iterator var9;if (node.getNodeId() == NodeId.sequence) {t = arguments[0];SequenceNode snode = (SequenceNode)node;Iterable<Object> memberList = Collections.emptyList();if (object.getClass().isArray()) {memberList = Arrays.asList((Object[])object);} else if (object instanceof Iterable) {memberList = (Iterable)object;}iter = ((Iterable)memberList).iterator();if (iter.hasNext()) {var9 = snode.getValue().iterator();while(var9.hasNext()) {Node childNode = (Node)var9.next();Object member = iter.next();if (member != null && t.equals(member.getClass()) && childNode.getNodeId() == NodeId.mapping) {childNode.setTag(Tag.MAP);}}}} else if (object instanceof Set) {t = arguments[0];MappingNode mnode = (MappingNode)node;Iterator<NodeTuple> ite = mnode.getValue().iterator();Set<?> set = (Set)object;var9 = set.iterator();while(var9.hasNext()) {Object member = var9.next();NodeTuple tuple = (NodeTuple)ite.next();Node keyNode = tuple.getKeyNode();if (t.equals(member.getClass()) && keyNode.getNodeId() == NodeId.mapping) {keyNode.setTag(Tag.MAP);}}} else if (object instanceof Map) {t = arguments[0];Class<?> valueType = arguments[1];MappingNode mnode = (MappingNode)node;iter = mnode.getValue().iterator();while(iter.hasNext()) {NodeTuple tuple = (NodeTuple)iter.next();this.resetTag(t, tuple.getKeyNode());this.resetTag(valueType, tuple.getValueNode());}}}}}private void resetTag(Class<? extends Object> type, Node node) {Tag tag = node.getTag();if (tag.matches(type)) {if (Enum.class.isAssignableFrom(type)) {node.setTag(Tag.STR);} else {node.setTag(Tag.MAP);}}}protected Set<Property> getProperties(Class<? extends Object> type) {return this.typeDefinitions.containsKey(type) ? ((TypeDescription)this.typeDefinitions.get(type)).getProperties() : this.getPropertyUtils().getProperties(type);}protected class RepresentJavaBean implements Represent {protected RepresentJavaBean() {}public Node representData(Object data) {return Representer.this.representJavaBean(Representer.this.getProperties(data.getClass()), data);}}
}
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//package org.yaml.snakeyaml.representer;import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TimeZone;
import java.util.UUID;
import java.util.regex.Pattern;
import org.yaml.snakeyaml.DumperOptions;
import org.yaml.snakeyaml.DumperOptions.FlowStyle;
import org.yaml.snakeyaml.DumperOptions.NonPrintableStyle;
import org.yaml.snakeyaml.DumperOptions.ScalarStyle;
import org.yaml.snakeyaml.error.YAMLException;
import org.yaml.snakeyaml.external.biz.base64Coder.Base64Coder;
import org.yaml.snakeyaml.nodes.Node;
import org.yaml.snakeyaml.nodes.Tag;
import org.yaml.snakeyaml.reader.StreamReader;class SafeRepresenter extends BaseRepresenter {protected Map<Class<? extends Object>, Tag> classTags;protected TimeZone timeZone = null;protected DumperOptions.NonPrintableStyle nonPrintableStyle;private static final Pattern MULTILINE_PATTERN = Pattern.compile("\n|\u0085|\u2028|\u2029");public SafeRepresenter() {this(new DumperOptions());}public SafeRepresenter(DumperOptions options) {if (options == null) {throw new NullPointerException("DumperOptions must be provided.");} else {this.nullRepresenter = new RepresentNull();this.representers.put(String.class, new RepresentString());this.representers.put(Boolean.class, new RepresentBoolean());this.representers.put(Character.class, new RepresentString());this.representers.put(UUID.class, new RepresentUuid());this.representers.put(byte[].class, new RepresentByteArray());Represent primitiveArray = new RepresentPrimitiveArray();this.representers.put(short[].class, primitiveArray);this.representers.put(int[].class, primitiveArray);this.representers.put(long[].class, primitiveArray);this.representers.put(float[].class, primitiveArray);this.representers.put(double[].class, primitiveArray);this.representers.put(char[].class, primitiveArray);this.representers.put(boolean[].class, primitiveArray);this.multiRepresenters.put(Number.class, new RepresentNumber());this.multiRepresenters.put(List.class, new RepresentList());this.multiRepresenters.put(Map.class, new RepresentMap());this.multiRepresenters.put(Set.class, new RepresentSet());this.multiRepresenters.put(Iterator.class, new RepresentIterator());this.multiRepresenters.put((new Object[0]).getClass(), new RepresentArray());this.multiRepresenters.put(Date.class, new RepresentDate());this.multiRepresenters.put(Enum.class, new RepresentEnum());this.multiRepresenters.put(Calendar.class, new RepresentDate());this.classTags = new HashMap();this.nonPrintableStyle = options.getNonPrintableStyle();this.setDefaultScalarStyle(options.getDefaultScalarStyle());this.setDefaultFlowStyle(options.getDefaultFlowStyle());}}protected Tag getTag(Class<?> clazz, Tag defaultTag) {return this.classTags.containsKey(clazz) ? (Tag)this.classTags.get(clazz) : defaultTag;}public Tag addClassTag(Class<? extends Object> clazz, Tag tag) {if (tag == null) {throw new NullPointerException("Tag must be provided.");} else {return (Tag)this.classTags.put(clazz, tag);}}public TimeZone getTimeZone() {return this.timeZone;}public void setTimeZone(TimeZone timeZone) {this.timeZone = timeZone;}protected class RepresentUuid implements Represent {protected RepresentUuid() {}public Node representData(Object data) {return SafeRepresenter.this.representScalar(SafeRepresenter.this.getTag(data.getClass(), new Tag(UUID.class)), data.toString());}}protected class RepresentByteArray implements Represent {protected RepresentByteArray() {}public Node representData(Object data) {char[] binary = Base64Coder.encode((byte[])data);return SafeRepresenter.this.representScalar(Tag.BINARY, String.valueOf(binary), ScalarStyle.LITERAL);}}protected class RepresentEnum implements Represent {protected RepresentEnum() {}public Node representData(Object data) {Tag tag = new Tag(data.getClass());return SafeRepresenter.this.representScalar(SafeRepresenter.this.getTag(data.getClass(), tag), ((Enum)data).name());}}protected class RepresentDate implements Represent {protected RepresentDate() {}public Node representData(Object data) {Calendar calendar;if (data instanceof Calendar) {calendar = (Calendar)data;} else {calendar = Calendar.getInstance(SafeRepresenter.this.getTimeZone() == null ? TimeZone.getTimeZone("UTC") : SafeRepresenter.this.timeZone);calendar.setTime((Date)data);}int years = calendar.get(1);int months = calendar.get(2) + 1;int days = calendar.get(5);int hour24 = calendar.get(11);int minutes = calendar.get(12);int seconds = calendar.get(13);int millis = calendar.get(14);StringBuilder buffer = new StringBuilder(String.valueOf(years));while(buffer.length() < 4) {buffer.insert(0, "0");}buffer.append("-");if (months < 10) {buffer.append("0");}buffer.append(months);buffer.append("-");if (days < 10) {buffer.append("0");}buffer.append(days);buffer.append("T");if (hour24 < 10) {buffer.append("0");}buffer.append(hour24);buffer.append(":");if (minutes < 10) {buffer.append("0");}buffer.append(minutes);buffer.append(":");if (seconds < 10) {buffer.append("0");}buffer.append(seconds);if (millis > 0) {if (millis < 10) {buffer.append(".00");} else if (millis < 100) {buffer.append(".0");} else {buffer.append(".");}buffer.append(millis);}int gmtOffset = calendar.getTimeZone().getOffset(calendar.getTime().getTime());if (gmtOffset == 0) {buffer.append('Z');} else {if (gmtOffset < 0) {buffer.append('-');gmtOffset *= -1;} else {buffer.append('+');}int minutesOffset = gmtOffset / '\uea60';int hoursOffset = minutesOffset / 60;int partOfHour = minutesOffset % 60;if (hoursOffset < 10) {buffer.append('0');}buffer.append(hoursOffset);buffer.append(':');if (partOfHour < 10) {buffer.append('0');}buffer.append(partOfHour);}return SafeRepresenter.this.representScalar(SafeRepresenter.this.getTag(data.getClass(), Tag.TIMESTAMP), buffer.toString(), ScalarStyle.PLAIN);}}protected class RepresentSet implements Represent {protected RepresentSet() {}public Node representData(Object data) {Map<Object, Object> value = new LinkedHashMap();Set<Object> set = (Set)data;Iterator var4 = set.iterator();while(var4.hasNext()) {Object key = var4.next();value.put(key, (Object)null);}return SafeRepresenter.this.representMapping(SafeRepresenter.this.getTag(data.getClass(), Tag.SET), value, FlowStyle.AUTO);}}protected class RepresentMap implements Represent {protected RepresentMap() {}public Node representData(Object data) {return SafeRepresenter.this.representMapping(SafeRepresenter.this.getTag(data.getClass(), Tag.MAP), (Map)data, FlowStyle.AUTO);}}protected class RepresentPrimitiveArray implements Represent {protected RepresentPrimitiveArray() {}public Node representData(Object data) {Class<?> type = data.getClass().getComponentType();if (Byte.TYPE == type) {return SafeRepresenter.this.representSequence(Tag.SEQ, this.asByteList(data), FlowStyle.AUTO);} else if (Short.TYPE == type) {return SafeRepresenter.this.representSequence(Tag.SEQ, this.asShortList(data), FlowStyle.AUTO);} else if (Integer.TYPE == type) {return SafeRepresenter.this.representSequence(Tag.SEQ, this.asIntList(data), FlowStyle.AUTO);} else if (Long.TYPE == type) {return SafeRepresenter.this.representSequence(Tag.SEQ, this.asLongList(data), FlowStyle.AUTO);} else if (Float.TYPE == type) {return SafeRepresenter.this.representSequence(Tag.SEQ, this.asFloatList(data), FlowStyle.AUTO);} else if (Double.TYPE == type) {return SafeRepresenter.this.representSequence(Tag.SEQ, this.asDoubleList(data), FlowStyle.AUTO);} else if (Character.TYPE == type) {return SafeRepresenter.this.representSequence(Tag.SEQ, this.asCharList(data), FlowStyle.AUTO);} else if (Boolean.TYPE == type) {return SafeRepresenter.this.representSequence(Tag.SEQ, this.asBooleanList(data), FlowStyle.AUTO);} else {throw new YAMLException("Unexpected primitive '" + type.getCanonicalName() + "'");}}private List<Byte> asByteList(Object in) {byte[] array = (byte[])in;List<Byte> list = new ArrayList(array.length);for(int i = 0; i < array.length; ++i) {list.add(array[i]);}return list;}private List<Short> asShortList(Object in) {short[] array = (short[])in;List<Short> list = new ArrayList(array.length);for(int i = 0; i < array.length; ++i) {list.add(array[i]);}return list;}private List<Integer> asIntList(Object in) {int[] array = (int[])in;List<Integer> list = new ArrayList(array.length);for(int i = 0; i < array.length; ++i) {list.add(array[i]);}return list;}private List<Long> asLongList(Object in) {long[] array = (long[])in;List<Long> list = new ArrayList(array.length);for(int i = 0; i < array.length; ++i) {list.add(array[i]);}return list;}private List<Float> asFloatList(Object in) {float[] array = (float[])in;List<Float> list = new ArrayList(array.length);for(int i = 0; i < array.length; ++i) {list.add(array[i]);}return list;}private List<Double> asDoubleList(Object in) {double[] array = (double[])in;List<Double> list = new ArrayList(array.length);for(int i = 0; i < array.length; ++i) {list.add(array[i]);}return list;}private List<Character> asCharList(Object in) {char[] array = (char[])in;List<Character> list = new ArrayList(array.length);for(int i = 0; i < array.length; ++i) {list.add(array[i]);}return list;}private List<Boolean> asBooleanList(Object in) {boolean[] array = (boolean[])in;List<Boolean> list = new ArrayList(array.length);for(int i = 0; i < array.length; ++i) {list.add(array[i]);}return list;}}protected class RepresentArray implements Represent {protected RepresentArray() {}public Node representData(Object data) {Object[] array = (Object[])data;List<Object> list = Arrays.asList(array);return SafeRepresenter.this.representSequence(Tag.SEQ, list, FlowStyle.AUTO);}}private static class IteratorWrapper implements Iterable<Object> {private final Iterator<Object> iter;public IteratorWrapper(Iterator<Object> iter) {this.iter = iter;}public Iterator<Object> iterator() {return this.iter;}}protected class RepresentIterator implements Represent {protected RepresentIterator() {}public Node representData(Object data) {Iterator<Object> iter = (Iterator)data;return SafeRepresenter.this.representSequence(SafeRepresenter.this.getTag(data.getClass(), Tag.SEQ), new IteratorWrapper(iter), FlowStyle.AUTO);}}protected class RepresentList implements Represent {protected RepresentList() {}public Node representData(Object data) {return SafeRepresenter.this.representSequence(SafeRepresenter.this.getTag(data.getClass(), Tag.SEQ), (List)data, FlowStyle.AUTO);}}protected class RepresentNumber implements Represent {protected RepresentNumber() {}public Node representData(Object data) {Tag tag;String value;if (!(data instanceof Byte) && !(data instanceof Short) && !(data instanceof Integer) && !(data instanceof Long) && !(data instanceof BigInteger)) {Number number = (Number)data;tag = Tag.FLOAT;if (number.equals(Double.NaN)) {value = ".NaN";} else if (number.equals(Double.POSITIVE_INFINITY)) {value = ".inf";} else if (number.equals(Double.NEGATIVE_INFINITY)) {value = "-.inf";} else {value = number.toString();}} else {tag = Tag.INT;value = data.toString();}return SafeRepresenter.this.representScalar(SafeRepresenter.this.getTag(data.getClass(), tag), value);}}protected class RepresentBoolean implements Represent {protected RepresentBoolean() {}public Node representData(Object data) {String value;if (Boolean.TRUE.equals(data)) {value = "true";} else {value = "false";}return SafeRepresenter.this.representScalar(Tag.BOOL, value);}}protected class RepresentString implements Represent {protected RepresentString() {}public Node representData(Object data) {Tag tag = Tag.STR;DumperOptions.ScalarStyle style = SafeRepresenter.this.defaultScalarStyle;String value = data.toString();if (SafeRepresenter.this.nonPrintableStyle == NonPrintableStyle.BINARY && !StreamReader.isPrintable(value)) {tag = Tag.BINARY;byte[] bytes = value.getBytes(StandardCharsets.UTF_8);String checkValue = new String(bytes, StandardCharsets.UTF_8);if (!checkValue.equals(value)) {throw new YAMLException("invalid string value has occurred");}char[] binary = Base64Coder.encode(bytes);value = String.valueOf(binary);style = ScalarStyle.LITERAL;}if (SafeRepresenter.this.defaultScalarStyle == ScalarStyle.PLAIN && SafeRepresenter.MULTILINE_PATTERN.matcher(value).find()) {style = ScalarStyle.LITERAL;}return SafeRepresenter.this.representScalar(tag, value, style);}}protected class RepresentNull implements Represent {protected RepresentNull() {}public Node representData(Object data) {return SafeRepresenter.this.representScalar(Tag.NULL, "null");}}
}

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

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

相关文章

dom4j 操作 xml 之按照顺序插入标签

最近学了一下 dom4j 操作 xml 文件&#xff0c;特此记录一下。 public class Dom4jNullTagFiller {public static void main(String[] args) throws DocumentException {SAXReader reader new SAXReader();//加载 xml 文件Document document reader.read("C:\\Users\\24…

【数据结构】探索排序的奥秘

若有不懂地方&#xff0c;可查阅我之前文章哦&#xff01; 个人主页&#xff1a;小八哥向前冲~_csdn博客 所属专栏&#xff1a;数据结构_专栏 目录 排序的概念 几种排序方法介绍 冒泡排序 选择排序 插入排序 堆排序 向上调整建堆排序 向下调整建堆排序 希尔排序 快速…

前后端数据交互设计到的跨域问题

前后端分离项目的跨域问题及解决办法 一、跨域简述 1、问题描述 这里前端vue项目的端口号为9000&#xff0c;后端springboot项目的端口号为8080 2、什么是跨域 当一个请求url的协议、域名、端口三者之间任意一个与当前页面url不同即为跨域 当前页面url被请求页面url是否…

K8S 上部署 Emqx

文章目录 安装方式一&#xff1a;1. 快速部署一个简单的 EMQX 集群&#xff1a;2. 部署一个持久化的 EMQX 集群&#xff1a;3. 部署 EMQX Edge 集群和 EMQX 企业版集群&#xff1a; 安装方式二&#xff1a;定制化部署1. 使用 Pod 直接部署 EMQX Broker2. 使用 Deoloyment 部署 …

Jmeter关联

案例脚本实现&#xff1a;选择商品加入购物车 客户端发送一个登录的HTTP请求&#xff0c;服务端返回一个带着token的响应&#xff0c;后续发出一个带token信息的加入购物车的HTTP请求&#xff0c;返回响应。 关联&#xff1a;当请求直接由依赖关系的时候&#xff0c;比如一个请…

LLM基础模型系列:Prompt-Tuning

------->更多内容&#xff0c;请移步“鲁班秘笈”&#xff01;&#xff01;<------ 大型预训练语言模型的规模不断扩大&#xff0c;在许多自然语言处理 &#xff08;NLP&#xff09; 基准测试中取得了最先进的结果。自GPT和BERT开发以来&#xff0c;标准做法一直是在下游…

IDEA中Git常用操作及Git存储原理

Git简介与使用 Intro Git is a free and open source distributed version control system designed to handle everything from small to very large projects with speed and efficiency. Git是一款分布式版本控制系统&#xff08;VCS&#xff09;&#xff0c;是团队合作开发…

2010-2022年别克英朗维修手册电路图线路图接线图资料更新

经过整理&#xff0c;2010-2022年别克英朗汽车全系列已经更新至汽修帮手资料库内&#xff0c;覆盖市面上99%车型&#xff0c;包括维修手册、电路图、新车特征、车身钣金维修数据、全车拆装、扭力、发动机大修、发动机正时、保养、电路图、针脚定义、模块传感器、保险丝盒图解对…

How to integrate GPT-4 model hosted on Azure with the gptstudio package

题意&#xff1a;怎样将托管在Azure上的GPT-4模型与gptstudio包集成&#xff1f; 问题背景&#xff1a; I am looking to integrate the OpenAI GPT-4 model into my application. Here are the details I have: Endpoint: https://xxxxxxxxxxxxxxx.openai.azure.com/Locatio…

uniapp 开发 App 对接官方更新功能

插件地址&#xff1a;升级中心 uni-upgrade-center - App - DCloud 插件市场 首先创建一个 uni-admin 项目&#xff0c;选择你要部署的云开发服务商&#xff1a; 然后会自动下载模板&#xff0c;部署云数据库、云函数 第二步&#xff1a;将新创建的 uni-admin 项目托管到…

[算法] 优先算法(六):二分查找算法(下)

&#x1f338;个人主页:https://blog.csdn.net/2301_80050796?spm1000.2115.3001.5343 &#x1f3f5;️热门专栏: &#x1f9ca; Java基本语法(97平均质量分)https://blog.csdn.net/2301_80050796/category_12615970.html?spm1001.2014.3001.5482 &#x1f355; Collection与…

传输层和网络层的关系,ip协议+ip地址+ip报头字段介绍(4位TOP字段,8位生存时间(ttl)),ip地址和端口号的作用

目录 传输层和网络层的关系 引入 介绍 ip协议 介绍 ip地址 引入 数据传递过程 举例(ip地址的作用) ip报头 格式 4位版本号 ip地址不足的问题 8位服务类型 4位TOP(type of service)字段 最小延时 最大吞吐量 4位首部长度 16位总长度 8位协议号 首部校验和…

vivado FFT IP Core

文章目录 前言FFT IP 接口介绍接口简介tdata 格式说明 其他细节关于计算精度及缩放系数计算溢出架构选择数据顺序实时/非实时模式数据输入输出时序关于配置信息的应用时间节点 FFT IP 例化介绍控制代码实现 & 测试参考文献 前言 由于计算资源受限&#xff0c;准备将上位机 …

【Linux应用编程】系统信息与资源 | 如获取、设置系统时间、日期、/proc 虚拟文件系统等

系统信息与系统资源 通过 Linux 系统调用或 C 库函数获取系统信息&#xff08;如获取系统时间、日期以及设置系统时间、日期等&#xff09;&#xff1b; Linux 系统下的/proc 虚拟文件系统&#xff08;读取系统、进程有关信息&#xff09;&#xff1b; 系统信息 主要介绍了用…

成都亚恒丰创教育科技有限公司 【插画猴子:笔尖下的灵动世界】

在浩瀚的艺术海洋中&#xff0c;每一种创作形式都是人类情感与想象力的独特表达。而插画&#xff0c;作为这一广阔领域中的璀璨明珠&#xff0c;以其独特的视觉语言和丰富的叙事能力&#xff0c;构建了一个又一个令人遐想连篇的梦幻空间。成都亚恒丰创教育科技有限公司 在众多插…

数据采集监控平台:挖掘数据价值 高效高速生产!

在当今数字化的时代&#xff0c;数据已成为企业非常宝贵的资产之一。然而&#xff0c;要充分发挥数据的潜力&#xff0c;离不开一个强大的数据采集监控平台&#xff0c;尤其是生产制造行业。它不仅是数据的收集者&#xff0c;更是洞察生产的智慧之眼&#xff0c;高效高速处理产…

昇思MindSpore学习开始

昇思MindSpore是一个全场景深度学习框架&#xff0c;旨在实现易开发、高效执行、全场景统一部署三大目标。 其中&#xff0c;易开发表现为API友好、调试难度低&#xff1b;高效执行包括计算效率、数据预处理效率和分布式训练效率&#xff1b;全场景则指框架同时支持云、边缘以…

stm32:CAN通讯

目录 介绍 协议层 CAN的 帧/报文 种类 数据帧 远程帧&#xff08;遥控帧&#xff09; 错误帧 过载帧 帧间隔 总线仲裁 stm32的CAN外设 工作模式 测试模式 功能框图 时序 标准时序 例子 环回静默模式测试 寄存器代码 HAL版本 介绍 一种功能丰富的车用总线标…

基于JAVA+SpringBoot+Vue+uniapp+协同过滤算法+爬虫+AI的减肥小程序

✌全网粉丝20W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取项目下载方式&#x1f345; 一、项目背景介绍&#xff1a; 小程序用户登录&#…

Guava LocalCache源码分析:LocalCache的get、put、expand、refresh、remove、clear、cleanUp(一)

Guava LocalCache源码分析&#xff1a;LocalCache的get、put、expand 前言一、get二、put三、expand相关链接 前言 上篇文章&#xff0c;详细描写了Guava LocalCache怎样如ConcurrentHashMap对缓存数据进行了分段存储。本章主要针对LocalCache重要的几个接口进行说明。 一、g…