anyline 入門

2022-09-16 11:34 更新

配置maven環(huán)境

如果需要私服參考這里>maven私服

通常情況下每個(gè)公司會(huì)有自己的*-starter或*-dependency來(lái)統(tǒng)一管理maven依賴版本號(hào)

如:用anyline-simple-dependency來(lái)定義所有外部依賴的版本號(hào)

anyline-simple-start-mvc-mysql繼承anyline-simple-dependency并添加mvc與mysql的依賴,

有需要myql和mvc環(huán)境的項(xiàng)目繼承自anyline-simple-start-mvc-mysql

常用示例

源碼地址: https://gitee.com/anyline/anyline-simple

關(guān)于更新部分屬性(列)、忽略部分屬性(列)

添加到DataRow中但不需要參與更新(插入)

row.put("-NAME", "ZH");


添加了空值,  默認(rèn)情況下不參與更新(插入) 如果需要強(qiáng)制參與更新(插入)

row.put("+NAME",null);


如果這樣指定了更新(插入)列,則只會(huì)更新(插入)指定的列,其他列都不會(huì)參與更新(插入)

service.save(row,"NAME");


強(qiáng)制更新(插入)NAME,忽略CODE,其他列不受影響,按默認(rèn)情況處理

service.save(row,"+NAME","-CODE");


插入所有列,更新所有值發(fā)生過(guò)變化的列

service.save(row);

關(guān)于自動(dòng)檢測(cè)表結(jié)構(gòu)

在執(zhí)行數(shù)據(jù)庫(kù)操作時(shí),許多參數(shù)是以String形式獲取到的,無(wú)法參數(shù)識(shí)別數(shù)據(jù)類型,如url中的參數(shù)

還有一些數(shù)據(jù)類型在Java中沒(méi)有對(duì)應(yīng)關(guān)系,如xml/josn/幾何圖形等

而有些數(shù)據(jù)庫(kù)在執(zhí)行SQL時(shí)會(huì)執(zhí)行強(qiáng)類型檢測(cè)。

不像我們平時(shí)用的MySQL在執(zhí)行時(shí)會(huì)進(jìn)行隱式轉(zhuǎn)換,無(wú)論什么類型只要能轉(zhuǎn)換成功就可以執(zhí)行。

而PostgreSQL則要求jdbc參數(shù)與表結(jié)構(gòu)對(duì)應(yīng),如果在varchar列中執(zhí)行int類型會(huì)失敗。

要求開(kāi)發(fā)人員在編碼過(guò)程中記住表數(shù)據(jù)類型,或進(jìn)行類型轉(zhuǎn)換顯示不合理,何況表結(jié)構(gòu)有可能會(huì)變動(dòng)。

可以開(kāi)啟表結(jié)構(gòu)自動(dòng)檢測(cè),在執(zhí)行SQL前把參數(shù)轉(zhuǎn)換成與表結(jié)構(gòu)對(duì)應(yīng)的類型

這樣就可以像MySQL一樣隨意了

ConfigTable.IS_AUTO_CHECK_METADATA = true;可以參考anyline-simple-jdbc-postgresql

DataSet構(gòu)造多級(jí)樹(shù)型結(jié)構(gòu)

表結(jié)構(gòu)類似這樣

IDBASE_IDNAME
1NULL中國(guó)
21山東
32濟(jì)南
42青島
52煙臺(tái)
63歷下區(qū)
73天橋區(qū)
84市南區(qū)
94城陽(yáng)區(qū)

//先取出完整列表

DataSet set = service.querys("SYS_AREA"); 

//ID:主鍵  BASE_ID:表示上一級(jí)ID的列名

set.dispatchs(true,true, "ID:BASE_ID"); 

set.dispatchs("children",true,true, "ID:BASE_ID");

//執(zhí)行完成后會(huì)把每個(gè)DataRow中存入當(dāng)前DataRow的下一級(jí)

//這里會(huì)生成多個(gè)樹(shù)型結(jié)構(gòu),一般需要根據(jù)ID取出最頂級(jí)的DataRow  set.getRow("ID",1);

get(String key)與getString(String key)的區(qū)別

get(String key)與Map的get(String key)效果一樣

getString(String key)支持表達(dá)式getString("${ID}-${NAME}")

關(guān)于分頁(yè)參數(shù)

默認(rèn)的分頁(yè)參數(shù)名比較長(zhǎng):

public static String DEFAULT_KEY_PAGE_ROWS          = "_anyline_page_rows"          ; //設(shè)置每頁(yè)顯示多少條的key
public static String DEFAULT_KEY_PAGE_NO            = "_anyline_page"               ; //設(shè)置當(dāng)前第幾頁(yè)的key
public static String DEFAULT_KEY_TOTAL_PAGE         = "_anyline_total_page"         ; //顯示一共多少頁(yè)的key
public static String DEFAULT_KEY_TOTAL_ROW          = "_anyline_total_row"          ; //顯示一共多少條的key
public static String DEFAULT_KEY_SHOW_STAT          = "_anyline_navi_show_stat"     ; //設(shè)置是否顯示統(tǒng)計(jì)數(shù)據(jù)的key
public static String DEFAULT_KEY_SHOW_JUMP          = "_anyline_navi_show_jump"     ; //設(shè)置是否顯示頁(yè)數(shù)跳轉(zhuǎn)key
public static String DEFAULT_KEY_SHOW_VOL           = "_anyline_navi_show_vol"      ; //設(shè)置是否顯示每頁(yè)條數(shù)設(shè)置key
public static String DEFAULT_KEY_GUIDE              = "_anyline_navi_guide"         ; //設(shè)置分頁(yè)樣式的key
public static String DEFAULT_KEY_ID_FLAG            = "_anyline_navi_conf_"         ; //生成配置文件標(biāo)識(shí)
public String KEY_PAGE_ROWS         = DEFAULT_KEY_PAGE_ROWS         ; //設(shè)置每頁(yè)顯示多少條的key
public String KEY_PAGE_NO           = DEFAULT_KEY_PAGE_NO           ; //設(shè)置當(dāng)前第幾頁(yè)的key
public String KEY_TOTAL_PAGE        = DEFAULT_KEY_TOTAL_PAGE        ; //顯示一共多少頁(yè)的key
public String KEY_TOTAL_ROW         = DEFAULT_KEY_TOTAL_ROW         ; //顯示一共多少條的key
public String KEY_SHOW_STAT         = DEFAULT_KEY_SHOW_STAT         ; //設(shè)置是否顯示統(tǒng)計(jì)數(shù)據(jù)的key
public String KEY_SHOW_JUMP         = DEFAULT_KEY_SHOW_JUMP         ; //設(shè)置是否顯示頁(yè)數(shù)跳轉(zhuǎn)key
public String KEY_SHOW_VOL          = DEFAULT_KEY_SHOW_VOL          ; //設(shè)置是否顯示每頁(yè)條數(shù)設(shè)置key
public String KEY_GUIDE             = DEFAULT_KEY_GUIDE             ; //設(shè)置分頁(yè)樣式的key
public String KEY_ID_FLAG           = DEFAULT_KEY_ID_FLAG           ; //生成配置文件標(biāo)識(shí)

是為了防止跟業(yè)務(wù)參數(shù)重名,但一般項(xiàng)目不會(huì)寫(xiě)這長(zhǎng)啰嗦的參數(shù)名可以在配置文件anyline-navi.xml中修改參數(shù)名

<!--當(dāng)前第幾頁(yè)-->

<property key="KEY_PAGE_NO">page</property>或者直接寫(xiě)在Java中,一般寫(xiě)在啟動(dòng)類中

PageNaviConfig.DEFAULT_KEY_PAGE_NO = "page"; 
PageNaviConfig.DEFAULT_KEY_PAGE_ROWS = "size";
PageNaviConfig.DEFAULT_VAR_PAGE_MAX_VOL = 1000;
PageNaviConfig.DEFAULT_VAR_CLIENT_SET_VOL_ENABLE = true;

幾個(gè)常用的配置參數(shù)

//DataRow的key大小寫(xiě)(默認(rèn)大寫(xiě))
DataRow.DEFAULT_KEY_KASE = KeyAdapter.KEY_CASE.LOWER;
//http分頁(yè)參數(shù)-當(dāng)前當(dāng)前第幾頁(yè)(默認(rèn)page)
PageNaviConfig.DEFAULT_KEY_PAGE_NO = "pageNum";
//http分頁(yè)參數(shù)-每頁(yè)多少條(默認(rèn)vol)
PageNaviConfig.DEFAULT_KEY_PAGE_ROWS = "pageSize";
//是否允許前端設(shè)置每頁(yè)多少條(默認(rèn)false)
PageNaviConfig.DEFAULT_VAR_CLIENT_SET_VOL_ENABLE = true;

