mirror of
https://gitee.com/dromara/hutool.git
synced 2025-04-05 17:37:59 +08:00
Merge branch 'v5-dev' of https://github.com/totalo/hutool into v5-dev
This commit is contained in:
commit
d97db8c2e1
19
CHANGELOG.md
19
CHANGELOG.md
@ -3,6 +3,23 @@
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
|
||||
# 5.4.5 (2020-10-09)
|
||||
|
||||
### 新特性
|
||||
* 【core 】 ConsoleTable代码优化(pr#190@Gitee)
|
||||
* 【http 】 HttpRequest增加setProxy重载(pr#190@Gitee)
|
||||
* 【core 】 XmlUtil.cleanComment(pr#191@Gitee)
|
||||
* 【core 】 ArrayUtil.unWrap增加默认值(pr#1149@Github)
|
||||
* 【core 】 ArrayUtil.indexOf修改double的equals判断(pr#1147@Github)
|
||||
* 【core 】 优化StrUtil中部分参数校验以及逻辑处理(pr#1144@Github)
|
||||
* 【core 】 简化CreditCode逻辑去除无用Character.toUpperCase(pr#1145@Github)
|
||||
|
||||
### Bug修复
|
||||
* 【core 】 解决农历判断节日未判断大小月导致的问题(issue#I1XHSF@Gitee)
|
||||
* 【core 】 解决ListUtil计算总量可能的int溢出问题(pr#1150@Github)
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
|
||||
# 5.4.4 (2020-09-28)
|
||||
|
||||
### 新特性
|
||||
@ -31,6 +48,8 @@
|
||||
* 【core 】 NumberUtil.factorial注释明确(pr#1126@Github)
|
||||
* 【core 】 NumberUtil增加isPowerOfTwo方法(pr#1132@Github)
|
||||
* 【core 】 优化BooleanUtil的校验逻辑(pr#1137@Github)
|
||||
* 【poi 】 改进sax方式读取逻辑,支持sheetId(issue#1141@Github)
|
||||
* 【core 】 XmlUtil增加readBySax方法
|
||||
|
||||
### Bug修复
|
||||
* 【crypto 】 修复SM2验签后无法解密问题(issue#I1W0VP@Gitee)
|
||||
|
@ -120,19 +120,19 @@ Each module can be introduced individually, or all modules can be introduced by
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-all</artifactId>
|
||||
<version>5.4.4</version>
|
||||
<version>5.4.5</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
### Gradle
|
||||
```
|
||||
compile 'cn.hutool:hutool-all:5.4.4'
|
||||
compile 'cn.hutool:hutool-all:5.4.5'
|
||||
```
|
||||
|
||||
## Download
|
||||
|
||||
- [Maven1](https://repo1.maven.org/maven2/cn/hutool/hutool-all/5.4.4/)
|
||||
- [Maven2](http://repo2.maven.org/maven2/cn/hutool/hutool-all/5.4.4/)
|
||||
- [Maven1](https://repo1.maven.org/maven2/cn/hutool/hutool-all/5.4.5/)
|
||||
- [Maven2](http://repo2.maven.org/maven2/cn/hutool/hutool-all/5.4.5/)
|
||||
|
||||
> note:
|
||||
> Hutool 5.x supports JDK8+ and is not tested on Android platforms, and cannot guarantee that all tool classes or tool methods are available.
|
||||
|
20
README.md
20
README.md
@ -119,21 +119,21 @@ Hutool的存在就是为了减少代码搜索成本,避免网络上参差不
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-all</artifactId>
|
||||
<version>5.4.4</version>
|
||||
<version>5.4.5</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
### Gradle
|
||||
```
|
||||
compile 'cn.hutool:hutool-all:5.4.4'
|
||||
compile 'cn.hutool:hutool-all:5.4.5'
|
||||
```
|
||||
|
||||
### 非Maven项目
|
||||
|
||||
点击以下任一链接,下载`hutool-all-X.X.X.jar`即可:
|
||||
|
||||
- [Maven中央库1](https://repo1.maven.org/maven2/cn/hutool/hutool-all/5.4.4/)
|
||||
- [Maven中央库2](http://repo2.maven.org/maven2/cn/hutool/hutool-all/5.4.4/)
|
||||
- [Maven中央库1](https://repo1.maven.org/maven2/cn/hutool/hutool-all/5.4.5/)
|
||||
- [Maven中央库2](http://repo2.maven.org/maven2/cn/hutool/hutool-all/5.4.5/)
|
||||
|
||||
> 注意
|
||||
> Hutool 5.x支持JDK8+,对Android平台没有测试,不能保证所有工具类或工具方法可用。
|
||||
@ -141,7 +141,7 @@ compile 'cn.hutool:hutool-all:5.4.4'
|
||||
|
||||
### 编译安装
|
||||
|
||||
访问Hutool的码云主页:[https://gitee.com/loolly/hutool](https://gitee.com/loolly/hutool) 下载整个项目源码(v5-master或v5-dev分支都可)然后进入Hutool项目目录执行:
|
||||
访问Hutool的Gitee主页:[https://gitee.com/loolly/hutool](https://gitee.com/loolly/hutool) 下载整个项目源码(v5-master或v5-dev分支都可)然后进入Hutool项目目录执行:
|
||||
|
||||
```sh
|
||||
./hutool.sh install
|
||||
@ -166,7 +166,7 @@ Hutool的源码分为两个分支,功能如下:
|
||||
|
||||
提交问题反馈请说明正在使用的JDK版本呢、Hutool版本和相关依赖库版本。
|
||||
|
||||
- [码云Gitee issue](https://gitee.com/loolly/hutool/issues)
|
||||
- [Gitee issue](https://gitee.com/loolly/hutool/issues)
|
||||
- [Github issue](https://github.com/looly/hutool/issues)
|
||||
|
||||
|
||||
@ -177,14 +177,14 @@ Hutool的源码分为两个分支,功能如下:
|
||||
3. 修改代码(记得一定要修改v5-dev分支)
|
||||
4. commit后push到自己的库(v5-dev分支)
|
||||
5. 登录Gitee或Github在你首页可以看到一个 pull request 按钮,点击它,填写一些说明信息,然后提交即可。
|
||||
6. 等待作者合并
|
||||
6. 等待维护者合并
|
||||
|
||||
### PR遵照的原则
|
||||
|
||||
Hutool欢迎任何人为Hutool添砖加瓦,贡献代码,不过作者是一个强迫症患者,为了照顾病人,需要提交的pr(pull request)符合一些规范,规范如下:
|
||||
Hutool欢迎任何人为Hutool添砖加瓦,贡献代码,不过维护者是一个强迫症患者,为了照顾病人,需要提交的pr(pull request)符合一些规范,规范如下:
|
||||
|
||||
1. 注释完备,尤其每个新增的方法应按照Java文档规范标明方法说明、参数说明、返回值说明等信息,必要时请添加单元测试,如果愿意,也可以加上你的大名。
|
||||
2. Hutool的缩进按照Eclipse(~~不要跟我说IDEA多好用,作者非常懒,学不会~~,IDEA真香,改了Eclipse快捷键后舒服多了)默认(tab)缩进,所以请遵守(不要和我争执空格与tab的问题,这是一个病人的习惯)。
|
||||
2. Hutool的缩进按照Eclipse(~~不要跟我说IDEA多好用,维护者非常懒,学不会~~,IDEA真香,改了Eclipse快捷键后舒服多了)默认(tab)缩进,所以请遵守(不要和我争执空格与tab的问题,这是一个病人的习惯)。
|
||||
3. 新加的方法不要使用第三方库的方法,Hutool遵循无依赖原则(除非在extra模块中加方法工具)。
|
||||
4. 请pull request到`v5-dev`分支。Hutool在5.x版本后使用了新的分支:`v5-master`是主分支,表示已经发布中央库的版本,这个分支不允许pr,也不允许修改。
|
||||
|
||||
@ -192,7 +192,7 @@ Hutool欢迎任何人为Hutool添砖加瓦,贡献代码,不过作者是一
|
||||
|
||||
## 捐赠
|
||||
|
||||
如果你觉得Hutool不错,可以捐赠请作者吃包辣条~,在此表示感谢^_^。
|
||||
如果你觉得Hutool不错,可以捐赠请维护者吃包辣条~,在此表示感谢^_^。
|
||||
|
||||
点击以下链接,将页面拉到最下方点击“捐赠”即可。
|
||||
|
||||
|
@ -1 +1 @@
|
||||
5.4.4
|
||||
5.4.5
|
||||
|
@ -1 +1 @@
|
||||
var version = '5.4.4'
|
||||
var version = '5.4.5'
|
@ -9,7 +9,7 @@
|
||||
<parent>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-parent</artifactId>
|
||||
<version>5.4.4-SNAPSHOT</version>
|
||||
<version>5.4.5-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hutool-all</artifactId>
|
||||
|
@ -9,7 +9,7 @@
|
||||
<parent>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-parent</artifactId>
|
||||
<version>5.4.4-SNAPSHOT</version>
|
||||
<version>5.4.5-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hutool-aop</artifactId>
|
||||
|
@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-parent</artifactId>
|
||||
<version>5.4.4-SNAPSHOT</version>
|
||||
<version>5.4.5-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hutool-bloomFilter</artifactId>
|
||||
|
@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-parent</artifactId>
|
||||
<version>5.4.4-SNAPSHOT</version>
|
||||
<version>5.4.5-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hutool-bom</artifactId>
|
||||
|
@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-parent</artifactId>
|
||||
<version>5.4.4-SNAPSHOT</version>
|
||||
<version>5.4.5-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hutool-cache</artifactId>
|
||||
|
@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-parent</artifactId>
|
||||
<version>5.4.4-SNAPSHOT</version>
|
||||
<version>5.4.5-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hutool-captcha</artifactId>
|
||||
|
@ -9,7 +9,7 @@
|
||||
<parent>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-parent</artifactId>
|
||||
<version>5.4.4-SNAPSHOT</version>
|
||||
<version>5.4.5-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hutool-core</artifactId>
|
||||
|
@ -252,8 +252,8 @@ public class ListUtil {
|
||||
return new ArrayList<>(0);
|
||||
}
|
||||
}
|
||||
|
||||
if ((pageNo * pageSize) > resultSize) {
|
||||
// 相乘可能会导致越界 临时用long
|
||||
if (((long)pageNo * pageSize) > resultSize) {
|
||||
// 越界直接返回空
|
||||
return new ArrayList<>(0);
|
||||
}
|
||||
|
@ -167,7 +167,7 @@ public class ChineseDate {
|
||||
* @return 是否为闰月
|
||||
* @since 5.4.2
|
||||
*/
|
||||
public boolean isLeapMonth(){
|
||||
public boolean isLeapMonth() {
|
||||
return ChineseMonth.isLeapMonth(this.year, this.month);
|
||||
}
|
||||
|
||||
@ -230,7 +230,7 @@ public class ChineseDate {
|
||||
* @return 获得农历节日
|
||||
*/
|
||||
public String getFestivals() {
|
||||
return StrUtil.join(",", LunarFestival.getFestivals(this.month, this.day));
|
||||
return StrUtil.join(",", LunarFestival.getFestivals(this.year, this.month, day));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -258,7 +258,7 @@ public class ChineseDate {
|
||||
* @return 获得天干地支的年月日信息
|
||||
*/
|
||||
public String getCyclicalYMD() {
|
||||
if (gyear >= LunarInfo.BASE_YEAR && gmonth > 0 && gday > 0){
|
||||
if (gyear >= LunarInfo.BASE_YEAR && gmonth > 0 && gday > 0) {
|
||||
return (cyclicalm(gyear, gmonth, gday));
|
||||
}
|
||||
return null;
|
||||
|
@ -17,6 +17,7 @@ public class LunarFestival {
|
||||
// 来自:https://baike.baidu.com/item/%E4%B8%AD%E5%9B%BD%E4%BC%A0%E7%BB%9F%E8%8A%82%E6%97%A5/396100
|
||||
private static final TableMap<Pair<Integer, Integer>, String> L_FTV = new TableMap<>(16);
|
||||
static{
|
||||
// 节日
|
||||
L_FTV.put(new Pair<>(1, 1), "春节");
|
||||
L_FTV.put(new Pair<>(1, 2), "犬日");
|
||||
L_FTV.put(new Pair<>(1, 3), "猪日");
|
||||
@ -78,7 +79,6 @@ public class LunarFestival {
|
||||
L_FTV.put(new Pair<>(12, 8), "腊八节");
|
||||
L_FTV.put(new Pair<>(12, 16), "尾牙");
|
||||
L_FTV.put(new Pair<>(12, 23), "小年");
|
||||
L_FTV.put(new Pair<>(12, 29), "除夕");
|
||||
L_FTV.put(new Pair<>(12, 30), "除夕");
|
||||
}
|
||||
|
||||
@ -88,6 +88,24 @@ public class LunarFestival {
|
||||
* @param month 月
|
||||
* @param day 日
|
||||
* @return 获得农历节日
|
||||
* @since 5.4.5
|
||||
*/
|
||||
public static List<String> getFestivals(int year, int month, int day) {
|
||||
// 春节判断,如果12月是小月,则29为除夕,否则30为除夕
|
||||
if(12 == month && 29 == day){
|
||||
if(29 == LunarInfo.monthDays(year, month)){
|
||||
day++;
|
||||
}
|
||||
}
|
||||
return getFestivals(month, day);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得节日列表,此方法无法判断月是否为大月或小月
|
||||
*
|
||||
* @param month 月
|
||||
* @param day 日
|
||||
* @return 获得农历节日
|
||||
*/
|
||||
public static List<String> getFestivals(int month, int day) {
|
||||
return L_FTV.getValues(new Pair<>(month, day));
|
||||
|
151
hutool-core/src/main/java/cn/hutool/core/lang/ConsoleTable.java
Normal file
151
hutool-core/src/main/java/cn/hutool/core/lang/ConsoleTable.java
Normal file
@ -0,0 +1,151 @@
|
||||
package cn.hutool.core.lang;
|
||||
|
||||
import cn.hutool.core.convert.Convert;
|
||||
import cn.hutool.core.util.CharUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 控制台打印表格工具
|
||||
*
|
||||
* @author 孙宇
|
||||
* @since 5.4.4
|
||||
*/
|
||||
public class ConsoleTable {
|
||||
|
||||
private static final char ROW_LINE = '-';
|
||||
private static final char COLUMN_LINE = '|';
|
||||
private static final char CORNER = '+';
|
||||
private static final char SPACE = '\u3000';
|
||||
private static final char LF = CharUtil.LF;
|
||||
|
||||
/**
|
||||
* 表格头信息
|
||||
*/
|
||||
private final List<List<String>> HEADER_LIST = new ArrayList<>();
|
||||
/**
|
||||
* 表格体信息
|
||||
*/
|
||||
private final List<List<String>> BODY_LIST = new ArrayList<>();
|
||||
/**
|
||||
* 每列最大字符个数
|
||||
*/
|
||||
private List<Integer> columnCharNumber;
|
||||
|
||||
/**
|
||||
* 添加头信息
|
||||
*
|
||||
* @param titles 列名
|
||||
* @return 自身对象
|
||||
*/
|
||||
public ConsoleTable addHeader(String... titles) {
|
||||
if (columnCharNumber == null) {
|
||||
columnCharNumber = new ArrayList<>(Collections.nCopies(titles.length, 0));
|
||||
}
|
||||
List<String> l = new ArrayList<>();
|
||||
fillColumns(l, titles);
|
||||
HEADER_LIST.add(l);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加体信息
|
||||
*
|
||||
* @param values 列值
|
||||
* @return 自身对象
|
||||
*/
|
||||
public ConsoleTable addBody(String... values) {
|
||||
List<String> l = new ArrayList<>();
|
||||
BODY_LIST.add(l);
|
||||
fillColumns(l, values);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 填充表格头或者体
|
||||
*
|
||||
* @param l 被填充列表
|
||||
* @param columns 填充内容
|
||||
*/
|
||||
private void fillColumns(List<String> l, String[] columns) {
|
||||
for (int i = 0; i < columns.length; i++) {
|
||||
String column = columns[i];
|
||||
String col = Convert.toSBC(column);
|
||||
l.add(col);
|
||||
int width = col.length();
|
||||
if (width > columnCharNumber.get(i)) {
|
||||
columnCharNumber.set(i, width);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取表格字符串
|
||||
*
|
||||
* @return 表格字符串
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
fillBorder(sb);
|
||||
fillRow(sb, HEADER_LIST);
|
||||
fillBorder(sb);
|
||||
fillRow(sb, BODY_LIST);
|
||||
fillBorder(sb);
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 填充表头或者表体信息
|
||||
*
|
||||
* @param sb
|
||||
* @param list 表头列表或者表体列表
|
||||
*/
|
||||
private void fillRow(StringBuilder sb, List<List<String>> list) {
|
||||
for (List<String> r : list) {
|
||||
for (int i = 0; i < r.size(); i++) {
|
||||
if (i == 0) {
|
||||
sb.append(COLUMN_LINE);
|
||||
}
|
||||
String header = r.get(i);
|
||||
sb.append(SPACE);
|
||||
sb.append(header);
|
||||
sb.append(SPACE);
|
||||
int l = header.length();
|
||||
int lw = columnCharNumber.get(i);
|
||||
if (lw > l) {
|
||||
for (int j = 0; j < (lw - l); j++) {
|
||||
sb.append(SPACE);
|
||||
}
|
||||
}
|
||||
sb.append(COLUMN_LINE);
|
||||
}
|
||||
sb.append(LF);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 拼装边框
|
||||
*
|
||||
* @param sb StringBuilder
|
||||
*/
|
||||
private void fillBorder(StringBuilder sb) {
|
||||
sb.append(CORNER);
|
||||
for (Integer width : columnCharNumber) {
|
||||
sb.append(Convert.toSBC(StrUtil.fillAfter("", ROW_LINE, width + 2)));
|
||||
sb.append(CORNER);
|
||||
}
|
||||
sb.append(LF);
|
||||
}
|
||||
|
||||
/**
|
||||
* 打印到控制台
|
||||
*/
|
||||
public void print() {
|
||||
Console.print(toString());
|
||||
}
|
||||
|
||||
}
|
@ -1,177 +0,0 @@
|
||||
package cn.hutool.core.lang;
|
||||
|
||||
import cn.hutool.core.convert.Convert;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 控制台打印表格工具
|
||||
*
|
||||
* @author 孙宇
|
||||
*/
|
||||
public class ConsoleTableUtil {
|
||||
/**
|
||||
* 表格头信息
|
||||
*/
|
||||
private final List<List<String>> HEADER_LIST = new ArrayList<>();
|
||||
/**
|
||||
* 表格体信息
|
||||
*/
|
||||
private final List<List<String>> BODY_LIST = new ArrayList<>();
|
||||
/**
|
||||
* 每列最大字符个数
|
||||
*/
|
||||
private List<Integer> columnCharNumber;
|
||||
|
||||
/**
|
||||
* 测试
|
||||
*
|
||||
* @param args
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
ConsoleTableUtil t = new ConsoleTableUtil();
|
||||
t.addHeader("姓名", "年龄");
|
||||
t.addBody("张三", "15");
|
||||
t.addBody("李四", "29");
|
||||
t.addBody("王二麻子", "37");
|
||||
t.print();
|
||||
|
||||
t = new ConsoleTableUtil();
|
||||
t.addHeader("体温", "占比");
|
||||
t.addHeader("℃", "%");
|
||||
t.addBody("36.8", "10");
|
||||
t.addBody("37", "5");
|
||||
t.print();
|
||||
|
||||
t = new ConsoleTableUtil();
|
||||
t.addHeader("标题1", "标题2");
|
||||
t.addBody("12345", "混合321654asdfcSDF");
|
||||
t.addBody("sd e3ee ff22", "ff值");
|
||||
t.print();
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加头信息
|
||||
*
|
||||
* @param titles 列名
|
||||
* @return 自身对象
|
||||
*/
|
||||
public ConsoleTableUtil addHeader(String... titles) {
|
||||
if (columnCharNumber == null) {
|
||||
columnCharNumber = new ArrayList<>(Collections.nCopies(titles.length, 0));
|
||||
}
|
||||
List<String> l = new ArrayList<>();
|
||||
HEADER_LIST.add(l);
|
||||
fillColumns(l, titles);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加体信息
|
||||
*
|
||||
* @param values 列值
|
||||
* @return 自身对象
|
||||
*/
|
||||
public ConsoleTableUtil addBody(String... values) {
|
||||
List<String> l = new ArrayList<>();
|
||||
BODY_LIST.add(l);
|
||||
fillColumns(l, values);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 填充表格头或者体
|
||||
*
|
||||
* @param l
|
||||
* @param columns
|
||||
*/
|
||||
private void fillColumns(List<String> l, String[] columns) {
|
||||
for (int i = 0; i < columns.length; i++) {
|
||||
String column = columns[i];
|
||||
String col = Convert.toSBC(column);
|
||||
l.add(col);
|
||||
int width = col.length();
|
||||
if (width > columnCharNumber.get(i)) {
|
||||
columnCharNumber.set(i, width);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取表格字符串
|
||||
*
|
||||
* @return 表格字符串
|
||||
*/
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
fillBorder(sb);
|
||||
for (List<String> headers : HEADER_LIST) {
|
||||
for (int i = 0; i < headers.size(); i++) {
|
||||
if (i == 0) {
|
||||
sb.append('|');
|
||||
}
|
||||
String header = headers.get(i);
|
||||
sb.append(Convert.toSBC(" "));
|
||||
sb.append(header);
|
||||
sb.append(Convert.toSBC(" "));
|
||||
int l = header.length();
|
||||
int lw = columnCharNumber.get(i);
|
||||
if (lw > l) {
|
||||
for (int j = 0; j < (lw - l); j++) {
|
||||
sb.append(Convert.toSBC(" "));
|
||||
}
|
||||
}
|
||||
sb.append('|');
|
||||
}
|
||||
sb.append('\n');
|
||||
}
|
||||
fillBorder(sb);
|
||||
for (List<String> bodys : BODY_LIST) {
|
||||
for (int i = 0; i < bodys.size(); i++) {
|
||||
if (i == 0) {
|
||||
sb.append('|');
|
||||
}
|
||||
String body = bodys.get(i);
|
||||
sb.append(Convert.toSBC(" "));
|
||||
sb.append(body);
|
||||
sb.append(Convert.toSBC(" "));
|
||||
int l = body.length();
|
||||
int lw = columnCharNumber.get(i);
|
||||
if (lw > l) {
|
||||
for (int j = 0; j < (lw - l); j++) {
|
||||
sb.append(Convert.toSBC(" "));
|
||||
}
|
||||
}
|
||||
sb.append('|');
|
||||
}
|
||||
sb.append('\n');
|
||||
}
|
||||
fillBorder(sb);
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 拼装边框
|
||||
*
|
||||
* @param sb
|
||||
*/
|
||||
private void fillBorder(StringBuilder sb) {
|
||||
sb.append('*');
|
||||
for (Integer width : columnCharNumber) {
|
||||
sb.append(Convert.toSBC(StrUtil.fillAfter("", '-', width + 2)));
|
||||
sb.append('*');
|
||||
}
|
||||
sb.append('\n');
|
||||
}
|
||||
|
||||
/**
|
||||
* 打印到控制台
|
||||
*/
|
||||
public void print() {
|
||||
Console.print(toString());
|
||||
}
|
||||
|
||||
}
|
@ -1613,7 +1613,7 @@ public class ArrayUtil {
|
||||
public static int indexOf(double[] array, double value) {
|
||||
if (null != array) {
|
||||
for (int i = 0; i < array.length; i++) {
|
||||
if (value == array[i]) {
|
||||
if (NumberUtil.equals(value, array[i])) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
@ -1632,7 +1632,7 @@ public class ArrayUtil {
|
||||
public static int lastIndexOf(double[] array, double value) {
|
||||
if (null != array) {
|
||||
for (int i = array.length - 1; i >= 0; i--) {
|
||||
if (value == array[i]) {
|
||||
if (NumberUtil.equals(value, array[i])) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
@ -1663,7 +1663,7 @@ public class ArrayUtil {
|
||||
public static int indexOf(float[] array, float value) {
|
||||
if (null != array) {
|
||||
for (int i = 0; i < array.length; i++) {
|
||||
if (value == array[i]) {
|
||||
if (NumberUtil.equals(value, array[i])) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
@ -1682,7 +1682,7 @@ public class ArrayUtil {
|
||||
public static int lastIndexOf(float[] array, float value) {
|
||||
if (null != array) {
|
||||
for (int i = array.length - 1; i >= 0; i--) {
|
||||
if (value == array[i]) {
|
||||
if (NumberUtil.equals(value, array[i])) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
@ -1777,7 +1777,7 @@ public class ArrayUtil {
|
||||
}
|
||||
|
||||
/**
|
||||
* 包装类数组转为原始类型数组
|
||||
* 包装类数组转为原始类型数组,null转为0
|
||||
*
|
||||
* @param values 包装类型数组
|
||||
* @return 原始类型数组
|
||||
@ -1793,7 +1793,7 @@ public class ArrayUtil {
|
||||
|
||||
final int[] array = new int[length];
|
||||
for (int i = 0; i < length; i++) {
|
||||
array[i] = values[i];
|
||||
array[i] = ObjectUtil.defaultIfNull(values[i], 0);
|
||||
}
|
||||
return array;
|
||||
}
|
||||
@ -1837,7 +1837,7 @@ public class ArrayUtil {
|
||||
|
||||
final long[] array = new long[length];
|
||||
for (int i = 0; i < length; i++) {
|
||||
array[i] = values[i];
|
||||
array[i] = ObjectUtil.defaultIfNull(values[i], 0L);
|
||||
}
|
||||
return array;
|
||||
}
|
||||
@ -1881,7 +1881,7 @@ public class ArrayUtil {
|
||||
|
||||
char[] array = new char[length];
|
||||
for (int i = 0; i < length; i++) {
|
||||
array[i] = values[i];
|
||||
array[i] = ObjectUtil.defaultIfNull(values[i], Character.MIN_VALUE);
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
@ -98,11 +98,11 @@ public class CreditCodeUtil {
|
||||
}
|
||||
for (int i = 2; i < 8; i++) {
|
||||
int num = RandomUtil.randomInt(10);
|
||||
buf.append(Character.toUpperCase(BASE_CODE_ARRAY[num]));
|
||||
buf.append(BASE_CODE_ARRAY[num]);
|
||||
}
|
||||
for (int i = 8; i < 17; i++) {
|
||||
int num = RandomUtil.randomInt(BASE_CODE_ARRAY.length - 1);
|
||||
buf.append(Character.toUpperCase(BASE_CODE_ARRAY[num]));
|
||||
buf.append(BASE_CODE_ARRAY[num]);
|
||||
}
|
||||
|
||||
final String code = buf.toString();
|
||||
|
@ -1712,7 +1712,7 @@ public class NumberUtil {
|
||||
|
||||
/**
|
||||
* 比较大小,值相等 返回true<br>
|
||||
* 此方法通过调用{@link BigDecimal#compareTo(BigDecimal)}方法来判断是否相等<br>
|
||||
* 此方法通过调用{@link Double#doubleToLongBits(double)}方法来判断是否相等<br>
|
||||
* 此方法判断值相等时忽略精度的,即0.00 == 0
|
||||
*
|
||||
* @param num1 数字1
|
||||
@ -1721,7 +1721,21 @@ public class NumberUtil {
|
||||
* @since 5.4.2
|
||||
*/
|
||||
public static boolean equals(double num1, double num2) {
|
||||
return equals(toBigDecimal(num1), toBigDecimal(num2));
|
||||
return Double.doubleToLongBits(num1) == Double.doubleToLongBits(num2);
|
||||
}
|
||||
|
||||
/**
|
||||
* 比较大小,值相等 返回true<br>
|
||||
* 此方法通过调用{@link Double#doubleToLongBits(double)}方法来判断是否相等<br>
|
||||
* 此方法判断值相等时忽略精度的,即0.00 == 0
|
||||
*
|
||||
* @param num1 数字1
|
||||
* @param num2 数字2
|
||||
* @return 是否相等
|
||||
* @since 5.4.5
|
||||
*/
|
||||
public static boolean equals(float num1, float num2) {
|
||||
return Float.floatToIntBits(num1) == Float.floatToIntBits(num2);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -48,8 +48,8 @@ public class RandomUtil {
|
||||
* ThreadLocalRandom是JDK 7之后提供并发产生随机数,能够解决多个线程发生的竞争争夺。
|
||||
*
|
||||
* <p>
|
||||
* 注意:此方法返回的{@link ThreadLocalRandom}不可以在多线程环境下共享对象,否则有重复随机数问题。
|
||||
* 见:https://www.jianshu.com/p/89dfe990295c
|
||||
* 注意:此方法返回的{@link ThreadLocalRandom}不可以在多线程环境下共享对象,否则有重复随机数问题。
|
||||
* 见:https://www.jianshu.com/p/89dfe990295c
|
||||
* </p>
|
||||
*
|
||||
* @return {@link ThreadLocalRandom}
|
||||
@ -522,9 +522,10 @@ public class RandomUtil {
|
||||
*
|
||||
* @return 随机颜色
|
||||
* @since 4.1.5
|
||||
* @deprecated 使用{@link ImagUtil#randomColor()}
|
||||
* @deprecated 使用ImgUtil.randomColor()
|
||||
*/
|
||||
public static Color randomColor() {
|
||||
@Deprecated
|
||||
public static Color randomColor() {
|
||||
final Random random = getRandom();
|
||||
return new Color(random.nextInt(256), random.nextInt(256), random.nextInt(256));
|
||||
}
|
||||
|
@ -34,53 +34,95 @@ public class StrUtil {
|
||||
|
||||
public static final int INDEX_NOT_FOUND = -1;
|
||||
|
||||
/** 字符常量:空格符 ' ' */
|
||||
/**
|
||||
* 字符常量:空格符 ' '
|
||||
*/
|
||||
public static final char C_SPACE = CharUtil.SPACE;
|
||||
/** 字符常量:制表符 \t */
|
||||
/**
|
||||
* 字符常量:制表符 \t
|
||||
*/
|
||||
public static final char C_TAB = CharUtil.TAB;
|
||||
/** 字符常量:点 . */
|
||||
/**
|
||||
* 字符常量:点 .
|
||||
*/
|
||||
public static final char C_DOT = CharUtil.DOT;
|
||||
/** 字符常量:斜杠 / */
|
||||
/**
|
||||
* 字符常量:斜杠 /
|
||||
*/
|
||||
public static final char C_SLASH = CharUtil.SLASH;
|
||||
/** 字符常量:反斜杠 \ */
|
||||
/**
|
||||
* 字符常量:反斜杠 \
|
||||
*/
|
||||
public static final char C_BACKSLASH = CharUtil.BACKSLASH;
|
||||
/** 字符常量:回车符 \r */
|
||||
/**
|
||||
* 字符常量:回车符 \r
|
||||
*/
|
||||
public static final char C_CR = CharUtil.CR;
|
||||
/** 字符常量:换行符 \n */
|
||||
/**
|
||||
* 字符常量:换行符 \n
|
||||
*/
|
||||
public static final char C_LF = CharUtil.LF;
|
||||
/** 字符常量:下划线 _ */
|
||||
/**
|
||||
* 字符常量:下划线 _
|
||||
*/
|
||||
public static final char C_UNDERLINE = CharUtil.UNDERLINE;
|
||||
/** 字符常量:逗号 , */
|
||||
/**
|
||||
* 字符常量:逗号 ,
|
||||
*/
|
||||
public static final char C_COMMA = CharUtil.COMMA;
|
||||
/** 字符常量:花括号(左) { */
|
||||
/**
|
||||
* 字符常量:花括号(左) {
|
||||
*/
|
||||
public static final char C_DELIM_START = CharUtil.DELIM_START;
|
||||
/** 字符常量:花括号(右) } */
|
||||
/**
|
||||
* 字符常量:花括号(右) }
|
||||
*/
|
||||
public static final char C_DELIM_END = CharUtil.DELIM_END;
|
||||
/** 字符常量:中括号(左) [ */
|
||||
/**
|
||||
* 字符常量:中括号(左) [
|
||||
*/
|
||||
public static final char C_BRACKET_START = CharUtil.BRACKET_START;
|
||||
/** 字符常量:中括号(右) ] */
|
||||
/**
|
||||
* 字符常量:中括号(右) ]
|
||||
*/
|
||||
public static final char C_BRACKET_END = CharUtil.BRACKET_END;
|
||||
/** 字符常量:冒号 : */
|
||||
/**
|
||||
* 字符常量:冒号 :
|
||||
*/
|
||||
public static final char C_COLON = CharUtil.COLON;
|
||||
/** 字符常量:艾特 @ */
|
||||
/**
|
||||
* 字符常量:艾特 @
|
||||
*/
|
||||
public static final char C_AT = CharUtil.AT;
|
||||
|
||||
/** 字符串常量:空格符 ' ' */
|
||||
/**
|
||||
* 字符串常量:空格符 ' '
|
||||
*/
|
||||
public static final String SPACE = " ";
|
||||
/** 字符串常量:制表符 \t */
|
||||
/**
|
||||
* 字符串常量:制表符 \t
|
||||
*/
|
||||
public static final String TAB = " ";
|
||||
/** 字符串常量:点 . */
|
||||
/**
|
||||
* 字符串常量:点 .
|
||||
*/
|
||||
public static final String DOT = ".";
|
||||
/**
|
||||
* 字符串常量:双点 ..
|
||||
* 用途:作为指向上级文件夹的路径 "../path"
|
||||
*/
|
||||
public static final String DOUBLE_DOT = "..";
|
||||
/** 字符串常量:斜杠 / */
|
||||
/**
|
||||
* 字符串常量:斜杠 /
|
||||
*/
|
||||
public static final String SLASH = "/";
|
||||
/** 字符串常量:反斜杠 \ */
|
||||
/**
|
||||
* 字符串常量:反斜杠 \
|
||||
*/
|
||||
public static final String BACKSLASH = "\\";
|
||||
/** 字符串常量:空字符串 "" */
|
||||
/**
|
||||
* 字符串常量:空字符串 ""
|
||||
*/
|
||||
public static final String EMPTY = "";
|
||||
/**
|
||||
* 字符串常量:"null"
|
||||
@ -92,45 +134,79 @@ public class StrUtil {
|
||||
* 解释:该字符常用于表示 Linux 系统和 MacOS 系统下的文本换行
|
||||
*/
|
||||
public static final String CR = "\r";
|
||||
/** 字符串常量:换行符 \n */
|
||||
/**
|
||||
* 字符串常量:换行符 \n
|
||||
*/
|
||||
public static final String LF = "\n";
|
||||
/**
|
||||
* 字符串常量:Windows 换行 \r\n
|
||||
* 解释:该字符串常用于表示 Windows 系统下的文本换行
|
||||
*/
|
||||
public static final String CRLF = "\r\n";
|
||||
/** 字符串常量:下划线 _ */
|
||||
/**
|
||||
* 字符串常量:下划线 _
|
||||
*/
|
||||
public static final String UNDERLINE = "_";
|
||||
/** 字符串常量:减号(中划线) - */
|
||||
/**
|
||||
* 字符串常量:减号(中划线) -
|
||||
*/
|
||||
public static final String DASHED = "-";
|
||||
/** 字符串常量:逗号 , */
|
||||
/**
|
||||
* 字符串常量:逗号 ,
|
||||
*/
|
||||
public static final String COMMA = ",";
|
||||
/** 字符串常量:花括号(左) { */
|
||||
/**
|
||||
* 字符串常量:花括号(左) {
|
||||
*/
|
||||
public static final String DELIM_START = "{";
|
||||
/** 字符串常量:花括号(右) } */
|
||||
/**
|
||||
* 字符串常量:花括号(右) }
|
||||
*/
|
||||
public static final String DELIM_END = "}";
|
||||
/** 字符串常量:中括号(左) [ */
|
||||
/**
|
||||
* 字符串常量:中括号(左) [
|
||||
*/
|
||||
public static final String BRACKET_START = "[";
|
||||
/** 字符串常量:中括号(右) ] */
|
||||
/**
|
||||
* 字符串常量:中括号(右) ]
|
||||
*/
|
||||
public static final String BRACKET_END = "]";
|
||||
/** 字符串常量:冒号 : */
|
||||
/**
|
||||
* 字符串常量:冒号 :
|
||||
*/
|
||||
public static final String COLON = ":";
|
||||
/** 字符串常量:艾特 @ */
|
||||
/**
|
||||
* 字符串常量:艾特 @
|
||||
*/
|
||||
public static final String AT = "@";
|
||||
|
||||
/** 字符串常量:HTML 空格转义 */
|
||||
/**
|
||||
* 字符串常量:HTML 空格转义
|
||||
*/
|
||||
public static final String HTML_NBSP = " ";
|
||||
/** 字符串常量:HTML And 符转义 & */
|
||||
/**
|
||||
* 字符串常量:HTML And 符转义 &
|
||||
*/
|
||||
public static final String HTML_AMP = "&";
|
||||
/** 字符串常量:HTML 双引号转义 " */
|
||||
/**
|
||||
* 字符串常量:HTML 双引号转义 "
|
||||
*/
|
||||
public static final String HTML_QUOTE = """;
|
||||
/** 字符串常量:HTML 单引号转义 ' */
|
||||
/**
|
||||
* 字符串常量:HTML 单引号转义 '
|
||||
*/
|
||||
public static final String HTML_APOS = "'";
|
||||
/** 字符串常量:HTML 小于号转义 < */
|
||||
/**
|
||||
* 字符串常量:HTML 小于号转义 <
|
||||
*/
|
||||
public static final String HTML_LT = "<";
|
||||
/** 字符串常量:HTML 大于号转义 > */
|
||||
/**
|
||||
* 字符串常量:HTML 大于号转义 >
|
||||
*/
|
||||
public static final String HTML_GT = ">";
|
||||
/** 字符串常量:空 JSON "{}" */
|
||||
/**
|
||||
* 字符串常量:空 JSON "{}"
|
||||
*/
|
||||
public static final String EMPTY_JSON = "{}";
|
||||
|
||||
// ------------------------------------------------------------------------ Blank
|
||||
@ -189,8 +265,7 @@ public class StrUtil {
|
||||
*
|
||||
* @param obj 对象
|
||||
* @return 如果为字符串是否为空串
|
||||
*
|
||||
* @see StrUtil#isBlank(CharSequence)
|
||||
* @see StrUtil#isBlank(CharSequence)
|
||||
* @since 3.3.0
|
||||
*/
|
||||
public static boolean isBlankIfStr(Object obj) {
|
||||
@ -667,6 +742,9 @@ public class StrUtil {
|
||||
* @return 是否开始
|
||||
*/
|
||||
public static boolean startWith(CharSequence str, char c) {
|
||||
if (isEmpty(str)) {
|
||||
return false;
|
||||
}
|
||||
return c == str.charAt(0);
|
||||
}
|
||||
|
||||
@ -674,8 +752,8 @@ public class StrUtil {
|
||||
* 是否以指定字符串开头<br>
|
||||
* 如果给定的字符串和开头字符串都为null则返回true,否则任意一个值为null返回false
|
||||
*
|
||||
* @param str 被监测字符串
|
||||
* @param prefix 开头字符串
|
||||
* @param str 被监测字符串
|
||||
* @param prefix 开头字符串
|
||||
* @param ignoreCase 是否忽略大小写
|
||||
* @return 是否以指定字符串开头
|
||||
* @since 5.4.3
|
||||
@ -690,14 +768,14 @@ public class StrUtil {
|
||||
*
|
||||
* @param str 被监测字符串
|
||||
* @param prefix 开头字符串
|
||||
* @param ignoreCase 是否忽略大小写
|
||||
* @param ignoreCase 是否忽略大小写
|
||||
* @param ignoreEquals 是否忽略字符串相等的情况
|
||||
* @return 是否以指定字符串开头
|
||||
* @since 5.4.3
|
||||
*/
|
||||
public static boolean startWith(CharSequence str, CharSequence prefix, boolean ignoreCase, boolean ignoreEquals) {
|
||||
if (null == str || null == prefix) {
|
||||
if(false == ignoreEquals){
|
||||
if (false == ignoreEquals) {
|
||||
return false;
|
||||
}
|
||||
return null == str && null == prefix;
|
||||
@ -710,7 +788,7 @@ public class StrUtil {
|
||||
isStartWith = str.toString().startsWith(prefix.toString());
|
||||
}
|
||||
|
||||
if(isStartWith){
|
||||
if (isStartWith) {
|
||||
return (false == ignoreEquals) || (false == equals(str, prefix, ignoreCase));
|
||||
}
|
||||
return false;
|
||||
@ -779,6 +857,9 @@ public class StrUtil {
|
||||
* @return 是否结尾
|
||||
*/
|
||||
public static boolean endWith(CharSequence str, char c) {
|
||||
if (isEmpty(str)) {
|
||||
return false;
|
||||
}
|
||||
return c == str.charAt(str.length() - 1);
|
||||
}
|
||||
|
||||
@ -1073,7 +1154,8 @@ public class StrUtil {
|
||||
* @return 移除后的字符串
|
||||
*/
|
||||
public static String removeAll(CharSequence str, CharSequence strToRemove) {
|
||||
if (isEmpty(str)) {
|
||||
// strToRemove如果为空, 也不用继续后面的逻辑
|
||||
if (isEmpty(str) || isEmpty(strToRemove)) {
|
||||
return str(str);
|
||||
}
|
||||
return str.toString().replace(strToRemove, EMPTY);
|
||||
@ -2125,7 +2207,6 @@ public class StrUtil {
|
||||
}
|
||||
|
||||
final List<String> result = new LinkedList<>();
|
||||
final String[] split = split(str, prefix);
|
||||
for (String fragment : split(str, prefix)) {
|
||||
int suffixIndex = fragment.indexOf(suffix.toString());
|
||||
if (suffixIndex > 0) {
|
||||
@ -2205,10 +2286,10 @@ public class StrUtil {
|
||||
if (null == str) {
|
||||
return null;
|
||||
}
|
||||
if (count <= 0) {
|
||||
if (count <= 0 || str.length() == 0) {
|
||||
return EMPTY;
|
||||
}
|
||||
if (count == 1 || str.length() == 0) {
|
||||
if (count == 1) {
|
||||
return str.toString();
|
||||
}
|
||||
|
||||
@ -3997,11 +4078,12 @@ public class StrUtil {
|
||||
return false;
|
||||
}
|
||||
int len = value.length();
|
||||
boolean isAllMatch = true;
|
||||
for (int i = 0; i < len; i++) {
|
||||
isAllMatch &= matcher.match(value.charAt(i));
|
||||
if (false == matcher.match(value.charAt(i))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return isAllMatch;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -4,6 +4,7 @@ import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.exceptions.UtilException;
|
||||
import cn.hutool.core.io.FileUtil;
|
||||
import cn.hutool.core.io.IORuntimeException;
|
||||
import cn.hutool.core.io.IoUtil;
|
||||
import cn.hutool.core.lang.Assert;
|
||||
import cn.hutool.core.map.BiMap;
|
||||
@ -13,7 +14,11 @@ import org.w3c.dom.Element;
|
||||
import org.w3c.dom.NamedNodeMap;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
import org.xml.sax.ContentHandler;
|
||||
import org.xml.sax.InputSource;
|
||||
import org.xml.sax.SAXException;
|
||||
import org.xml.sax.XMLReader;
|
||||
import org.xml.sax.helpers.DefaultHandler;
|
||||
|
||||
import javax.xml.XMLConstants;
|
||||
import javax.xml.namespace.NamespaceContext;
|
||||
@ -21,6 +26,8 @@ import javax.xml.namespace.QName;
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import javax.xml.parsers.SAXParser;
|
||||
import javax.xml.parsers.SAXParserFactory;
|
||||
import javax.xml.transform.OutputKeys;
|
||||
import javax.xml.transform.Result;
|
||||
import javax.xml.transform.Source;
|
||||
@ -62,6 +69,10 @@ public class XmlUtil {
|
||||
* 在XML中无效的字符 正则
|
||||
*/
|
||||
public static final String INVALID_REGEX = "[\\x00-\\x08\\x0b-\\x0c\\x0e-\\x1f]";
|
||||
/**
|
||||
* 在XML中注释的内容 正则
|
||||
*/
|
||||
public static final String COMMENT_REGEX = "(?s)<!--.+?-->";
|
||||
/**
|
||||
* XML格式化输出默认缩进量
|
||||
*/
|
||||
@ -76,6 +87,10 @@ public class XmlUtil {
|
||||
* 是否打开命名空间支持
|
||||
*/
|
||||
private static boolean namespaceAware = true;
|
||||
/**
|
||||
* Sax读取器工厂缓存
|
||||
*/
|
||||
private static SAXParserFactory factory;
|
||||
|
||||
/**
|
||||
* 禁用默认的DocumentBuilderFactory,禁用后如果有第三方的实现(如oracle的xdb包中的xmlparse),将会自动加载实现。
|
||||
@ -184,6 +199,92 @@ public class XmlUtil {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用Sax方式读取指定的XML<br>
|
||||
* 如果用户传入的contentHandler为{@link DefaultHandler},则其接口都会被处理
|
||||
*
|
||||
* @param file XML源文件,使用后自动关闭
|
||||
* @param contentHandler XML流处理器,用于按照Element处理xml
|
||||
* @since 5.4.4
|
||||
*/
|
||||
public static void readBySax(File file, ContentHandler contentHandler) {
|
||||
InputStream in = null;
|
||||
try{
|
||||
in = FileUtil.getInputStream(file);
|
||||
readBySax(new InputSource(in), contentHandler);
|
||||
} finally {
|
||||
IoUtil.close(in);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用Sax方式读取指定的XML<br>
|
||||
* 如果用户传入的contentHandler为{@link DefaultHandler},则其接口都会被处理
|
||||
*
|
||||
* @param reader XML源Reader,使用后自动关闭
|
||||
* @param contentHandler XML流处理器,用于按照Element处理xml
|
||||
* @since 5.4.4
|
||||
*/
|
||||
public static void readBySax(Reader reader, ContentHandler contentHandler) {
|
||||
try{
|
||||
readBySax(new InputSource(reader), contentHandler);
|
||||
} finally {
|
||||
IoUtil.close(reader);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用Sax方式读取指定的XML<br>
|
||||
* 如果用户传入的contentHandler为{@link DefaultHandler},则其接口都会被处理
|
||||
*
|
||||
* @param source XML源流,使用后自动关闭
|
||||
* @param contentHandler XML流处理器,用于按照Element处理xml
|
||||
* @since 5.4.4
|
||||
*/
|
||||
public static void readBySax(InputStream source, ContentHandler contentHandler) {
|
||||
try{
|
||||
readBySax(new InputSource(source), contentHandler);
|
||||
} finally {
|
||||
IoUtil.close(source);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用Sax方式读取指定的XML<br>
|
||||
* 如果用户传入的contentHandler为{@link DefaultHandler},则其接口都会被处理
|
||||
*
|
||||
* @param source XML源,可以是文件、流、路径等
|
||||
* @param contentHandler XML流处理器,用于按照Element处理xml
|
||||
* @since 5.4.4
|
||||
*/
|
||||
public static void readBySax(InputSource source, ContentHandler contentHandler) {
|
||||
// 1.获取解析工厂
|
||||
if (null == factory) {
|
||||
factory = SAXParserFactory.newInstance();
|
||||
factory.setValidating(false);
|
||||
factory.setNamespaceAware(namespaceAware);
|
||||
}
|
||||
// 2.从解析工厂获取解析器
|
||||
final SAXParser parse;
|
||||
XMLReader reader;
|
||||
try {
|
||||
parse = factory.newSAXParser();
|
||||
if (contentHandler instanceof DefaultHandler) {
|
||||
parse.parse(source, (DefaultHandler) contentHandler);
|
||||
return;
|
||||
}
|
||||
|
||||
// 3.得到解读器
|
||||
reader = parse.getXMLReader();
|
||||
reader.setContentHandler(contentHandler);
|
||||
reader.parse(source);
|
||||
} catch (ParserConfigurationException | SAXException e) {
|
||||
throw new UtilException(e);
|
||||
} catch (IOException e) {
|
||||
throw new IORuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将String类型的XML转换为XML文档
|
||||
*
|
||||
@ -574,6 +675,20 @@ public class XmlUtil {
|
||||
return xmlContent.replaceAll(INVALID_REGEX, "");
|
||||
}
|
||||
|
||||
/**
|
||||
* 去除XML文本中的注释内容
|
||||
*
|
||||
* @param xmlContent XML文本
|
||||
* @return 当传入为null时返回null
|
||||
* @since 5.4.5
|
||||
*/
|
||||
public static String cleanComment(String xmlContent) {
|
||||
if (xmlContent == null) {
|
||||
return null;
|
||||
}
|
||||
return xmlContent.replaceAll(COMMENT_REGEX, StrUtil.EMPTY);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据节点名获得子节点列表
|
||||
*
|
||||
|
@ -1,5 +1,6 @@
|
||||
package cn.hutool.core.date;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
@ -77,4 +78,11 @@ public class ChineseDateTest {
|
||||
chineseDate = new ChineseDate(2020,4,15);
|
||||
Assert.assertEquals("闰四月", chineseDate.getChineseMonth());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getFestivalsTest(){
|
||||
// issue#I1XHSF@Gitee,2023-01-20对应农历腊月29,非除夕
|
||||
ChineseDate chineseDate = new ChineseDate(DateUtil.parseDate("2023-01-20"));
|
||||
Assert.assertTrue(StrUtil.isEmpty(chineseDate.getFestivals()));
|
||||
}
|
||||
}
|
||||
|
@ -25,7 +25,9 @@ public class ImgUtilTest {
|
||||
@Test
|
||||
@Ignore
|
||||
public void scaleTest2() {
|
||||
ImgUtil.scale(FileUtil.file("e:/pic/test.jpg"), FileUtil.file("e:/pic/test_result.jpg"), 0.8f);
|
||||
ImgUtil.scale(
|
||||
FileUtil.file("d:/test/2.png"),
|
||||
FileUtil.file("d:/test/2_result.jpg"), 600, 337, null);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -0,0 +1,35 @@
|
||||
package cn.hutool.core.lang;
|
||||
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
public class ConsoleTableTest {
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void printTest() {
|
||||
ConsoleTable t = new ConsoleTable();
|
||||
t.addHeader("姓名", "年龄");
|
||||
t.addBody("张三", "15");
|
||||
t.addBody("李四", "29");
|
||||
t.addBody("王二麻子", "37");
|
||||
t.print();
|
||||
|
||||
Console.log();
|
||||
|
||||
t = new ConsoleTable();
|
||||
t.addHeader("体温", "占比");
|
||||
t.addHeader("℃", "%");
|
||||
t.addBody("36.8", "10");
|
||||
t.addBody("37", "5");
|
||||
t.print();
|
||||
|
||||
Console.log();
|
||||
|
||||
t = new ConsoleTable();
|
||||
t.addHeader("标题1", "标题2");
|
||||
t.addBody("12345", "混合321654asdfcSDF");
|
||||
t.addBody("sd e3ee ff22", "ff值");
|
||||
t.print();
|
||||
}
|
||||
}
|
@ -263,10 +263,10 @@ public class NumberUtilTest {
|
||||
|
||||
@Test
|
||||
public void isPowerOfTwoTest() {
|
||||
Assert.assertEquals(false, NumberUtil.isPowerOfTwo(-1));
|
||||
Assert.assertEquals(true, NumberUtil.isPowerOfTwo(16));
|
||||
Assert.assertEquals(true, NumberUtil.isPowerOfTwo(65536));
|
||||
Assert.assertEquals(true, NumberUtil.isPowerOfTwo(1));
|
||||
Assert.assertEquals(false, NumberUtil.isPowerOfTwo(17));
|
||||
Assert.assertFalse(NumberUtil.isPowerOfTwo(-1));
|
||||
Assert.assertTrue(NumberUtil.isPowerOfTwo(16));
|
||||
Assert.assertTrue(NumberUtil.isPowerOfTwo(65536));
|
||||
Assert.assertTrue(NumberUtil.isPowerOfTwo(1));
|
||||
Assert.assertFalse(NumberUtil.isPowerOfTwo(17));
|
||||
}
|
||||
}
|
||||
|
@ -9,10 +9,13 @@ import org.junit.Assert;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.w3c.dom.Document;
|
||||
import org.xml.sax.Attributes;
|
||||
import org.xml.sax.helpers.DefaultHandler;
|
||||
|
||||
import javax.xml.xpath.XPathConstants;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* {@link XmlUtil} 工具类
|
||||
@ -148,6 +151,18 @@ public class XmlUtilTest {
|
||||
Assert.assertNotNull(doc);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void readBySaxTest(){
|
||||
final Set<String> eles = CollUtil.newHashSet(
|
||||
"returnsms", "returnstatus", "message", "remainpoint", "taskID", "successCounts");
|
||||
XmlUtil.readBySax(ResourceUtil.getStream("test.xml"), new DefaultHandler(){
|
||||
@Override
|
||||
public void startElement(String uri, String localName, String qName, Attributes attributes) {
|
||||
Assert.assertTrue(eles.contains(localName));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mapToXmlTestWithOmitXmlDeclaration() {
|
||||
|
||||
@ -196,6 +211,13 @@ public class XmlUtilTest {
|
||||
Assert.assertEquals(testBean.getBankCode(), testBean2.getBankCode());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void cleanCommentTest() {
|
||||
final String xmlContent = "<info><title>hutool</title><!-- 这是注释 --><lang>java</lang></info>";
|
||||
final String ret = XmlUtil.cleanComment(xmlContent);
|
||||
Assert.assertEquals("<info><title>hutool</title><lang>java</lang></info>", ret);
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class TestBean {
|
||||
private String ReqCode;
|
||||
|
@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-parent</artifactId>
|
||||
<version>5.4.4-SNAPSHOT</version>
|
||||
<version>5.4.5-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hutool-cron</artifactId>
|
||||
|
@ -9,7 +9,7 @@
|
||||
<parent>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-parent</artifactId>
|
||||
<version>5.4.4-SNAPSHOT</version>
|
||||
<version>5.4.5-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hutool-crypto</artifactId>
|
||||
|
@ -9,7 +9,7 @@
|
||||
<parent>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-parent</artifactId>
|
||||
<version>5.4.4-SNAPSHOT</version>
|
||||
<version>5.4.5-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hutool-db</artifactId>
|
||||
@ -19,9 +19,9 @@
|
||||
<properties>
|
||||
<!-- versions -->
|
||||
<c3p0.version>0.9.5.5</c3p0.version>
|
||||
<dbcp2.version>2.7.0</dbcp2.version>
|
||||
<dbcp2.version>2.8.0</dbcp2.version>
|
||||
<tomcat-jdbc.version>9.0.30</tomcat-jdbc.version>
|
||||
<druid.version>1.1.23</druid.version>
|
||||
<druid.version>1.1.24</druid.version>
|
||||
<hikariCP.version>2.4.13</hikariCP.version>
|
||||
<mongo.version>3.12.7</mongo.version>
|
||||
<sqlite.version>3.32.3.2</sqlite.version>
|
||||
|
@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-parent</artifactId>
|
||||
<version>5.4.4-SNAPSHOT</version>
|
||||
<version>5.4.5-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hutool-dfa</artifactId>
|
||||
|
@ -9,7 +9,7 @@
|
||||
<parent>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-parent</artifactId>
|
||||
<version>5.4.4-SNAPSHOT</version>
|
||||
<version>5.4.5-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hutool-extra</artifactId>
|
||||
@ -19,15 +19,15 @@
|
||||
<properties>
|
||||
<!-- versions -->
|
||||
<velocity.version>2.2</velocity.version>
|
||||
<beetl.version>3.2.0.RELEASE</beetl.version>
|
||||
<beetl.version>3.2.1.RELEASE</beetl.version>
|
||||
<rythm.version>1.3.0</rythm.version>
|
||||
<freemarker.version>2.3.30</freemarker.version>
|
||||
<enjoy.version>4.9.01</enjoy.version>
|
||||
<thymeleaf.version>3.0.11.RELEASE</thymeleaf.version>
|
||||
<mail.version>1.6.2</mail.version>
|
||||
<jsch.version>0.1.55</jsch.version>
|
||||
<zxing.version>3.4.0</zxing.version>
|
||||
<net.version>3.6</net.version>
|
||||
<zxing.version>3.4.1</zxing.version>
|
||||
<net.version>3.7</net.version>
|
||||
<emoji-java.version>5.1.1</emoji-java.version>
|
||||
<servlet-api.version>4.0.1</servlet-api.version>
|
||||
<spring-boot.version>2.3.4.RELEASE</spring-boot.version>
|
||||
|
@ -9,7 +9,7 @@
|
||||
<parent>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-parent</artifactId>
|
||||
<version>5.4.4-SNAPSHOT</version>
|
||||
<version>5.4.5-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hutool-http</artifactId>
|
||||
|
@ -28,6 +28,7 @@ import java.io.OutputStream;
|
||||
import java.net.CookieManager;
|
||||
import java.net.HttpCookie;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.Proxy;
|
||||
import java.net.URLStreamHandler;
|
||||
import java.util.Collection;
|
||||
@ -841,6 +842,20 @@ public class HttpRequest extends HttpBase<HttpRequest> {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置Http代理
|
||||
*
|
||||
* @param host 代理 主机
|
||||
* @param port 代理 端口
|
||||
* @return this
|
||||
* @since 5.4.5
|
||||
*/
|
||||
public HttpRequest setHttpProxy(String host, int port) {
|
||||
final Proxy proxy = new Proxy(Proxy.Type.HTTP,
|
||||
new InetSocketAddress(host, port));
|
||||
return setProxy(proxy);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置代理
|
||||
*
|
||||
|
@ -9,7 +9,7 @@
|
||||
<parent>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-parent</artifactId>
|
||||
<version>5.4.4-SNAPSHOT</version>
|
||||
<version>5.4.5-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hutool-json</artifactId>
|
||||
|
@ -154,4 +154,11 @@ public class JSONUtilTest {
|
||||
Assert.assertEquals("aa", json.get("name"));
|
||||
Assert.assertEquals(1, json.get("gender"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doubleTest(){
|
||||
String json = "{\"test\": 12.00}";
|
||||
final JSONObject jsonObject = JSONUtil.parseObj(json);
|
||||
Assert.assertEquals("12.00", jsonObject.getBigDecimal("test").setScale(2).toString());
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,7 @@
|
||||
<parent>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-parent</artifactId>
|
||||
<version>5.4.4-SNAPSHOT</version>
|
||||
<version>5.4.5-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hutool-log</artifactId>
|
||||
|
@ -8,7 +8,7 @@
|
||||
<parent>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-parent</artifactId>
|
||||
<version>5.4.4-SNAPSHOT</version>
|
||||
<version>5.4.5-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hutool-poi</artifactId>
|
||||
|
@ -1,9 +1,10 @@
|
||||
package cn.hutool.poi.excel;
|
||||
|
||||
import cn.hutool.core.io.IORuntimeException;
|
||||
import cn.hutool.core.io.IoUtil;
|
||||
import org.apache.poi.poifs.filesystem.FileMagic;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
@ -48,11 +49,24 @@ public class ExcelFileUtil {
|
||||
* @return 是否为XLSX格式的Excel文件(XSSF)
|
||||
*/
|
||||
public static boolean isXlsx(InputStream in) {
|
||||
if (false == in.markSupported()) {
|
||||
in = new BufferedInputStream(in);
|
||||
}
|
||||
try {
|
||||
return FileMagic.valueOf(in) == FileMagic.OOXML;
|
||||
return FileMagic.valueOf(IoUtil.toMarkSupportStream(in)) == FileMagic.OOXML;
|
||||
} catch (IOException e) {
|
||||
throw new IORuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否为XLSX格式的Excel文件(XSSF)<br>
|
||||
* XLSX文件主要用于Excel 2007+创建
|
||||
*
|
||||
* @param file excel文件
|
||||
* @return 是否为XLSX格式的Excel文件(XSSF)
|
||||
* @since 5.4.4
|
||||
*/
|
||||
public static boolean isXlsx(File file) {
|
||||
try {
|
||||
return FileMagic.valueOf(file) == FileMagic.OOXML;
|
||||
} catch (IOException e) {
|
||||
throw new IORuntimeException(e);
|
||||
}
|
||||
|
@ -2,7 +2,6 @@ package cn.hutool.poi.excel;
|
||||
|
||||
import cn.hutool.core.exceptions.DependencyException;
|
||||
import cn.hutool.core.io.FileUtil;
|
||||
import cn.hutool.core.io.IoUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.ReUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
@ -10,9 +9,10 @@ import cn.hutool.poi.PoiChecker;
|
||||
import cn.hutool.poi.excel.cell.CellLocation;
|
||||
import cn.hutool.poi.excel.sax.Excel03SaxReader;
|
||||
import cn.hutool.poi.excel.sax.Excel07SaxReader;
|
||||
import cn.hutool.poi.excel.sax.ExcelSaxReader;
|
||||
import cn.hutool.poi.excel.sax.ExcelSaxUtil;
|
||||
import cn.hutool.poi.excel.sax.handler.RowHandler;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
|
||||
@ -29,67 +29,92 @@ public class ExcelUtil {
|
||||
* 通过Sax方式读取Excel,同时支持03和07格式
|
||||
*
|
||||
* @param path Excel文件路径
|
||||
* @param sheetIndex sheet序号
|
||||
* @param rid sheet rid,-1表示全部Sheet, 0表示第一个Sheet
|
||||
* @param rowHandler 行处理器
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public static void readBySax(String path, int sheetIndex, RowHandler rowHandler) {
|
||||
BufferedInputStream in = null;
|
||||
try {
|
||||
in = FileUtil.getInputStream(path);
|
||||
readBySax(in, sheetIndex, rowHandler);
|
||||
} finally {
|
||||
IoUtil.close(in);
|
||||
}
|
||||
public static void readBySax(String path, int rid, RowHandler rowHandler) {
|
||||
readBySax(FileUtil.file(path), rid, rowHandler);
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过Sax方式读取Excel,同时支持03和07格式
|
||||
*
|
||||
* @param path Excel文件路径
|
||||
* @param idOrRid Excel中的sheet id或者rid编号,rid必须加rId前缀,例如rId1,如果为-1处理所有编号的sheet
|
||||
* @param rowHandler 行处理器
|
||||
* @since 5.4.4
|
||||
*/
|
||||
public static void readBySax(String path, String idOrRid, RowHandler rowHandler) {
|
||||
readBySax(FileUtil.file(path), idOrRid, rowHandler);
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过Sax方式读取Excel,同时支持03和07格式
|
||||
*
|
||||
* @param file Excel文件
|
||||
* @param sheetIndex sheet序号
|
||||
* @param rid sheet rid,-1表示全部Sheet, 0表示第一个Sheet
|
||||
* @param rowHandler 行处理器
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public static void readBySax(File file, int sheetIndex, RowHandler rowHandler) {
|
||||
BufferedInputStream in = null;
|
||||
try {
|
||||
in = FileUtil.getInputStream(file);
|
||||
readBySax(in, sheetIndex, rowHandler);
|
||||
} finally {
|
||||
IoUtil.close(in);
|
||||
}
|
||||
public static void readBySax(File file, int rid, RowHandler rowHandler) {
|
||||
final ExcelSaxReader<?> reader = ExcelSaxUtil.createSaxReader(ExcelFileUtil.isXlsx(file), rowHandler);
|
||||
reader.read(file, rid);
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过Sax方式读取Excel,同时支持03和07格式
|
||||
*
|
||||
* @param file Excel文件
|
||||
* @param idOrRid Excel中的sheet id或者rid编号,rid必须加rId前缀,例如rId1,如果为-1处理所有编号的sheet
|
||||
* @param rowHandler 行处理器
|
||||
* @since 5.4.4
|
||||
*/
|
||||
public static void readBySax(File file, String idOrRid, RowHandler rowHandler) {
|
||||
final ExcelSaxReader<?> reader = ExcelSaxUtil.createSaxReader(ExcelFileUtil.isXlsx(file), rowHandler);
|
||||
reader.read(file, idOrRid);
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过Sax方式读取Excel,同时支持03和07格式
|
||||
*
|
||||
* @param in Excel流
|
||||
* @param sheetIndex sheet序号
|
||||
* @param rid sheet rid,-1表示全部Sheet, 0表示第一个Sheet
|
||||
* @param rowHandler 行处理器
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public static void readBySax(InputStream in, int sheetIndex, RowHandler rowHandler) {
|
||||
in = IoUtil.toMarkSupportStream(in);
|
||||
if (ExcelFileUtil.isXlsx(in)) {
|
||||
read07BySax(in, sheetIndex, rowHandler);
|
||||
} else {
|
||||
read03BySax(in, sheetIndex, rowHandler);
|
||||
}
|
||||
public static void readBySax(InputStream in, int rid, RowHandler rowHandler) {
|
||||
final ExcelSaxReader<?> reader = ExcelSaxUtil.createSaxReader(ExcelFileUtil.isXlsx(in), rowHandler);
|
||||
reader.read(in, rid);
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过Sax方式读取Excel,同时支持03和07格式
|
||||
*
|
||||
* @param in Excel流
|
||||
* @param idOrRid Excel中的sheet id或者rid编号,rid必须加rId前缀,例如rId1,如果为-1处理所有编号的sheet
|
||||
* @param rowHandler 行处理器
|
||||
* @since 5.4.4
|
||||
*/
|
||||
public static void readBySax(InputStream in, String idOrRid, RowHandler rowHandler) {
|
||||
final ExcelSaxReader<?> reader = ExcelSaxUtil.createSaxReader(ExcelFileUtil.isXlsx(in), rowHandler);
|
||||
reader.read(in, idOrRid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sax方式读取Excel07
|
||||
*
|
||||
* @param in 输入流
|
||||
* @param sheetIndex Sheet索引,-1表示全部Sheet, 0表示第一个Sheet
|
||||
* @param rid Sheet rid,-1表示全部Sheet, 0表示第一个Sheet
|
||||
* @param rowHandler 行处理器
|
||||
* @return {@link Excel07SaxReader}
|
||||
* @since 3.2.0
|
||||
* @deprecated 请使用 {@link #readBySax(InputStream, int, RowHandler)}
|
||||
*/
|
||||
public static Excel07SaxReader read07BySax(InputStream in, int sheetIndex, RowHandler rowHandler) {
|
||||
@Deprecated
|
||||
public static Excel07SaxReader read07BySax(InputStream in, int rid, RowHandler rowHandler) {
|
||||
try {
|
||||
return new Excel07SaxReader(rowHandler).read(in, sheetIndex);
|
||||
return new Excel07SaxReader(rowHandler).read(in, rid);
|
||||
} catch (NoClassDefFoundError e) {
|
||||
throw new DependencyException(ObjectUtil.defaultIfNull(e.getCause(), e), PoiChecker.NO_POI_ERROR_MSG);
|
||||
}
|
||||
@ -99,14 +124,16 @@ public class ExcelUtil {
|
||||
* Sax方式读取Excel07
|
||||
*
|
||||
* @param file 文件
|
||||
* @param sheetIndex Sheet索引,-1表示全部Sheet, 0表示第一个Sheet
|
||||
* @param rid Sheet rid,-1表示全部Sheet, 0表示第一个Sheet
|
||||
* @param rowHandler 行处理器
|
||||
* @return {@link Excel07SaxReader}
|
||||
* @since 3.2.0
|
||||
* @deprecated 请使用 {@link #readBySax(File, int, RowHandler)}
|
||||
*/
|
||||
public static Excel07SaxReader read07BySax(File file, int sheetIndex, RowHandler rowHandler) {
|
||||
@Deprecated
|
||||
public static Excel07SaxReader read07BySax(File file, int rid, RowHandler rowHandler) {
|
||||
try {
|
||||
return new Excel07SaxReader(rowHandler).read(file, sheetIndex);
|
||||
return new Excel07SaxReader(rowHandler).read(file, rid);
|
||||
} catch (NoClassDefFoundError e) {
|
||||
throw new DependencyException(ObjectUtil.defaultIfNull(e.getCause(), e), PoiChecker.NO_POI_ERROR_MSG);
|
||||
}
|
||||
@ -116,14 +143,16 @@ public class ExcelUtil {
|
||||
* Sax方式读取Excel07
|
||||
*
|
||||
* @param path 路径
|
||||
* @param sheetIndex Sheet索引,-1表示全部Sheet, 0表示第一个Sheet
|
||||
* @param rid Sheet rid,-1表示全部Sheet, 0表示第一个Sheet
|
||||
* @param rowHandler 行处理器
|
||||
* @return {@link Excel07SaxReader}
|
||||
* @since 3.2.0
|
||||
* @deprecated 请使用 {@link #readBySax(String, int, RowHandler)}
|
||||
*/
|
||||
public static Excel07SaxReader read07BySax(String path, int sheetIndex, RowHandler rowHandler) {
|
||||
@Deprecated
|
||||
public static Excel07SaxReader read07BySax(String path, int rid, RowHandler rowHandler) {
|
||||
try {
|
||||
return new Excel07SaxReader(rowHandler).read(path, sheetIndex);
|
||||
return new Excel07SaxReader(rowHandler).read(path, rid);
|
||||
} catch (NoClassDefFoundError e) {
|
||||
throw new DependencyException(ObjectUtil.defaultIfNull(e.getCause(), e), PoiChecker.NO_POI_ERROR_MSG);
|
||||
}
|
||||
@ -135,9 +164,11 @@ public class ExcelUtil {
|
||||
* @param in 输入流
|
||||
* @param sheetIndex Sheet索引,-1表示全部Sheet, 0表示第一个Sheet
|
||||
* @param rowHandler 行处理器
|
||||
* @return {@link Excel07SaxReader}
|
||||
* @return {@link Excel03SaxReader}
|
||||
* @since 3.2.0
|
||||
* @deprecated 请使用 {@link #readBySax(InputStream, int, RowHandler)}
|
||||
*/
|
||||
@Deprecated
|
||||
public static Excel03SaxReader read03BySax(InputStream in, int sheetIndex, RowHandler rowHandler) {
|
||||
try {
|
||||
return new Excel03SaxReader(rowHandler).read(in, sheetIndex);
|
||||
@ -154,7 +185,9 @@ public class ExcelUtil {
|
||||
* @param rowHandler 行处理器
|
||||
* @return {@link Excel03SaxReader}
|
||||
* @since 3.2.0
|
||||
* @deprecated 请使用 {@link #readBySax(File, int, RowHandler)}
|
||||
*/
|
||||
@Deprecated
|
||||
public static Excel03SaxReader read03BySax(File file, int sheetIndex, RowHandler rowHandler) {
|
||||
try {
|
||||
return new Excel03SaxReader(rowHandler).read(file, sheetIndex);
|
||||
@ -171,7 +204,9 @@ public class ExcelUtil {
|
||||
* @param rowHandler 行处理器
|
||||
* @return {@link Excel03SaxReader}
|
||||
* @since 3.2.0
|
||||
* @deprecated 请使用 {@link #readBySax(String, int, RowHandler)}
|
||||
*/
|
||||
@Deprecated
|
||||
public static Excel03SaxReader read03BySax(String path, int sheetIndex, RowHandler rowHandler) {
|
||||
try {
|
||||
return new Excel03SaxReader(rowHandler).read(path, sheetIndex);
|
||||
|
@ -1,38 +0,0 @@
|
||||
package cn.hutool.poi.excel.sax;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
|
||||
import cn.hutool.core.io.FileUtil;
|
||||
import cn.hutool.poi.exceptions.POIException;
|
||||
|
||||
/**
|
||||
* 抽象的Sax方式Excel读取器,提供一些共用方法
|
||||
*
|
||||
* @author looly
|
||||
*
|
||||
* @param <T> 子对象类型,用于标记返回值this
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public abstract class AbstractExcelSaxReader<T> implements ExcelSaxReader<T> {
|
||||
|
||||
@Override
|
||||
public T read(String path) throws POIException {
|
||||
return read(FileUtil.file(path));
|
||||
}
|
||||
|
||||
@Override
|
||||
public T read(File file) throws POIException {
|
||||
return read(file, -1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T read(InputStream in) throws POIException {
|
||||
return read(in, -1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T read(String path, int sheetIndex) throws POIException {
|
||||
return read(FileUtil.file(path), sheetIndex);
|
||||
}
|
||||
}
|
@ -30,7 +30,7 @@ import java.util.List;
|
||||
*
|
||||
* @author looly
|
||||
*/
|
||||
public class Excel03SaxReader extends AbstractExcelSaxReader<Excel03SaxReader> implements HSSFListener {
|
||||
public class Excel03SaxReader implements HSSFListener, ExcelSaxReader<Excel03SaxReader> {
|
||||
|
||||
/**
|
||||
* 如果为公式,true表示输出公式计算后的结果值,false表示输出公式本身
|
||||
@ -83,18 +83,18 @@ public class Excel03SaxReader extends AbstractExcelSaxReader<Excel03SaxReader> i
|
||||
|
||||
// ------------------------------------------------------------------------------ Read start
|
||||
@Override
|
||||
public Excel03SaxReader read(File file, int rid) throws POIException {
|
||||
public Excel03SaxReader read(File file, String idOrRid) throws POIException {
|
||||
try {
|
||||
return read(new POIFSFileSystem(file), rid);
|
||||
return read(new POIFSFileSystem(file), idOrRid);
|
||||
} catch (IOException e) {
|
||||
throw new POIException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Excel03SaxReader read(InputStream excelStream, int rid) throws POIException {
|
||||
public Excel03SaxReader read(InputStream excelStream, String idOrRid) throws POIException {
|
||||
try {
|
||||
return read(new POIFSFileSystem(excelStream), rid);
|
||||
return read(new POIFSFileSystem(excelStream), idOrRid);
|
||||
} catch (IOException e) {
|
||||
throw new POIException(e);
|
||||
}
|
||||
@ -104,12 +104,12 @@ public class Excel03SaxReader extends AbstractExcelSaxReader<Excel03SaxReader> i
|
||||
* 读取
|
||||
*
|
||||
* @param fs {@link POIFSFileSystem}
|
||||
* @param rid sheet序号
|
||||
* @param id sheet序号
|
||||
* @return this
|
||||
* @throws POIException IO异常包装
|
||||
*/
|
||||
public Excel03SaxReader read(POIFSFileSystem fs, int rid) throws POIException {
|
||||
this.rid = rid;
|
||||
public Excel03SaxReader read(POIFSFileSystem fs, String id) throws POIException {
|
||||
this.rid = Integer.parseInt(id);
|
||||
|
||||
formatListener = new FormatTrackingHSSFListener(new MissingRecordAwareHSSFListener(this));
|
||||
final HSSFRequest request = new HSSFRequest();
|
||||
|
@ -1,10 +1,14 @@
|
||||
package cn.hutool.poi.excel.sax;
|
||||
|
||||
import cn.hutool.core.io.IORuntimeException;
|
||||
import cn.hutool.core.io.IoUtil;
|
||||
import cn.hutool.core.text.StrBuilder;
|
||||
import cn.hutool.core.util.NumberUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.poi.excel.sax.handler.RowHandler;
|
||||
import cn.hutool.poi.exceptions.POIException;
|
||||
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
|
||||
import org.apache.poi.openxml4j.exceptions.OpenXML4JException;
|
||||
import org.apache.poi.openxml4j.opc.OPCPackage;
|
||||
import org.apache.poi.ss.usermodel.BuiltinFormats;
|
||||
import org.apache.poi.xssf.eventusermodel.XSSFReader;
|
||||
@ -12,10 +16,10 @@ import org.apache.poi.xssf.model.SharedStringsTable;
|
||||
import org.apache.poi.xssf.model.StylesTable;
|
||||
import org.apache.poi.xssf.usermodel.XSSFCellStyle;
|
||||
import org.xml.sax.Attributes;
|
||||
import org.xml.sax.ContentHandler;
|
||||
import org.xml.sax.Locator;
|
||||
import org.xml.sax.helpers.DefaultHandler;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
@ -28,7 +32,7 @@ import java.util.List;
|
||||
* @author Looly
|
||||
* @since 3.1.2
|
||||
*/
|
||||
public class Excel07SaxReader extends AbstractExcelSaxReader<Excel07SaxReader> implements ContentHandler {
|
||||
public class Excel07SaxReader extends DefaultHandler implements ExcelSaxReader<Excel07SaxReader> {
|
||||
|
||||
// sheet r:Id前缀
|
||||
private static final String RID_PREFIX = "rId";
|
||||
@ -92,20 +96,30 @@ public class Excel07SaxReader extends AbstractExcelSaxReader<Excel07SaxReader> i
|
||||
// ------------------------------------------------------------------------------ Read start
|
||||
@Override
|
||||
public Excel07SaxReader read(File file, int rid) throws POIException {
|
||||
return read(file, RID_PREFIX + rid);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Excel07SaxReader read(File file, String idOrRid) throws POIException {
|
||||
try {
|
||||
return read(OPCPackage.open(file), rid);
|
||||
} catch (Exception e) {
|
||||
return read(OPCPackage.open(file), idOrRid);
|
||||
} catch (InvalidFormatException e) {
|
||||
throw new POIException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Excel07SaxReader read(InputStream in, int rid) throws POIException {
|
||||
try {
|
||||
return read(OPCPackage.open(in), rid);
|
||||
} catch (RuntimeException e) {
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
return read(in, RID_PREFIX + rid);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Excel07SaxReader read(InputStream in, String idOrRid) throws POIException {
|
||||
try (final OPCPackage opcPackage = OPCPackage.open(in)) {
|
||||
return read(opcPackage, idOrRid);
|
||||
} catch (IOException e) {
|
||||
throw new IORuntimeException(e);
|
||||
} catch (InvalidFormatException e) {
|
||||
throw new POIException(e);
|
||||
}
|
||||
}
|
||||
@ -113,53 +127,60 @@ public class Excel07SaxReader extends AbstractExcelSaxReader<Excel07SaxReader> i
|
||||
/**
|
||||
* 开始读取Excel,Sheet编号从0开始计数
|
||||
*
|
||||
* @param opcPackage {@link OPCPackage},Excel包
|
||||
* @param opcPackage {@link OPCPackage},Excel包,读取后不关闭
|
||||
* @param rid Excel中的sheet rid编号,如果为-1处理所有编号的sheet
|
||||
* @return this
|
||||
* @throws POIException POI异常
|
||||
*/
|
||||
public Excel07SaxReader read(OPCPackage opcPackage, int rid) throws POIException {
|
||||
InputStream sheetInputStream = null;
|
||||
return read(opcPackage, RID_PREFIX + rid);
|
||||
}
|
||||
|
||||
/**
|
||||
* 开始读取Excel,Sheet编号从0开始计数
|
||||
*
|
||||
* @param opcPackage {@link OPCPackage},Excel包,读取后不关闭
|
||||
* @param idOrRid Excel中的sheet id或者rid编号,rid必须加rId前缀,例如rId1,如果为-1处理所有编号的sheet
|
||||
* @return this
|
||||
* @throws POIException POI异常
|
||||
*/
|
||||
public Excel07SaxReader read(OPCPackage opcPackage, String idOrRid) throws POIException {
|
||||
try {
|
||||
final XSSFReader xssfReader = new XSSFReader(opcPackage);
|
||||
|
||||
// 获取共享样式表
|
||||
try {
|
||||
stylesTable = xssfReader.getStylesTable();
|
||||
} catch (Exception e) {
|
||||
//ignore
|
||||
}
|
||||
// 获取共享字符串表
|
||||
this.sharedStringsTable = xssfReader.getSharedStringsTable();
|
||||
|
||||
if (rid > -1) {
|
||||
this.sheetIndex = rid;
|
||||
// 根据 rId# 或 rSheet# 查找sheet
|
||||
sheetInputStream = xssfReader.getSheet(RID_PREFIX + (rid + 1));
|
||||
ExcelSaxUtil.readFrom(sheetInputStream, this);
|
||||
rowHandler.doAfterAllAnalysed();
|
||||
} else {
|
||||
this.sheetIndex = -1;
|
||||
// 遍历所有sheet
|
||||
final Iterator<InputStream> sheetInputStreams = xssfReader.getSheetsData();
|
||||
while (sheetInputStreams.hasNext()) {
|
||||
// 重新读取一个sheet时行归零
|
||||
index = 0;
|
||||
this.sheetIndex++;
|
||||
sheetInputStream = sheetInputStreams.next();
|
||||
ExcelSaxUtil.readFrom(sheetInputStream, this);
|
||||
rowHandler.doAfterAllAnalysed();
|
||||
}
|
||||
}
|
||||
} catch (RuntimeException e) {
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
return read(new XSSFReader(opcPackage), idOrRid);
|
||||
} catch (OpenXML4JException e) {
|
||||
throw new POIException(e);
|
||||
} finally {
|
||||
IoUtil.close(sheetInputStream);
|
||||
IoUtil.close(opcPackage);
|
||||
} catch (IOException e) {
|
||||
throw new IORuntimeException(e);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 开始读取Excel,Sheet编号从0开始计数
|
||||
*
|
||||
* @param xssfReader {@link XSSFReader},Excel读取器
|
||||
* @param idOrRid Excel中的sheet id或者rid编号,rid必须加rId前缀,例如rId1,如果为-1处理所有编号的sheet
|
||||
* @return this
|
||||
* @throws POIException POI异常
|
||||
* @since 5.4.4
|
||||
*/
|
||||
public Excel07SaxReader read(XSSFReader xssfReader, String idOrRid) throws POIException {
|
||||
// 获取共享样式表
|
||||
try {
|
||||
stylesTable = xssfReader.getStylesTable();
|
||||
} catch (Exception e) {
|
||||
//ignore
|
||||
}
|
||||
|
||||
// 获取共享字符串表
|
||||
try {
|
||||
this.sharedStringsTable = xssfReader.getSharedStringsTable();
|
||||
} catch (IOException e) {
|
||||
throw new IORuntimeException(e);
|
||||
} catch (InvalidFormatException e) {
|
||||
throw new POIException(e);
|
||||
}
|
||||
|
||||
return readSheets(xssfReader, idOrRid);
|
||||
}
|
||||
// ------------------------------------------------------------------------------ Read end
|
||||
|
||||
@ -196,53 +217,57 @@ public class Excel07SaxReader extends AbstractExcelSaxReader<Excel07SaxReader> i
|
||||
lastContent.append(ch, start, length);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------- Pass method start
|
||||
@Override
|
||||
public void setDocumentLocator(Locator locator) {
|
||||
// pass
|
||||
}
|
||||
// --------------------------------------------------------------------------------------- Private method start
|
||||
|
||||
/**
|
||||
* ?xml标签的回调处理方法
|
||||
* 开始读取Excel,Sheet编号从0开始计数
|
||||
*
|
||||
* @param xssfReader {@link XSSFReader},Excel读取器
|
||||
* @param idOrRid Excel中的sheet id或者rid编号,rid必须加rId前缀,例如rId0,如果为-1处理所有编号的sheet
|
||||
* @return this
|
||||
* @throws POIException POI异常
|
||||
* @since 5.4.4
|
||||
*/
|
||||
@Override
|
||||
public void startDocument() {
|
||||
// pass
|
||||
private Excel07SaxReader readSheets(XSSFReader xssfReader, String idOrRid) throws POIException {
|
||||
// 将sheetId转换为rid
|
||||
if (NumberUtil.isInteger(idOrRid)) {
|
||||
final SheetRidReader ridReader = new SheetRidReader();
|
||||
final String rid = ridReader.read(xssfReader).getRidBySheetId(idOrRid);
|
||||
if (StrUtil.isNotEmpty(rid)) {
|
||||
idOrRid = rid;
|
||||
}
|
||||
}
|
||||
this.sheetIndex = Integer.parseInt(StrUtil.removePrefixIgnoreCase(idOrRid, RID_PREFIX));
|
||||
InputStream sheetInputStream = null;
|
||||
try {
|
||||
if (this.sheetIndex > -1) {
|
||||
// 根据 rId# 或 rSheet# 查找sheet
|
||||
sheetInputStream = xssfReader.getSheet(RID_PREFIX + (this.sheetIndex + 1));
|
||||
ExcelSaxUtil.readFrom(sheetInputStream, this);
|
||||
rowHandler.doAfterAllAnalysed();
|
||||
} else {
|
||||
this.sheetIndex = -1;
|
||||
// 遍历所有sheet
|
||||
final Iterator<InputStream> sheetInputStreams = xssfReader.getSheetsData();
|
||||
while (sheetInputStreams.hasNext()) {
|
||||
// 重新读取一个sheet时行归零
|
||||
index = 0;
|
||||
this.sheetIndex++;
|
||||
sheetInputStream = sheetInputStreams.next();
|
||||
ExcelSaxUtil.readFrom(sheetInputStream, this);
|
||||
rowHandler.doAfterAllAnalysed();
|
||||
}
|
||||
}
|
||||
} catch (RuntimeException e) {
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
throw new POIException(e);
|
||||
} finally {
|
||||
IoUtil.close(sheetInputStream);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endDocument() {
|
||||
// pass
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startPrefixMapping(String prefix, String uri) {
|
||||
// pass
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endPrefixMapping(String prefix) {
|
||||
// pass
|
||||
}
|
||||
|
||||
@Override
|
||||
public void ignorableWhitespace(char[] ch, int start, int length) {
|
||||
// pass
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processingInstruction(String target, String data) {
|
||||
// pass
|
||||
}
|
||||
|
||||
@Override
|
||||
public void skippedEntity(String name) {
|
||||
// pass
|
||||
}
|
||||
// --------------------------------------------------------------------------------------- Pass method end
|
||||
|
||||
// --------------------------------------------------------------------------------------- Private method start
|
||||
|
||||
/**
|
||||
* 行开始
|
||||
*
|
||||
@ -317,10 +342,11 @@ public class Excel07SaxReader extends AbstractExcelSaxReader<Excel07SaxReader> i
|
||||
|
||||
/**
|
||||
* 在一行中的指定列增加值
|
||||
*
|
||||
* @param index 位置
|
||||
* @param value 值
|
||||
*/
|
||||
private void addCellValue(int index, Object value){
|
||||
private void addCellValue(int index, Object value) {
|
||||
this.rowCellList.add(index, value);
|
||||
this.rowHandler.handleCell(this.sheetIndex, this.rowNumber, index, value, this.xssfCellStyle);
|
||||
}
|
||||
|
@ -1,10 +1,11 @@
|
||||
package cn.hutool.poi.excel.sax;
|
||||
|
||||
import cn.hutool.core.io.FileUtil;
|
||||
import cn.hutool.poi.exceptions.POIException;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
|
||||
import cn.hutool.poi.exceptions.POIException;
|
||||
|
||||
/**
|
||||
* Sax方式读取Excel接口,提供一些共用方法
|
||||
* @author looly
|
||||
@ -13,60 +14,105 @@ import cn.hutool.poi.exceptions.POIException;
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public interface ExcelSaxReader<T> {
|
||||
|
||||
/**
|
||||
* 开始读取Excel
|
||||
*
|
||||
* @param file Excel文件
|
||||
* @param idOrRid Excel中的sheet id或者rid编号,rid必须加rId前缀,例如rId1,如果为-1处理所有编号的sheet
|
||||
* @return this
|
||||
* @throws POIException POI异常
|
||||
*/
|
||||
T read(File file, String idOrRid) throws POIException;
|
||||
|
||||
/**
|
||||
* 开始读取Excel,读取结束后并不关闭流
|
||||
*
|
||||
* @param in Excel流
|
||||
* @param idOrRid Excel中的sheet id或者rid编号,rid必须加rId前缀,例如rId1,如果为-1处理所有编号的sheet
|
||||
* @return this
|
||||
* @throws POIException POI异常
|
||||
*/
|
||||
T read(InputStream in, String idOrRid) throws POIException;
|
||||
|
||||
/**
|
||||
* 开始读取Excel,读取所有sheet
|
||||
*
|
||||
*
|
||||
* @param path Excel文件路径
|
||||
* @return this
|
||||
* @throws POIException POI异常
|
||||
*/
|
||||
T read(String path) throws POIException;
|
||||
default T read(String path) throws POIException {
|
||||
return read(FileUtil.file(path));
|
||||
}
|
||||
|
||||
/**
|
||||
* 开始读取Excel,读取所有sheet
|
||||
*
|
||||
*
|
||||
* @param file Excel文件
|
||||
* @return this
|
||||
* @throws POIException POI异常
|
||||
*/
|
||||
T read(File file) throws POIException;
|
||||
default T read(File file) throws POIException {
|
||||
return read(file, -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* 开始读取Excel,读取所有sheet,读取结束后并不关闭流
|
||||
*
|
||||
*
|
||||
* @param in Excel包流
|
||||
* @return this
|
||||
* @throws POIException POI异常
|
||||
*/
|
||||
T read(InputStream in) throws POIException;
|
||||
default T read(InputStream in) throws POIException {
|
||||
return read(in, -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* 开始读取Excel
|
||||
*
|
||||
*
|
||||
* @param path 文件路径
|
||||
* @param rid Excel中的sheet rid编号,如果为-1处理所有编号的sheet
|
||||
* @return this
|
||||
* @throws POIException POI异常
|
||||
*/
|
||||
T read(String path, int rid) throws POIException;
|
||||
default T read(String path, int rid) throws POIException {
|
||||
return read(FileUtil.file(path), rid);
|
||||
}
|
||||
|
||||
/**
|
||||
* 开始读取Excel
|
||||
*
|
||||
*
|
||||
* @param path 文件路径
|
||||
* @param rid Excel中的sheet rid编号,如果为-1处理所有编号的sheet
|
||||
* @return this
|
||||
* @throws POIException POI异常
|
||||
*/
|
||||
default T read(String path, String rid) throws POIException {
|
||||
return read(FileUtil.file(path), rid);
|
||||
}
|
||||
|
||||
/**
|
||||
* 开始读取Excel
|
||||
*
|
||||
* @param file Excel文件
|
||||
* @param rid Excel中的sheet rid编号,如果为-1处理所有编号的sheet
|
||||
* @return this
|
||||
* @throws POIException POI异常
|
||||
*/
|
||||
T read(File file, int rid) throws POIException;
|
||||
default T read(File file, int rid) throws POIException{
|
||||
return read(file, String.valueOf(rid));
|
||||
}
|
||||
|
||||
/**
|
||||
* 开始读取Excel,读取结束后并不关闭流
|
||||
*
|
||||
*
|
||||
* @param in Excel流
|
||||
* @param rid Excel中的sheet rid编号,如果为-1处理所有编号的sheet
|
||||
* @return this
|
||||
* @throws POIException POI异常
|
||||
*/
|
||||
T read(InputStream in, int rid) throws POIException;
|
||||
default T read(InputStream in, int rid) throws POIException{
|
||||
return read(in, String.valueOf(rid));
|
||||
};
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.exceptions.DependencyException;
|
||||
import cn.hutool.core.io.IORuntimeException;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.poi.excel.sax.handler.RowHandler;
|
||||
import cn.hutool.poi.exceptions.POIException;
|
||||
import org.apache.poi.ooxml.util.SAXHelper;
|
||||
import org.apache.poi.ss.usermodel.DataFormatter;
|
||||
@ -73,9 +74,9 @@ public class ExcelSaxUtil {
|
||||
}
|
||||
break;
|
||||
case NUMBER:
|
||||
try{
|
||||
try {
|
||||
result = getNumberValue(value, numFmtString);
|
||||
}catch (NumberFormatException e){
|
||||
} catch (NumberFormatException e) {
|
||||
result = value;
|
||||
}
|
||||
break;
|
||||
@ -150,6 +151,7 @@ public class ExcelSaxUtil {
|
||||
public static void readFrom(InputStream xmlDocStream, ContentHandler handler) throws DependencyException, POIException, IORuntimeException {
|
||||
XMLReader xmlReader;
|
||||
try {
|
||||
// xmlReader = XMLReaderFactory.createXMLReader();
|
||||
//noinspection deprecation
|
||||
xmlReader = SAXHelper.newXMLReader();
|
||||
} catch (SAXException | ParserConfigurationException e) {
|
||||
@ -191,6 +193,20 @@ public class ExcelSaxUtil {
|
||||
return DateUtil.date(org.apache.poi.ss.usermodel.DateUtil.getJavaDate(value, false));
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建 {@link ExcelSaxReader}
|
||||
*
|
||||
* @param isXlsx 是否为xlsx格式(07格式)
|
||||
* @param rowHandler 行处理器
|
||||
* @return {@link ExcelSaxReader}
|
||||
* @since 5.4.4
|
||||
*/
|
||||
public static ExcelSaxReader<?> createSaxReader(boolean isXlsx, RowHandler rowHandler) {
|
||||
return isXlsx
|
||||
? new Excel07SaxReader(rowHandler)
|
||||
: new Excel03SaxReader(rowHandler);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取数字类型值
|
||||
*
|
||||
|
@ -0,0 +1,111 @@
|
||||
package cn.hutool.poi.excel.sax;
|
||||
|
||||
import cn.hutool.core.io.IORuntimeException;
|
||||
import cn.hutool.core.io.IoUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.poi.exceptions.POIException;
|
||||
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
|
||||
import org.apache.poi.xssf.eventusermodel.XSSFReader;
|
||||
import org.xml.sax.Attributes;
|
||||
import org.xml.sax.helpers.DefaultHandler;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 在Sax方式读取Excel时,读取sheet标签中sheetId和rid的对应关系,类似于:
|
||||
* <pre>
|
||||
* <sheet name="Sheet6" sheetId="4" r:id="6"/>
|
||||
* </pre>
|
||||
* <p>
|
||||
* 读取结果为:
|
||||
*
|
||||
* <pre>
|
||||
* {"4": "6"}
|
||||
* </pre>
|
||||
*
|
||||
* @author looly
|
||||
* @since 5.4.4
|
||||
*/
|
||||
public class SheetRidReader extends DefaultHandler {
|
||||
|
||||
private final static String TAG_NAME = "sheet";
|
||||
private final static String RID_ATTR = "r:id";
|
||||
private final static String SHEET_ID_ATTR = "sheetId";
|
||||
private final static String NAME_ATTR = "name";
|
||||
|
||||
private final Map<String, String> ID_RID_MAP = new HashMap<>();
|
||||
private final Map<String, String> NAME_RID_MAP = new HashMap<>();
|
||||
|
||||
/**
|
||||
* 读取Wordkbook的XML中sheet标签中sheetId和rid的对应关系
|
||||
*
|
||||
* @param xssfReader XSSF读取器
|
||||
* @return this
|
||||
*/
|
||||
public SheetRidReader read(XSSFReader xssfReader) {
|
||||
InputStream workbookData = null;
|
||||
try {
|
||||
workbookData = xssfReader.getWorkbookData();
|
||||
ExcelSaxUtil.readFrom(workbookData, this);
|
||||
} catch (InvalidFormatException e) {
|
||||
throw new POIException(e);
|
||||
} catch (IOException e) {
|
||||
throw new IORuntimeException(e);
|
||||
} finally {
|
||||
IoUtil.close(workbookData);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据sheetId获取rid
|
||||
*
|
||||
* @param sheetId Sheet的ID
|
||||
* @return rid
|
||||
*/
|
||||
public String getRidBySheetId(String sheetId) {
|
||||
return ID_RID_MAP.get(sheetId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据sheet name获取rid
|
||||
*
|
||||
* @param sheetName Sheet的name
|
||||
* @return rid
|
||||
*/
|
||||
public String getRidByName(String sheetName) {
|
||||
return NAME_RID_MAP.get(sheetName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startElement(String uri, String localName, String qName, Attributes attributes) {
|
||||
if (TAG_NAME.equalsIgnoreCase(localName)) {
|
||||
final int length = attributes.getLength();
|
||||
String sheetId = null;
|
||||
String rid = null;
|
||||
String name = null;
|
||||
for (int i = 0; i < length; i++) {
|
||||
switch (attributes.getLocalName(i)) {
|
||||
case SHEET_ID_ATTR:
|
||||
sheetId = attributes.getValue(i);
|
||||
break;
|
||||
case RID_ATTR:
|
||||
rid = attributes.getValue(i);
|
||||
break;
|
||||
case NAME_ATTR:
|
||||
name = attributes.getValue(i);
|
||||
break;
|
||||
}
|
||||
if (StrUtil.isNotEmpty(sheetId)) {
|
||||
ID_RID_MAP.put(sheetId, rid);
|
||||
}
|
||||
if (StrUtil.isNotEmpty(name)) {
|
||||
NAME_RID_MAP.put(name, rid);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -25,7 +25,7 @@ public class ExcelSaxReadTest {
|
||||
@Test
|
||||
public void excel07Test() {
|
||||
// 工具化快速读取
|
||||
ExcelUtil.read07BySax("aaa.xlsx", 0, createRowHandler());
|
||||
ExcelUtil.readBySax("aaa.xlsx", 0, createRowHandler());
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -33,7 +33,7 @@ public class ExcelSaxReadTest {
|
||||
Excel03SaxReader reader = new Excel03SaxReader(createRowHandler());
|
||||
reader.read("aaa.xls", 1);
|
||||
// Console.log("Sheet index: [{}], Sheet name: [{}]", reader.getSheetIndex(), reader.getSheetName());
|
||||
ExcelUtil.read03BySax("aaa.xls", 1, createRowHandler());
|
||||
ExcelUtil.readBySax("aaa.xls", 1, createRowHandler());
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -60,7 +60,7 @@ public class ExcelSaxReadTest {
|
||||
|
||||
private RowHandler createRowHandler() {
|
||||
return (sheetIndex, rowIndex, rowlist) -> {
|
||||
// Console.log("[{}] [{}] {}", sheetIndex, rowIndex, rowlist);
|
||||
// Console.log("[{}] [{}] {}", sheetIndex, rowIndex, rowlist);
|
||||
if (5 != rowIndex && 6 != rowIndex) {
|
||||
// 测试样例中除第五行、第六行都为非空行
|
||||
Assert.assertTrue(CollUtil.isNotEmpty(rowlist));
|
||||
@ -105,14 +105,14 @@ public class ExcelSaxReadTest {
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void dateReadTest(){
|
||||
public void dateReadTest() {
|
||||
ExcelUtil.readBySax("d:/test/sax_date_test.xlsx", 0, (i, i1, list) ->
|
||||
Console.log(StrUtil.join(", ", list)));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void readBlankTest(){
|
||||
public void readBlankTest() {
|
||||
File file = new File("D:/test/b.xlsx");
|
||||
|
||||
ExcelUtil.readBySax(file, 0, (sheetIndex, rowIndex, rowList) -> rowList.forEach(Console::log));
|
||||
|
@ -8,7 +8,7 @@
|
||||
<parent>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-parent</artifactId>
|
||||
<version>5.4.4-SNAPSHOT</version>
|
||||
<version>5.4.5-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hutool-script</artifactId>
|
||||
@ -18,7 +18,7 @@
|
||||
<properties>
|
||||
<jython.version>2.7.2</jython.version>
|
||||
<luaj.version>3.0.1</luaj.version>
|
||||
<groovy.version>3.0.2</groovy.version>
|
||||
<groovy.version>3.0.6</groovy.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
|
@ -9,7 +9,7 @@
|
||||
<parent>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-parent</artifactId>
|
||||
<version>5.4.4-SNAPSHOT</version>
|
||||
<version>5.4.5-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hutool-setting</artifactId>
|
||||
|
@ -9,7 +9,7 @@
|
||||
<parent>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-parent</artifactId>
|
||||
<version>5.4.4-SNAPSHOT</version>
|
||||
<version>5.4.5-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hutool-socket</artifactId>
|
||||
|
@ -9,7 +9,7 @@
|
||||
<parent>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-parent</artifactId>
|
||||
<version>5.4.4-SNAPSHOT</version>
|
||||
<version>5.4.5-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hutool-system</artifactId>
|
||||
|
2
pom.xml
2
pom.xml
@ -8,7 +8,7 @@
|
||||
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-parent</artifactId>
|
||||
<version>5.4.4-SNAPSHOT</version>
|
||||
<version>5.4.5-SNAPSHOT</version>
|
||||
<name>hutool</name>
|
||||
<description>Hutool是一个小而全的Java工具类库,通过静态方法封装,降低相关API的学习成本,提高工作效率,使Java拥有函数式语言般的优雅,让Java语言也可以“甜甜的”。</description>
|
||||
<url>https://github.com/looly/hutool</url>
|
||||
|
Loading…
Reference in New Issue
Block a user