add YamlUtil

This commit is contained in:
Looly 2021-09-24 15:29:56 +08:00
parent ba00f03026
commit 7b6593fe68
43 changed files with 798 additions and 1433 deletions

View File

@ -3,14 +3,17 @@
------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------
# 5.7.14 (2021-09-23) # 5.7.14 (2021-09-24)
### 🐣新特性 ### 🐣新特性
* 【extra 】 修复HttpCookie设置cookies的方法不符合RFC6265规范问题issue#I4B70D@Gitee * 【extra 】 修复HttpCookie设置cookies的方法不符合RFC6265规范问题issue#I4B70D@Gitee
* 【http 】 优化Browser版本正则判断 * 【http 】 优化Browser版本正则判断
* 【setting】 增加YamlUtil
* 【extra 】 SenvenZExtractor改名为SevenZExtractor增加getFirst、get方法
### 🐞Bug修复 ### 🐞Bug修复
* 【http 】 修复HttpCookie设置cookies的方法不符合RFC6265规范问题pr#418@Gitee * 【http 】 修复HttpCookie设置cookies的方法不符合RFC6265规范问题pr#418@Gitee
* 【http 】 修复Extractor中filter无效问题
------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------

View File

@ -147,8 +147,8 @@ public class AnimatedGifEncoder {
/** /**
* Adds next GIF frame. The frame is not written immediately, but is * Adds next GIF frame. The frame is not written immediately, but is
* actually deferred until the next frame is received so that timing * actually deferred until the next frame is received so that timing
* data can be inserted. Invoking <code>finish()</code> flushes all * data can be inserted. Invoking {@code finish()} flushes all
* frames. If <code>setSize</code> was not invoked, the size of the * frames. If {@code setSize} was not invoked, the size of the
* first image is used for all subsequent frames. * first image is used for all subsequent frames.
* *
* @param im BufferedImage containing frame to write. * @param im BufferedImage containing frame to write.
@ -225,7 +225,7 @@ public class AnimatedGifEncoder {
/** /**
* Sets frame rate in frames per second. Equivalent to * Sets frame rate in frames per second. Equivalent to
* <code>setDelay(1000/fps)</code>. * {@code setDelay(1000/fps)}.
* *
* @param fps float frame rate (frames per second) * @param fps float frame rate (frames per second)
*/ */

View File

@ -25,6 +25,8 @@ import java.io.PushbackInputStream;
* </code> * </code>
* <br><br> * <br><br>
* 参考 http://akini.mbnet.fi/java/unicodereader/UnicodeInputStream.java.txt * 参考 http://akini.mbnet.fi/java/unicodereader/UnicodeInputStream.java.txt
*
* @author looly
*/ */
public class BOMInputStream extends InputStream { public class BOMInputStream extends InputStream {
@ -36,10 +38,21 @@ public class BOMInputStream extends InputStream {
private static final int BOM_SIZE = 4; private static final int BOM_SIZE = 4;
// ----------------------------------------------------------------- Constructor start // ----------------------------------------------------------------- Constructor start
/**
* 构造
* @param in
*/
public BOMInputStream(InputStream in) { public BOMInputStream(InputStream in) {
this(in, CharsetUtil.UTF_8); this(in, CharsetUtil.UTF_8);
} }
/**
* 构造
*
* @param in
* @param defaultCharset 默认编码
*/
public BOMInputStream(InputStream in, String defaultCharset) { public BOMInputStream(InputStream in, String defaultCharset) {
this.in = new PushbackInputStream(in, BOM_SIZE); this.in = new PushbackInputStream(in, BOM_SIZE);
this.defaultCharset = defaultCharset; this.defaultCharset = defaultCharset;
@ -61,7 +74,7 @@ public class BOMInputStream extends InputStream {
* @return 编码 * @return 编码
*/ */
public String getCharset() { public String getCharset() {
if (!isInited) { if (false == isInited) {
try { try {
init(); init();
} catch (IOException ex) { } catch (IOException ex) {
@ -117,7 +130,6 @@ public class BOMInputStream extends InputStream {
charset = defaultCharset; charset = defaultCharset;
unread = n; unread = n;
} }
// System.out.println("read=" + n + ", unread=" + unread);
if (unread > 0) { if (unread > 0) {
in.unread(bom, (n - unread), unread); in.unread(bom, (n - unread), unread);

View File

@ -0,0 +1,58 @@
package cn.hutool.core.io;
import cn.hutool.core.lang.Assert;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.UnsupportedEncodingException;
/**
* 读取带BOM头的流内容的Reader如果非bom的流或无法识别的编码则默认UTF-8<br>
* BOM定义http://www.unicode.org/unicode/faq/utf_bom.html
*
* <ul>
* <li>00 00 FE FF = UTF-32, big-endian</li>
* <li>FF FE 00 00 = UTF-32, little-endian</li>
* <li>EF BB BF = UTF-8</li>
* <li>FE FF = UTF-16, big-endian</li>
* <li>FF FE = UTF-16, little-endian</li>
* </ul>
* 使用 <br>
* <code>
* FileInputStream fis = new FileInputStream(file); <br>
* BomReader uin = new BomReader(fis); <br>
* </code>
*
* @author looly
* @since 5.7.14
*/
public class BomReader extends Reader {
private InputStreamReader reader;
/**
* 构造
*
* @param in
*/
public BomReader(InputStream in) {
Assert.notNull(in, "InputStream must be not null!");
final BOMInputStream bin = (in instanceof BOMInputStream) ? (BOMInputStream) in : new BOMInputStream(in);
try {
this.reader = new InputStreamReader(bin, bin.getCharset());
} catch (UnsupportedEncodingException ignore) {
}
}
@Override
public int read(char[] cbuf, int off, int len) throws IOException {
return reader.read(cbuf, off, len);
}
@Override
public void close() throws IOException {
reader.close();
}
}

View File

@ -224,6 +224,17 @@ public class IoUtil extends NioUtil {
return getReader(in, in.getCharset()); return getReader(in, in.getCharset());
} }
/**
* {@link InputStream}中获取{@link BomReader}
*
* @param in {@link InputStream}
* @return {@link BomReader}
* @since 5.7.14
*/
public static BomReader getBomReader(InputStream in) {
return new BomReader(in);
}
/** /**
* 获得一个Reader * 获得一个Reader
* *

View File

@ -1,5 +1,6 @@
package cn.hutool.core.lang; package cn.hutool.core.lang;
import cn.hutool.core.bean.BeanPath;
import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert; import cn.hutool.core.convert.Convert;
@ -76,7 +77,7 @@ public class Dict extends LinkedHashMap<String, Object> implements BasicTypeGett
* <p>奇数参数必须为value可以为任意类型</p> * <p>奇数参数必须为value可以为任意类型</p>
* *
* <pre> * <pre>
Dict dict = Dict.of( * Dict dict = Dict.of(
* "RED", "#FF0000", * "RED", "#FF0000",
* "GREEN", "#00FF00", * "GREEN", "#00FF00",
* "BLUE", "#0000FF" * "BLUE", "#0000FF"
@ -91,10 +92,10 @@ public class Dict extends LinkedHashMap<String, Object> implements BasicTypeGett
final Dict dict = create(); final Dict dict = create();
String key = null; String key = null;
for(int i = 0; i < keysAndValues.length; i++){ for (int i = 0; i < keysAndValues.length; i++) {
if(i % 2 == 0){ if (i % 2 == 0) {
key = Convert.toStr(keysAndValues[i]); key = Convert.toStr(keysAndValues[i]);
} else{ } else {
dict.put(key, keysAndValues[i]); dict.put(key, keysAndValues[i]);
} }
} }
@ -504,6 +505,61 @@ public class Dict extends LinkedHashMap<String, Object> implements BasicTypeGett
public Number getNumber(String attr) { public Number getNumber(String attr) {
return get(attr, null); return get(attr, null);
} }
/**
* 通过表达式获取JSON中嵌套的对象<br>
* <ol>
* <li>.表达式可以获取Bean对象中的属性字段值或者Map中key对应的值</li>
* <li>[]表达式可以获取集合等对象中对应index的值</li>
* </ol>
* <p>
* 表达式栗子
*
* <pre>
* persion
* persion.name
* persons[3]
* person.friends[5].name
* </pre>
*
* @param expression 表达式
* @return 对象
* @see BeanPath#get(Object)
* @since 5.7.14
*/
@SuppressWarnings("unchecked")
public <T> T getByPath(String expression) {
return (T) BeanPath.create(expression).get(this);
}
/**
* 通过表达式获取JSON中嵌套的对象<br>
* <ol>
* <li>.表达式可以获取Bean对象中的属性字段值或者Map中key对应的值</li>
* <li>[]表达式可以获取集合等对象中对应index的值</li>
* </ol>
* <p>
* 表达式栗子
*
* <pre>
* persion
* persion.name
* persons[3]
* person.friends[5].name
* </pre>
* <p>
* 获取表达式对应值后转换为对应类型的值
*
* @param <T> 返回值类型
* @param expression 表达式
* @param resultType 返回值类型
* @return 对象
* @see BeanPath#get(Object)
* @since 5.7.14
*/
public <T> T getByPath(String expression, Class<T> resultType) {
return Convert.convert(resultType, getByPath(expression));
}
// -------------------------------------------------------------------- Get end // -------------------------------------------------------------------- Get end
@Override @Override

View File

@ -14,45 +14,61 @@ import java.util.List;
* 此模板用于简化对指定表的操作简化的操作如下<br> * 此模板用于简化对指定表的操作简化的操作如下<br>
* 1在初始化时指定了表名CRUD操作时便不需要表名<br> * 1在初始化时指定了表名CRUD操作时便不需要表名<br>
* 2在初始化时指定了主键某些需要主键的操作便不需要指定主键类型 * 2在初始化时指定了主键某些需要主键的操作便不需要指定主键类型
* @author Looly
* *
* @author Looly
*/ */
public class DaoTemplate { public class DaoTemplate {
/** 表名 */ /**
* 表名
*/
protected String tableName; protected String tableName;
/** 本表的主键字段请在子类中覆盖或构造方法中指定默认为id */ /**
* 本表的主键字段请在子类中覆盖或构造方法中指定默认为id
*/
protected String primaryKeyField = "id"; protected String primaryKeyField = "id";
/** SQL运行器 */ /**
* SQL运行器
*/
protected Db db; protected Db db;
//--------------------------------------------------------------- Constructor start //--------------------------------------------------------------- Constructor start
/** /**
* 构造此构造需要自定义SqlRunner主键默认为id * 构造此构造需要自定义SqlRunner主键默认为id
*
* @param tableName 数据库表名 * @param tableName 数据库表名
*/ */
public DaoTemplate(String tableName) { public DaoTemplate(String tableName) {
this(tableName, (String)null); this(tableName, (String) null);
} }
/** /**
* 构造使用默认的池化连接池读取默认配置文件的空分组适用于只有一个数据库的情况 * 构造使用默认的池化连接池读取默认配置文件的空分组适用于只有一个数据库的情况
* @param tableName 数据库表名 *
* @param tableName 数据库表名
* @param primaryKeyField 主键字段名 * @param primaryKeyField 主键字段名
*/ */
public DaoTemplate(String tableName, String primaryKeyField) { public DaoTemplate(String tableName, String primaryKeyField) {
this(tableName, primaryKeyField, DSFactory.get()); this(tableName, primaryKeyField, DSFactory.get());
} }
/**
* 构造
*
* @param tableName
* @param ds 数据源
*/
public DaoTemplate(String tableName, DataSource ds) { public DaoTemplate(String tableName, DataSource ds) {
this(tableName, null, ds); this(tableName, null, ds);
} }
/** /**
* 构造 * 构造
* @param tableName 表名 *
* @param tableName 表名
* @param primaryKeyField 主键字段名 * @param primaryKeyField 主键字段名
* @param ds 数据源 * @param ds 数据源
*/ */
public DaoTemplate(String tableName, String primaryKeyField, DataSource ds) { public DaoTemplate(String tableName, String primaryKeyField, DataSource ds) {
this(tableName, primaryKeyField, Db.use(ds)); this(tableName, primaryKeyField, Db.use(ds));
@ -60,13 +76,14 @@ public class DaoTemplate {
/** /**
* 构造 * 构造
* @param tableName 表名 *
* @param tableName 表名
* @param primaryKeyField 主键字段名 * @param primaryKeyField 主键字段名
* @param db Db对象 * @param db Db对象
*/ */
public DaoTemplate(String tableName, String primaryKeyField, Db db) { public DaoTemplate(String tableName, String primaryKeyField, Db db) {
this.tableName = tableName; this.tableName = tableName;
if(StrUtil.isNotBlank(primaryKeyField)){ if (StrUtil.isNotBlank(primaryKeyField)) {
this.primaryKeyField = primaryKeyField; this.primaryKeyField = primaryKeyField;
} }
this.db = db; this.db = db;
@ -74,8 +91,10 @@ public class DaoTemplate {
//--------------------------------------------------------------- Constructor end //--------------------------------------------------------------- Constructor end
//------------------------------------------------------------- Add start //------------------------------------------------------------- Add start
/** /**
* 添加 * 添加
*
* @param entity 实体对象 * @param entity 实体对象
* @return 插入行数 * @return 插入行数
* @throws SQLException SQL执行异常 * @throws SQLException SQL执行异常
@ -86,6 +105,7 @@ public class DaoTemplate {
/** /**
* 添加 * 添加
*
* @param entity 实体对象 * @param entity 实体对象
* @return 主键列表 * @return 主键列表
* @throws SQLException SQL执行异常 * @throws SQLException SQL执行异常
@ -96,6 +116,7 @@ public class DaoTemplate {
/** /**
* 添加 * 添加
*
* @param entity 实体对象 * @param entity 实体对象
* @return 自增主键 * @return 自增主键
* @throws SQLException SQL执行异常 * @throws SQLException SQL执行异常
@ -106,11 +127,12 @@ public class DaoTemplate {
//------------------------------------------------------------- Add end //------------------------------------------------------------- Add end
//------------------------------------------------------------- Delete start //------------------------------------------------------------- Delete start
/** /**
* 删除 * 删除
* @param <T> 主键类型
* *
* @param pk 主键 * @param <T> 主键类型
* @param pk 主键
* @return 删除行数 * @return 删除行数
* @throws SQLException SQL执行异常 * @throws SQLException SQL执行异常
*/ */
@ -124,7 +146,7 @@ public class DaoTemplate {
/** /**
* 删除 * 删除
* *
* @param <T> 主键类型 * @param <T> 主键类型
* @param field 字段名 * @param field 字段名
* @param value 字段值 * @param value 字段值
* @return 删除行数 * @return 删除行数
@ -141,7 +163,7 @@ public class DaoTemplate {
/** /**
* 删除 * 删除
* *
* @param <T> 主键类型 * @param <T> 主键类型
* @param where 删除条件当条件为空时返回0防止误删全表 * @param where 删除条件当条件为空时返回0防止误删全表
* @return 删除行数 * @return 删除行数
* @throws SQLException SQL执行异常 * @throws SQLException SQL执行异常
@ -155,14 +177,16 @@ public class DaoTemplate {
//------------------------------------------------------------- Delete end //------------------------------------------------------------- Delete end
//------------------------------------------------------------- Update start //------------------------------------------------------------- Update start
/** /**
* 按照条件更新 * 按照条件更新
*
* @param record 更新的内容 * @param record 更新的内容
* @param where 条件 * @param where 条件
* @return 更新条目数 * @return 更新条目数
* @throws SQLException SQL执行异常 * @throws SQLException SQL执行异常
*/ */
public int update(Entity record, Entity where) throws SQLException{ public int update(Entity record, Entity where) throws SQLException {
if (MapUtil.isEmpty(record)) { if (MapUtil.isEmpty(record)) {
return 0; return 0;
} }
@ -171,6 +195,7 @@ public class DaoTemplate {
/** /**
* 更新 * 更新
*
* @param entity 实体对象必须包含主键 * @param entity 实体对象必须包含主键
* @return 更新行数 * @return 更新行数
* @throws SQLException SQL执行异常 * @throws SQLException SQL执行异常
@ -194,6 +219,7 @@ public class DaoTemplate {
/** /**
* 增加或者更新实体 * 增加或者更新实体
*
* @param entity 实体当包含主键时更新否则新增 * @param entity 实体当包含主键时更新否则新增
* @return 新增或更新条数 * @return 新增或更新条数
* @throws SQLException SQL执行异常 * @throws SQLException SQL执行异常
@ -204,11 +230,12 @@ public class DaoTemplate {
//------------------------------------------------------------- Update end //------------------------------------------------------------- Update end
//------------------------------------------------------------- Get start //------------------------------------------------------------- Get start
/** /**
* 根据主键获取单个记录 * 根据主键获取单个记录
* *
* @param <T> 主键类型 * @param <T> 主键类型
* @param pk 主键值 * @param pk 主键值
* @return 记录 * @return 记录
* @throws SQLException SQL执行异常 * @throws SQLException SQL执行异常
*/ */
@ -220,7 +247,7 @@ public class DaoTemplate {
* 根据某个字段最好是唯一字段查询单个记录<br> * 根据某个字段最好是唯一字段查询单个记录<br>
* 当有多条返回时只显示查询到的第一条 * 当有多条返回时只显示查询到的第一条
* *
* @param <T> 字段值类型 * @param <T> 字段值类型
* @param field 字段名 * @param field 字段名
* @param value 字段值 * @param value 字段值
* @return 记录 * @return 记录
@ -243,10 +270,11 @@ public class DaoTemplate {
//------------------------------------------------------------- Get end //------------------------------------------------------------- Get end
//------------------------------------------------------------- Find start //------------------------------------------------------------- Find start
/** /**
* 根据某个字段值查询结果 * 根据某个字段值查询结果
* *
* @param <T> 字段值类型 * @param <T> 字段值类型
* @param field 字段名 * @param field 字段名
* @param value 字段值 * @param value 字段值
* @return 记录 * @return 记录
@ -258,6 +286,7 @@ public class DaoTemplate {
/** /**
* 查询当前表的所有记录 * 查询当前表的所有记录
*
* @return 记录 * @return 记录
* @throws SQLException SQL执行异常 * @throws SQLException SQL执行异常
*/ */
@ -281,14 +310,14 @@ public class DaoTemplate {
* SQL语句可以是非完整SQL语句可以只提供查询的条件部分例如WHERE部分<br> * SQL语句可以是非完整SQL语句可以只提供查询的条件部分例如WHERE部分<br>
* 此方法会自动补全SELECT * FROM [tableName] 部分这样就无需关心表名直接提供条件即可 * 此方法会自动补全SELECT * FROM [tableName] 部分这样就无需关心表名直接提供条件即可
* *
* @param sql SQL语句 * @param sql SQL语句
* @param params SQL占位符中对应的参数 * @param params SQL占位符中对应的参数
* @return 记录 * @return 记录
* @throws SQLException SQL执行异常 * @throws SQLException SQL执行异常
*/ */
public List<Entity> findBySql(String sql, Object... params) throws SQLException { public List<Entity> findBySql(String sql, Object... params) throws SQLException {
String selectKeyword = StrUtil.subPre(sql.trim(), 6).toLowerCase(); String selectKeyword = StrUtil.subPre(sql.trim(), 6).toLowerCase();
if(false == "select".equals(selectKeyword)){ if (false == "select".equals(selectKeyword)) {
sql = "SELECT * FROM " + this.tableName + " " + sql; sql = "SELECT * FROM " + this.tableName + " " + sql;
} }
return db.query(sql, params); return db.query(sql, params);
@ -297,13 +326,13 @@ public class DaoTemplate {
/** /**
* 分页 * 分页
* *
* @param where 条件 * @param where 条件
* @param page 分页对象 * @param page 分页对象
* @param selectFields 查询的字段列表 * @param selectFields 查询的字段列表
* @return 分页结果集 * @return 分页结果集
* @throws SQLException SQL执行异常 * @throws SQLException SQL执行异常
*/ */
public PageResult<Entity> page(Entity where, Page page, String... selectFields) throws SQLException{ public PageResult<Entity> page(Entity where, Page page, String... selectFields) throws SQLException {
return db.page(Arrays.asList(selectFields), fixEntity(where), page); return db.page(Arrays.asList(selectFields), fixEntity(where), page);
} }
@ -311,11 +340,11 @@ public class DaoTemplate {
* 分页 * 分页
* *
* @param where 条件 * @param where 条件
* @param page 分页对象 * @param page 分页对象
* @return 分页结果集 * @return 分页结果集
* @throws SQLException SQL执行异常 * @throws SQLException SQL执行异常
*/ */
public PageResult<Entity> page(Entity where, Page page) throws SQLException{ public PageResult<Entity> page(Entity where, Page page) throws SQLException {
return db.page(fixEntity(where), page); return db.page(fixEntity(where), page);
} }
@ -326,7 +355,7 @@ public class DaoTemplate {
* @return 数量 * @return 数量
* @throws SQLException SQL执行异常 * @throws SQLException SQL执行异常
*/ */
public long count(Entity where) throws SQLException{ public long count(Entity where) throws SQLException {
return db.count(fixEntity(where)); return db.count(fixEntity(where));
} }
@ -337,20 +366,21 @@ public class DaoTemplate {
* @return 是否存在 * @return 是否存在
* @throws SQLException SQL执行异常 * @throws SQLException SQL执行异常
*/ */
public boolean exist(Entity where) throws SQLException{ public boolean exist(Entity where) throws SQLException {
return this.count(where) > 0; return this.count(where) > 0;
} }
//------------------------------------------------------------- Find end //------------------------------------------------------------- Find end
/** /**
* 修正Entity对象避免null和填充表名 * 修正Entity对象避免null和填充表名
*
* @param entity 实体类 * @param entity 实体类
* @return 修正后的实体类 * @return 修正后的实体类
*/ */
private Entity fixEntity(Entity entity){ private Entity fixEntity(Entity entity) {
if(null == entity){ if (null == entity) {
entity = Entity.create(tableName); entity = Entity.create(tableName);
}else if(StrUtil.isBlank(entity.getTableName())){ } else if (StrUtil.isBlank(entity.getTableName())) {
entity.setTableName(tableName); entity.setTableName(tableName);
} }
return entity; return entity;

View File

@ -0,0 +1,34 @@
package cn.hutool.db;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import org.junit.Ignore;
import org.junit.Test;
import java.sql.ResultSet;
import java.sql.SQLException;
public class PicTransferTest {
@Test
@Ignore
public void findTest() throws SQLException {
Db.use().find(
ListUtil.of("NAME", "TYPE", "GROUP", "PIC"),
Entity.create("PIC_INFO").set("TYPE", 1),
rs -> {
while(rs.next()){
save(rs);
}
return null;
}
);
}
private static void save(ResultSet rs) throws SQLException{
String destDir = "d:/test/pic";
String path = StrUtil.format("{}/{}-{}.jpg", destDir, rs.getString("NAME"), rs.getString("GROUP"));
FileUtil.writeFromStream(rs.getBlob("PIC").getBinaryStream(), path);
}
}

View File

@ -451,11 +451,5 @@
<scope>compile</scope> <scope>compile</scope>
<optional>true</optional> <optional>true</optional>
</dependency> </dependency>
<dependency>
<groupId>org.tukaani</groupId>
<artifactId>xz</artifactId>
<version>1.9</version>
<scope>test</scope>
</dependency>
</dependencies> </dependencies>
</project> </project>

View File

@ -6,7 +6,7 @@ import cn.hutool.extra.compress.archiver.Archiver;
import cn.hutool.extra.compress.archiver.SevenZArchiver; import cn.hutool.extra.compress.archiver.SevenZArchiver;
import cn.hutool.extra.compress.archiver.StreamArchiver; import cn.hutool.extra.compress.archiver.StreamArchiver;
import cn.hutool.extra.compress.extractor.Extractor; import cn.hutool.extra.compress.extractor.Extractor;
import cn.hutool.extra.compress.extractor.SenvenZExtractor; import cn.hutool.extra.compress.extractor.SevenZExtractor;
import cn.hutool.extra.compress.extractor.StreamExtractor; import cn.hutool.extra.compress.extractor.StreamExtractor;
import org.apache.commons.compress.archivers.ArchiveStreamFactory; import org.apache.commons.compress.archivers.ArchiveStreamFactory;
import org.apache.commons.compress.archivers.StreamingNotSupportedException; import org.apache.commons.compress.archivers.StreamingNotSupportedException;
@ -168,14 +168,14 @@ public class CompressUtil {
*/ */
public static Extractor createExtractor(Charset charset, String archiverName, File file) { public static Extractor createExtractor(Charset charset, String archiverName, File file) {
if (ArchiveStreamFactory.SEVEN_Z.equalsIgnoreCase(archiverName)) { if (ArchiveStreamFactory.SEVEN_Z.equalsIgnoreCase(archiverName)) {
return new SenvenZExtractor(file); return new SevenZExtractor(file);
} }
try { try {
return new StreamExtractor(charset, archiverName, file); return new StreamExtractor(charset, archiverName, file);
} catch (CompressException e) { } catch (CompressException e) {
final Throwable cause = e.getCause(); final Throwable cause = e.getCause();
if (cause instanceof StreamingNotSupportedException && cause.getMessage().contains("7z")) { if (cause instanceof StreamingNotSupportedException && cause.getMessage().contains("7z")) {
return new SenvenZExtractor(file); return new SevenZExtractor(file);
} }
throw e; throw e;
} }
@ -218,14 +218,15 @@ public class CompressUtil {
*/ */
public static Extractor createExtractor(Charset charset, String archiverName, InputStream in) { public static Extractor createExtractor(Charset charset, String archiverName, InputStream in) {
if (ArchiveStreamFactory.SEVEN_Z.equalsIgnoreCase(archiverName)) { if (ArchiveStreamFactory.SEVEN_Z.equalsIgnoreCase(archiverName)) {
return new SenvenZExtractor(in); return new SevenZExtractor(in);
} }
try { try {
return new StreamExtractor(charset, archiverName, in); return new StreamExtractor(charset, archiverName, in);
} catch (CompressException e) { } catch (CompressException e) {
final Throwable cause = e.getCause(); final Throwable cause = e.getCause();
if (cause instanceof StreamingNotSupportedException && cause.getMessage().contains("7z")) { if (cause instanceof StreamingNotSupportedException && cause.getMessage().contains("7z")) {
return new SenvenZExtractor(in); return new SevenZExtractor(in);
} }
throw e; throw e;
} }

View File

@ -27,7 +27,7 @@ public interface Extractor extends Closeable {
* 释放解压到指定目录结束后自动关闭流此方法只能调用一次 * 释放解压到指定目录结束后自动关闭流此方法只能调用一次
* *
* @param targetDir 目标目录 * @param targetDir 目标目录
* @param filter 解压文件过滤器用于指定需要释放的文件null表示不过滤{@link Filter#accept(Object)}为true时释放 * @param filter 解压文件过滤器用于指定需要释放的文件{@code null}表示不过滤{@link Filter#accept(Object)}为true时释放
*/ */
void extract(File targetDir, Filter<ArchiveEntry> filter); void extract(File targetDir, Filter<ArchiveEntry> filter);

View File

@ -20,8 +20,9 @@ public class Seven7EntryInputStream extends InputStream {
/** /**
* 构造 * 构造
*
* @param sevenZFile {@link SevenZFile} * @param sevenZFile {@link SevenZFile}
* @param entry {@link SevenZArchiveEntry} * @param entry {@link SevenZArchiveEntry}
*/ */
public Seven7EntryInputStream(SevenZFile sevenZFile, SevenZArchiveEntry entry) { public Seven7EntryInputStream(SevenZFile sevenZFile, SevenZArchiveEntry entry) {
this.sevenZFile = sevenZFile; this.sevenZFile = sevenZFile;
@ -30,13 +31,23 @@ public class Seven7EntryInputStream extends InputStream {
@Override @Override
public int available() throws IOException { public int available() throws IOException {
try{ try {
return Math.toIntExact(this.size); return Math.toIntExact(this.size);
} catch (ArithmeticException e){ } catch (ArithmeticException e) {
throw new IOException("Entry size is too large!(max than Integer.MAX)", e); throw new IOException("Entry size is too large!(max than Integer.MAX)", e);
} }
} }
/**
* 获取读取的长度字节数
*
* @return 读取的字节数
* @since 5.7.14
*/
public long getReadSize() {
return this.readSize;
}
@Override @Override
public int read() throws IOException { public int read() throws IOException {
this.readSize++; this.readSize++;

View File

@ -5,6 +5,7 @@ import cn.hutool.core.io.IORuntimeException;
import cn.hutool.core.io.IoUtil; import cn.hutool.core.io.IoUtil;
import cn.hutool.core.lang.Assert; import cn.hutool.core.lang.Assert;
import cn.hutool.core.lang.Filter; import cn.hutool.core.lang.Filter;
import cn.hutool.core.util.StrUtil;
import org.apache.commons.compress.archivers.ArchiveEntry; import org.apache.commons.compress.archivers.ArchiveEntry;
import org.apache.commons.compress.archivers.sevenz.SevenZArchiveEntry; import org.apache.commons.compress.archivers.sevenz.SevenZArchiveEntry;
import org.apache.commons.compress.archivers.sevenz.SevenZFile; import org.apache.commons.compress.archivers.sevenz.SevenZFile;
@ -14,6 +15,7 @@ import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.nio.channels.SeekableByteChannel; import java.nio.channels.SeekableByteChannel;
import java.util.RandomAccess;
/** /**
* 7z格式数据解压器即将归档打包的数据释放 * 7z格式数据解压器即将归档打包的数据释放
@ -21,7 +23,7 @@ import java.nio.channels.SeekableByteChannel;
* @author looly * @author looly
* @since 5.5.0 * @since 5.5.0
*/ */
public class SenvenZExtractor implements Extractor { public class SevenZExtractor implements Extractor, RandomAccess {
private final SevenZFile sevenZFile; private final SevenZFile sevenZFile;
@ -30,7 +32,7 @@ public class SenvenZExtractor implements Extractor {
* *
* @param file 包文件 * @param file 包文件
*/ */
public SenvenZExtractor(File file) { public SevenZExtractor(File file) {
this(file, null); this(file, null);
} }
@ -40,7 +42,7 @@ public class SenvenZExtractor implements Extractor {
* @param file 包文件 * @param file 包文件
* @param password 密码null表示无密码 * @param password 密码null表示无密码
*/ */
public SenvenZExtractor(File file, char[] password) { public SevenZExtractor(File file, char[] password) {
try { try {
this.sevenZFile = new SevenZFile(file, password); this.sevenZFile = new SevenZFile(file, password);
} catch (IOException e) { } catch (IOException e) {
@ -53,7 +55,7 @@ public class SenvenZExtractor implements Extractor {
* *
* @param in 包流 * @param in 包流
*/ */
public SenvenZExtractor(InputStream in) { public SevenZExtractor(InputStream in) {
this(in, null); this(in, null);
} }
@ -63,7 +65,7 @@ public class SenvenZExtractor implements Extractor {
* @param in 包流 * @param in 包流
* @param password 密码null表示无密码 * @param password 密码null表示无密码
*/ */
public SenvenZExtractor(InputStream in, char[] password) { public SevenZExtractor(InputStream in, char[] password) {
this(new SeekableInMemoryByteChannel(IoUtil.readBytes(in)), password); this(new SeekableInMemoryByteChannel(IoUtil.readBytes(in)), password);
} }
@ -72,7 +74,7 @@ public class SenvenZExtractor implements Extractor {
* *
* @param channel {@link SeekableByteChannel} * @param channel {@link SeekableByteChannel}
*/ */
public SenvenZExtractor(SeekableByteChannel channel) { public SevenZExtractor(SeekableByteChannel channel) {
this(channel, null); this(channel, null);
} }
@ -82,7 +84,7 @@ public class SenvenZExtractor implements Extractor {
* @param channel {@link SeekableByteChannel} * @param channel {@link SeekableByteChannel}
* @param password 密码null表示无密码 * @param password 密码null表示无密码
*/ */
public SenvenZExtractor(SeekableByteChannel channel, char[] password) { public SevenZExtractor(SeekableByteChannel channel, char[] password) {
try { try {
this.sevenZFile = new SevenZFile(channel, password); this.sevenZFile = new SevenZFile(channel, password);
} catch (IOException e) { } catch (IOException e) {
@ -107,6 +109,44 @@ public class SenvenZExtractor implements Extractor {
} }
} }
/**
* 获取满足指定过滤要求的压缩包内的第一个文件流
*
* @param filter 用于指定需要释放的文件null表示不过滤{@link Filter#accept(Object)}为true时返回对应流
* @return 满足过滤要求的第一个文件的流,无满足条件的文件返回{@code null}
* @since 5.7.14
*/
public InputStream getFirst(Filter<ArchiveEntry> filter) {
final SevenZFile sevenZFile = this.sevenZFile;
for(SevenZArchiveEntry entry : sevenZFile.getEntries()){
if(null != filter && false == filter.accept(entry)){
continue;
}
if(entry.isDirectory()){
continue;
}
try {
return sevenZFile.getInputStream(entry);
} catch (IOException e) {
throw new IORuntimeException(e);
}
}
return null;
}
/**
* 获取指定名称的文件流
*
* @param entryName entry名称
* @return 文件流无文件返回{@code null}
* @since 5.7.14
*/
public InputStream get(String entryName){
return getFirst((entry)-> StrUtil.equals(entryName, entry.getName()));
}
/** /**
* 释放解压到指定目录 * 释放解压到指定目录
* *
@ -120,6 +160,9 @@ public class SenvenZExtractor implements Extractor {
SevenZArchiveEntry entry; SevenZArchiveEntry entry;
File outItemFile; File outItemFile;
while (null != (entry = this.sevenZFile.getNextEntry())) { while (null != (entry = this.sevenZFile.getNextEntry())) {
if(null != filter && false == filter.accept(entry)){
continue;
}
outItemFile = FileUtil.file(targetDir, entry.getName()); outItemFile = FileUtil.file(targetDir, entry.getName());
if (entry.isDirectory()) { if (entry.isDirectory()) {
// 创建对应目录 // 创建对应目录

View File

@ -109,6 +109,9 @@ public class StreamExtractor implements Extractor{
ArchiveEntry entry; ArchiveEntry entry;
File outItemFile; File outItemFile;
while (null != (entry = in.getNextEntry())) { while (null != (entry = in.getNextEntry())) {
if(null != filter && false == filter.accept(entry)){
continue;
}
if (false == in.canReadEntryData(entry)) { if (false == in.canReadEntryData(entry)) {
// 无法读取的文件直接跳过 // 无法读取的文件直接跳过
continue; continue;

View File

@ -50,7 +50,7 @@ public class ArchiverTest {
@Test @Test
@Ignore @Ignore
public void senvenZTest(){ public void sevenZTest(){
final File file = FileUtil.file("d:/test/compress/test.7z"); final File file = FileUtil.file("d:/test/compress/test.7z");
CompressUtil.createArchiver(CharsetUtil.CHARSET_UTF_8, ArchiveStreamFactory.SEVEN_Z, file) CompressUtil.createArchiver(CharsetUtil.CHARSET_UTF_8, ArchiveStreamFactory.SEVEN_Z, file)
.add(FileUtil.file("d:/Java/apache-maven-3.6.3"), (f)->{ .add(FileUtil.file("d:/Java/apache-maven-3.6.3"), (f)->{

View File

@ -21,7 +21,7 @@ public class ExtractorTest {
@Test @Test
@Ignore @Ignore
public void sevenZTest(){ public void sevenZTest(){
Extractor extractor = CompressUtil.createExtractor( Extractor extractor = CompressUtil.createExtractor(
CharsetUtil.defaultCharset(), CharsetUtil.defaultCharset(),
FileUtil.file("d:/test/compress/test.7z")); FileUtil.file("d:/test/compress/test.7z"));

View File

@ -1,14 +1,6 @@
package cn.hutool.json.test.bean; package cn.hutool.json.test.bean;
@lombok.Data
public class Data { public class Data {
private Price Price; private Price Price;
public void setPrice(Price Price) {
this.Price = Price;
}
public Price getPrice() {
return Price;
}
} }

View File

@ -1,63 +1,22 @@
package cn.hutool.json.test.bean; package cn.hutool.json.test.bean;
import lombok.Data;
import java.io.Serializable; import java.io.Serializable;
import java.util.Objects;
/** /**
* *
* @author 质量过关 * @author 质量过关
* *
*/ */
@Data
public class ExamInfoDict implements Serializable { public class ExamInfoDict implements Serializable {
private static final long serialVersionUID = 3640936499125004525L; private static final long serialVersionUID = 3640936499125004525L;
// 主键 // 主键
private Integer id; // 可当作题号 private Integer id; // 可当作题号
// 试题类型 客观题 0主观题 1 // 试题类型 客观题 0主观题 1
private Integer examType; private Integer examType;
// 试题是否作答 // 试题是否作答
private Integer answerIs; private Integer answerIs;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getExamType() {
return examType;
}
public void setExamType(Integer examType) {
this.examType = examType;
}
public Integer getAnswerIs() {
return answerIs;
}
public void setAnswerIs(Integer answerIs) {
this.answerIs = answerIs;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
ExamInfoDict that = (ExamInfoDict) o;
return Objects.equals(id, that.id) && Objects.equals(examType, that.examType) && Objects.equals(answerIs, that.answerIs);
}
@Override
public int hashCode() {
return Objects.hash(id, examType, answerIs);
}
@Override
public String toString() {
return "ExamInfoDict{" + "id=" + id + ", examType=" + examType + ", answerIs=" + answerIs + '}';
}
} }

View File

@ -1,22 +1,10 @@
package cn.hutool.json.test.bean; package cn.hutool.json.test.bean;
import cn.hutool.json.JSONObject; import cn.hutool.json.JSONObject;
import lombok.Data;
@Data
public class JSONBean { public class JSONBean {
private int code; private int code;
private JSONObject data; private JSONObject data;
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public JSONObject getData() {
return data;
}
public void setData(JSONObject data) {
this.data = data;
}
} }

View File

@ -1,7 +1,10 @@
package cn.hutool.json.test.bean; package cn.hutool.json.test.bean;
import lombok.Data;
import java.io.Serializable; import java.io.Serializable;
@Data
public class JsonNode implements Serializable { public class JsonNode implements Serializable {
private static final long serialVersionUID = -2280206942803550272L; private static final long serialVersionUID = -2280206942803550272L;
@ -17,33 +20,4 @@ public class JsonNode implements Serializable {
this.parentId = parentId; this.parentId = parentId;
this.name = name; this.name = name;
} }
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Integer getParentId() {
return parentId;
}
public void setParentId(Integer parentId) {
this.parentId = parentId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "JsonNode{" + "id=" + id + ", parentId=" + parentId + ", name='" + name + '\'' + '}';
}
}

View File

@ -1,61 +0,0 @@
package cn.hutool.json.test.bean;
import java.util.List;
public class JsonRootBean {
private int statusCode;
private String message;
private int skip;
private int limit;
private int total;
private List<Data> data;
public void setStatusCode(int statusCode) {
this.statusCode = statusCode;
}
public int getStatusCode() {
return statusCode;
}
public void setMessage(String message) {
this.message = message;
}
public String getMessage() {
return message;
}
public void setSkip(int skip) {
this.skip = skip;
}
public int getSkip() {
return skip;
}
public void setLimit(int limit) {
this.limit = limit;
}
public int getLimit() {
return limit;
}
public void setTotal(int total) {
this.total = total;
}
public int getTotal() {
return total;
}
public void setData(List<Data> data) {
this.data = data;
}
public List<Data> getData() {
return data;
}
}

View File

@ -1,13 +1,15 @@
package cn.hutool.json.test.bean; package cn.hutool.json.test.bean;
import lombok.Data;
import java.io.Serializable; import java.io.Serializable;
/** /**
* @author wangyan E-mail:wangyan@pospt.cn * @author wangyan E-mail:wangyan@pospt.cn
* @version 创建时间2017年9月11日 上午9:33:01 类说明 * @version 创建时间2017年9月11日 上午9:33:01 类说明
*/ */
@Data
public class ProductResBase implements Serializable { public class ProductResBase implements Serializable {
private static final long serialVersionUID = -6708040074002451511L; private static final long serialVersionUID = -6708040074002451511L;
/** /**
* 请求结果成功0 * 请求结果成功0
@ -21,6 +23,7 @@ public class ProductResBase implements Serializable {
* 成功code * 成功code
*/ */
public static final String REQUEST_CODE_SUCCESS = "0000"; public static final String REQUEST_CODE_SUCCESS = "0000";
/** /**
* 结果 成功0 失败1 * 结果 成功0 失败1
*/ */
@ -32,40 +35,4 @@ public class ProductResBase implements Serializable {
* 成本总计 * 成本总计
*/ */
private Integer costTotal; private Integer costTotal;
public Integer getCostTotal() {
return costTotal;
}
public ProductResBase setCostTotal(Integer costTotal) {
this.costTotal = costTotal;
return this;
}
public int getResResult() {
return resResult;
}
public String getResCode() {
return resCode;
}
public String getResMsg() {
return resMsg;
}
public ProductResBase setResResult(int resResult) {
this.resResult = resResult;
return this;
}
public ProductResBase setResCode(String resCode) {
this.resCode = resCode;
return this;
}
public ProductResBase setResMsg(String resMsg) {
this.resMsg = resMsg;
return this;
}
} }

View File

@ -1,7 +1,10 @@
package cn.hutool.json.test.bean; package cn.hutool.json.test.bean;
import lombok.Data;
import java.io.Serializable; import java.io.Serializable;
@Data
public class ResultDto<T> implements Serializable { public class ResultDto<T> implements Serializable {
private static final long serialVersionUID = -1417999729205654379L; private static final long serialVersionUID = -1417999729205654379L;
@ -128,28 +131,4 @@ public class ResultDto<T> implements Serializable {
public boolean error() { public boolean error() {
return !success(); return !success();
} }
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public T getResult() {
return result;
}
public void setResult(T result) {
this.result = result;
}
} }

View File

@ -1,25 +1,15 @@
package cn.hutool.json.test.bean; package cn.hutool.json.test.bean;
import lombok.Data;
@Data
public class Seq { public class Seq {
private String seq; private String seq;
public Seq() { public Seq() {
} }
public Seq(String seq) { public Seq(String seq) {
this.seq = seq; this.seq = seq;
} }
public String getSeq() {
return seq;
}
public void setSeq(String seq) {
this.seq = seq;
}
@Override
public String toString() {
return "Seq [seq=" + seq + "]";
}
} }

View File

@ -1,22 +1,9 @@
package cn.hutool.json.test.bean; package cn.hutool.json.test.bean;
import lombok.Data;
@Data
public class TokenAuthResponse { public class TokenAuthResponse {
private String token; private String token;
private String userId; private String userId;
public String getToken() {
return token;
}
public void setToken(String token) {
this.token = token;
}
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
} }

View File

@ -1,24 +1,13 @@
package cn.hutool.json.test.bean; package cn.hutool.json.test.bean;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class TokenAuthWarp extends UUMap<TokenAuthResponse> { public class TokenAuthWarp extends UUMap<TokenAuthResponse> {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private String targetUrl; private String targetUrl;
private String success; private String success;
public String getTargetUrl() {
return targetUrl;
}
public void setTargetUrl(String targetUrl) {
this.targetUrl = targetUrl;
}
public String getSuccess() {
return success;
}
public void setSuccess(String success) {
this.success = success;
}
} }

View File

@ -1,9 +1,5 @@
package cn.hutool.json.test.bean; package cn.hutool.json.test.bean;
public class TokenAuthWarp2 extends TokenAuthWarp { public class TokenAuthWarp2 extends TokenAuthWarp {
/**
*
*/
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
} }

View File

@ -1,20 +1,15 @@
package cn.hutool.json.test.bean; package cn.hutool.json.test.bean;
import lombok.Data;
import java.io.Serializable; import java.io.Serializable;
@Data
public class UUMap<T> implements Serializable{ public class UUMap<T> implements Serializable{
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private T result; private T result;
public T getResult() {
return result;
}
public void setResult(T result) {
this.result = result;
}
public static long getSerialversionuid() { public static long getSerialversionuid() {
return serialVersionUID; return serialVersionUID;
} }

View File

@ -1,28 +1,12 @@
package cn.hutool.json.test.bean; package cn.hutool.json.test.bean;
import lombok.Data;
import java.util.Date; import java.util.Date;
@Data
public class UserB { public class UserB {
private String name; private String name;
private String b; private String b;
private Date date; private Date date;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getB() {
return b;
}
public void setB(String a) {
this.b = a;
}
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
} }

View File

@ -1,31 +1,10 @@
package cn.hutool.json.test.bean; package cn.hutool.json.test.bean;
import lombok.Data;
@Data
public class UserC { public class UserC {
private Integer id; private Integer id;
private String name; private String name;
private String prop; private String prop;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getProp() {
return prop;
}
public void setProp(String prop) {
this.prop = prop;
}
} }

View File

@ -1,14 +1,16 @@
package cn.hutool.json.test.bean; package cn.hutool.json.test.bean;
import lombok.Data;
import java.io.Serializable; import java.io.Serializable;
import java.util.List; import java.util.List;
import java.util.Objects;
/** /**
* 用户信息 * 用户信息
* @author 质量过关 * @author 质量过关
* *
*/ */
@Data
public class UserInfoDict implements Serializable { public class UserInfoDict implements Serializable {
private static final long serialVersionUID = -936213991463284306L; private static final long serialVersionUID = -936213991463284306L;
// 用户Id // 用户Id
@ -19,61 +21,4 @@ public class UserInfoDict implements Serializable {
private String photoPath; private String photoPath;
private List<ExamInfoDict> examInfoDict; private List<ExamInfoDict> examInfoDict;
private UserInfoRedundCount userInfoRedundCount; private UserInfoRedundCount userInfoRedundCount;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getRealName() {
return realName;
}
public void setRealName(String realName) {
this.realName = realName;
}
public String getPhotoPath() {
return photoPath;
}
public void setPhotoPath(String photoPath) {
this.photoPath = photoPath;
}
public List<ExamInfoDict> getExamInfoDict() {
return examInfoDict;
}
public void setExamInfoDict(List<ExamInfoDict> examInfoDict) {
this.examInfoDict = examInfoDict;
}
public UserInfoRedundCount getUserInfoRedundCount() {
return userInfoRedundCount;
}
public void setUserInfoRedundCount(UserInfoRedundCount userInfoRedundCount) {
this.userInfoRedundCount = userInfoRedundCount;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
UserInfoDict that = (UserInfoDict) o;
return Objects.equals(id, that.id) && Objects.equals(realName, that.realName) && Objects.equals(photoPath, that.photoPath) && Objects.equals(examInfoDict, that.examInfoDict);
}
@Override
public int hashCode() {
return Objects.hash(id, realName, photoPath, examInfoDict);
}
@Override
public String toString() {
return "UserInfoDict [id=" + id + ", realName=" + realName + ", photoPath=" + photoPath + ", examInfoDict=" + examInfoDict + ", userInfoRedundCount=" + userInfoRedundCount + "]";
}
} }

View File

@ -1,38 +1,14 @@
package cn.hutool.json.test.bean; package cn.hutool.json.test.bean;
import lombok.Data;
import java.io.Serializable; import java.io.Serializable;
@Data
public class UserInfoRedundCount implements Serializable { public class UserInfoRedundCount implements Serializable {
private static final long serialVersionUID = -8397291070139255181L; private static final long serialVersionUID = -8397291070139255181L;
private String finishedRatio; // 完成率 private String finishedRatio; // 完成率
private Integer ownershipExamCount; // 自己有多少道题 private Integer ownershipExamCount; // 自己有多少道题
private Integer answeredExamCount; // 当前回答了多少道题 private Integer answeredExamCount; // 当前回答了多少道题
public Integer getOwnershipExamCount() {
return ownershipExamCount;
}
public void setOwnershipExamCount(Integer ownershipExamCount) {
this.ownershipExamCount = ownershipExamCount;
}
public Integer getAnsweredExamCount() {
return answeredExamCount;
}
public void setAnsweredExamCount(Integer answeredExamCount) {
this.answeredExamCount = answeredExamCount;
}
public String getFinishedRatio() {
return finishedRatio;
}
public void setFinishedRatio(String finishedRatio) {
this.finishedRatio = finishedRatio;
}
} }

View File

@ -27,5 +27,11 @@
<artifactId>hutool-log</artifactId> <artifactId>hutool-log</artifactId>
<version>${project.parent.version}</version> <version>${project.parent.version}</version>
</dependency> </dependency>
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
<version>1.29</version>
<optional>true</optional>
</dependency>
</dependencies> </dependencies>
</project> </project>

View File

@ -0,0 +1,133 @@
package cn.hutool.setting.yaml;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.io.resource.ResourceUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.lang.Dict;
import org.yaml.snakeyaml.DumperOptions;
import org.yaml.snakeyaml.Yaml;
import java.io.InputStream;
import java.io.Reader;
import java.io.Writer;
/**
* 基于Snakeyaml的的YAML读写工具
*
* @author looly
* @since 5.7.14
*/
public class YamlUtil {
/**
* 从classpath或绝对路径加载YAML文件
*
* @param path YAML路径相对路径相对classpath
* @return 加载的内容默认Map
*/
public static Dict loadByPath(String path) {
return loadByPath(path, Dict.class);
}
/**
* 从classpath或绝对路径加载YAML文件
*
* @param <T> Bean类型默认map
* @param path YAML路径相对路径相对classpath
* @param type 加载的Bean类型即转换为的bean
* @return 加载的内容默认Map
*/
public static <T> T loadByPath(String path, Class<T> type) {
return load(ResourceUtil.getStream(path), type);
}
/**
* 从流中加载YAML
*
* @param <T> Bean类型默认map
* @param in
* @param type 加载的Bean类型即转换为的bean
* @return 加载的内容默认Map
*/
public static <T> T load(InputStream in, Class<T> type) {
return load(IoUtil.getBomReader(in), type);
}
/**
* 加载YAML加载完毕后关闭{@link Reader}
*
* @param reader {@link Reader}
* @return 加载的Map
*/
public static Dict load(Reader reader) {
return load(reader, Dict.class);
}
/**
* 加载YAML加载完毕后关闭{@link Reader}
*
* @param <T> Bean类型默认map
* @param reader {@link Reader}
* @param type 加载的Bean类型即转换为的bean
* @return 加载的内容默认Map
*/
public static <T> T load(Reader reader, Class<T> type) {
return load(reader, type, true);
}
/**
* 加载YAML
*
* @param <T> Bean类型默认map
* @param reader {@link Reader}
* @param type 加载的Bean类型即转换为的bean
* @param isCloseReader 加载完毕后是否关闭{@link Reader}
* @return 加载的内容默认Map
*/
public static <T> T load(Reader reader, Class<T> type, boolean isCloseReader) {
Assert.notNull(reader, "Reader must be not null !");
if (null == type) {
//noinspection unchecked
type = (Class<T>) Object.class;
}
final Yaml yaml = new Yaml();
try {
return yaml.loadAs(reader, type);
} finally {
if (isCloseReader) {
IoUtil.close(reader);
}
}
}
/**
* 将Bean对象或者Map写出到{@link Writer}
*
* @param object 对象
* @param writer {@link Writer}
*/
public static void dump(Object object, Writer writer) {
final DumperOptions options = new DumperOptions();
options.setIndent(2);
options.setPrettyFlow(true);
options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
dump(object, writer, options);
}
/**
* 将Bean对象或者Map写出到{@link Writer}
*
* @param object 对象
* @param writer {@link Writer}
* @param dumperOptions 输出风格
*/
public static void dump(Object object, Writer writer, DumperOptions dumperOptions) {
if (null == dumperOptions) {
dumperOptions = new DumperOptions();
}
final Yaml yaml = new Yaml(dumperOptions);
yaml.dump(object, writer);
}
}

View File

@ -0,0 +1,7 @@
/**
* YAML文件的读写封装基于snakeyaml
*
* @author looly
*
*/
package cn.hutool.setting.yaml;

View File

@ -1,4 +1,4 @@
package cn.hutool.setting.test; package cn.hutool.setting;
import cn.hutool.core.date.DateUtil; import cn.hutool.core.date.DateUtil;
import cn.hutool.log.LogFactory; import cn.hutool.log.LogFactory;
@ -17,7 +17,7 @@ import java.util.Objects;
/** /**
* Setting单元测试 * Setting单元测试
* *
* @author Looly * @author Looly
* *
*/ */
@ -50,23 +50,23 @@ public class PropsTest {
String driver = props.getStr("driver"); String driver = props.getStr("driver");
Assert.assertEquals(driver, "com.mysql.jdbc.Driver"); Assert.assertEquals(driver, "com.mysql.jdbc.Driver");
} }
@Test @Test
public void toBeanTest() { public void toBeanTest() {
Props props = Props.getProp("to_bean_test.properties"); Props props = Props.getProp("to_bean_test.properties");
ConfigProperties cfg = props.toBean(ConfigProperties.class, "mail"); ConfigProperties cfg = props.toBean(ConfigProperties.class, "mail");
Assert.assertEquals("mailer@mail.com", cfg.getHost()); Assert.assertEquals("mailer@mail.com", cfg.getHost());
Assert.assertEquals(9000, cfg.getPort()); Assert.assertEquals(9000, cfg.getPort());
Assert.assertEquals("mailer@mail.com", cfg.getFrom()); Assert.assertEquals("mailer@mail.com", cfg.getFrom());
Assert.assertEquals("john", cfg.getCredentials().getUsername()); Assert.assertEquals("john", cfg.getCredentials().getUsername());
Assert.assertEquals("password", cfg.getCredentials().getPassword()); Assert.assertEquals("password", cfg.getCredentials().getPassword());
Assert.assertEquals("SHA1", cfg.getCredentials().getAuthMethod()); Assert.assertEquals("SHA1", cfg.getCredentials().getAuthMethod());
Assert.assertEquals("true", cfg.getAdditionalHeaders().get("redelivery")); Assert.assertEquals("true", cfg.getAdditionalHeaders().get("redelivery"));
Assert.assertEquals("true", cfg.getAdditionalHeaders().get("secure")); Assert.assertEquals("true", cfg.getAdditionalHeaders().get("secure"));
Assert.assertEquals("admin@mail.com", cfg.getDefaultRecipients().get(0)); Assert.assertEquals("admin@mail.com", cfg.getDefaultRecipients().get(0));
Assert.assertEquals("owner@mail.com", cfg.getDefaultRecipients().get(1)); Assert.assertEquals("owner@mail.com", cfg.getDefaultRecipients().get(1));
} }
@ -98,7 +98,7 @@ public class PropsTest {
private List<String> defaultRecipients; private List<String> defaultRecipients;
private Map<String, String> additionalHeaders; private Map<String, String> additionalHeaders;
} }
@Data @Data
public static class Credentials { public static class Credentials {
private String authMethod; private String authMethod;

View File

@ -1,4 +1,4 @@
package cn.hutool.setting.test; package cn.hutool.setting;
import cn.hutool.setting.dialect.PropsUtil; import cn.hutool.setting.dialect.PropsUtil;
import org.junit.Assert; import org.junit.Assert;
@ -7,7 +7,7 @@ import org.junit.Test;
import java.util.Objects; import java.util.Objects;
public class PropsUtilTest { public class PropsUtilTest {
@Test @Test
public void getTest() { public void getTest() {
String driver = PropsUtil.get("test").getStr("driver"); String driver = PropsUtil.get("test").getStr("driver");

View File

@ -1,12 +1,10 @@
package cn.hutool.setting.test; package cn.hutool.setting;
import cn.hutool.core.lang.Console;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Ignore; import org.junit.Ignore;
import org.junit.Test; import org.junit.Test;
import cn.hutool.core.lang.Console;
import cn.hutool.setting.Setting;
/** /**
* Setting单元测试 * Setting单元测试
* *

View File

@ -1,12 +1,10 @@
package cn.hutool.setting.test; package cn.hutool.setting;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
import cn.hutool.setting.SettingUtil;
public class SettingUtilTest { public class SettingUtilTest {
@Test @Test
public void getTest() { public void getTest() {
String driver = SettingUtil.get("test").get("demo", "driver"); String driver = SettingUtil.get("test").get("demo", "driver");

View File

@ -0,0 +1,36 @@
package cn.hutool.setting.yaml;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.lang.Dict;
import cn.hutool.core.util.CharsetUtil;
import org.junit.Assert;
import org.junit.Ignore;
import org.junit.Test;
import java.util.List;
public class YamlUtilTest {
@Test
public void loadByPathTest() {
final Dict result = YamlUtil.loadByPath("test.yaml", Dict.class);
Assert.assertEquals("John", result.getStr("firstName"));
final List<Integer> numbers = result.getByPath("contactDetails.number");
Assert.assertEquals(123456789, (int) numbers.get(0));
Assert.assertEquals(456786868, (int) numbers.get(1));
}
@Test
@Ignore
public void dumpTest() {
final Dict dict = Dict.create()
.set("name", "hutool")
.set("count", 1000);
YamlUtil.dump(
dict
, FileUtil.getWriter("d:/test/dump.yaml", CharsetUtil.CHARSET_UTF_8, false));
}
}

View File

@ -0,0 +1,13 @@
firstName: "John"
lastName: "Doe"
age: 31
contactDetails:
- type: "mobile"
number: 123456789
- type: "landline"
number: 456786868
homeAddress:
line: "Xyz, DEF Street"
city: "City Y"
state: "State Y"
zip: 345657

View File

@ -9,6 +9,7 @@ import org.junit.Test;
public class OshiPrintTest { public class OshiPrintTest {
@Test @Test
@Ignore
public void printCpuInfo(){ public void printCpuInfo(){
Console.log(OshiUtil.getCpuInfo()); Console.log(OshiUtil.getCpuInfo());
} }