anyline 入门

2022-09-16 11:34 更新

配置maven环境

如果需要私服参考这里>maven私服

通常情况下每个公司会有自己的*-starter或*-dependency来统一管理maven依赖版本号

如:用anyline-simple-dependency来定义所有外部依赖的版本号

anyline-simple-start-mvc-mysql继承anyline-simple-dependency并添加mvc与mysql的依赖,

有需要myql和mvc环境的项目继承自anyline-simple-start-mvc-mysql

常用示例

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

关于更新部分属性(列)、忽略部分属性(列)

添加到DataRow中但不需要参与更新(插入)

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


添加了空值,  默认情况下不参与更新(插入) 如果需要强制参与更新(插入)

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


如果这样指定了更新(插入)列,则只会更新(插入)指定的列,其他列都不会参与更新(插入)

service.save(row,"NAME");


强制更新(插入)NAME,忽略CODE,其他列不受影响,按默认情况处理

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


插入所有列,更新所有值发生过变化的列

service.save(row);

关于自动检测表结构

在执行数据库操作时,许多参数是以String形式获取到的,无法参数识别数据类型,如url中的参数

还有一些数据类型在Java中没有对应关系,如xml/josn/几何图形等

而有些数据库在执行SQL时会执行强类型检测。

不像我们平时用的MySQL在执行时会进行隐式转换,无论什么类型只要能转换成功就可以执行。

而PostgreSQL则要求jdbc参数与表结构对应,如果在varchar列中执行int类型会失败。

要求开发人员在编码过程中记住表数据类型,或进行类型转换显示不合理,何况表结构有可能会变动。

可以开启表结构自动检测,在执行SQL前把参数转换成与表结构对应的类型

这样就可以像MySQL一样随意了

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

DataSet构造多级树型结构

表结构类似这样

IDBASE_IDNAME
1NULL中国
21山东
32济南
42青岛
52烟台
63历下区
73天桥区
84市南区
94城阳区

//先取出完整列表

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

//ID:主键  BASE_ID:表示上一级ID的列名

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

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

//执行完成后会把每个DataRow中存入当前DataRow的下一级

//这里会生成多个树型结构,一般需要根据ID取出最顶级的DataRow  set.getRow("ID",1);

get(String key)与getString(String key)的区别

get(String key)与Map的get(String key)效果一样

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

关于分页参数

默认的分页参数名比较长:

public static String DEFAULT_KEY_PAGE_ROWS          = "_anyline_page_rows"          ; //设置每页显示多少条的key
public static String DEFAULT_KEY_PAGE_NO            = "_anyline_page"               ; //设置当前第几页的key
public static String DEFAULT_KEY_TOTAL_PAGE         = "_anyline_total_page"         ; //显示一共多少页的key
public static String DEFAULT_KEY_TOTAL_ROW          = "_anyline_total_row"          ; //显示一共多少条的key
public static String DEFAULT_KEY_SHOW_STAT          = "_anyline_navi_show_stat"     ; //设置是否显示统计数据的key
public static String DEFAULT_KEY_SHOW_JUMP          = "_anyline_navi_show_jump"     ; //设置是否显示页数跳转key
public static String DEFAULT_KEY_SHOW_VOL           = "_anyline_navi_show_vol"      ; //设置是否显示每页条数设置key
public static String DEFAULT_KEY_GUIDE              = "_anyline_navi_guide"         ; //设置分页样式的key
public static String DEFAULT_KEY_ID_FLAG            = "_anyline_navi_conf_"         ; //生成配置文件标识
public String KEY_PAGE_ROWS         = DEFAULT_KEY_PAGE_ROWS         ; //设置每页显示多少条的key
public String KEY_PAGE_NO           = DEFAULT_KEY_PAGE_NO           ; //设置当前第几页的key
public String KEY_TOTAL_PAGE        = DEFAULT_KEY_TOTAL_PAGE        ; //显示一共多少页的key
public String KEY_TOTAL_ROW         = DEFAULT_KEY_TOTAL_ROW         ; //显示一共多少条的key
public String KEY_SHOW_STAT         = DEFAULT_KEY_SHOW_STAT         ; //设置是否显示统计数据的key
public String KEY_SHOW_JUMP         = DEFAULT_KEY_SHOW_JUMP         ; //设置是否显示页数跳转key
public String KEY_SHOW_VOL          = DEFAULT_KEY_SHOW_VOL          ; //设置是否显示每页条数设置key
public String KEY_GUIDE             = DEFAULT_KEY_GUIDE             ; //设置分页样式的key
public String KEY_ID_FLAG           = DEFAULT_KEY_ID_FLAG           ; //生成配置文件标识

是为了防止跟业务参数重名,但一般项目不会写这长啰嗦的参数名可以在配置文件anyline-navi.xml中修改参数名

<!--当前第几页-->

<property key="KEY_PAGE_NO">page</property>或者直接写在Java中,一般写在启动类中

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;

几个常用的配置参数

//DataRow的key大小写(默认大写)
DataRow.DEFAULT_KEY_KASE = KeyAdapter.KEY_CASE.LOWER;
//http分页参数-当前当前第几页(默认page)
PageNaviConfig.DEFAULT_KEY_PAGE_NO = "pageNum";
//http分页参数-每页多少条(默认vol)
PageNaviConfig.DEFAULT_KEY_PAGE_ROWS = "pageSize";
//是否允许前端设置每页多少条(默认false)
PageNaviConfig.DEFAULT_VAR_CLIENT_SET_VOL_ENABLE = true;

关于日期类的链式操作

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

excel根据内容定位单元格

用户提交的excel内容经常不固定行列,而是需要根据单元格内容来确定表头位置或数据起止位置。

如根据内容中包含"结算日期"的单元格来确定当前行是表头,下一行是数据

根据内容中包含"会计年度"的单元格来确定当前数据年度。

int[] position = org.anyline.poi.excel.ExcelUtil.position(file.getInputStream(),"时间.*");

返回第1个包含"时间"的单元格位置(下标从0开始)

支持正则表达式,

可以根据返回的坐标来读取单元格内容

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

以上默认第0个Sheet页,可以指定Sheet下标或名称

IN条件下多种参数格式的接收

对于标准的url格式 /list?id=1&id=2

以及标准的json格式 {id:[1,2]}

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

对于非标准格式如 /list?id=1,2

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

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

DataSet拆分

有些情况下需要对DataSet分组处理。如:查询出2000个手机号,如果一短信平台一次只能发500个

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

从列式数据库中取出坐标数据,格式化成地图轨迹需要的数据

轨迹原始数据(保存在列式数据库或thingsboard平台上)
lng=[{"ts":1655007789001,"value":120.1}, {"ts":1655007759002,"value":120.2}],
lat=[{"ts":1655007789001,"value":36.1}, {"ts":1655007759002,"value":36.2}]
 
通过org.anyline.thingsboard.util.ThingsBoardClient.getTimeseries()取出列的DataSet结构:
[{"TS":1657707789001, "LNG":120.1, "LAT":36.1},
{"TS":1657707759002, "LNG":120.2, "LAT":36.2}]
 
 
 
DataSet转换成地图轨迹常用的格式:
{
 //点位时间
 time: [1657707789001, 1657707759002],
 //点位坐标
 path: [   
 [120.1, 36.1], 
 [120.2, 36.2],
 ]
}
 
 
取出时间 List<Long> times = set.getLongs("TS");
取出坐标 List<Double[]> points = set.getDoubleArrays("LNG", "LAT");

不同环境下的配置文件

以anyline-aliyun-sms为例,每个工具类都会对应一个配置类与默认实例化类

如SMSUtil对应SMSConfig与SMSBeanSMSConfig用来配置帐号密码等

SMSBean用来在系统启动中往Spring上下文中注入一个默认的SMSUtil实例

SMSUtil就是开发中常用的工具了,如发送短信、查询短信接收状态、创建短信模板等

其中SMSConfig中的变量可以通过多种方式设置

1.配置文件anyline-aliyun-sms.xml(根据SMSConfig中的静态变量CONFIG_NAME = "anyline-aliyun-sms.xml";)

这个配置文件中可以配置多组帐号密码,开发过程中根据需要生成针对不同帐号的util

一般这样配置

<configs>

<config key="default">帐号、密码等</config>

<config key="instance-oa">帐号、密码等</config>

<config key="instance-crm">帐号、密码等</config>

</configs>


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

2.如果帐号无限多、如开发一个SAAS平台,这时的帐号密码会由不同的租户或用户自己设置,数据通常要保存在数据中。在运行过程中根据用户环境来调用不同的util

在实例化util前可以通过

SMSConfig.register("用户编号", DataRow)的方式先注册,其中DataRow中的KEY与配置文件中的KEY相对应

SMSConfig中一般会提供多个register的重载

再通过SMSUtil.getInstance("用户编号")的方式获取util

3.对于一些简单的项目,不想使用配置文件的可以通过2的方式直接register方式注册一个

也可以设置SMSConfig中的静态变更 DEFAULT_配置文件中的KEY  

如DEFAULT_ACCOUNT(对应配置文件中的ACCOUNT)、DEFAULT_PASSWORD(对应配置文件中的PASSWORD)

这样在系统启动后会在Spring上下文中默认注入一个SMSUtil实例

4.现有的项目配置文件中设置,参考SMSBean中的属性

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

这样在系统启动后会在Spring上下文中默认注入一个SMSUtil实例

5.nacos配置中心

需要添加依赖anyline-nacos

anyline-nacos本身也有配置文件用来指定NACOS配置中心地址以及namespace/group

可以通过anyline-nacos.xml配置文件设置

如果是spring boot项目则按spring boot方式来配置如 nacos.config.server-addr

如果是spring cloud项目则按spring cloud方式来配置如 spring.cloud.nacos.config.server-addr

配置好nacos后在nacos中根据 根据SMSConfig中的静态变量CONFIG_NAME = "anyline-aliyun-sms.xml" 命名nacos中的dataId

关于merge与join的区别

都是用来合并集合, 都有返回值
merge将结果保存到新集合中
join把其他参数合并到前一个参数中,如果前一个参数为null则创建新集合

关于几种OR条件查询的情况

//以下三种格式,只有cd取值成功时,条件才生效
 
//当cd=1,id=2时 WHERE CODE = 1 OR CODE =2
//当cd=null,id=2时 条件不生效
//当cd=1,id=null时 WHERE CODE = 1
service.querys("HR_USER", condition("CODE:cd|id"));
 
//当cd=1时 WHERE CODE =1 OR CODE = 9
//当cd=null时 条件不生效
service.querys("HR_USER", condition("CODE:cd|{9}"));
 
 
//当cd=1时 WHERE CODE =1 OR CODE IS NULL
//当cd=null时 条件不生效
service.querys("HR_USER", condition("CODE:cd|{NULL}"));
//当type=1,dept=null时 WHERE TYPE_CODE = 1
//当type=1,dept=2时 WHERE TYPE_CODE =1 OR DEPT_ID =2 
//当type=null,dept=2时 WHERE DEPT_ID = 2
service.querys("HR_USER", condition("TYPE_CODE:type|DEPT_ID:dept"));
//依次取c1,c2的值,如果c1取值成功则忽略c2,如果都失败则取默认值9
service.querys("HR_USER", condition("CODE:c1:c2:{9}"));

anyline加载service失败

经常是因为没有扫描org.anyline包

如果是springboot项目 需要添加注释

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

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


如果是spring-mvc项目 需要添加配置

<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个sheet(下标从0开始)
        .setHead(0)     //表头在第0行,如果没有表头,结果集以下标作为key
        .setData(1)     //数据从第1行开始
        .setFoot(1)     //到第1行结束(如果负数表示 表尾有多少行不需要读取)
        ;
DataSet set = reader.read();
log.warn(set.toJSON());

关于DataRow parse xml与parse json区别

**json结构相对简单每一对key value可以直接存入DataRow **
{name:zhang,age:20}
对应:
row.put("name","zhang");
row.put("age",20);

但xml比json多了一个attribute,这个attribute不直接存入DataRow
<user id="1"><name>zhang</name></user>
对应:
user.attr("id","1");
user.put("name","zhang");
同样取值时也通过user.attr("id");

html中抽取标签时嵌套问题

从html中抽取多个标签,如需要抽取a标签和li标签

最简单的是抽取两次RegularUtil.fetchAllTag(html,"a")RegularUtil.fetchAllTag(html,"li")

但这样有个问题,两个标签的顺序会乱,

如果需要保持顺序可以通过RegularUtil.fetchAllTag(html,"a","li");

但是一定注意:这里的a有可能被包含在li内部,这时li中的a不会再单独抽取

html代码中抽取指定标签

//获取所有超链接(a标签)
        /*
         * 提取单标签+双标签
         * 不区分大小写
         * 0:全文 1:开始标签 2:标签name 3:标签体 (单标签时null) 4:结束标签 (单标签时null)
         * 注意标签体有可能是HTML片段,而不是纯文本
         */
        List<List<String>> list = RegularUtil.fetchAllTag(html,"a");
        log.warn("标签数量:"+list.size());
        for(List<String> item:list){
            log.warn("全文:"+item.get(0));
            log.warn("开始标签:"+item.get(1));
            log.warn("标签名称:"+item.get(2));
            log.warn("标签体:"+item.get(3));
            log.warn("结束标签:"+item.get(4));
        }
 
        //抽取所有 a标签和li标签
        //一定注意:这里的a有可能被包含在li内部,这时的a不会再抽取
        list = RegularUtil.fetchAllTag(html,"a","li");

从html源码中截取字符串

        //放多情况下我们并不需要复杂的标签内容,只需要截取几个关键字
        //如提取商品名称和商品价格,而这两个值有可能是根其他内容混在一块的
        //如以下这段源码
        String html ="<div class='title' data-product='1001'>商品名称(限时)</div>"
        +"<div class='price'>一个货币符号:100.00</div>";
        //这时可以通过字符串截取的方式提取出价格
        //第0个参数:源数据
        //第1个到倒数第2个参数:100.00(就是我们要提取的价格) 之前出现的关键字
        //最后1个参数:100.00之后出现的第1个关键字

        //参数顺序:  源码,k1,k2,k3,kn-1,内容,kn

        String price = RegularUtil.cut(html, "price",":","</div>");
        log.warn("价格:{}",price);

        //许多情况下price有可能在源码中出现多次,这时需要多个关键字的组合来确认100.00的位置

        html = DateUtil.format("yyyy-MM-dd")+ "<div class='title' data-product='1001'>商品名称(限时)</div>" +
                "div class='src-price price'></div>" +
                "<div class='price'>一个货币符号:100.00</div>元";

        price = RegularUtil.cut(html,"src-price","price", "price",":","</div>");
        log.warn("价格:{}",price);

        //如果需要提取的内容在最后 如上面的单位:元
        String unit = RegularUtil.cut(html,"src-price","price", "price",":","</div>", RegularUtil.TAG_END);
        log.warn("单位:{}", unit);

        //同样的如果需要提取的内容在最开始位置 如上面的日期

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

导出复杂的表格需要借助TableBuilder先生成Table,再将Table导出到excel中

TableBuilder builder = TableBuilder.init()
        .setDatas(set)                                  //设置数据源
        .setFields(                                     //需要导出的列
                "{num}(EMPLOYEE_NM)"                    //{num}表示序号,(DEPARTMENT_NM)表示根据哪一列计算序号,这里部门名称需要分组合并,所以num不是按行计算
                ,"DEPARTMENT_NM"
                ,"EMPLOYEE_NM"
                ,"YM"
                ,"BASE_PRICE")
        .addUnion(                                      //需要合并的列
                "DEPARTMENT_NM"                         //如果部门名称相同则合并
                ,"EMPLOYEE_NM(DEPARTMENT_NM)"
                ,"YM(DEPARTMENT_NM)"                    //如果月份相同则合并,前提是部门已经合并
        )
        .setReplaceEmpty("/")                           //如果值为空则以/代替
        .addIgnoreUnionValue("/")                       //不参与合并的值
        .setCellBorder(true)                            //设置默认边框
        .setMergeCellHorizontalAlign("center")          //设置合并的列 水平对齐方式
        .setMergeCellVerticalAlign("top")               //设置合并的列 垂直对齐方式
        .setEmptyCellHorizontalAlign("center")          //设置空单元格 水平对齐方式(为空时有可能需要替换成其他值)
        .setEmptyCellVerticalAlign("top")               //设置空单元格 垂直对齐方式
        .setHorizontalAlign("YM","center")  //设置月份列 水平对齐方式
        .setVerticalAlign("middle")                     //设置所有数据单元格 垂直对齐方式
        .setLineHeight("50px")                          //设置数据区域行高
        .setWidth("YM","200px")             //设置月份列 宽度
        ;
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");
//最简单的导出一个列表,如果文件已存在,则在原文件内容基础上插入行
File file = new File(dir,"export_list.xlsx");
//1表示从第1行插入,如果原来文件有内容,则下移
//{num}表示第几行,下标从1开始
//这里支持复合KEY
ExcelUtil.export(file,1, set,"序号:{num}","部门:DEPARTMENT_NM","姓名:EMPLOYEE_NM","月份:YM","底薪:{BASE_PRICE}+{REWARD_PRICE}");
 
//如果表头、表尾格式比较复杂,可先创建模板,再根据模板导出
File template = new File(dir,"template.xlsx");//这里是一个模板文件
//根据模板导出时就不需要指定表头了,只要对应好顺序,并计算好从哪一行开始写入
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);   //默认读取第0个sheet从第0行开始
list = ExcelUtil.read(file,1,3);    //读取第1个sheet从第3行读取
 
//遇到合并单元格的,将拆分开未合并前的状态,拆分后补上每个单元格的值
//返回的是一个二维数组
//为了操作方便可以把返回值转换成DataSet,DataSet中的条目(DataRow)以excel列下标作为属性key
DataSet set = new DataSet(list);

导出excel,多个sheet

//默认情况下导出的第0个sheet也就是sheet1
//如果要导出到多个sheet需要执行多次export导出到同一个文件,每次执行时指定sheet名称或下标
Table table = null;
File file = new File(dir, "export_sheet.xlsx");
ExcelUtil.export(file, "shet1", table);
ExcelUtil.export(file, "shet2", table);

从人员列表中,查出所有不重复的部门名称

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

set.distinct("DEPARTMENT_NM");    //这里返回的还是人员列表,但一个部门只返回一个

.concat("DEPARTMENT_NM");        //这里返回String并以逗号分隔:部门A,部门B


List<String> departments = set.getDistinctStrings("DEPARTMENT_NM"); //这里返回一个不重复的部门名称List

设置单元格默认边框

TableBuilder.init()..setCellBorder(true)

设置所有空值单元格对齐方式

有些情况下,需要把空值替换成其他固定的符号如(/)

这时可以设置这些单元格的对齐方式

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

设置指定列的对齐方式

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

设置所有合并单元格的对齐方式

TableBuilder.init()
.setMergeCellHorizontalAlign("center")  //设置合并单元格水平对齐方式
.setMergeCellVerticalAlign("center")    //设置合并单元格垂直对齐方式

导出EXCEL中的序号合并单元格

在导出excel时有可能不是每行一个序号,而是每组一个序号,如按部门分组,每个部门一个序号

1人事部张三20
张三三22
2财务部李四25
王五26

王五五

20

这时num需要部门列来合并单元格

TableBuilder builder = TableBuilder.init()
.setDatas(set)                          //设置数据源
.setFields("{num}(DEPARTMENT_NAME)"
            ,"DEPARTMENT_NAME"
            ,"USER_NAME"
            ,"USER_AGE")                //设置需要导出的属性(列)
