DBUnit增强:填充随机数据和相对时间数据

embedded/2024/12/22 21:39:18/

痛点

测试环境验证时,遇到与当前相对时间相关的测试吗?准备一份SQL?隔一段时间就不能用了。每过一段时间去更新脚本或重置系统时间?看上去也不是很合适的解决方案。依赖数据测试时要重新做,演示时候得全部改,如果你遇到一样的问题,可以看下本人使用的这个解决方案

DBUnit

DBUnit是一个测试框架,它通过一份XML数据反向设置到数据库,能自动维护数据的格式(有多少人遇到数值字段忘记加引号的BUG的举手)。准备的数据类似这样:

java">	<!-- 省份树节点 --><SYS_TREE_NODE TREE_NODE_ID="10000" UPPER_TREE_NODE_ID="5" TREE_NODE_TYPE_CODE="4" SYS_OBJECT_ID="10000" ICON="[null]" TREE_NODE_NM="安徽省" TREE_NODE_POSITION="100" IF_SYS_RESERVE="N" NODE_PATH_DATA="5" CREATE_TIME="$R{T0*}R$" UPDATE_TIME="$R{T0*}R$" CREATE_USER_ID="1" UPDATE_USER_ID="1"/><SYS_TREE_NODE TREE_NODE_ID="10900" UPPER_TREE_NODE_ID="5" TREE_NODE_TYPE_CODE="4" SYS_OBJECT_ID="10900" ICON="[null]" TREE_NODE_NM="北京市" TREE_NODE_POSITION="100" IF_SYS_RESERVE="N" NODE_PATH_DATA="5" CREATE_TIME="$R{T0*}R$" UPDATE_TIME="$R{T0*}R$" CREATE_USER_ID="1" UPDATE_USER_ID="1"/><SYS_TREE_NODE TREE_NODE_ID="11800" UPPER_TREE_NODE_ID="5" TREE_NODE_TYPE_CODE="4" SYS_OBJECT_ID="11800" ICON="[null]" TREE_NODE_NM="重庆市" TREE_NODE_POSITION="100" IF_SYS_RESERVE="N" NODE_PATH_DATA="5" CREATE_TIME="$R{T0*}R$" UPDATE_TIME="$R{T0*}R$" CREATE_USER_ID="1" UPDATE_USER_ID="1"/>

由于统一都是字符形式,手写比较舒服。也可以从数据库导出为XML

方案

DBUnit有一个扩展点,就是可以添加FilteredDataSet来实现加载过程中的数据过滤/替换,因为操作的执行接口:

java">    public abstract void execute(IDatabaseConnection connection,IDataSet dataSet) throws DatabaseUnitException, SQLException;

执行的是一个IDataSet接口,该接口实现数据的状态过程,我们可以基于该接口进行扩展,在状态的过程中,对于我们需要的数据进行替换。这里我们选择从AbstractDataSet进行扩展。

替换处理器

我们定义了一组ReplacementProcessor,用于对读取过程的数据进行替换处理

java">public interface ReplacementProcessor {Object replacementSubStrToObject(ITable table, String column,  String string, IDatabaseConnection connection, DBTYPE dbType);String getStartDelim();String getEndDelim();
}

我们实现的ReplacementDataSet如下

java">package org.ccframe.commons.dbunit;import org.ccframe.commons.util.DbUnitUtils.DBTYPE;
import org.dbunit.database.IDatabaseConnection;
import org.dbunit.dataset.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import java.util.ArrayList;
import java.util.List;public class ReplacementDataSet extends AbstractDataSet {/*** Logger for this class*/private static final Logger LOGGER = LoggerFactory.getLogger(ReplacementDataSet.class);private final IDataSet dataSet;private IDatabaseConnection connection;private DBTYPE dbType;private List<ReplacementProcessor> processorList = new ArrayList<ReplacementProcessor>();private static int tableId = 0;public ReplacementDataSet(IDataSet dataSet, IDatabaseConnection connection, DBTYPE dbType, List<ReplacementProcessor> processorList){this.dataSet = dataSet;this.connection = connection;this.dbType = dbType;this.processorList.addAll(processorList);}private ReplacementTable createReplacementTable(ITable table){tableId ++;return  new ReplacementTable(table, tableId, connection, dbType, processorList);}// AbstractDataSet classprotected ITableIterator createIterator(boolean reversed)throws DataSetException{return new ReplacementIterator(reversed ?dataSet.reverseIterator() : dataSet.iterator());}// IDataSet interfacepublic String[] getTableNames() throws DataSetException{LOGGER.debug("getTableNames() - start");return dataSet.getTableNames();}public ITableMetaData getTableMetaData(String tableName)throws DataSetException{return dataSet.getTableMetaData(tableName);}public ITable getTable(String tableName) throws DataSetException{return createReplacementTable(dataSet.getTable(tableName));}// ReplacementIterator classprivate class ReplacementIterator implements ITableIterator{//        private final Logger logger = LoggerFactory.getLogger(ReplacementIterator.class);private final ITableIterator iterator;public ReplacementIterator(ITableIterator iterator){this.iterator = iterator;}// ITableIterator interfacepublic boolean next() throws DataSetException{return iterator.next();}public ITableMetaData getTableMetaData() throws DataSetException{return iterator.getTableMetaData();}public ITable getTable() throws DataSetException{return createReplacementTable(iterator.getTable());}}
}

这里我们针对ITable实现了自己的替换用的数据表ReplacementTable,用于在读取过程中getValue时进行替换

