以下JSON結(jié)構(gòu)為例
{
key1:{
key11:{
key111:111 //提取111 value(map,key1,key11, key111)
},
key12:{
key121:{
key1211:1211,
key1212:1212 //提取1212 value(map,key1, key12, key121, key1212)
}
}
}
}
/ *
* @param src 數(shù)據(jù)源
* @param voluntary 遇到基礎(chǔ)類型是否停止(不取下一級(jí))
* voluntary=false時(shí)遇到提取基礎(chǔ)類型屬性值時(shí)返回null
* voluntary=true時(shí)遇到提取基礎(chǔ)類型屬性值時(shí)返回當(dāng)前value并return value
* @param keys keys 一級(jí)key.二級(jí)key.三級(jí)key
* @return Object
*/
public static Object extract(Object src, boolean voluntary, String ... keys);
BeanUtil.extract(json,"key1","key11","key111");//提取111
//如果中途遇到基礎(chǔ)類型,如key111的值是1111,但1111并沒有key0屬性
BeanUtil.extract(json,false,"key1","key11","key111","key0"); //返回null
BeanUtil.extract(json,true,"key1","key11","key111","key0"); //遇到基礎(chǔ)類型停止 直接返回1111
String ymd = DateBuilder.init().addYear(1).addDay(-1).format("yyyy-MM-dd");
在JAVA_HOME/jre/lib/securiy目錄下執(zhí)行 keytool -keystore cacerts -importcert -alias 別名 -file 上一步下載的文件,如果找不到keytool命令配置一下path
如果設(shè)置xy為小數(shù)則按長或?qū)挼陌俜直扔?jì)算偏移量如wihth=100,x=0.5則按左側(cè)偏移50(100*0.5)像素
?WatermarkUtil util = new WatermarkUtil();?
在左上(10,10)生成水印
util.offset(10,10);
在距離右下邊距(10,10)生成水印
util.offset(-10,-10);
在左上10%,10%生成水印
util.offset(0.1,0.1);
在距離右下邊距(10%,10%)生成水印
util.offset(-0.1,-0.1);
生成水印并保存成新文件
util.makeIcon(iconFike, srcFile, dstFile);
生成水印并覆蓋原文件
util.makeIcon(iconFike, srcFile);
指定水印長寬
util.makeIcon(iconFike, iconWidth, iconHeight,srcFile, dstFile);
把item文件壓縮到zip文件中
如果item是一個(gè)目錄,則遞歸item中所有文件
如果zip已存在則覆蓋原文件
public static boolean zip(File item, File zip)
ZipUtil.zip(new File("D:\\users\\user.xml"), new File("D:\\user.zip"));
ZipUtil.zip(new File("D:\\users"), new File("D:\\user.zip"));
把item文件壓縮到zip文件中的dir目錄
public static boolean zip(File item, File zip, String dir)
public static boolean zip(Collection<file> items, File zip)
把items文件集合壓縮到zip文件中,以key作為壓縮目錄
public static boolean zip(Map<string,file> items, File zip)
//替換zip壓縮包中的item文件
public static void replace(File zip, File content, String item)
public static void replace(File zip, String content, String item)
//刪除zip壓縮包中的item文件
public static boolean remove(File zip, String item)
//讀取zip壓縮包中的item文件內(nèi)容
public static InputStream read(File zip, String item)
public static String read(File zip, String item, String encode)
</string,file></file>
//zip壓縮包中的item文件替換成content文件
public static void replace(File zip, File content, String item)
//zip壓縮包中的item文件替換成content內(nèi)容
public static void replace(File zip, String content, String item)
public static boolean append(File item, File zip, String dir, String comment)
public static boolean append(File item, File zip)
刪除zip中的item文件(含目錄)
public static boolean remove(File zip, String item)
ZipUtil.remove(new File(”users.zip“),"user1.xml")
ZipUtil.remove(new File(”users.zip“),"list/user1.xml")
//讀取zip壓縮包中的item文件內(nèi)容
public static InputStream read(File zip, String item)
以String格式返回
public static String read(File zip, String item, String encode)
視頻截圖需要依賴anyline-video
取第index幀截圖
VideoUtil.frame(videoFile,imgFile,indx);
取中間幀截圖
VideoUtil.frame(videoFile,imgFile);
導(dǎo)出excel時(shí)如果每行需要一個(gè)序號(hào)可以用{num}來代替屬性名,如
export(file, list, "序號(hào):{num}","姓名:NAME","年齡:AGE")
1 | 張三 | 20 |
2 | 李四 | 22 |
3 | 王五 | 25 |
在導(dǎo)出excel時(shí)有可能不是每行一個(gè)序號(hào),而是每組一個(gè)序號(hào),如按部門分組,每個(gè)部門一個(gè)序號(hào)
1 | 人事部 | 張三 | 20 |
張三三 | 22 | ||
2 | 財(cái)務(wù)部 | 李四 | 25 |
王五 | 26 | ||
王五五 | 20 |
這時(shí)num需要部門列來合并單元格
TableBuilder builder = TableBuilder.init()
.setDatas(set) //設(shè)置數(shù)據(jù)源
.setFields("{num}(DEPARTMENT_NAME)"
,"DEPARTMENT_NAME"
,"USER_NAME"
,"USER_AGE") //設(shè)置需要導(dǎo)出的屬性(列)
.addUnion("DEPARTMENT_NAME"); /設(shè)置需要合并行的列,如果年相同的合并,月相同的合并(前提是年相同)
File file = new File("模板地址");
ExcelUtil.export(file, "sheet名稱", 2, builder.build()); //從第2行插入(根據(jù)表頭行數(shù))
TableBuilder.init()
.setMergeCellHorizontalAlign("center") //設(shè)置合并單元格水平對(duì)齊方式
.setMergeCellVerticalAlign("center") //設(shè)置合并單元格垂直對(duì)齊方式
TableBuilder.init()
.setHorizontalAlign("CHECK_CODE", "center")
.setVerticalAlign("CHECK_CODE", "top")
有些情況下,需要把空值替換成其他固定的符號(hào)如(/)
這時(shí)可以設(shè)置這些單元格的對(duì)齊方式
TableBuilder.init()
.setEmptyCellVerticalAlign("top")
.setEmptyCellHorizontalAlign("center")
TableBuilder.init()..setCellBorder(true)
數(shù)據(jù)是這樣
模板是這樣
導(dǎo)出后是這樣
DataSet set = new DataSet();
DataRow row = new DataRow();
row.put("Y","2020");
row.put("M","1");
row.put("D","1");
set.add(row);
DataRow row2 = new DataRow();
row2.put("Y","2020");
row2.put("M","1");
row2.put("D","2");
set.add(row2);
DataRow row3 = new DataRow();
row3.put("Y","1999");
row3.put("M","1");
row3.put("D", null);
set.add(row3);
set.replaceEmpty("/");//替換空值的數(shù)據(jù)
TableBuilder builder = TableBuilder.init()
.setDatas(set)//設(shè)置數(shù)據(jù)源
.setFields("Y","M","D")//設(shè)置需要導(dǎo)出的屬性(列)
.addUnion("Y","M(Y)");//設(shè)置需要合并行的列,如果年相同的合并,月相同的合并(前提是年相同)
File file = new File("模板地址");
ExcelUtil.export(file, "sheet名稱", 2, builder.build()); //從第2行插入(根據(jù)表頭行數(shù))
System.out.println(builder.build().build()); //看一下輸入對(duì)應(yīng)的html
用戶提交的excel內(nèi)容經(jīng)常不固定行列,而是需要根據(jù)單元格內(nèi)容來確定表頭位置或數(shù)據(jù)起止位置。
如根據(jù)內(nèi)容中包含"結(jié)算日期"的單元格來確定當(dāng)前行是表頭,下一行是數(shù)據(jù)
根據(jù)內(nèi)容中包含"會(huì)計(jì)年度"的單元格來確定當(dāng)前數(shù)據(jù)年度。
int[] position = org.anyline.poi.excel.ExcelUtil.position(file.getInputStream(),"時(shí)間.*");
返回第1個(gè)包含"時(shí)間"的單元格位置(下標(biāo)從0開始)
支持正則表達(dá)式,
可以根據(jù)返回的坐標(biāo)來讀取單元格內(nèi)容
String value = ExcelUtil.value(File或InputStream, position[0], position[1]);
以上默認(rèn)第0個(gè)Sheet頁,可以指定Sheet下標(biāo)或名稱
File file = new File(dir,"template_102.xlsx");
ExcelReader reader = ExcelReader.init()
.setFile(file) //文件位置
.setSheet(1) //讀取第1個(gè)sheet(下標(biāo)從0開始)
.setHead(0) //表頭在第0行,如果沒有表頭,結(jié)果集以下標(biāo)作為key
.setData(1) //數(shù)據(jù)從第1行開始
.setFoot(1) //到第1行結(jié)束(如果負(fù)數(shù)表示 表尾有多少行不需要讀取)
;
DataSet set = reader.read();
log.warn(set.toJSON());
TableBuilder builder = TableBuilder.init()
.setDatas(set) //設(shè)置數(shù)據(jù)源
.setFields( //需要導(dǎo)出的列
"{num}(EMPLOYEE_NM)" //{num}表示序號(hào),(DEPARTMENT_NM)表示根據(jù)哪一列計(jì)算序號(hào),這里部門名稱需要分組合并,所以num不是按行計(jì)算
,"DEPARTMENT_NM"
,"EMPLOYEE_NM"
,"YM"
,"BASE_PRICE")
.addUnion( //需要合并的列
"DEPARTMENT_NM" //如果部門名稱相同則合并
,"EMPLOYEE_NM(DEPARTMENT_NM)"
,"YM(DEPARTMENT_NM)" //如果月份相同則合并,前提是部門已經(jīng)合并
)
.setReplaceEmpty("/") //如果值為空則以/代替
.addIgnoreUnionValue("/") //不參與合并的值
.setCellBorder(true) //設(shè)置默認(rèn)邊框
.setMergeCellHorizontalAlign("center") //設(shè)置合并的列 水平對(duì)齊方式
.setMergeCellVerticalAlign("top") //設(shè)置合并的列 垂直對(duì)齊方式
.setEmptyCellHorizontalAlign("center") //設(shè)置空單元格 水平對(duì)齊方式(為空時(shí)有可能需要替換成其他值)
.setEmptyCellVerticalAlign("top") //設(shè)置空單元格 垂直對(duì)齊方式
.setHorizontalAlign("YM","center") //設(shè)置月份列 水平對(duì)齊方式
.setVerticalAlign("middle") //設(shè)置所有數(shù)據(jù)單元格 垂直對(duì)齊方式
.setLineHeight("50px") //設(shè)置數(shù)據(jù)區(qū)域行高
.setWidth("YM","200px") //設(shè)置月份列 寬度
;
Table table = builder.build();
File file = new File(dir, "export_table.xlsx");
ExcelUtil.export(file, table);
DataSet set = service.querys("V_HR_SALARY","YYYY:"+ (DateUtil.year()-1), "ORDER BY EMPLOYEE_ID, YM");
//最簡單的導(dǎo)出一個(gè)列表,如果文件已存在,則在原文件內(nèi)容基礎(chǔ)上插入行
File file = new File(dir,"export_list.xlsx");
//1表示從第1行插入,如果原來文件有內(nèi)容,則下移
//{num}表示第幾行,下標(biāo)從1開始
//這里支持復(fù)合KEY
ExcelUtil.export(file,1, set,"序號(hào):{num}","部門:DEPARTMENT_NM","姓名:EMPLOYEE_NM","月份:YM","底薪:{BASE_PRICE}+{REWARD_PRICE}");
//如果表頭、表尾格式比較復(fù)雜,可先創(chuàng)建模板,再根據(jù)模板導(dǎo)出
File template = new File(dir,"template.xlsx");//這里是一個(gè)模板文件
//根據(jù)模板導(dǎo)出時(shí)就不需要指定表頭了,只要對(duì)應(yīng)好順序,并計(jì)算好從哪一行開始寫入
if(template.exists()) {
ExcelUtil.export(template, file, 1, set, "{num}", "DEPARTMENT_NM", "EMPLOYEE_NM", "YM", "{BASE_PRICE}+{REWARD_PRICE}");
}
File file = new File(dir,"export_table.xlsx");
List list = ExcelUtil.read(file); //默認(rèn)讀取第0個(gè)sheet從第0行開始
list = ExcelUtil.read(file,1,3); //讀取第1個(gè)sheet從第3行讀取
//遇到合并單元格的,將拆分開未合并前的狀態(tài),拆分后補(bǔ)上每個(gè)單元格的值
//返回的是一個(gè)二維數(shù)組
//為了操作方便可以把返回值轉(zhuǎn)換成DataSet,DataSet中的條目(DataRow)以excel列下標(biāo)作為屬性key
DataSet set = new DataSet(list);
//默認(rèn)情況下導(dǎo)出的第0個(gè)sheet也就是sheet1
//如果要導(dǎo)出到多個(gè)sheet需要執(zhí)行多次export導(dǎo)出到同一個(gè)文件,每次執(zhí)行時(shí)指定sheet名稱或下標(biāo)
Table table = null;
File file = new File(dir, "export_sheet.xlsx");
ExcelUtil.export(file, "shet1", table);
ExcelUtil.export(file, "shet2", table);
public static boolean export(File file, String sheet, int rows, DataSet set, String ... configs)
如果文件存在則在當(dāng)前文件中插入數(shù)據(jù),如果文件不存在則新創(chuàng)建文件
這里的sheet如果在file中已存在,則往這個(gè)sheet中插入數(shù)據(jù),如果不存在則新創(chuàng)建sheet再繼續(xù)插入數(shù)據(jù),其他重載函數(shù)規(guī)則相同。
如
File file = new File();
export(file, "s1",0, set, "ID"); //這一行執(zhí)行完成后在文件中有一個(gè)sheet(s1)
export(file, "s2",0, set, "ID");//這一行執(zhí)行完后文件中有兩個(gè)sheet(s1,s2)
讀取被合并行的單元格時(shí),會(huì)從當(dāng)前合并組中取第一個(gè)單元格的值
以上讀取結(jié)果[[11, 12, 13], [21, 22, 23], [21, 32, 33]]
org.anyline.poi.excel.ExcelUtil提供了讀取excel的工具,
file:需要讀取的文件
sheet:需要讀取的sheet名稱或下標(biāo)
rows:從第幾行開始讀取
返回二維List<List<String>>
public static List<List<String>> read(File file, int sheet, int rows)
public static List<List<String>> read(File file, int sheet)
public static List<List<String>> read(File file)
public static List<List<String>> read(File file, String sheet, int rows)
public static List<List<String>> read(File file, String sheet)
導(dǎo)出excel兩種情況:有模板或沒有模板
如果沒有模板直接導(dǎo)出一個(gè)新文件
如果有模板則在原模板基礎(chǔ)上追加內(nèi)容
如果模板文件中有多個(gè)sheet一般是先復(fù)制一個(gè)新文件,再以新文件作為輸入?yún)?shù)調(diào)用多次沒有模板參數(shù)的export()往新文件中的插入數(shù)據(jù)
/**
* 導(dǎo)出EXCEL
* @param file 導(dǎo)致文件位置,如果文件已存存,則以當(dāng)前文件作為模板
* @param rows 開始寫入的行數(shù)
* @param headers 表頭
* @param keys 讀取集合條目的屬性
* @param set 數(shù)據(jù)集合
* @return boolean
*/
public static boolean export(File file, int rows, List<String>headers, List<String> keys, DataSet set)
/**
* 導(dǎo)出EXCEL
* @param file 導(dǎo)致文件位置,如果文件已存存,則以當(dāng)前文件作為模板
* @param keys 讀取集合條目的屬性
* @param set 數(shù)據(jù)集合
* @return boolean
*/
public static boolean export(File file, List<String> keys, DataSet set)
/**
* 導(dǎo)出EXCEL
* @param file 導(dǎo)致文件位置,如果文件已存存,則以當(dāng)前文件作為模板
* @param headers 表頭
* @param keys 讀取集合條目的屬性
* @param set 數(shù)據(jù)集合
* @return boolean
*/
public static boolean export(File file, List<String> headers,List<String> keys, DataSet set)
/**
* 導(dǎo)出EXCEL
* @param file 導(dǎo)致文件位置,如果文件已存存,則以當(dāng)前文件作為模板
* @param rows 從第幾行開始寫入
* @param keys 讀取集合條目的屬性
* @param set 數(shù)據(jù)集合
* @return boolean
*/
public static boolean export(File file, int rows, List<String> keys, DataSet set)
/**
* 導(dǎo)出excel
* @param file 導(dǎo)致文件位置,如果文件已存存,則以當(dāng)前文件作為模板
* @param sheet sheet 如果文件存在 并且為空時(shí) 則取第0個(gè)sheet
* @param rows 行數(shù)
* @param set 數(shù)據(jù)
* @param configs 姓名:NAME或NAME
* @return boolean
*/
public static boolean export(File file, String sheet, int rows, DataSet set, String ... configs)
/**
* 導(dǎo)出excel
* @param file 導(dǎo)致文件位置,如果文件已存存,則以當(dāng)前文件作為模板
* @param rows 行數(shù)
* @param set 數(shù)據(jù)
* @param configs 姓名:NAME或NAME
* @return boolean
*/
public static boolean export(File file, int rows, DataSet set, String ... configs)
/**
* 導(dǎo)出excel
* @param file 導(dǎo)致文件位置,如果文件已存存,則以當(dāng)前文件作為模板
* @param set 數(shù)據(jù)
* @param configs 姓名:NAME或NAME
* @return boolean
*/
public static boolean export(File file, DataSet set, String ... configs)
以下需要有模板文件
/**
* 導(dǎo)出EXCEL
* @param template 模板
* @param file 導(dǎo)致文件位置
* @param headers 表頭 headers 表頭
* @param sheet sheet
* @param insert 導(dǎo)出的開始位置
* @param keys 對(duì)應(yīng)列名屬性名 keys 對(duì)應(yīng)列名屬性名
* @param set 數(shù)據(jù)源 set 數(shù)據(jù)源
* @return return
*/
public static boolean export(File template, File file, String sheet, int insert, List<String>headers, List<String> keys, DataSet set)
/**
* 導(dǎo)出EXCEL
* @param file 導(dǎo)致文件位置,如果文件已存存,則以當(dāng)前文件作為模板
* @param rows 開始寫入的行數(shù)
* @param headers 表頭
* @param keys 讀取集合條目的屬性
* @param set 數(shù)據(jù)集合
* @return boolean
*/
public static boolean export(File template, File file, int rows, List<String>headers, List<String> keys, DataSet set)
/**
* 導(dǎo)出EXCEL
* @param file 導(dǎo)致文件位置,如果文件已存存,則以當(dāng)前文件作為模板
* @param keys 讀取集合條目的屬性
* @param set 數(shù)據(jù)集合
* @return boolean
*/
public static boolean export(File template, File file, List<String> keys, DataSet set)
/**
* 導(dǎo)出EXCEL
* @param file 導(dǎo)致文件位置,如果文件已存存,則以當(dāng)前文件作為模板
* @param headers 表頭
* @param keys 讀取集合條目的屬性
* @param set 數(shù)據(jù)集合
* @return boolean
*/
public static boolean export(File template, File file, List<String> headers,List<String> keys, DataSet set)
/**
* 導(dǎo)出EXCEL
* @param file 導(dǎo)致文件位置,如果文件已存存,則以當(dāng)前文件作為模板
* @param rows 從第幾行開始寫入
* @param keys 讀取集合條目的屬性
* @param set 數(shù)據(jù)集合
* @return boolean
*/
public static boolean export(File template, File file, int rows, List<String> keys, DataSet set)
/**
* 導(dǎo)出excel
* @param file 導(dǎo)致文件位置,如果文件已存存,則以當(dāng)前文件作為模板
* @param sheet sheet 如果文件存在 并且為空時(shí) 則取第0個(gè)sheet
* @param rows 行數(shù)
* @param set 數(shù)據(jù)
* @param configs 姓名:NAME或NAME
* @return boolean
*/
public static boolean export(File template, File file, String sheet, int rows, DataSet set, String ... configs)
/**
* 導(dǎo)出excel
* @param file 導(dǎo)致文件位置,如果文件已存存,則以當(dāng)前文件作為模板
* @param rows 行數(shù)
* @param set 數(shù)據(jù)
* @param configs 姓名:NAME或NAME
* @return boolean
*/
public static boolean export(File template, File file, int rows, DataSet set, String ... configs)
/**
* 導(dǎo)出excel
* @param file 導(dǎo)致文件位置,如果文件已存存,則以當(dāng)前文件作為模板
* @param set 數(shù)據(jù)
* @param configs 姓名:NAME或NAME
* @return boolean
*/
public static boolean export(File template, File file, DataSet set, String ... configs)
//獲取所有超鏈接(a標(biāo)簽)
/*
* 提取單標(biāo)簽+雙標(biāo)簽
* 不區(qū)分大小寫
* 0:全文 1:開始標(biāo)簽 2:標(biāo)簽name 3:標(biāo)簽體 (單標(biāo)簽時(shí)null) 4:結(jié)束標(biāo)簽 (單標(biāo)簽時(shí)null)
* 注意標(biāo)簽體有可能是HTML片段,而不是純文本
*/
List<List<String>> list = RegularUtil.fetchAllTag(html,"a");
log.warn("標(biāo)簽數(shù)量:"+list.size());
for(List<String> item:list){
log.warn("全文:"+item.get(0));
log.warn("開始標(biāo)簽:"+item.get(1));
log.warn("標(biāo)簽名稱:"+item.get(2));
log.warn("標(biāo)簽體:"+item.get(3));
log.warn("結(jié)束標(biāo)簽:"+item.get(4));
}
//抽取所有 a標(biāo)簽和li標(biāo)簽
//一定注意:這里的a有可能被包含在li內(nèi)部,這時(shí)的a不會(huì)再抽取
list = RegularUtil.fetchAllTag(html,"a","li");
從html中抽取多個(gè)標(biāo)簽,如需要抽取a標(biāo)簽和li標(biāo)簽
最簡單的是抽取兩次
RegularUtil.fetchAllTag(html,"a")
RegularUtil.fetchAllTag(html,"li")
但這樣有個(gè)問題,兩個(gè)標(biāo)簽的順序會(huì)亂,
如果需要保持順序可以通過
RegularUtil.fetchAllTag(html,"a","li");
但是一定注意:這里的a有可能被包含在li內(nèi)部,這時(shí)li中的a不會(huì)再單獨(dú)抽取
//放多情況下我們并不需要復(fù)雜的標(biāo)簽內(nèi)容,只需要截取幾個(gè)關(guān)鍵字
//如提取商品名稱和商品價(jià)格,而這兩個(gè)值有可能是根其他內(nèi)容混在一塊的
//如以下這段源碼
String html ="<div class='title' data-product='1001'>商品名稱(限時(shí))</div>"
+"<div class='price'>一個(gè)貨幣符號(hào):100.00</div>";
//這時(shí)可以通過字符串截取的方式提取出價(jià)格
//第0個(gè)參數(shù):源數(shù)據(jù)
//第1個(gè)到倒數(shù)第2個(gè)參數(shù):100.00(就是我們要提取的價(jià)格) 之前出現(xiàn)的關(guān)鍵字
//最后1個(gè)參數(shù):100.00之后出現(xiàn)的第1個(gè)關(guān)鍵字
//參數(shù)順序: 源碼,k1,k2,k3,kn-1,內(nèi)容,kn
String price = RegularUtil.cut(html, "price",":","</div>");
log.warn("價(jià)格:{}",price);
//許多情況下price有可能在源碼中出現(xiàn)多次,這時(shí)需要多個(gè)關(guān)鍵字的組合來確認(rèn)100.00的位置
html = DateUtil.format("yyyy-MM-dd")+ "<div class='title' data-product='1001'>商品名稱(限時(shí))</div>" +
"div class='src-price price'></div>" +
"<div class='price'>一個(gè)貨幣符號(hào):100.00</div>元";
price = RegularUtil.cut(html,"src-price","price", "price",":","</div>");
log.warn("價(jià)格:{}",price);
//如果需要提取的內(nèi)容在最后 如上面的單位:元
String unit = RegularUtil.cut(html,"src-price","price", "price",":","</div>", RegularUtil.TAG_END);
log.warn("單位:{}", unit);
//同樣的如果需要提取的內(nèi)容在最開始位置 如上面的日期
String ymd = RegularUtil.cut(html, RegularUtil.TAG_BEGIN, "<");
log.warn("日期:{}", ymd);
更多建議: