表单提交超链接……………………………………………………… 2 单元格不改变时不参与更新………………………………………… 6 及时校验……………………………………………………………… 8 跨格数据及时校验…………………………………………………… 12 扩展数据的数据校验………………………………………………… 16 批量修改单元格……………………………………………………… 17 填报保存值类型……………………………………………………… 19 填报流水号…………………………………………………………… 22 填报自动匹配值……………………………………………………… 26 文本域换行…………………………………………………………… 29 下拉框的快速查询…………………………………………………… 33 行式报表……………………………………………………………… 34 用户自定义填报……………………………………………………… 39 表单提交超链接 在填报时,提交会出现两种结果,提交成功和提交失败,可以对这两种结果进行事件编辑,在FineReport6.5中可以通过报表->报表Web属性->填报页面设置添加提交成功和提交失败事件进行编辑。 1. 打开模板 2. 添加提交事件 点击填报|报表Web属性,选择填报页面设置栏目,进入填报页面设置窗口,在右边栏中添加提交成功和提交失败事件,如下图所示 ![]() 具体的填报成功事件和填报失败事件代码如下 填报成功事件,添加JS代码:window.open(“http://www.baidu.com”); 在填报成功后,打开百度连接。
![]() 提交失败事件,JS代码: window.open("http://localhost:8079/WebReport/ReportServer?op=fs"); 该代码用于填报提交失败后打开产品演示文档。
3. 填报并预览 点击设计器的填报预览,效果如图
![]() 点击提交,显示提交成功 ![]()
点击确定按钮,这是触发提交成功事件,链接到百度首页 ![]()
不填用户编号时提交失败,如图 ![]()
点击确定按钮,触发提交失败事件,页面跳转到产品演示文档
![]() 单元格不改变时不参与更新 填报提交时,将根据情况进行insert/update操作,当填报列数较多时,速度可能较慢,因为他要对所有字段进行操作。此时可以设置单元格不改变时不参与更新,这样,相应的数据列在数据不改变时,不会参与更新操作,即SQL语句中update中不包含该列,进而提高填报的效率。但这个功能只有在填报更新数据的时候有效,如果是插入操作的话仍是插入所有字段,因此需要在使用报表主键的的基础上使用该功能。 1. 新建报表 新建一张空白报表,添加数据库查询ds1,SQL语句为:SELECT * FROM stscore WHERE studentno=1014,设计成如下格式的报表 ![]() 2. 控件设置 给单元格加上控件,分别定义如下单元格控件属性
3. 报表填报属性 添加内置SQL,具体设置如下图,将studentno设为主键,所有的单元格设置不改变时不参与更新,这样进行update操作时只有单元格改变的列才参与更新。 ![]() 4. 保存并预览 保存模板,点击设计器的填报预览,结果如下图所示
![]() 我们修改Achilles这个学生的英语成绩,原为93,我们改为100,点击提交 此时,日志面板中的更新语句为 INFO:UPDATE [STSCORE] SET [GRADE]=? WHERE [STUDENTNO]=? AND [COURSE]=? 可以看到,数据库只更新了GRADE的值,且只对三个字段进行了操作。 但若是不设置“单元格不改变时不参与更新”,同样的操作我们将会得到如下更新语句: INFO:UPDATE [STSCORE] SET [CLASSNO]=?,[NAME]=?,[SEX]=?,[GRADE]=? WHERE [STUDENTNO]=? AND [COURSE]=? 数据库对每个字段都进行了更新操作,若列数量多的情况就会非常耗时了。 及时校验 现有的控件设置面板中包含有各种及时校验,如文本控件的填写规则校验、数字的精度校验、日期时间可以规定范围等,以下介绍几种常用的及时校验设置。 1. 文本控件及时校验 文本控件类型有不为空的校验,也有填写规则校验,更有自定义校验,FineReport报表中自带有长度,邮件,身份证,邮政编码,电话 ,手机等及时校验,自定义校验可以根据需要自己书写正则表达式。 ![]() 例如输入验证用户密码的正则表达式:“^[a-zA-Z]\w{5,17}$”表示密码规则是以字母开头,长度在6-18之间,只能包含字符、数字和下划线。 l \d任意一个数字,0~9中的任意一个 l \w任意一个字母或数字或下划线,也就是A-Z,a-z,0-9中任意一个 l \s包括空格、制表符、换页符等空白字符的其中任意一个 l .小数点可以匹配除了换行符(\n)以外的任意一个字符 l ^开始 l $结束 一些表达式的作用: {n}:表示重复n次,比如"\w{2}" 相当于 "\w\w";"a{5}" 相当于 "aaaaa" {m,n}:表示至少重复m次,最多重复n次,比如"ba{1,3}"可以匹配 "ba"或"baa"或"baaa" {m,}:表示至少重复m次,比如"\w\d{2,}"可以匹配 "a12","_456","M12344" :匹配表达式0次或者1次,相当于 {0,1},比如"a[cd]?"可以匹配 "a","ac","ad" +:表达式至少出现1次,相当于 {1,},比如"a+b"可以匹配 "ab","aab","aaab" *:表达式不出现或出现任意次,相当于 {0,},比如"\^*b"可以匹配 "b","^^^b"。 一些常用小例子举例: (1) 检查手机号是否合法:/^1(3\d|5[36789])\d{8}$/ 说明:手机号共11位,第一位为1,第二位为3或者5,当第二位为5的时候,第三位只能是36789中的一个 (2) 检查中文名是否合法:/^[\u4e00-\u9fa5]+$/ 说明:若不是中文或中文的前后有空格,都认为是不合法的 (3) 检查html标记是否匹配:/<(.*)>.*<\/\1>|<(.*) \/>/ 说明:如若只出现<html> 而无对应的</html>,则检验结果是html 标记不匹配 (4) 检查URL格式是否合法:”[a-zA-z]+://[^\s]*” 说明:URL合法格式应该以字母连接:// 开头 (5) 检查IP格式是否合法:/(\d+)\.(\d+)\.(\d+)\.(\d+)/ 说明:IP的格式是点分十进制格式,例如:192.168.100.11就是正确的IP (6) 检查账号是否合法:/^[a-zA-Z][a-zA-Z0-9_]{4,15}$/ 说明:账号字母开头,其他位可以有大小写字母、数字、下划线,允许5-16字节 (7) 检查QQ号是否合法:/^\s*[.0-9]{5,10}\s*$/ 说明:QQ号码必须是数字,最长10位 (8) 检查邮政编码是否合法:/^[1-9]\d{5}$/ 说明:邮编首位不为0,长度是6位的数字 (9) 检查身份证号是否合法:/(^\d{15}$)|(^\d{17}([0-9]|X)$)/ 说明:身份证号码为15位或者18位,15位时全为数字,18位前17位为数字,最后一位是校验位,可能为数字或字符X 2. 数字控件及时校验 数字控件有不为空校验,同时也可以控制其是否允许小数与父数,还可以设置数值的范围。 ![]() 3. 日期和时间控件及时校验 日期和时间控件可以设置其所在范围,如下图 ![]() 4. 下拉框的不为空 对于下拉框、下拉复选框、下拉树等下拉选项控件,他们的允许为空设置除了表示该控件不允许为空值,同时也可以控制他们的下拉选项中不允许有空选项,结合“空值将显示为:”一起使用。例如下图设置 ![]() 此时下拉选项中空值记录便会显示为ALL,效果如下 ![]() 若未选择任何项,确定后编辑其他单元格时将弹出及时校验对话框 ![]() 跨格数据及时校验 在实现填报时,有时需要在编辑完数据后跟其他具体某个格子对比,进行及时校验。当报表中提供的及时校验不能满足需求时,可以通过js事件来进行及时校验 1. 连接数据库FRDemo 2. 设计模板 2.1 新建报表 2.2 表样设计,如下图所示 ![]() 2.3 定义单元格填报属性 l 设置B2的控件类型为数字,如图所示 ![]() l 设置B3的控件类型为文本,如图所示 ![]() 2.4 事件编辑 l 对B2单元格控件设置进行事件编辑,添加编辑结束事件: var D2value = arguments[1].getCellValue("D2"); if (this.getValue() < D2value){ FR.Msg.alert(FR.i18n.Alert, "该值不能小于" + D2Value); return false; } 其中,D2value是自定义变量,用于获得D2单元格的值,if语句是用来判断该单元格输入后的值是否小于D2value,如果是则弹出警告:该值不能小于6 ![]() l 对B3单元格控件设计进行事件编辑,添加编辑结束事件: var D3value = arguments[1].getCellValue("D3"); if (this.getValue() != D3value){ FR.Msg.alert(FR.i18n.Alert, "该值应等于" + D3value); return false; } 其中,D3value是自定义变量,用于获得D3单元格的值,if语句是用来判断该单元格输入后的值是否等于D3value,如果不是是则弹出警告:该值应等于abc。 ![]() 3. 保存并预览 点击填报预览,在B2单元格中输入数字9,并按回车确定,则弹出警告,如图
![]() 在B3单元格中输入add,并按回车确定,也弹出校验警告,如图 扩展数据的数据校验 在填报模块中,有时需要对扩展的数据进行数据校验,例如:已知商品的价格,数量,总额,在填报提交时需要对总额进行校验,看总额是不是等于价格*数量。 1. 连接数据库FRDemo 2. 设计模板 2.1 新建报表 新建一张空白报表,添加数据集ds1:SELECT orders.orderid,amount,quantity,price FROM orders,ordersdetail WHERE orders.orderid = ordersdetail.orderid AND orders.orderid<’ ![]() 2.2 定义报表填报属性,添加两个内置SQL,具体设置如图 l 内置SQL1 ![]() l 内置SQL2 ![]() 2.3 定义单元格填报属性 单元格分别定义如下填报属性
2.4 数据校验 打开报表|报表填报属性,选择数据校验,插入新的验证信息。校验公式为 D3>=5&&D3<=100,表示D3单元格中的数据必须小于5并且小于100,否则数据校验时报错 ![]() 3. 保存并预览 点击设计器中的填报预览,并在BS界面点击数据校验,发现有一条数据不符合规范,报错,如图 ![]() 批量修改单元格 在大批量数据填报时,有时可能需要将置数单元格整体偏移多行或多列,若手动进行修改将会很麻烦,FineReport提供了批量修改单元格的功能,可以对大批量数据进行处理。 1. 打开报表 打开已有报表 2. 调整报表布局 ![]() 3. 报表填报属性 打开报表|报表填报属性,如下图所示 ![]() 我们发现,修改了样式后,所有填报的值对应的单元格存在偏差,应为A3、B3、C3、D3、E3、F3,此时一个一个的修改可能比较麻烦,我们可以利用批量修改单元格,具体操作如图 ![]() 点击确定后,填报单元格统一进行了修改,如图 ![]() 这样填报的值对应的单元格就通过批量修改单元格修改成功了! 填报保存值类型 在填报时控件类型为日期或者数字时,如果数据库Oracle中类型与填报控件中的类型不一致,填报时就无法插入数据,需要对填报控件进行处理才能插入。下面对Oracle数据中数据类型为Date 和 Number 类型数据进行填报介绍。 1. 连接数据库Oracle 点击报表菜单栏服务器|自定义数据连接,添加数据库,名为Oracle ![]() 2. 新建报表 新建一张空白的表格,添加数据ds1: SELECT * FROM temp.testdate 然后设计一张如下格式的报表 ![]() 3. 定义报表填报属性 自定义如下填报属性 ![]() 4. 自定义单元格填报属性 单元格分别定义如下填报属性
其中D2单元格的控件需要处理,日期的返回值类型选择日期 ![]() 5. 保存并预览 点击设计器填报预览,如图 ![]() 在生日单元格中修改数据,并提交 提交成功 对于电话填报,Oracle中的数据类型是Number时,当Oracle中的Number大小小于10位时,填报中能保存的数字位数为Number的大小,即Oracle中Number大小是多少,填报就能保持几位;当Oracle中的Number大小大于10时,填报数字控件只能保存10位数字。 填报流水号 在填报中,批量数据处理时为了方便,需要使用流水号来作为自增长型主键进行数据的更新。在Oracle数据库中,提供了序列的功能,可以通过Oracle的序列及触发器,实现主键的自增长。下面具体介绍自增长的实现。 1. 连接数据库 点击报表菜单栏服务器|自定义数据连接,添加数据库oracle ![]() 2. 创建表,序列,触发器,插入数据 进入Oracle数据库的Sqlplus窗口,创建表,序列,触发器 l 创建表:create table list (id number,name varchar2(50)); l 创建序列: create sequence list_seq minvalue 1 //最小值为1 maxvalue 9999 //最大值为9999 start with 1 //以1为初始值 increment by 1 //以1为增长间隔 cache 20 //缓存大小为20 order; l 创建触发器 create or replace trigger list_tg before insert on list //触发器依据的表 for each row //逐行触发 begin //触发器主体 select list_seq.nextval into:new.id from dual; end; l 插入数据 insert into list values(‘’,’aaa’); insert into list values(‘’,’bbb’); l 提交 commit; 3. 模板设计 3.1 新建模板 3.2 表样设计 新建一张空白的表格,添加数据ds1: SELECT * FROM temp.list 然后设计一张如下格式的报表 ![]() 3.3 定义报表填报属性 自定义如下填报属性 ![]() 3.4 自定义单元格填报属性 单元格分别定义如下填报属性
4. 填报并预览 点击设计器填报预览,ID列实现了自增长 ![]() 在NAME控件中填入cccc,并提交,显示填报成功 ![]() 再次刷新,ID列自增长 ![]() 填报自动匹配值 在填报中,有时需要在输入一个数据后,自动从数据库中获取对应的数值,自动匹配至 相应的单元格,这样就避免了填报时手动一个一个输入,该例子主要是通过写公式实现。 1. 新建报表 2. 报表设计 如下设计报表 ![]()
3. 控件设置 右击C3单元格|控件设置,控件类型选择下拉框,具体设置如下 ![]() D3至H3单元格控件类型设置为文本,如下图
4. 填报属性设置 打开菜单报表|报表填报属性,如下图所示设置 ![]() 5. 将A2列宽设置为零,进行隐藏
6. 保存模板,点击填报预览 在客户编号中选中相应的编号,后面的客户姓名,国家,城市,电话会自动匹配,如下图所示,只需要输入金额数值即可入库 ![]() 选择客户编号后点击其他地方,后面的信息就会自动匹配进来。 7. 批量匹配数据 同时若我们将需要的客户编号写入excel文件中,导入到页面中,就可以批量的匹配数据了 l 在报表|报表Web属性|填报页面设置中,给默认的工具栏加上excel导入按钮。 l 新建一个excel,在C3至C12中输入1至10 ![]() l 点击填报预览,导入该excel,导入后,即会批量进行置数。 文本域换行 在填报中,有时需要输入大量的文本,这时就需要用到文本域这个控件,但在用这个控件时,换行不能直接按Enter键,必须按Ctrl+Enter,才能达到换行的效果。 1. 新建报表 新建一张空白的表格,添加数据ds1: SELECT * FROM employee WHERE empid=‘1001‘ 然后设计一张如下格式的报表 ![]() 2. 定义报表填报属性 定义如下填报属性
![]() 3. 定义单元格填报属性 单元格分别定义如下填报属性:
4. 保存并填报 点击设计器中的填报预览
![]() 在员工地址文本域中输入地址,换行时用Ctri+Enter键,不能用Enter键(Enter键使用后表示清空)
![]() 下拉框的快速查询 在填报控件或者参数控件的下拉框类型控件中,下拉框有快速查询的功能,即输入部分值之后自动将符合条件的值显示出来。 1. 连接数据库FRDemo 2. 设计模板 2.1 新建模板 2.2 表样设计,具体样式如下图所示 ![]() 2.3 定义报表填报属性,具体设置如图 ![]() 2.4 定义单元格填报属性 单元格分别定义如下填报属性
D2单元格控件设置的类型是下拉框,具体如图 ![]() 3. 保存并预览 点击设计器的填报预览,如下图所示 ![]() 在城市的下拉框中,输入W会出来所有以W开头的城市名,这就是下拉框的快速查询功能,预览如图所示 ![]() 行式报表 在填报时,有时行式填报希望能从数据库取出来的行不能编辑,只能编辑通过添加行产生新的行,FR报表软件可以通过条件属性来设置 1. 新建报表 新建一张空白的表格,添加数据ds1: SELECT * FROM employee 然后设计一张如下格式的报表
![]() 2. 定义报表填报属性 自定义如下填报属性
![]() 3. 自定义单元格填报属性 单元格分别定义如下填报属性
A2的填报属性可以用条件属性设置 4. 条件属性设置 右击A2单元格,选择条件属性,进入条件属性窗口,添加条件属性,属性选择空间,并选中使用控件,编辑,控件类型选择文本,并添加公式(row()-1)>rowcount(“ds2”) 该公式表示,如果当前行号大于数据集中的总行数,则行号控件可用,具体如图
![]() 5. 填报并预览 点击设计器中的填报预览,如下图,从数据库中取出来的行的行号是不可编辑的
![]() 在BS界面上选中最后一行,并在上方的工具栏中点击增加记录,新出现一行,该行的行号可编辑,如图
![]() 用户自定义填报 在填报时,个别用户为了需求,需要自定义填报。FR报表在报表web属性中的填报页面设置中可以自定义填报功能 1. 连接数据库FRDemo 2. 设计报表 2.1 新建报表 2.2 表样设计 添加一个名为ds1的数据库查询:SELECT * FROM customer,表样设计,如图 ![]() 2.3 自定义报表填报属性 ![]() 2.4 定义单元格填报属性
2.5 自定义报表Web属性 点击菜单栏报表|报表Web属性,进入报表Web属性窗口,在填报页面设置栏目中,将左边需要显示的按钮拖到中间的窗口中,并在右边窗口添加加载结束事件,实现自定义的填报功能,如图所示 ![]() 在加载结束事件窗口中添加事件的JS代码 ![]() 具体js代码如下 var $toolbar = $('.FR-ToolBar-disabled > table > tbody > tr'); var option = { //"icon": "css:x-emb-email", "listeners": [ {"once": false, "action": function(e){ var xml = _g('${SessionID}').generateReportXML(); $.ajax({ url : "test.jsp", type : 'POST', data : {op : 'test1', sessionID : '${SessionID}', reportXML : xml}, complete : function(res, status) { FR.showDialog("Relation", 300, 400, res.responseText); }}) }, "eventName": "click" }], "text": "测试", "invisible": false, "type": "button", "disabled": false, "render": true}; $button = $('<div></div>'); FR.comp.create($button, "button", option); $tc = $("<td>").append($button); $toolbar.append($tc); 此段JS代码引用了一个test.jsp,代码为: <%@ page import="com.fr.web.CustomSubmit" %> <%@ page contentType="text/html" %> <% CustomSubmit.dealWithTest(request, response); %> 将该test.jsp文件放在设计器安装的WebReport目录下。 该test.jsp文件又引用了一个CustomSubmit类,将该类编译后的.class文件放在 %WebReport\WEB-INF\classes\com\fr\web目录下,该类的代码具体如下 package com.fr.web; import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.fr.base.ColumnRow; import com.fr.report.Report; import com.fr.report.core.FormReport; import com.fr.report.core.PackedReport; import com.fr.web.ParameterConsts; import com.fr.web.core.SessionDealWith; import com.fr.web.core.SessionIDInfor; import com.fr.web.core.WebUtils; public class CustomSubmit { public static void dealWithTest(HttpServletRequest req, HttpServletResponse res) throws Exception { String sessionID = WebUtils.getHTTPRequestParameter(req,ParameterConsts.SESSION_ID); SessionIDInfor sessionIDInfor = SessionDealWith.getSessionIDInfor(sessionID); List cellRelation = new ArrayList(); for(int i = 0, len = sessionIDInfor.getWorkBook2Show().getReportCount(); i < len; i++) { Report report = sessionIDInfor.getWorkBook2Show().getReport(i); if (report instanceof FormReport && report instanceof PackedReport) { Report fr = (PackedReport)report; //请注意这步,我想要取的是A1和B1两个格子扩展以后的他们之间关系和值,如果是想拿A1,B1,D5,对应添加ColumnRow.valueOf("D5")既可 List rl = ((FormReport)report).getExtendColumnRowList(new ColumnRow[] {ColumnRow.valueOf("A1"), ColumnRow.valueOf("B1")}); for (int c = 0, cl = rl.size(); c < cl; c++) { ColumnRow[] crs = (ColumnRow[])rl.get(c); ColumnRowValue[] crvs = new ColumnRowValue[crs.length]; for (int index = 0, il = crs.length; index < il; index++) { crvs[index] = new ColumnRowValue(crs[index], fr.getCellValue(crs[index].column, crs[index].row)); } cellRelation.add(crvs); } } } //cellRelation 里面存放着扩展以后的格子之间的关系和格子的值 //以111.cpt模板为例,数据列扩展后城市NewYork对应ID 1和4,在cellRelation里面就是 cellRelation.get(0)和cellRelation.get(1),对应着两个 ColumnRowValue[] //第一个ColumnRowValue数组的ColumnRowValue[0]的ColumnRow是A1,Value是NewYork,ColumnRowValue[1]的ColumnRow是B1,Value是1 //第二个ColumnRowValue数组的ColumnRowValue[0]的ColumnRow是A1,Value是NewYork,ColumnRowValue[1]的ColumnRow是B2,Value是4 if (cellRelation.size() > 0) { PrintWriter writer = WebUtils.createPrintWriter(res); for (int i = 0, len = cellRelation.size(); i < len; i++) { ColumnRowValue[] crvs = (ColumnRowValue[])cellRelation.get(i); StringBuffer sb = new StringBuffer(); for (int v = 0, vl = crvs.length; v < vl; v++) { if (v != 0) { sb.append(" "); } sb.append(crvs[v].toString()); if (v == vl - 1) { sb.append("<br />"); } } writer.println(sb.toString()); } writer.flush(); writer.close(); } } public static class ColumnRowValue { private ColumnRow cr; private Object value; public ColumnRowValue(ColumnRow cr, Object value) { this.cr = cr; this.value = value; } public ColumnRow getColumnRow() { return cr; } public Object getValue() { return value; } public String toString() { return new StringBuffer().append(cr.toString()).append(":").append(value.toString()).toString(); } } } 3. 保存并预览 点击填报预览,BS界面除了FR报表自带的提交按钮和数据校验按钮外,还多了一个测试按钮 ![]() 点击测试按钮,出现测试界面
|
|