今年7月分刚毕业,8月中旬入职一家刚起步不久的小公司。在这之前还在一家在国内比较著名的集团分公司研发中心呆过一个月,感觉不是我喜欢做的工作,于是果断辞职。我想大概我是那家公司入职最短的员工吧,还不满一个月。来到新的东家,便跟着项目经理接手一个已经做了一部分的项目,该项目主要是收集、处理和展示数据。其中使用到了FineReport 这个报表工具,这个报表工具的确是很强大,在业内也是具有良好的口碑的。我觉得,软件就是用来解决现实生活中的问题的,只要能解决我的问题,它就很好。好了,不废话,直接进入正题。
在报表中填好的数据如何入库呢?该工具提供了两种方式入库:内置SQL和自定义提交。我没有使用内置SQL, 因为我收集的数据需要经过后台方法过滤,所以选择了自定义提交。在此项目中,我为该自定义提交分了两种方式:非grid式和grid式;
非grid:对应的数据表只有一张,即单表操作,所有填报的数据就一条记录。这种情况的提交方式比较简单,直接简单地配置属性和属性值即可提交到后台处理。在一般开发中实体的属性和数据库表的字段是一致的,我们公司要求一致(大写)。以下是报表填报属性的自定义提交配置图:
图 1
从图中可以看到,名字就是你的实体属性,而值就是要从单元格中取来的。这里有8种取法供你选择,如下图所示,我一般使用单元格和公式,而且公式也是我在grid式报表的主要取值手段。
图 2
对于单元格,你填报的数据在哪个格子上,就直接该格子对应的坐标即可,就跟Excel一样,例如:F13。对于公式,我们可以使用报表工具提供的公式方便地对要取的数据做一些预处理,以便后台进行处理,比如:CONCATENATE(C7,D7,E7,F7,G7,H7,I7,J7,K7,L7,M7,N7),表示拼接C7~N7这个些格子的值,并返回一个字符串。当然,你也可以在公式中直接输入格子的坐标来拼接,比如需要使用‘-’来拼接,直接在公式中输入:U15+'-'+V15+'-'+W15即可。
现在需要提交的数据配置好了,那么就需要将这些数据提交到后台处理了。在图 1中,有没有看到需要配置一个类,对!这个类就是用来接收你要提交的数据的。所以你需要自定义一个类并继承该报表工具提供的一个父类 TotalSubmitJob,实现该类的方法doTotalJob。以下是部分代码:
protected void doTotalJob(Data data, Calculator calculator)
throws Exception {
//一次提交可能含有多条记录
JSONArray ja = new JSONArray();
for (int i = 0; i < data.getRowCount(); i++) { // getRowCount 获取一共多少行数据
Map result_map = new HashMap();
for (int j = 0; j < data.getColumnCount(); j++) {
Object value = data.getValueAt(i, j); // 获取对应位置的值
if (value instanceof JobValue) {
JobValue ce = (JobValue) value;
value = ce.getValue(); // 通过JobValue的getValue方法获得单元格的值
}
/*
* 网格式报表 得到的value 可能有 FArray和"{....}"格式数据。模版上做了特殊配置。
* 非网格式的报表每次得到的数据为普通字符串
* */
if(value instanceof FArray){
FArray fArray = (FArray)value;
List list = fArray.toList();
JSONArray jsonArr = new JSONArray();
for(int k = 0; k < list.size(); k++){
jsonArr.add(JSONObject.fromObject(list.get(k)));
}
value = jsonArr;
} else if(String.valueOf(value).startsWith("{") && String.valueOf(value).endsWith("}")){
JSONArray jsonArr = new JSONArray();
jsonArr.add(JSONObject.fromObject(value));
value = jsonArr;
} else { //表单式报表 现在不需要做任何处理,
}
result_map.put(data.getColumnName(j), value);
}
//System.out.println(JSONObject.fromObject(result_map).toString());
ja.add(JSONObject.fromObject(result_map));
}
//特殊处理如表311的值json,对于表111报表式的报表将JSONArray-->JSONObject
JSONObject jo = JsonobjMerger(ja.toString());
//省略之后的代码
}
我们可以从 data 这个参数中取得我们需要的数据,至于取得的数据的状态是什么样的,想了解具体细节的可参考: 点击打开链接,将取到的数据放到一个JSONArray中。然而在这个JSONArray中对于grid式的报表可能存在重复数据,所将其合并返回一个JSONObject。
private JSONObject JsonobjMerger(String jsonStr) {
JSONArray jsonArr = JSONArray.fromObject(jsonStr);
JSONObject jsonObj = new JSONObject();
for (int i = 0; i < jsonArr.size(); i++) {
JSONObject jo = jsonArr.getJSONObject(i);
if (jsonObj.size() == 0) {
jsonObj = jo;
} else {
for (Object keyObj : jo.keySet()) {
String key = keyObj + "";
if (jo.get(key) instanceof JSONArray) {
JSONArray tempJa = JSONArray.fromObject(jo.get(key));
for (int j = 0; j < tempJa.size(); j++) {
if (jsonObj.containsKey(key)) {
if (jsonObj.getJSONArray(key).indexOf(
tempJa.get(j)) == -1) {
jsonObj.accumulate(key, tempJa.get(j));
}
} else {
jsonObj.accumulate(key, tempJa);
}
}
} else {
jsonObj.accumulate(key, jo.get(key));
}
}
}
}
return jsonObj;
}
//非网格式填报报表
if(jo.containsKey("table_index")) {
jo = processMainData(jo);
String table_index = (String) jo.remove("table_index");
//补充报表式报表中缺少的数据,例如:创建人,创建时间等
if(VTools.StringIsNullOrSpace((String)jo.get("ID"))) {
jo.remove("ID");
jo.put("ID", VTools.getNewUUID());
}
jo.put("CREATE_USER", "");
jo.put("CREATE_TIME", VTools.getTimeNow("yyyy-MM-dd HH:mm:ss"));
jo.put("STATE", "1");
jo.put("AUTH_USER", "");
jo.put("AUTH_USER", "");
jo.put("AUTH_TIME", "");
jo.put("MORGID", "");
ISession session = SessionFactory.openSession();
session.getTransaction().begin();
saveHBRReportOfMain(table_index, jo, session); //利用反射设置实体属性
session.getTransaction().commit();
DBUtil.closeSession(session);
}
图 3-1
图3-2
其关键点在于grid式报表一个属性(某些特殊属性除外)对应一个实体(一条记录)。所以需要将此种属性的值配置成图3-2所示,将属性和属性值拼接成JSON文本即可。其取值直接输入该格子对应的坐标即可。将数据传递到后台方法中,通过JsonobjMerger方法合并重复的项,利用反射设置数据,入库即可。以下是关键代码:
if(jo.containsKey("ISGRID")) {
//判断是否是网格式报表
JSONArray joA = jo.getJSONArray("ISGRID");
String isTrue = joA.getJSONObject(0).getString("ISGRID");
String main_id = null;
if("true".equalsIgnoreCase(isTrue)) {
ISession session = SessionFactory.openSession();
session.getTransaction().begin();
String table_index = null;
//取得MAIN_ID和表索引table_index
if(jo.containsKey("MAIN_ID") && jo.containsKey("table_index")) {
JSONArray jo_mainId = jo.getJSONArray("MAIN_ID");
main_id = jo_mainId.getJSONObject(0).getString("MAIN_ID");
JSONArray jo_tableIndex = jo.getJSONArray("table_index");
table_index = jo_tableIndex.getJSONObject(0).getString("table_index");
String table_index_item = table_index.split("_")[0];
JSONArray jo_version = jo.getJSONArray("VERSION");
String versionId = jo_version.getJSONObject(0).getString("VERSION");
if(VTools.StringIsNullOrSpace(main_id) && !VTools.StringIsNullOrSpace(table_index_item)) {
main_id = VTools.getNewUUID();
//生成主表信息
JSONObject jo_main = new JSONObject();
jo_main.put("ID", main_id);
jo_main.put("CREATE_USER", "");
jo_main.put("CREATE_TIME", VTools.getTimeNow("yyyy-MM-dd HH:mm:ss"));
jo_main.put("STATE", "1");
jo_main.put("AUTH_USER", "");
jo_main.put("AUTH_USER", "");
jo_main.put("AUTH_TIME", "");
jo_main.put("MORGID", "");
jo_main.put("VERSION", versionId);
saveHBRReportOfMain(table_index_item, jo_main, session);
}
}
//操作子表
//将josn对象中附件的信息去掉,只保留实体相关的数据
jo.remove("ISGRID");
jo.remove("MAIN_ID");
jo.remove("table_index");
jo.remove("VERSION");
List entityList = null;
if(jo.size() > 0) {
entityList = new ArrayList();
Set keySet = jo.keySet();
Iterator ite = keySet.iterator();
String className_item = "com.wisdragon.stdb.entity.STDB_HBR" + table_index;
while (ite.hasNext()) {
Object obj = ite.next();
if(jo.get(obj) instanceof JSONArray) {
JSONArray ja_temp = JSONArray.fromObject(jo.get(obj));
for (int i = 0; i < ja_temp.size(); i++) {
JSONObject jo_temp = ja_temp.getJSONObject(i);
Class> clazz_temp = Class.forName(className_item);
entityList.add(bind(clazz_temp, jo_temp));
}
}
}
//保存或更新子表
saveHBRReportOfItem(main_id, entityList, session); //反射设置属性
}
session.getTransaction().commit();
DBUtil.closeSession(session);
}
}