關(guān)于日期類的鏈?zhǔn)讲僮?/h3>

String ymd = DateBuilder.init().addYear(1).addDay(-1).format("yyyy-MM-dd");

excel根據(jù)內(nèi)容定位單元格

用戶提交的excel內(nèi)容經(jīng)常不固定行列,而是需要根據(jù)單元格內(nèi)容來(lái)確定表頭位置或數(shù)據(jù)起止位置。

如根據(jù)內(nèi)容中包含"結(jié)算日期"的單元格來(lái)確定當(dāng)前行是表頭,下一行是數(shù)據(jù)

根據(jù)內(nèi)容中包含"會(huì)計(jì)年度"的單元格來(lái)確定當(dāng)前數(shù)據(jù)年度。

int[] position = org.anyline.poi.excel.ExcelUtil.position(file.getInputStream(),"時(shí)間.*");

返回第1個(gè)包含"時(shí)間"的單元格位置(下標(biāo)從0開(kāi)始)

支持正則表達(dá)式,

可以根據(jù)返回的坐標(biāo)來(lái)讀取單元格內(nèi)容

 String value = ExcelUtil.value(File或InputStream, position[0], position[1]);

以上默認(rèn)第0個(gè)Sheet頁(yè),可以指定Sheet下標(biāo)或名稱

IN條件下多種參數(shù)格式的接收

對(duì)于標(biāo)準(zhǔn)的url格式 /list?id=1&id=2

以及標(biāo)準(zhǔn)的json格式 {id:[1,2]}

可以通過(guò)condition("ID:[id]")的形式接收

對(duì)于非標(biāo)準(zhǔn)格式如 /list?id=1,2

可以通過(guò)condition("ID:[split(id)]")的形式接收

最終都是生成SQL  WHERE ID IN(1,2)

DataSet拆分

有些情況下需要對(duì)DataSet分組處理。如:查詢出2000個(gè)手機(jī)號(hào),如果一短信平臺(tái)一次只能發(fā)500個(gè)

List<DataSet> list = set.split(set.size()/500);
for(DataSet items:list) {
    List<String> mobiles = items.getDistinctStrings("mobile");
    //發(fā)送短信
}

從列式數(shù)據(jù)庫(kù)中取出坐標(biāo)數(shù)據(jù),格式化成地圖軌跡需要的數(shù)據(jù)

軌跡原始數(shù)據(jù)(保存在列式數(shù)據(jù)庫(kù)或thingsboard平臺(tái)上)
lng=[{"ts":1655007789001,"value":120.1}, {"ts":1655007759002,"value":120.2}],
lat=[{"ts":1655007789001,"value":36.1}, {"ts":1655007759002,"value":36.2}]
 
通過(guò)org.anyline.thingsboard.util.ThingsBoardClient.getTimeseries()取出列的DataSet結(jié)構(gòu):
[{"TS":1657707789001, "LNG":120.1, "LAT":36.1},
{"TS":1657707759002, "LNG":120.2, "LAT":36.2}]
 
 
 
DataSet轉(zhuǎn)換成地圖軌跡常用的格式:
{
 //點(diǎn)位時(shí)間
 time: [1657707789001, 1657707759002],
 //點(diǎn)位坐標(biāo)
 path: [   
 [120.1, 36.1], 
 [120.2, 36.2],
 ]
}
 
 
取出時(shí)間 List<Long> times = set.getLongs("TS");
取出坐標(biāo) List<Double[]> points = set.getDoubleArrays("LNG", "LAT");

不同環(huán)境下的配置文件

以anyline-aliyun-sms為例,每個(gè)工具類都會(huì)對(duì)應(yīng)一個(gè)配置類與默認(rèn)實(shí)例化類

如SMSUtil對(duì)應(yīng)SMSConfig與SMSBeanSMSConfig用來(lái)配置帳號(hào)密碼等