java">package org.ccframe.commons.dbunit;import com.google.common.base.CaseFormat;
import org.ccframe.commons.helper.SpringContextHelper;
import org.ccframe.commons.util.DbUnitUtils.DBTYPE;
import org.ccframe.config.Global;
import org.dbunit.database.IDatabaseConnection;
import org.dbunit.dataset.DataSetException;
import org.dbunit.dataset.ITable;
import org.dbunit.dataset.ITableMetaData;
import org.redisson.api.RAtomicLong;
import org.redisson.api.RedissonClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;public class ReplacementTable implements ITable{/*** Logger for this class*/private static final Logger LOGGER = LoggerFactory.getLogger(ReplacementTable.class);private static final int OBJECT_CACHE_SIZE = 50; //50个fieldprivate final ITable table;private IDatabaseConnection connection;private DBTYPE dbType;private List<ReplacementProcessor> processorList;/*** 每切换一个不同的表代表一个新的tableId,用于结合行号标记唯一的XML表位置。例如XML1和XML2的SYS_USER表的tableId就会不一样.*/private int tableId;private String pkId;private RAtomicLong atomicLong;private RAtomicLong getAtomicLong() {if(atomicLong == null) {atomicLong = SpringContextHelper.getBean(RedissonClient.class).getAtomicLong(Global.REDIS_PERFIX + CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, this.pkId));if(atomicLong.get() == 0) {atomicLong.getAndIncrement();}}return atomicLong;}private Map<String, Object> getRowObjectCache = new LinkedHashMap<String, Object>(5){private static final long serialVersionUID = 1L;@Overrideprotected boolean removeEldestEntry(Map.Entry<String, Object> eldest) {// 当前记录数大于设置的最大的记录数,删除最旧记录(即最近访问最少的记录)return size() > OBJECT_CACHE_SIZE;}};private Map<String, Object> getRowIdCache = new LinkedHashMap<String, Object>(5){private static final long serialVersionUID = 1L;@Overrideprotected boolean removeEldestEntry(Map.Entry<String, Object> eldest) {// 当前记录数大于设置的最大的记录数,删除最旧记录(即最近访问最少的记录)return size() > OBJECT_CACHE_SIZE;}};public ReplacementTable(ITable table, int tableId, IDatabaseConnection connection, DBTYPE dbType, List<ReplacementProcessor> processorList){this.table = table;this.connection = connection;this.dbType = dbType;this.processorList = processorList;this.tableId = tableId;this.pkId = table.getTableMetaData().getTableName();this.pkId = this.pkId.substring(this.pkId.indexOf("_") + 1) + "_ID";}// ITable interfacepublic ITableMetaData getTableMetaData(){return table.getTableMetaData();}public int getRowCount(){return table.getRowCount();}public Object getValue(int row, String column) throws DataSetException{//注意会进来2次,第一次是ignore mapping,第二次才是取值。因此要cache住行号列号位置,避免某些替换的动作重复了2次String value = (String)table.getValue(row, column);if(pkId.equals(column)) { //主键if(value == null) {Object objectCached = getRowIdCache.get(tableId + "-" + row);if(objectCached == null) {objectCached = new Long(getAtomicLong().getAndIncrement()).intValue();getRowIdCache.put(tableId + "-" + row, objectCached);}return objectCached;} else { //同步IDlong next = getAtomicLong().get();int dbId = Integer.parseInt(value); //id必须是Integerif(next <= dbId) {getAtomicLong().set(dbId + 1);}return dbId;}}else { //非主键if (value == null){return null;}for(ReplacementProcessor processor: processorList){if (processor.getStartDelim() != null && processor.getEndDelim() != null && value.toString().startsWith(processor.getStartDelim()) && value.toString().endsWith( processor.getEndDelim())){Object objectCached = getRowObjectCache.get(tableId + "-" + row + "-" + column);if(objectCached == null) {objectCached = processor.replacementSubStrToObject(table, column, value.substring(processor.getStartDelim().length(), value.length() - processor.getEndDelim().length()), connection, dbType); getRowObjectCache.put(tableId + "-" + row + "-" + column, objectCached);}return objectCached;}}return value;}}public String toString(){StringBuffer sb = new StringBuffer();sb.append(getClass().getName()).append("[");sb.append(", table=").append(table);sb.append("]");return sb.toString();}
}

语法

接下来我们实现一个替换处理器,该处理器实现了随机数、相对时间等常用的逻辑。为了避免和正常数据冲突,我定义了一组前缀/后缀正则$R{<控制语法>}R$来激活我们的替换:

