原文地址:如何动态创建table
需求:
因为系统中有几千个QA plan 但是不能手动创建几千个 质量收集页面
所有需要根据 不同的plan 动态创建对应的 质量收集页面。
但是创建tabel 都要绑定一个 具体的vo 而我需要一个动态的
如果用 select ... from dual 的话 字段的个数如何动态?
感谢答主sumury
方案0.1版本
//用以下的代码可以实现,但是有一点不足,就是当数据量比较多的时候,无法按照指定的行数进行分页显示。 //先在页面上创建一个advancedTable,名字叫“region5”,即可。 public void processRequest(OAPageContext pageContext, OAWebBean webBean) { super.processRequest(pageContext, webBean); final String CHILD_DATA_LIST = "childDataList"; final String TEXT = "text"; int COLUMN_COUNT = 0; // write your Personalization SQL in here. StringBuffer sbfSQL = new StringBuffer(200); // set title in the advancedTable sbfSQL.append("SELECT '名' user_name, 'ID' user_id, '開始日' FROM dual \r\n"); sbfSQL.append("UNION ALL \r\n"); sbfSQL.append("SELECT fu.user_name, to_char(fu.user_id), to_char(fu.start_date) FROM fnd_user fu"); ResultSet rs = null; Statement s = null; Connection con = pageContext.getApplicationModule(webBean).getOADBTransaction().getJdbcConnection(); try { s = con.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE); rs = s.executeQuery(sbfSQL.toString()); ResultSetMetaData rsmd = rs.getMetaData(); COLUMN_COUNT = rsmd.getColumnCount(); rs.last(); int intRowCount = rs.getRow(); rs.first(); // find the advancedTable OAAdvancedTableBean tableBean = (OAAdvancedTableBean)webBean.findChildRecursive("region5"); tableBean.setViewUsageName(""); for (int i = 1; i <= COLUMN_COUNT; i++) { // create a column OAColumnBean cb = (OAColumnBean)createWebBean(pageContext, COLUMN_BEAN, null, null); tableBean.addIndexedChild(cb); // create MessageStyledText OAMessageStyledTextBean mst = (OAMessageStyledTextBean)createWebBean(pageContext, MESSAGE_STYLED_TEXT_BEAN, null, null); mst.setTextBinding(TEXT + i); cb.addIndexedChild(mst); // create title OASortableHeaderBean shb = (OASortableHeaderBean)createWebBean(pageContext, SORTABLE_HEADER_BEAN, null, null); shb.setPrompt(rs.getString(i)); cb.setColumnHeader(shb); if (i != 1) { UINodeList colList = new DataObjectListNodeList(mst, new DataBoundValue(CHILD_DATA_LIST + i)); cb.setIndexedNodeList(colList); } } // get row count; DictionaryData rowData[] = new DictionaryData[intRowCount - 1]; int intRowLoop = 2; // loop row while (rs.next()) { // setting 1 column cell value rowData[intRowLoop - 2] = new DictionaryData(TEXT + "1", rs.getString(1)); // setting 2 to N column cell value DictionaryData otherColumn[] = new DictionaryData[COLUMN_COUNT]; // loop column for (int j = 2; j <= COLUMN_COUNT; j++) { otherColumn[j - 2] = new DictionaryData(TEXT + j, rs.getString(j)); rowData[intRowLoop - 2].put(CHILD_DATA_LIST + j , new ArrayDataSet(otherColumn)); } intRowLoop++; } tableBean.setTableData(new ArrayDataSet(rowData)); } catch (SQLException se) { se.printStackTrace(); } finally { if (s != null) { try { s.close(); } catch (SQLException se) { se.printStackTrace(); } } if (rs != null) { try { rs.close(); } catch (SQLException se) { se.printStackTrace(); } } } }
方案0.2版本
/*今天空下来,又研究了一下这个问题,有种比之前的方法更好些的方法。贴出来大家看看。 1、创建一个DynVO,里面不需要有SQL,而且只需要生成xml,就可以了 2、把DynVO加到AM中去。 3、在页面上创建advancedTable,取名region6,并且绑定DynVO1 4、在CO中追加以下代码:*/ public void processRequest(OAPageContext pageContext, OAWebBean webBean) { super.processRequest(pageContext, webBean); OAApplicationModule am = pageContext.getApplicationModule(webBean); String[][] strTitleAndAttributeName = (String[][])am.invokeMethod("initDynVO"); OAAdvancedTableBean tableBean = (OAAdvancedTableBean)webBean.findChildRecursive("region6"); for (int i = 0; i < strTitleAndAttributeName[0].length; i++) { // create a column OAColumnBean cb = (OAColumnBean)createWebBean(pageContext, COLUMN_BEAN, null, null); tableBean.addIndexedChild(cb); // create MessageStyledText OAMessageStyledTextBean mst = (OAMessageStyledTextBean)createWebBean(pageContext, MESSAGE_STYLED_TEXT_BEAN, null, null); mst.setViewAttributeName(strTitleAndAttributeName[1][i]); cb.addIndexedChild(mst); // create title OASortableHeaderBean shb = (OASortableHeaderBean)createWebBean(pageContext, SORTABLE_HEADER_BEAN, null, null); shb.setPrompt(strTitleAndAttributeName[0][i]); cb.setColumnHeader(shb); } } //5、在AM中追加以下代码 public String[][] initDynVO() { StringBuffer sbfSQLTitle = new StringBuffer(200); // set title in the advancedTable sbfSQLTitle.append("SELECT '名' user_name, 'ID' user_id, '開始日' start_date FROM dual"); StringBuffer sbfSQLValue = new StringBuffer(200); sbfSQLValue.append("SELECT fu.user_name, to_char(fu.user_id), to_char(fu.start_date) FROM fnd_user fu"); OAViewObjectImpl vo = getDynVO1(); vo.setQuery(sbfSQLTitle.toString()); vo.executeQuery(); // set attribute to updateable Row row = vo.first(); AttributeDefImpl[] ad = (AttributeDefImpl[])vo.getViewDefinition().getAttributeDefs(); int intAttributeCount = ad.length; String[] strTitle = new String[intAttributeCount]; for (int i = 0; i < intAttributeCount; i++) { ad[i].setUpdateableFlag(AttributeDefImpl.UPDATEABLE); // get title from SQL result. strTitle[i] = (String)row.getAttribute(i); } vo.setQuery(sbfSQLValue.toString()); vo.executeQuery(); return new String[][]{strTitle, row.getAttributeNames()}; } /*完毕。 残留问题: 虽然在AM的代码中写了ad[i].setUpdateableFlag(AttributeDefImpl.UPDATEABLE); 发现,对于VO中的数据,我们是可以更新了。 但是确不能insert和remove数据。 目前还想不出怎么解决这个问题。*/
终极版1.0
/*通过一天的研究,解决了原来的代码中,无法对row进行insert和remove的处理。 原来的代码,对VO进行了2次查询,第一次检索出advancedTable的标题,第二次检索出实际数据。 但是比较好的做法是,使用UNION ALL,将两段查询合并,进行一次查询。 对于查询结果而言,第一行是标题,待我们提取出来以后,再删除它,剩下的就是要在advancedTable中显示的数据了。 然而,使用原来的代码,运行到row.remove()方法的时候,就是抛出错误消息Oracle.jbo.ReadOnlyViewObjectException: JBO-25016. 所以,我们需要跟踪row.remove()方法看看,到底哪里抛出了这个错误消息。 通过反编译 ViewRowImpl.class,发现*/ void doRemove(int i) { ArrayList arraylist = null; try { useInner(); if(mInner.mVO.isReadOnly()) throw new ReadOnlyViewObjectException(mInner.mVO.getName()); ...... } //然后再查看ViewObjectImpl.class 文件 public boolean isReadOnly() { return mViewDef.isReadOnly() && getDynamicAttributeCount() == 0; } /*到这里发现一点苗头了,我们可以通过修改mViewDef.isReadOnly()或getDynamicAttributeCount() == 0;中的任何一个值,来实现我们的目的。 通过进一步的调查发现很难修改mViewDef.isReadOnly()的值,所以,只能将重点放在修改getDynamicAttributeCount()上了。 通过读源代码发现,使用vo.addDynamicAttribute()方法,可以改变getDynamicAttributeCount()的返回值,于是就实验了一把。结果成功了。 以下是修改好的代码,可以对VO中的数据进行insert、remove、update操作了。*/ public String[][] initDynVO() { StringBuffer sbfSQL = new StringBuffer(200); // set title in the advancedTable sbfSQL.append("SELECT '名' user_name, 'ID' user_id, '開始日' start_date FROM dual "); sbfSQL.append("UNION ALL "); sbfSQL.append("SELECT fu.user_name, to_char(fu.user_id), to_char(fu.start_date) FROM fnd_user fu"); OAViewObjectImpl vo = getDynVO1(); vo.setQuery(sbfSQL.toString()); vo.executeQuery(); // set attribute to updateable Row row = vo.first(); AttributeDefImpl[] ad = (AttributeDefImpl[])vo.getViewDefinition().getAttributeDefs(); int intAttributeCount = ad.length; String[] strTitle = new String[intAttributeCount]; String[] strAttributeNames = row.getAttributeNames(); for (int i = 0; i < intAttributeCount; i++) { // for update the attribute ad.setUpdateableFlag(AttributeDefImpl.UPDATEABLE); // get title from SQL result. strTitle = (String)row.getAttribute(i); } // for insert and remove row. vo.addDynamicAttribute("DUMMY_ATTRIBUTE"); row.remove(); return new String[][]{strTitle, strAttributeNames}; }
感谢这些热爱思考且愿意分享代码的人们。