SMSBean用來(lái)在系統(tǒng)啟動(dòng)中往Spring上下文中注入一個(gè)默認(rèn)的SMSUtil實(shí)例

SMSUtil就是開(kāi)發(fā)中常用的工具了,如發(fā)送短信、查詢短信接收狀態(tài)、創(chuàng)建短信模板等

其中SMSConfig中的變量可以通過(guò)多種方式設(shè)置

1.配置文件anyline-aliyun-sms.xml(根據(jù)SMSConfig中的靜態(tài)變量CONFIG_NAME = "anyline-aliyun-sms.xml";)

這個(gè)配置文件中可以配置多組帳號(hào)密碼,開(kāi)發(fā)過(guò)程中根據(jù)需要生成針對(duì)不同帳號(hào)的util

一般這樣配置

<configs>

<config key="default">帳號(hào)、密碼等</config>

<config key="instance-oa">帳號(hào)、密碼等</config>

<config key="instance-crm">帳號(hào)、密碼等</config>

</configs>


SMSUtil.getInstance("instance-crm")的方式獲取不同的util

2.如果帳號(hào)無(wú)限多、如開(kāi)發(fā)一個(gè)SAAS平臺(tái),這時(shí)的帳號(hào)密碼會(huì)由不同的租戶或用戶自己設(shè)置,數(shù)據(jù)通常要保存在數(shù)據(jù)中。在運(yùn)行過(guò)程中根據(jù)用戶環(huán)境來(lái)調(diào)用不同的util

在實(shí)例化util前可以通過(guò)

SMSConfig.register("用戶編號(hào)", DataRow)的方式先注冊(cè),其中DataRow中的KEY與配置文件中的KEY相對(duì)應(yīng)

SMSConfig中一般會(huì)提供多個(gè)register的重載

再通過(guò)SMSUtil.getInstance("用戶編號(hào)")的方式獲取util

3.對(duì)于一些簡(jiǎn)單的項(xiàng)目,不想使用配置文件的可以通過(guò)2的方式直接register方式注冊(cè)一個(gè)

也可以設(shè)置SMSConfig中的靜態(tài)變更 DEFAULT_配置文件中的KEY  

如DEFAULT_ACCOUNT(對(duì)應(yīng)配置文件中的ACCOUNT)、DEFAULT_PASSWORD(對(duì)應(yīng)配置文件中的PASSWORD)

這樣在系統(tǒng)啟動(dòng)后會(huì)在Spring上下文中默認(rèn)注入一個(gè)SMSUtil實(shí)例

4.現(xiàn)有的項(xiàng)目配置文件中設(shè)置,參考SMSBean中的屬性

    @Value("${anyline.aliyun.sms.key:}")    private String ACCESS_KEY;

這樣在系統(tǒng)啟動(dòng)后會(huì)在Spring上下文中默認(rèn)注入一個(gè)SMSUtil實(shí)例

5.nacos配置中心

需要添加依賴anyline-nacos

anyline-nacos本身也有配置文件用來(lái)指定NACOS配置中心地址以及namespace/group

可以通過(guò)anyline-nacos.xml配置文件設(shè)置

如果是spring boot項(xiàng)目則按spring boot方式來(lái)配置如 nacos.config.server-addr

如果是spring cloud項(xiàng)目則按spring cloud方式來(lái)配置如 spring.cloud.nacos.config.server-addr

配置好nacos后在nacos中根據(jù) 根據(jù)SMSConfig中的靜態(tài)變量CONFIG_NAME = "anyline-aliyun-sms.xml" 命名nacos中的dataId

關(guān)于merge與join的區(qū)別

都是用來(lái)合并集合, 都有返回值
merge將結(jié)果保存到新集合中
join把其他參數(shù)合并到前一個(gè)參數(shù)中,如果前一個(gè)參數(shù)為null則創(chuàng)建新集合

關(guān)于幾種OR條件查詢的情況

//以下三種格式,只有cd取值成功時(shí),條件才生效
 
//當(dāng)cd=1,id=2時(shí) WHERE CODE = 1 OR CODE =2
//當(dāng)cd=null,id=2時(shí) 條件不生效
//當(dāng)cd=1,id=null時(shí) WHERE CODE = 1
service.querys("HR_USER", condition("CODE:cd|id"));
 