随机数生成器,根据字段的类型自动填充数据.
内容格式:类型标识符+是否动态(-或+)+长度+是否必输(*),由于XML的<要转义,故用-代替
类型标识符:S=字符串 I=整型 L=长整 T=时间 B=二进制 Y=是否 E=ENUM D=浮点整型的长度是限制输入位数,而时间的长度是限制随机距离当前时间的天数范围.一个必输的从1个字符到16个字符的随机长度随机字符填充的表达式:S-16*
一个可以为空的从1位到5位的整数:I-5
一个不允许为空的11位长整数:L11*
一个不允许为空的距离当前时间前后30天内的时间:T30*
一个不允许为空的距离当前时间后60天的时间:T+60*
一个距离当前3天前时间:T-3*(注意前后的时间均只到日期的00:00:00),不包含时分秒
一个距离当前4天后时间:T+4*
一个现在的时间:T0*
一个不允许为空的10随机字符的二进制:B10*
java">package org.ccframe.commons.dbunit;import org.apache.commons.lang3.RandomUtils;
import org.ccframe.commons.util.DbUnitUtils.DBTYPE;
import org.ccframe.commons.util.UtilDateTime;
import org.dbunit.database.IDatabaseConnection;
import org.dbunit.dataset.ITable;import java.util.Date;
import java.util.Random;
import java.util.regex.Matcher;
import java.util.regex.Pattern;/*** 随机数生成器,根据字段的类型自动填充数据.** 内容格式:类型标识符+是否动态(-或+)+长度+是否必输(*),由于XML的<要转义,故用-代替* 类型标识符:S=字符串 I=整型 L=长整 T=时间 B=二进制 Y=是否 E=ENUM D=浮点* * 整型的长度是限制输入位数,而时间的长度是限制随机距离当前时间的天数范围.* * 一个必输的从1个字符到16个字符的随机长度随机字符填充的表达式:S-16** 一个可以为空的从1位到5位的整数:I-5* 一个不允许为空的11位长整数:L11** 一个不允许为空的距离当前时间前后30天内的时间:T30** 一个不允许为空的距离当前时间后60天的时间:T+60** 一个距离当前3天前时间:T-3*(注意前后的时间均只到日期的00:00:00),不包含时分秒* 一个距离当前4天后时间:T+4** 一个现在的时间:T0** 一个不允许为空的10随机字符的二进制:B10** * @author JIM**/
public class RandomReplacementProcessor implements ReplacementProcessor {private static final String FILE_START_DELIMITER = "$R{";private static final String FILE_END_DELIMITER = "}R$";//	private Logger logger = Logger.getLogger(RandomReplacementProcessor.class);private static Pattern extractPattern = Pattern.compile("([SILTBY])([-+]{1})?(\\d+)?(\\*)?"); @Overridepublic Object replacementSubStrToObject(ITable table, String column, String substring, IDatabaseConnection connection, DBTYPE dbType){Matcher matcher = extractPattern.matcher(substring);if(!matcher.find()) {return null;}String mode = matcher.group(1);Boolean growFlag = (matcher.group(2) == null ? null: "+".equals(matcher.group(2)));Integer maxLength = (matcher.group(3) == null ? null: Integer.parseInt(matcher.group(3)));boolean notNull = (matcher.group(4) != null);switch(mode.charAt(0)) {case 'S': //字符return randomString(growFlag, maxLength, notNull);case 'I': //return randomInteger(growFlag, maxLength, notNull);case 'L':return randomLong(growFlag, maxLength, notNull);case 'T':return randomTime(growFlag, maxLength, notNull);case 'B':return randomByteString(growFlag, maxLength, notNull);case 'Y':return randomBooleanString(notNull);case 'E':return randomEnumString(notNull);case 'D':return randomDouble(maxLength, notNull);default:return null;}}private static final boolean randomNull() { //如果可以为空,1/10 概率出现NULL或空串return RandomUtils.nextInt(0, 10) == 0;}private static final String ALLCHAR = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";private String randomString(Boolean growFlag, Integer maxLength, boolean notNull) {if(!notNull && randomNull()) {return "";}if(maxLength == null){maxLength = 16;}StringBuilder sb = new StringBuilder();int length = maxLength - 1;if (growFlag != null) {length = RandomUtils.nextInt(0, maxLength);}for (int i = 0; i <= length; i++) {sb.append(ALLCHAR.charAt(RandomUtils.nextInt(0, ALLCHAR.length())));}return sb.toString();}private Integer randomInteger(Boolean growFlag, Integer maxLength, boolean notNull) {return 0; //BoolCodeEnum.fromValue(RandomUtils.nextBoolean());}private Integer randomLong(Boolean growFlag, Integer maxLength, boolean notNull) {return 0;}private static final Random LONG_RANDOM = new Random();private static final Date NOW_TIME = new Date(); //系统初始化的时间private Date randomTime(Boolean growFlag, Integer maxLength, boolean notNull) {if(!notNull && randomNull()) {return null;}if(maxLength == null || maxLength == 0) {return NOW_TIME;}if(growFlag == null) { //随机范围时间long grow = LONG_RANDOM.nextLong() % (maxLength*2*24L*3600L*1000L); //随机天数范围return new Date(NOW_TIME.getTime() - (maxLength*24L*3600L*1000L) + grow);}else { //固定时间差return UtilDateTime.addDays(UtilDateTime.getDayStartTime(NOW_TIME), growFlag ? maxLength: -maxLength);}}private byte[] randomByteString(Boolean growFlag, Integer maxLength, boolean notNull) {String value = randomString(growFlag, maxLength, notNull);return value == null ? null : value.getBytes();}private String randomBooleanString(boolean notNull) {return null;}private String randomEnumString(boolean notNull) {return null;}private Double randomDouble(Integer maxLength, boolean notNull) { //double默认就是grow取范围return null;}@Overridepublic String getStartDelim() {return FILE_START_DELIMITER;}@Overridepublic String getEndDelim() {return FILE_END_DELIMITER;}
}

最终效果

这样,我们要实现一份相对于当前30天过期的租户就非常简单了,只需要给一个随机时间定义,让它范围在60天之内随机即可,这里的数据创建时间和更新时间都是当前的时间:

