Excel进行数据转换后执行导入
业务需求:填报表导入excel的时候,经常遇到实际excel中的数据需要入库前对其数据根据数据库或者其他文件中的数据规则进行一次转换后,将转换后的数据存入相应表中。
技术难点:润乾的导入excel功能,对excel读取是通过开源的poi包,再根据报表中设计的填报更新数据,将单元格和数据库字段映射来进行上报,而在这个过程中要加入这种数据转换可以通过表达式来做,但是更新属性中的表达式又不支持数据集函数或者query函数,后台api导入行式报表时,提供的api接口只能导入excel中的所见数据。
解决方案:提出了3种针对此问题的解决方案,包括前台和后台的。
准备工作:数据库表(也可是文件),存放数据为键值对的这种关系数据,用于针对excel中的数据进行转换。如下图:
上报excel模板,简单两列即可,一列为城市,一列为订单数量。
以及excel上报入库的数据库表。当然存的数据不能使城市和订单数量,则应该为城市ID和订单数量两列。
方案一:通过润乾的内置函数前台实现:
首先准备一张简单的行式填报表。并且设定相对应的更新属性。
当然,这样设定好,直接用之前准备的excel页面中上报,完全可以操作成功,只不过存入数据库中的就是城市的名称,并没有转成ID,之前提到过一个技术难点,是更新属性里更新值这里的表达式不能写数据集函数或者query函数,所以不能进行转换,所以,可以通过调用单元格来进行转换。
新增加一个数据集为城市ID和名称的字典表,在单元格中将该数据集的数据列出(此处需要注意,针对哪个单元格进行转换,这套字典表ID和名称的数据需列在这列下面)。然后将3、4隐藏(由于行式报表不能隐藏,可用其他方式,如显示值设成“”,行高设成0)。
根据初级教程中1、2替换成男、女来显示的灵感,这里也可以通过map函数进行转换,在更新属性中的更新值中加入表达式:=map(list(A4),list(A3)),用A3单元格的值来替换导入excel数据后对应的A4单元格的值,然后进行提交。
在页面中导入excel提交后,数据库中插入了相应转换后的数据:
这样就做到了前台导入excel并且进行了数据转换的功能。
方案二:通过api的方式后台实现:
还是先准备一张行式填报表,不过这张表比方案一的报表将对简单,只需要设定更新属性和增加字典表的数据集即可。
然后通过api的形式来进行 行式填报表提交。
public class ApiInput extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// String filePath1 = request.getParameter(“filePath1″);
// 设置报表模版
String AppPath = getServletContext().getRealPath(“/”);
System.out.print(AppPath);
String reportFile = AppPath + “/reportFiles/test.raq”;
Context cxt = new Context();
ReportDefine rd = null;
// 读取报表模版
try {
rd = (ReportDefine) ReportUtils.read(reportFile);
} catch (Exception exception) {
exception.printStackTrace();
}
// 加载引擎计算
Engine engine = new Engine(rd, cxt);
IReport iReport = engine.calc();
// 转为行式报表,因为只有行式报表才支持不定行导入数据
RowReport rr = (RowReport) iReport;
String did = rr.getDetailID(2); // 第几行是主扩展行
SimpleDateFormat dateF = new SimpleDateFormat(FormatUtils
.getDateFormat(Locale.getDefault()));
SimpleDateFormat timeF = new SimpleDateFormat(FormatUtils
.getTimeFormat(Locale.getDefault()));
SimpleDateFormat datetimeF = new SimpleDateFormat(FormatUtils
.getDatetimeFormat(Locale.getDefault()));
try {
ExcelImporter ei = new ExcelImporter(“D:/lalala3.xls”);
IReport excelReport = ei.getReport(0);
RowReportSaver rowSaver = new RowReportSaver(rr, null, cxt); // 构造数据保存对象
// 读入excel文件及其数据
for (int i = 1; i <= excelReport.getRowCount(); i++) { // //逐行逐列把excel数据写入填报表
Area area = rr.insertDetail(did);
for (int j = 1; j <= iReport.getColCount(); j++) {
INormalCell iExcelCell = excelReport.getCell(i, (short) j); // 取得excel单元格
if (iExcelCell == null)
continue;
String svalue = “”;
Object value = iExcelCell.getValue();
if (value != null) {
svalue = value.toString();
if (j == 1)
svalue = testDs(cxt, svalue);
}
// 执行保存方法
rowSaver.setCellInputValue(area.getBeginRow(), (short) j,
svalue, dateF, timeF, datetimeF);
}
}
rowSaver.save(); // 执行保存
} catch (Exception e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
private String testDs(Context cxt, String svalue) {
DataSet ds = cxt.getDataSet(“ds2″); // 根据数据集的名称获取已算出的数据集
if (ds == null)
return svalue;
// 保证id name没有空值,否则需要过滤下
int colCount = ds.getColCount(); // 获得数据集的行数列数
int rowCount = ds.getRowCount();
for (int i = 1; i <= rowCount; i++) { // 注意数据集的行号列号从1开始
for (int j = 1; j <= colCount; j++) {
Object value = ds.getData(i, j); // 获取某行某列的数据值
System.out.print(“第” + i + “行第” + j + “列的值为“); // 逐个打出数据集的值
System.out.println(value);
if (svalue.equals(value.toString())) {
return ds.getData(i, j – 1).toString();// 根据name值来定义所对应的id
}
}
}
return svalue;
}
}
在doGet()方法中调用润乾行式报表提交的rowSaver.setCellInputValue(area.getBeginRow(), (short) j, svalue, dateF, timeF, datetimeF);方法前,通过testDs()方法将excel中拿到的数据进行转换,读取报表中已有的数据集,然后遍历后进行数据转换后再调用setCellInputValue()方法进行上报,同样实现了导入excel并且进行了数据转换的功能。
方案三:用DAMS的EXCEL导入实现:
首先部署ExcelImportNew导入excel的项目环境。需要进行数据库初始化,用于excel后台导入校验自定义入库规则等使用。(t_excel_mapping.sql)
部署应用后,访问http://localhost:8080/ExcelImportNew/eds/excelImport/taskList.jsp进入页面中操作。
设置入库规则:
选择映射表:首先数据源连接通过润乾的reportconfig配置文件定义连接,数据库表通过xml文件进行设定,在web-inf下的mapping.xml,此文件是对应入库提交时对应的表,跟转换无关,所以对于字典表无需设置进去。
<?xml version=“1.0″ encoding=“UTF-8″?>
<mapping>
<table>
<name> demo_area</name>
<value>城市码表</value>
</table>
<table>
<name>test</name>
<value>测试表</value>
</table>
</mapping>
在列映射中,对于无需修改直接入库的字段,直接选定数据库字段即可,此处主键设置与数据库端无关。
需要转换的字段通过自定义设置里使用润乾提供能的query2函数来进行查询转换、
例如:城市字段需要在demo_area表中相关联,选择t1_id,自定义值为query2(“importExcel”,”select t.城市ID from demo_area t where t.城市=?”,@RQIMPORTEXCEL_A)
query2函数具体使用请参照润乾函数说明。importExcel为数据源名称
此处参数名称需要规范 @RQIMPORTEXCEL_A (A代表A列,B代表B列,依次类推,均需大写);列映射和自定义设置中如果同时定义了相同列,会以列映射为最终结果
最后执行导入:实现了导入excel并且进行了数据转换的功能。
以上是总结了3种方式导入excel以及进行数据转换的方式。