//當(dāng)cd=1時(shí) WHERE CODE =1 OR CODE = 9
//當(dāng)cd=null時(shí) 條件不生效
service.querys("HR_USER", condition("CODE:cd|{9}"));
 
 
//當(dāng)cd=1時(shí) WHERE CODE =1 OR CODE IS NULL
//當(dāng)cd=null時(shí) 條件不生效
service.querys("HR_USER", condition("CODE:cd|{NULL}"));
//當(dāng)type=1,dept=null時(shí) WHERE TYPE_CODE = 1
//當(dāng)type=1,dept=2時(shí) WHERE TYPE_CODE =1 OR DEPT_ID =2 
//當(dāng)type=null,dept=2時(shí) WHERE DEPT_ID = 2
service.querys("HR_USER", condition("TYPE_CODE:type|DEPT_ID:dept"));
//依次取c1,c2的值,如果c1取值成功則忽略c2,如果都失敗則取默認(rèn)值9
service.querys("HR_USER", condition("CODE:c1:c2:{9}"));

anyline加載service失敗

經(jīng)常是因?yàn)闆](méi)有掃描org.anyline包

如果是springboot項(xiàng)目 需要添加注釋

@ComponentScan(basePackages = {"org.anyline","org.anyboot"})

如果用了springboot注意掃描一下org.anyboot


如果是spring-mvc項(xiàng)目 需要添加配置

<context:component-scan base-package="org.anyline"></context:component-scan>

讀取帶表頭表尾的excel

File file = new File(dir,"template_102.xlsx");
ExcelReader reader = ExcelReader.init()
        .setFile(file)  //文件位置
        .setSheet(1)    //讀取第1個(gè)sheet(下標(biāo)從0開(kāi)始)
        .setHead(0)     //表頭在第0行,如果沒(méi)有表頭,結(jié)果集以下標(biāo)作為key
        .setData(1)     //數(shù)據(jù)從第1行開(kāi)始
        .setFoot(1)     //到第1行結(jié)束(如果負(fù)數(shù)表示 表尾有多少行不需要讀取)
        ;
DataSet set = reader.read();
log.warn(set.toJSON());

關(guān)于DataRow parse xml與parse json區(qū)別

**json結(jié)構(gòu)相對(duì)簡(jiǎn)單每一對(duì)key value可以直接存入DataRow **
{name:zhang,age:20}
對(duì)應(yīng):
row.put("name","zhang");
row.put("age",20);

但xml比json多了一個(gè)attribute,這個(gè)attribute不直接存入DataRow
<user id="1"><name>zhang</name></user>
對(duì)應(yīng):
user.attr("id","1");
user.put("name","zhang");
同樣取值時(shí)也通過(guò)user.attr("id");

html中抽取標(biāo)簽時(shí)嵌套問(wèn)題

從html中抽取多個(gè)標(biāo)簽,如需要抽取a標(biāo)簽和li標(biāo)簽

最簡(jiǎn)單的是抽取兩次RegularUtil.fetchAllTag(html,"a")RegularUtil.fetchAllTag(html,"li")

但這樣有個(gè)問(wèn)題,兩個(gè)標(biāo)簽的順序會(huì)亂,

如果需要保持順序可以通過(guò)RegularUtil.fetchAllTag(html,"a","li");

但是一定注意:這里的a有可能被包含在li內(nèi)部,這時(shí)li中的a不會(huì)再單獨(dú)抽取

html代碼中抽取指定標(biāo)簽