<?xml version="1.0" encoding="UTF-8"?>
<!-- DBUnit flatXml DataFile -->
<!-- 测试数据文件,注意.此文件的指定ID必须>70000 -->
<dataset><SYS_TENANT TENANT_ID="50001" TENANT_COMPANY="阿里巴巴集团" TENANT_EXPIRE_DATE="$R{T60*}R$" TENANT_NAME="阿里巴巴集团" TENANT_SUBDOMAIN="demo50001" IF_VALID="Y" MANAGER_MOBILE="[null]" MANAGER="[null]" TENANT_COMPANY_ADDRESS="" REMARK="测试企业阿里巴巴集团" UPDATE_TIME="$R{T0*}R$" CREATE_TIME="$R{T0*}R$" CREATE_USER_ID="1" UPDATE_USER_ID="1"/><SYS_TENANT TENANT_ID="50002" TENANT_COMPANY="腾讯科技有限公司" TENANT_EXPIRE_DATE="$R{T60*}R$" TENANT_NAME="腾讯科技" TENANT_SUBDOMAIN="demo50002" IF_VALID="Y" MANAGER_MOBILE="[null]" MANAGER="[null]" TENANT_COMPANY_ADDRESS="" REMARK="测试企业腾讯科技有限公司" UPDATE_TIME="$R{T0*}R$" CREATE_TIME="$R{T0*}R$" CREATE_USER_ID="1" UPDATE_USER_ID="1"/><SYS_TENANT TENANT_ID="50003" TENANT_COMPANY="百度公司" TENANT_EXPIRE_DATE="$R{T60*}R$" TENANT_NAME="百度" TENANT_SUBDOMAIN="demo50003" IF_VALID="Y" MANAGER_MOBILE="[null]" MANAGER="[null]" TENANT_COMPANY_ADDRESS="" REMARK="测试企业百度公司" UPDATE_TIME="$R{T0*}R$" CREATE_TIME="$R{T0*}R$" CREATE_USER_ID="1" UPDATE_USER_ID="1"/><SYS_TENANT TENANT_ID="50004" TENANT_COMPANY="华为技术有限公司" TENANT_EXPIRE_DATE="$R{T60*}R$" TENANT_NAME="华为技术" TENANT_SUBDOMAIN="demo50004" IF_VALID="Y" MANAGER_MOBILE="[null]" MANAGER="[null]" TENANT_COMPANY_ADDRESS="" REMARK="测试企业华为技术有限公司" UPDATE_TIME="$R{T0*}R$" CREATE_TIME="$R{T0*}R$" CREATE_USER_ID="1" UPDATE_USER_ID="1"/><SYS_TENANT TENANT_ID="50005" TENANT_COMPANY="字节跳动公司" TENANT_EXPIRE_DATE="$R{T60*}R$" TENANT_NAME="字节跳动" TENANT_SUBDOMAIN="demo50005" IF_VALID="Y" MANAGER_MOBILE="[null]" MANAGER="[null]" TENANT_COMPANY_ADDRESS="" REMARK="测试企业字节跳动公司" UPDATE_TIME="$R{T0*}R$" CREATE_TIME="$R{T0*}R$" CREATE_USER_ID="1" UPDATE_USER_ID="1"/><SYS_TENANT TENANT_ID="50006" TENANT_COMPANY="京东集团" TENANT_EXPIRE_DATE="$R{T60*}R$" TENANT_NAME="京东集团" TENANT_SUBDOMAIN="demo50006" IF_VALID="Y" MANAGER_MOBILE="[null]" MANAGER="[null]" TENANT_COMPANY_ADDRESS="" REMARK="测试企业京东集团" UPDATE_TIME="$R{T0*}R$" CREATE_TIME="$R{T0*}R$" CREATE_USER_ID="1" UPDATE_USER_ID="1"/><SYS_TENANT TENANT_ID="50007" TENANT_COMPANY="美团点评" TENANT_EXPIRE_DATE="$R{T60*}R$" TENANT_NAME="美团点评" TENANT_SUBDOMAIN="demo50007" IF_VALID="Y" MANAGER_MOBILE="[null]" MANAGER="[null]" TENANT_COMPANY_ADDRESS="" REMARK="测试企业美团点评" UPDATE_TIME="$R{T0*}R$" CREATE_TIME="$R{T0*}R$" CREATE_USER_ID="1" UPDATE_USER_ID="1"/><SYS_TENANT TENANT_ID="50008" TENANT_COMPANY="滴滴出行" TENANT_EXPIRE_DATE="$R{T60*}R$" TENANT_NAME="滴滴出行" TENANT_SUBDOMAIN="demo50008" IF_VALID="Y" MANAGER_MOBILE="[null]" MANAGER="[null]" TENANT_COMPANY_ADDRESS="" REMARK="测试企业滴滴出行" UPDATE_TIME="$R{T0*}R$" CREATE_TIME="$R{T0*}R$" CREATE_USER_ID="1" UPDATE_USER_ID="1"/><SYS_TENANT TENANT_ID="50009" TENANT_COMPANY="网易集团" TENANT_EXPIRE_DATE="$R{T60*}R$" TENANT_NAME="网易集团" TENANT_SUBDOMAIN="demo50009" IF_VALID="Y" MANAGER_MOBILE="[null]" MANAGER="[null]" TENANT_COMPANY_ADDRESS="" REMARK="测试企业网易集团" UPDATE_TIME="$R{T0*}R$" CREATE_TIME="$R{T0*}R$" CREATE_USER_ID="1" UPDATE_USER_ID="1"/><SYS_TENANT TENANT_ID="50010" TENANT_COMPANY="新浪公司" TENANT_EXPIRE_DATE="$R{T60*}R$" TENANT_NAME="新浪" TENANT_SUBDOMAIN="demo50010" IF_VALID="Y" MANAGER_MOBILE="[null]" MANAGER="[null]" TENANT_COMPANY_ADDRESS="" REMARK="测试企业新浪公司" UPDATE_TIME="$R{T0*}R$" CREATE_TIME="$R{T0*}R$" CREATE_USER_ID="1" UPDATE_USER_ID="1"/><SYS_TENANT TENANT_ID="50011" TENANT_COMPANY="中国石油天然气集团公司" TENANT_EXPIRE_DATE="$R{T60*}R$" TENANT_NAME="中国石油天然气集团" TENANT_SUBDOMAIN="demo50011" IF_VALID="Y" MANAGER_MOBILE="[null]" MANAGER="[null]" TENANT_COMPANY_ADDRESS="" REMARK="测试企业中国石油天然气集团公司" UPDATE_TIME="$R{T0*}R$" CREATE_TIME="$R{T0*}R$" CREATE_USER_ID="1" UPDATE_USER_ID="1"/><SYS_TENANT TENANT_ID="50012" TENANT_COMPANY="中国石化集团公司" TENANT_EXPIRE_DATE="$R{T60*}R$" TENANT_NAME="中国石化集团" TENANT_SUBDOMAIN="demo50012" IF_VALID="Y" MANAGER_MOBILE="[null]" MANAGER="[null]" TENANT_COMPANY_ADDRESS="" REMARK="测试企业中国石化集团公司" UPDATE_TIME="$R{T0*}R$" CREATE_TIME="$R{T0*}R$" CREATE_USER_ID="1" UPDATE_USER_ID="1"/><SYS_TENANT TENANT_ID="50013" TENANT_COMPANY="中国建筑股份有限公司" TENANT_EXPIRE_DATE="$R{T60*}R$" TENANT_NAME="中国建筑" TENANT_SUBDOMAIN="demo50013" IF_VALID="Y" MANAGER_MOBILE="[null]" MANAGER="[null]" TENANT_COMPANY_ADDRESS="" REMARK="测试企业中国建筑股份有限公司" UPDATE_TIME="$R{T0*}R$" CREATE_TIME="$R{T0*}R$" CREATE_USER_ID="1" UPDATE_USER_ID="1"/><SYS_TENANT TENANT_ID="50014" TENANT_COMPANY="中国工商银行" TENANT_EXPIRE_DATE="$R{T60*}R$" TENANT_NAME="中国工商银行" TENANT_SUBDOMAIN="demo50014" IF_VALID="Y" MANAGER_MOBILE="[null]" MANAGER="[null]" TENANT_COMPANY_ADDRESS="" REMARK="测试企业中国工商银行" UPDATE_TIME="$R{T0*}R$" CREATE_TIME="$R{T0*}R$" CREATE_USER_ID="1" UPDATE_USER_ID="1"/><SYS_TENANT TENANT_ID="50015" TENANT_COMPANY="中国农业银行" TENANT_EXPIRE_DATE="$R{T60*}R$" TENANT_NAME="中国农业银行" TENANT_SUBDOMAIN="demo50015" IF_VALID="Y" MANAGER_MOBILE="[null]" MANAGER="[null]" TENANT_COMPANY_ADDRESS="" REMARK="测试企业中国农业银行" UPDATE_TIME="$R{T0*}R$" CREATE_TIME="$R{T0*}R$" CREATE_USER_ID="1" UPDATE_USER_ID="1"/><SYS_TENANT TENANT_ID="50016" TENANT_COMPANY="中国银行" TENANT_EXPIRE_DATE="$R{T60*}R$" TENANT_NAME="中国银行" TENANT_SUBDOMAIN="demo50016" IF_VALID="Y" MANAGER_MOBILE="[null]" MANAGER="[null]" TENANT_COMPANY_ADDRESS="" REMARK="测试企业中国银行" UPDATE_TIME="$R{T0*}R$" CREATE_TIME="$R{T0*}R$" CREATE_USER_ID="1" UPDATE_USER_ID="1"/><SYS_TENANT TENANT_ID="50017" TENANT_COMPANY="中国建设银行" TENANT_EXPIRE_DATE="$R{T60*}R$" TENANT_NAME="中国建设银行" TENANT_SUBDOMAIN="demo50017" IF_VALID="Y" MANAGER_MOBILE="[null]" MANAGER="[null]" TENANT_COMPANY_ADDRESS="" REMARK="测试企业中国建设银行" UPDATE_TIME="$R{T0*}R$" CREATE_TIME="$R{T0*}R$" CREATE_USER_ID="1" UPDATE_USER_ID="1"/><SYS_TENANT TENANT_ID="50018" TENANT_COMPANY="中国交通银行" TENANT_EXPIRE_DATE="$R{T60*}R$" TENANT_NAME="中国交通银行" TENANT_SUBDOMAIN="demo50018" IF_VALID="Y" MANAGER_MOBILE="[null]" MANAGER="[null]" TENANT_COMPANY_ADDRESS="" REMARK="测试企业中国交通银行" UPDATE_TIME="$R{T0*}R$" CREATE_TIME="$R{T0*}R$" CREATE_USER_ID="1" UPDATE_USER_ID="1"/><SYS_TENANT TENANT_ID="50019" TENANT_COMPANY="中国人寿保险股份有限公司" TENANT_EXPIRE_DATE="$R{T60*}R$" TENANT_NAME="中国人寿保险" TENANT_SUBDOMAIN="demo50019" IF_VALID="Y" MANAGER_MOBILE="[null]" MANAGER="[null]" TENANT_COMPANY_ADDRESS="" REMARK="测试企业中国人寿保险股份有限公司" UPDATE_TIME="$R{T0*}R$" CREATE_TIME="$R{T0*}R$" CREATE_USER_ID="1" UPDATE_USER_ID="1"/><SYS_TENANT TENANT_ID="50020" TENANT_COMPANY="中国平安保险" TENANT_EXPIRE_DATE="$R{T60*}R$" TENANT_NAME="中国平安保险" TENANT_SUBDOMAIN="demo50020" IF_VALID="Y" MANAGER_MOBILE="[null]" MANAGER="[null]" TENANT_COMPANY_ADDRESS="" REMARK="测试企业中国平安保险" UPDATE_TIME="$R{T0*}R$" CREATE_TIME="$R{T0*}R$" CREATE_USER_ID="1" UPDATE_USER_ID="1"/><SYS_TENANT TENANT_ID="50021" TENANT_COMPANY="中国太平洋保险" TENANT_EXPIRE_DATE="$R{T60*}R$" TENANT_NAME="中国太平洋保险" TENANT_SUBDOMAIN="demo50021" IF_VALID="Y" MANAGER_MOBILE="[null]" MANAGER="[null]" TENANT_COMPANY_ADDRESS="" REMARK="测试企业中国太平洋保险" UPDATE_TIME="$R{T0*}R$" CREATE_TIME="$R{T0*}R$" CREATE_USER_ID="1" UPDATE_USER_ID="1"/><SYS_TENANT TENANT_ID="50022" TENANT_COMPANY="中国人民保险集团" TENANT_EXPIRE_DATE="$R{T60*}R$" TENANT_NAME="中国人民保险集团" TENANT_SUBDOMAIN="demo50022" IF_VALID="Y" MANAGER_MOBILE="[null]" MANAGER="[null]" TENANT_COMPANY_ADDRESS="" REMARK="测试企业中国人民保险集团" UPDATE_TIME="$R{T0*}R$" CREATE_TIME="$R{T0*}R$" CREATE_USER_ID="1" UPDATE_USER_ID="1"/><SYS_TENANT TENANT_ID="50023" TENANT_COMPANY="中国人民财产保险" TENANT_EXPIRE_DATE="$R{T60*}R$" TENANT_NAME="中国人民财产保险" TENANT_SUBDOMAIN="demo50023" IF_VALID="Y" MANAGER_MOBILE="[null]" MANAGER="[null]" TENANT_COMPANY_ADDRESS="" REMARK="测试企业中国人民财产保险" UPDATE_TIME="$R{T0*}R$" CREATE_TIME="$R{T0*}R$" CREATE_USER_ID="1" UPDATE_USER_ID="1"/><SYS_TENANT TENANT_ID="50024" TENANT_COMPANY="中国信达资产管理股份有限公司" TENANT_EXPIRE_DATE="$R{T60*}R$" TENANT_NAME="中国信达资产管理" TENANT_SUBDOMAIN="demo50024" IF_VALID="Y" MANAGER_MOBILE="[null]" MANAGER="[null]" TENANT_COMPANY_ADDRESS="" REMARK="测试企业中国信达资产管理股份有限公司" UPDATE_TIME="$R{T0*}R$" CREATE_TIME="$R{T0*}R$" CREATE_USER_ID="1" UPDATE_USER_ID="1"/><SYS_TENANT TENANT_ID="50025" TENANT_COMPANY="中国光大银行" TENANT_EXPIRE_DATE="$R{T60*}R$" TENANT_NAME="中国光大银行" TENANT_SUBDOMAIN="demo50025" IF_VALID="Y" MANAGER_MOBILE="[null]" MANAGER="[null]" TENANT_COMPANY_ADDRESS="" REMARK="测试企业中国光大银行" UPDATE_TIME="$R{T0*}R$" CREATE_TIME="$R{T0*}R$" CREATE_USER_ID="1" UPDATE_USER_ID="1"/><SYS_TENANT TENANT_ID="50026" TENANT_COMPANY="中国光大集团" TENANT_EXPIRE_DATE="$R{T60*}R$" TENANT_NAME="中国光大集团" TENANT_SUBDOMAIN="demo50026" IF_VALID="Y" MANAGER_MOBILE="[null]" MANAGER="[null]" TENANT_COMPANY_ADDRESS="" REMARK="测试企业中国光大集团" UPDATE_TIME="$R{T0*}R$" CREATE_TIME="$R{T0*}R$" CREATE_USER_ID="1" UPDATE_USER_ID="1"/><SYS_TENANT TENANT_ID="50027" TENANT_COMPANY="中国进出口银行" TENANT_EXPIRE_DATE="$R{T60*}R$" TENANT_NAME="中国进出口银行" TENANT_SUBDOMAIN="demo50027" IF_VALID="Y" MANAGER_MOBILE="[null]" MANAGER="[null]" TENANT_COMPANY_ADDRESS="" REMARK="测试企业中国进出口银行" UPDATE_TIME="$R{T0*}R$" CREATE_TIME="$R{T0*}R$" CREATE_USER_ID="1" UPDATE_USER_ID="1"/><SYS_TENANT TENANT_ID="50028" TENANT_COMPANY="中国国家开发银行" TENANT_EXPIRE_DATE="$R{T60*}R$" TENANT_NAME="中国国家开发银行" TENANT_SUBDOMAIN="demo50028" IF_VALID="Y" MANAGER_MOBILE="[null]" MANAGER="[null]" TENANT_COMPANY_ADDRESS="" REMARK="测试企业中国国家开发银行" UPDATE_TIME="$R{T0*}R$" CREATE_TIME="$R{T0*}R$" CREATE_USER_ID="1" UPDATE_USER_ID="1"/><SYS_TENANT TENANT_ID="50029" TENANT_COMPANY="中国农业发展银行" TENANT_EXPIRE_DATE="$R{T60*}R$" TENANT_NAME="中国农业发展银行" TENANT_SUBDOMAIN="demo50029" IF_VALID="Y" MANAGER_MOBILE="[null]" MANAGER="[null]" TENANT_COMPANY_ADDRESS="" REMARK="测试企业中国农业发展银行" UPDATE_TIME="$R{T0*}R$" CREATE_TIME="$R{T0*}R$" CREATE_USER_ID="1" UPDATE_USER_ID="1"/><SYS_TENANT TENANT_ID="50030" TENANT_COMPANY="中国银联股份有限公司" TENANT_EXPIRE_DATE="$R{T60*}R$" TENANT_NAME="中国银联" TENANT_SUBDOMAIN="demo50030" IF_VALID="Y" MANAGER_MOBILE="[null]" MANAGER="[null]" TENANT_COMPANY_ADDRESS="" REMARK="测试企业中国银联股份有限公司" UPDATE_TIME="$R{T0*}R$" CREATE_TIME="$R{T0*}R$" CREATE_USER_ID="1" UPDATE_USER_ID="1"/><SYS_TENANT TENANT_ID="50031" TENANT_COMPANY="中国邮政储蓄银行" TENANT_EXPIRE_DATE="$R{T60*}R$" TENANT_NAME="中国邮政储蓄银行" TENANT_SUBDOMAIN="demo50031" IF_VALID="Y" MANAGER_MOBILE="[null]" MANAGER="[null]" TENANT_COMPANY_ADDRESS="" REMARK="测试企业中国邮政储蓄银行" UPDATE_TIME="$R{T0*}R$" CREATE_TIME="$R{T0*}R$" CREATE_USER_ID="1" UPDATE_USER_ID="1"/><SYS_TENANT TENANT_ID="50032" TENANT_COMPANY="中国电信股份有限公司" TENANT_EXPIRE_DATE="$R{T60*}R$" TENANT_NAME="中国电信" TENANT_SUBDOMAIN="demo50032" IF_VALID="Y" MANAGER_MOBILE="[null]" MANAGER="[null]" TENANT_COMPANY_ADDRESS="" REMARK="测试企业中国电信股份有限公司" UPDATE_TIME="$R{T0*}R$" CREATE_TIME="$R{T0*}R$" CREATE_USER_ID="1" UPDATE_USER_ID="1"/><SYS_TENANT TENANT_ID="50033" TENANT_COMPANY="中国移动通信集团公司" TENANT_EXPIRE_DATE="$R{T60*}R$" TENANT_NAME="中国移动通信集团" TENANT_SUBDOMAIN="demo50033" IF_VALID="Y" MANAGER_MOBILE="[null]" MANAGER="[null]" TENANT_COMPANY_ADDRESS="" REMARK="测试企业中国移动通信集团公司" UPDATE_TIME="$R{T0*}R$" CREATE_TIME="$R{T0*}R$" CREATE_USER_ID="1" UPDATE_USER_ID="1"/><SYS_TENANT TENANT_ID="50034" TENANT_COMPANY="中国联合网络通信有限公司" TENANT_EXPIRE_DATE="$R{T60*}R$" TENANT_NAME="中国联合网络通信" TENANT_SUBDOMAIN="demo50034" IF_VALID="Y" MANAGER_MOBILE="[null]" MANAGER="[null]" TENANT_COMPANY_ADDRESS="" REMARK="测试企业中国联合网络通信有限公司" UPDATE_TIME="$R{T0*}R$" CREATE_TIME="$R{T0*}R$" CREATE_USER_ID="1" UPDATE_USER_ID="1"/><SYS_TENANT TENANT_ID="50035" TENANT_COMPANY="中国广播电影电视集团公司" TENANT_EXPIRE_DATE="$R{T60*}R$" TENANT_NAME="中国广播电影电视集团" TENANT_SUBDOMAIN="demo50035" IF_VALID="Y" MANAGER_MOBILE="[null]" MANAGER="[null]" TENANT_COMPANY_ADDRESS="" REMARK="测试企业中国广播电影电视集团公司" UPDATE_TIME="$R{T0*}R$" CREATE_TIME="$R{T0*}R$" CREATE_USER_ID="1" UPDATE_USER_ID="1"/><SYS_TENANT TENANT_ID="50036" TENANT_COMPANY="中国中央电视台" TENANT_EXPIRE_DATE="$R{T60*}R$" TENANT_NAME="中国中央电视台" TENANT_SUBDOMAIN="demo50036" IF_VALID="Y" MANAGER_MOBILE="[null]" MANAGER="[null]" TENANT_COMPANY_ADDRESS="" REMARK="测试企业中国中央电视台" UPDATE_TIME="$R{T0*}R$" CREATE_TIME="$R{T0*}R$" CREATE_USER_ID="1" UPDATE_USER_ID="1"/><SYS_TENANT TENANT_ID="50037" TENANT_COMPANY="中国移动" TENANT_EXPIRE_DATE="$R{T60*}R$" TENANT_NAME="中国移动" TENANT_SUBDOMAIN="demo50037" IF_VALID="Y" MANAGER_MOBILE="[null]" MANAGER="[null]" TENANT_COMPANY_ADDRESS="" REMARK="测试企业中国移动" UPDATE_TIME="$R{T0*}R$" CREATE_TIME="$R{T0*}R$" CREATE_USER_ID="1" UPDATE_USER_ID="1"/><SYS_TENANT TENANT_ID="50038" TENANT_COMPANY="中国电信" TENANT_EXPIRE_DATE="$R{T60*}R$" TENANT_NAME="中国电信" TENANT_SUBDOMAIN="demo50038" IF_VALID="Y" MANAGER_MOBILE="[null]" MANAGER="[null]" TENANT_COMPANY_ADDRESS="" REMARK="测试企业中国电信" UPDATE_TIME="$R{T0*}R$" CREATE_TIME="$R{T0*}R$" CREATE_USER_ID="1" UPDATE_USER_ID="1"/><SYS_TENANT TENANT_ID="50039" TENANT_COMPANY="中国联通" TENANT_EXPIRE_DATE="$R{T60*}R$" TENANT_NAME="中国联通" TENANT_SUBDOMAIN="demo50039" IF_VALID="Y" MANAGER_MOBILE="[null]" MANAGER="[null]" TENANT_COMPANY_ADDRESS="" REMARK="测试企业中国联通" UPDATE_TIME="$R{T0*}R$" CREATE_TIME="$R{T0*}R$" CREATE_USER_ID="1" UPDATE_USER_ID="1"/><SYS_TENANT TENANT_ID="50040" TENANT_COMPANY="中国航天科技集团公司" TENANT_EXPIRE_DATE="$R{T60*}R$" TENANT_NAME="中国航天科技集团" TENANT_SUBDOMAIN="demo50040" IF_VALID="Y" MANAGER_MOBILE="[null]" MANAGER="[null]" TENANT_COMPANY_ADDRESS="" REMARK="测试企业中国航天科技集团公司" UPDATE_TIME="$R{T0*}R$" CREATE_TIME="$R{T0*}R$" CREATE_USER_ID="1" UPDATE_USER_ID="1"/><SYS_TENANT TENANT_ID="50041" TENANT_COMPANY="中国航天科工集团公司" TENANT_EXPIRE_DATE="$R{T60*}R$" TENANT_NAME="中国航天科工集团" TENANT_SUBDOMAIN="demo50041" IF_VALID="Y" MANAGER_MOBILE="[null]" MANAGER="[null]" TENANT_COMPANY_ADDRESS="" REMARK="测试企业中国航天科工集团公司" UPDATE_TIME="$R{T0*}R$" CREATE_TIME="$R{T0*}R$" CREATE_USER_ID="1" UPDATE_USER_ID="1"/><SYS_TENANT TENANT_ID="50042" TENANT_COMPANY="中国航空工业集团公司" TENANT_EXPIRE_DATE="$R{T60*}R$" TENANT_NAME="中国航空工业集团" TENANT_SUBDOMAIN="demo50042" IF_VALID="Y" MANAGER_MOBILE="[null]" MANAGER="[null]" TENANT_COMPANY_ADDRESS="" REMARK="测试企业中国航空工业集团公司" UPDATE_TIME="$R{T0*}R$" CREATE_TIME="$R{T0*}R$" CREATE_USER_ID="1" UPDATE_USER_ID="1"/><SYS_TENANT TENANT_ID="50043" TENANT_COMPANY="中国船舶重工集团公司" TENANT_EXPIRE_DATE="$R{T60*}R$" TENANT_NAME="中国船舶重工集团" TENANT_SUBDOMAIN="demo50043" IF_VALID="Y" MANAGER_MOBILE="[null]" MANAGER="[null]" TENANT_COMPANY_ADDRESS="" REMARK="测试企业中国船舶重工集团公司" UPDATE_TIME="$R{T0*}R$" CREATE_TIME="$R{T0*}R$" CREATE_USER_ID="1" UPDATE_USER_ID="1"/><SYS_TENANT TENANT_ID="50044" TENANT_COMPANY="中国中车集团公司" TENANT_EXPIRE_DATE="$R{T60*}R$" TENANT_NAME="中国中车集团" TENANT_SUBDOMAIN="demo50044" IF_VALID="Y" MANAGER_MOBILE="[null]" MANAGER="[null]" TENANT_COMPANY_ADDRESS="" REMARK="测试企业中国中车集团公司" UPDATE_TIME="$R{T0*}R$" CREATE_TIME="$R{T0*}R$" CREATE_USER_ID="1" UPDATE_USER_ID="1"/><SYS_TENANT TENANT_ID="50045" TENANT_COMPANY="中国南车集团公司" TENANT_EXPIRE_DATE="$R{T60*}R$" TENANT_NAME="中国南车集团" TENANT_SUBDOMAIN="demo50045" IF_VALID="Y" MANAGER_MOBILE="[null]" MANAGER="[null]" TENANT_COMPANY_ADDRESS="" REMARK="测试企业中国南车集团公司" UPDATE_TIME="$R{T0*}R$" CREATE_TIME="$R{T0*}R$" CREATE_USER_ID="1" UPDATE_USER_ID="1"/><SYS_TENANT TENANT_ID="50046" TENANT_COMPANY="中国北车集团公司" TENANT_EXPIRE_DATE="$R{T60*}R$" TENANT_NAME="中国北车集团" TENANT_SUBDOMAIN="demo50046" IF_VALID="Y" MANAGER_MOBILE="[null]" MANAGER="[null]" TENANT_COMPANY_ADDRESS="" REMARK="测试企业中国北车集团公司" UPDATE_TIME="$R{T0*}R$" CREATE_TIME="$R{T0*}R$" CREATE_USER_ID="1" UPDATE_USER_ID="1"/><SYS_TENANT TENANT_ID="50047" TENANT_COMPANY="中国中铁股份有限公司" TENANT_EXPIRE_DATE="$R{T60*}R$" TENANT_NAME="中国中铁" TENANT_SUBDOMAIN="demo50047" IF_VALID="Y" MANAGER_MOBILE="[null]" MANAGER="[null]" TENANT_COMPANY_ADDRESS="" REMARK="测试企业中国中铁股份有限公司" UPDATE_TIME="$R{T0*}R$" CREATE_TIME="$R{T0*}R$" CREATE_USER_ID="1" UPDATE_USER_ID="1"/><SYS_TENANT TENANT_ID="50048" TENANT_COMPANY="中国铁路工程集团公司" TENANT_EXPIRE_DATE="$R{T60*}R$" TENANT_NAME="中国铁路工程集团" TENANT_SUBDOMAIN="demo50048" IF_VALID="Y" MANAGER_MOBILE="[null]" MANAGER="[null]" TENANT_COMPANY_ADDRESS="" REMARK="测试企业中国铁路工程集团公司" UPDATE_TIME="$R{T0*}R$" CREATE_TIME="$R{T0*}R$" CREATE_USER_ID="1" UPDATE_USER_ID="1"/><SYS_TENANT TENANT_ID="50049" TENANT_COMPANY="中国铁路建设股份有限公司" TENANT_EXPIRE_DATE="$R{T60*}R$" TENANT_NAME="中国铁路建设" TENANT_SUBDOMAIN="demo50049" IF_VALID="Y" MANAGER_MOBILE="[null]" MANAGER="[null]" TENANT_COMPANY_ADDRESS="" REMARK="测试企业中国铁路建设股份有限公司" UPDATE_TIME="$R{T0*}R$" CREATE_TIME="$R{T0*}R$" CREATE_USER_ID="1" UPDATE_USER_ID="1"/>
</dataset>