.addUnion("DEPARTMENT_NAME");                   /设置需要合并行的列,如果年相同的合并,月相同的合并(前提是年相同)
File file = new File("模板地址");
ExcelUtil.export(file, "sheet名称", 2, builder.build()); //从第2行插入(根据表头行数)

导出EXCEL中的序号

导出excel时如果每行需要一个序号可以用{num}来代替属性名,如
export(file,  list, "序号:{num}","姓名:NAME","年龄:AGE")

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

关于DataRow中get与getString的区别

DataRow中get是覆盖了父类Map的get

getString在get的基础上增加了复合KEY的支持,如getString("{ID}/{CODE}")

关于DataRow的复合KEY

许多情况下需要从DataRow中取多个值合并显示。如导出excel时地址列需要合并省市区详细地址

DataRow可以取多个值拼接,但DataSet则需要遍历,非常麻烦

DataRow提供了复合KEY取值的函数

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

row.getString("{ID}-{CODE}")可以取出   1-A01row.getString("编号:{CODE};姓名:{NAME}")可以取出   编号:A01;姓名:张三

需要注意的是如果其中一个KEY取值为null 或 KEY不存在则以""代替,而不是"null"

类似的在导出EXCEL时指定需要导出的列时也可以使用复合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

根据集合数据源生成checkbox时,默认情况下会取集合中条目的ID值作为input的value值,取条目的NM值作为label的标签体

但数据源经常是从数据库中查询出来的,列中并不一定有ID和NM,也有可能是CODE,TITLE或其他情况

这时需要显式指定value key与text key

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

往同一个excel中写多个sheet

public static boolean export(File file, String sheet, int rows, DataSet set, String ... configs)如果文件存在则在当前文件中插入数据,如果文件不存在则新创建文件

这里的sheet如果在file中已存在,则往这个sheet中插入数据,如果不存在则新创建sheet再继续插入数据,其他重载函数规则相同。


File file = new File();
export(file, "s1",0, set, "ID"); //这一行执行完成后在文件中有一个sheet(s1)
export(file, "s2",0, set, "ID");//这一行执行完后文件中有两个sheet(s1,s2)

关于al:number中的def与evl

def是指如果没有输入值,则取默认值,默认值同样会执行格式化与其他运算

evl/nvl是指如果结果为empt(null),则直接输出evl/nvl,不会执行格式化,不会执行运算

关于al:date中的nvl与dev

value与body为空的情况下

如果nvl=true则显示当前日期,如果nvl=false则不输出

如果nvl=其他值,则直接输出nvl

如果没有指定value,body,nvl都为空,同时def有值,则输入def

需要注意的是def与nvl=true时,日期都会参与格式化与运算(如增加一天),而nvl=其他值时,直接原样输出evl并不执行格式化与其他运算

关于分页后退保持页数

有一种典型的场景AJAX分页,
用户第一次打开列表页时默认显示第1页。

用户在列表页中切换到第2页后,在第2页中打开一个条目的明细。操作完明细后退。返回到到列表
这时列表页需要直接显示第2页数据。

如何区分是后退过来的还是页面刷新过来的。navi是在列表页中存放了一个隐藏的input在切换页数后修改这个input
刷新过来的页面这个input值为空,而后退过来的这个input值为2
根据浏览器加载机制,在页面加载完成之后才会给input赋值。所以在页面加载过程中取不到这个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内容
public static void replace(File zip, String content, String item)

读取压缩包中的文件内容

//读取zip压缩包中的item文件内容
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是一个目录,则递归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文件内容
public static InputStream read(File zip, String item)
public static String read(File zip, String item, String encode)
</string,file></file>

更多常用示例在后文中有所展现,囿于文章篇幅所限,此处不过多做介绍!











































































































































以上内容是否对您有帮助:
在线笔记
App下载
App下载

扫描二维码

下载编程狮App

公众号
微信公众号

编程狮公众号