//獲取所有超鏈接(a標(biāo)簽)
        /*
         * 提取單標(biāo)簽+雙標(biāo)簽
         * 不區(qū)分大小寫(xiě)
         * 0:全文 1:開(kāi)始標(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("開(kāi)始標(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源碼中截取字符串

        //放多情況下我們并不需要復(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í)可以通過(guò)字符串截取的方式提取出價(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)鍵字的組合來(lái)確認(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)容在最開(kāi)始位置 如上面的日期

        String ymd = RegularUtil.cut(html, RegularUtil.TAG_BEGIN, "<");
        log.warn("日期:{}", ymd);

導(dǎo)出復(fù)雜的表格需要借助TableBuilder先生成Table,再將Table導(dǎo)出到excel中

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);

最簡(jiǎn)單的導(dǎo)出一個(gè)列表,如果文件已存在,則在原文件內(nèi)容基礎(chǔ)上插入行

DataSet set = service.querys("V_HR_SALARY","YYYY:"+ (DateUtil.year()-1), "ORDER BY EMPLOYEE_ID, YM");
//最簡(jiǎn)單的導(dǎo)出一個(gè)列表,如果文件已存在,則在原文件內(nèi)容基礎(chǔ)上插入行
File file = new File(dir,"export_list.xlsx");
//1表示從第1行插入,如果原來(lái)文件有內(nèi)容,則下移
//{num}表示第幾行,下標(biāo)從1開(kāi)始
//這里支持復(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ì)算好從哪一行開(kāi)始寫(xiě)入
if(template.exists()) {
    ExcelUtil.export(template, file, 1, set, "{num}", "DEPARTMENT_NM", "EMPLOYEE_NM", "YM", "{BASE_PRICE}+{REWARD_PRICE}");
}

讀取合并單元格的excel

File file = new File(dir,"export_table.xlsx");
List list = ExcelUtil.read(file);   //默認(rèn)讀取第0個(gè)sheet從第0行開(kāi)始
list = ExcelUtil.read(file,1,3);    //讀取第1個(gè)sheet從第3行讀取
 
//遇到合并單元格的,將拆分開(kāi)未合并前的狀態(tài),拆分后補(bǔ)上每個(gè)單元格的值
//返回的是一個(gè)二維數(shù)組
//為了操作方便可以把返回值轉(zhuǎn)換成DataSet,DataSet中的條目(DataRow)以excel列下標(biāo)作為屬性key
DataSet set = new DataSet(list);

導(dǎo)出excel,多個(gè)sheet

//默認(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);

從人員列表中,查出所有不重復(fù)的部門名稱

DataSet set = service.query("HR_USER");

set.distinct("DEPARTMENT_NM");    //這里返回的還是人員列表,但一個(gè)部門只返回一個(gè)

.concat("DEPARTMENT_NM");        //這里返回String并以逗號(hào)分隔:部門A,部門B


List<String> departments = set.getDistinctStrings("DEPARTMENT_NM"); //這里返回一個(gè)不重復(fù)的部門名稱List

設(shè)置單元格默認(rèn)邊框

TableBuilder.init()..setCellBorder(true)

設(shè)置所有空值單元格對(duì)齊方式

有些情況下,需要把空值替換成其他固定的符號(hào)如(/)

這時(shí)可以設(shè)置這些單元格的對(duì)齊方式

TableBuilder.init()
.setEmptyCellVerticalAlign("top")
.setEmptyCellHorizontalAlign("center")

設(shè)置指定列的對(duì)齊方式

TableBuilder.init()
.setHorizontalAlign("CHECK_CODE", "center")
.setVerticalAlign("CHECK_CODE", "top")

設(shè)置所有合并單元格的對(duì)齊方式

TableBuilder.init()
.setMergeCellHorizontalAlign("center")  //設(shè)置合并單元格水平對(duì)齊方式
.setMergeCellVerticalAlign("center")    //設(shè)置合并單元格垂直對(duì)齊方式

導(dǎo)出EXCEL中的序號(hào)合并單元格

在導(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需要部門列來(lái)合并單元格

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ù))

導(dǎo)出EXCEL中的序號(hào)

導(dǎo)出excel時(shí)如果每行需要一個(gè)序號(hào)可以用{num}來(lái)代替屬性名,如
export(file,  list, "序號(hào):{num}","姓名:NAME","年齡:AGE")

1張三20
2李四22
3王五25

關(guān)于DataRow中g(shù)et與getString的區(qū)別

DataRow中g(shù)et是覆蓋了父類Map的get

getString在get的基礎(chǔ)上增加了復(fù)合KEY的支持,如getString("{ID}/{CODE}")

關(guān)于DataRow的復(fù)合KEY

許多情況下需要從DataRow中取多個(gè)值合并顯示。如導(dǎo)出excel時(shí)地址列需要合并省市區(qū)詳細(xì)地址

DataRow可以取多個(gè)值拼接,但DataSet則需要遍歷,非常麻煩

DataRow提供了復(fù)合KEY取值的函數(shù)

如{ID:1,CODE:A01,NAME:張三}

row.getString("{ID}-{CODE}")可以取出   1-A01row.getString("編號(hào):{CODE};姓名:{NAME}")可以取出   編號(hào):A01;姓名:張三

需要注意的是如果其中一個(gè)KEY取值為null 或 KEY不存在則以""代替,而不是"null"

類似的在導(dǎo)出EXCEL時(shí)指定需要導(dǎo)出的列時(shí)也可以使用復(fù)合KEY

將所有列中的oldChar替換成newChar

將key列中的oldChar替換成newChar
public DataSet replace(String key, String oldChar, String newChar) 

 將所有列中的oldChar替換成newChar
public DataSet replace(String oldChar, String newChar) 

替換DataSet,DataRow中所有空值(null,'')

將所有列中的空值替換成value

public DataSet replaceEmpty(String value)

al:checkbox 自定義value key與text key

根據(jù)集合數(shù)據(jù)源生成checkbox時(shí),默認(rèn)情況下會(huì)取集合中條目的ID值作為input的value值,取條目的NM值作為label的標(biāo)簽體

但數(shù)據(jù)源經(jīng)常是從數(shù)據(jù)庫(kù)中查詢出來(lái)的,列中并不一定有ID和NM,也有可能是CODE,TITLE或其他情況

這時(shí)需要顯式指定value key與text key

<al:checkbox data="${set }" valueKey="CODE" textKey="TITLE" />

往同一個(gè)excel中寫(xiě)多個(gè)sheet

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)

關(guān)于al:number中的def與evl

def是指如果沒(méi)有輸入值,則取默認(rèn)值,默認(rèn)值同樣會(huì)執(zhí)行格式化與其他運(yùn)算

evl/nvl是指如果結(jié)果為empt(null),則直接輸出evl/nvl,不會(huì)執(zhí)行格式化,不會(huì)執(zhí)行運(yùn)算

關(guān)于al:date中的nvl與dev

value與body為空的情況下

如果nvl=true則顯示當(dāng)前日期,如果nvl=false則不輸出

如果nvl=其他值,則直接輸出nvl

如果沒(méi)有指定value,body,nvl都為空,同時(shí)def有值,則輸入def

需要注意的是def與nvl=true時(shí),日期都會(huì)參與格式化與運(yùn)算(如增加一天),而nvl=其他值時(shí),直接原樣輸出evl并不執(zhí)行格式化與其他運(yùn)算

關(guān)于分頁(yè)后退保持頁(yè)數(shù)

有一種典型的場(chǎng)景AJAX分頁(yè),
用戶第一次打開(kāi)列表頁(yè)時(shí)默認(rèn)顯示第1頁(yè)。

用戶在列表頁(yè)中切換到第2頁(yè)后,在第2頁(yè)中打開(kāi)一個(gè)條目的明細(xì)。操作完明細(xì)后退。返回到到列表
這時(shí)列表頁(yè)需要直接顯示第2頁(yè)數(shù)據(jù)。

如何區(qū)分是后退過(guò)來(lái)的還是頁(yè)面刷新過(guò)來(lái)的。navi是在列表頁(yè)中存放了一個(gè)隱藏的input在切換頁(yè)數(shù)后修改這個(gè)input
刷新過(guò)來(lái)的頁(yè)面這個(gè)input值為空,而后退過(guò)來(lái)的這個(gè)input值為2
根據(jù)瀏覽器加載機(jī)制,在頁(yè)面加載完成之后才會(huì)給input賦值。所以在頁(yè)面加載過(guò)程中取不到這個(gè)input值。
可以把需要取input值的代碼放在setTimeout(function(){取值},0);

向壓縮文件中追加文件

public static boolean append(File item, File zip, String dir, String comment)

public static boolean append(File item, File zip)

替換壓縮包中的文件

//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)

讀取壓縮包中的文件內(nèi)容

//讀取zip壓縮包中的item文件內(nèi)容
public static InputStream read(File zip, String item)
以String格式返回
public static String read(File zip, String item, String encode)

刪除壓縮包中的指定文件

刪除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")

壓縮文件

把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>

更多常用示例在后文中有所展現(xiàn),囿于文章篇幅所限,此處不過(guò)多做介紹!











































































































































以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)