http://www.ppmy.cn/embedded/9348.html

相关文章

自然语言处理(Natural Language Processing, NLP)简介

自然语言处理 (NLP) 是计算机科学的一个分支&#xff0c;更具体地说&#xff0c;是人工智能 (AI) 的分支&#xff0c;旨在让计算机能够以与人类大致相同的方式理解文本和语音。 自然语言处理 (NLP) 将计算语言学&#xff08;基于规则的人类语言建模&#xff09;与统计、机器学…

helm介绍-部署helm私有仓库案例

helm介绍-部署helm私有仓库案例 helm介绍-部署helm私有仓库案例 在Kubernetes中部署容器云的应用也是一项有挑战性的工作&#xff0c;Helm就是为了简化在Kubernetes中安装部署容器云应用的一个客户端工具。通过helm能够帮助开发者定义、安装和升级Kubernetes中的容器云应用&a…

接口压力测试 jmeter--增强篇(二)

前期准备 1. JMeter的插件的安装 下载Jmeter Plugins Manager对插件进行管理 &#xff08;1&#xff09;下载地址&#xff1a;https://jmeter-plugins.org/install/Install/ &#xff08;2&#xff09;下载后&#xff0c;将jar包放到jmeter包目录下/lib/ext目录下 &#xff0…

Codeforces Round 938 (Div. 3) E(差分数组的开关用法)

题目链接 从大到小枚举k,差分数组标记翻转区间&#xff08;异或实现&#xff09;。 #include<bits/stdc.h> using namespace std;void solved() {int n; cin>>n;string s; cin>>s;s s;int d[n1];//把这个差分数组当成一个开关使用&#xff0c;d[i]1反转,d[…

数学建模--深入剖析线性规划(模型全方位解读+代码分析)

1.简介 &#xff08;1&#xff09;线性规划三要素 &#xff08;2&#xff09;模型适用赛题 2.典例讲解 &#xff08;1&#xff09;问题分析 目标函数是净收益尽可能大&#xff0c;风险尽可能小&#xff1b; 约束条件是交易费的分段函数&#xff0c;以及每一笔投资都是非负数&am…

elment-plus 中 table 左对齐

elment-plus 中 table 左对齐 <el-tablev-loading"loading"class"flex-1 !h-auto":data"roleList":header-cell-style"{text-align: left }":row-style"{ height: 55px }":cell-style"{ text-align: left }"&…

前端开发攻略---拖动归类,将元素拖拽到相应位置

1、演示 2、代码 <!DOCTYPE html><html lang"en"><head><meta charset"UTF-8" /><meta http-equiv"X-UA-Compatible" content"IEedge" /><meta name"viewport" content"widthdevice-…

Environment Modules工具

Environment Modules工具 简介 Module是一个环境变量管理工具&#xff0c;可以很好的实现开发环境的切换。 具体可以查看官网文档 安装 安装&#xff08;安装完成之后需要exit重新登录一下才会生效&#xff09; yum install -y environment-modules命令介绍 module avai…