OAF中输出PDF报表文件超链接
OAF中输出PDF报表文件超链接解决方案
解决思路
获取PDF文件的输出流
获取输出流之后将其转换为BLOB
将转化后的BLOB存储在附件表fnd_blobs中
构造该BLOB文件的URL
将URL存储在客户化表里形成一条唯一的记录,返回唯一ID FORM通过返回得唯一ID找到URL,调用方法,在浏览器打开URL
技术要点
- 使用TemplateHelper.processTemplate方法生成目标PDF的InputStream流
- 调用程序包将InputStream传入数据库中的BLOB字段中,并生成对应的记录
. 获取到唯一记录的 file_id,使用API生成对应的 URL
实现过程
-
使用TemplateHelper.processTemplate方法生成目标PDF的InputStream流
首先选择页面数据代码,点击多选框后,需要在触发事件中写入
/** - 查询界面 选择需要输出的数据(多选),调用获取xmlClob的程序包 - @param pageContext - @param webBean */ public static void doPrint_req(OAPageContext pageContext, OAWebBean webBean,String poNumber) { OAApplicationModule am = pageContext.getApplicationModule(webBean); //getRootApplicationModule(); CUX90POOrderDateilsVOImpl vo = (CUX90POOrderDateilsVOImpl)am.findViewObject("CUX90POOrderDateilsVO1"); CUX90POOrderDateilsVORowImpl row = null; String str = ""; String param = ""; boolean flag3 = true; int i = 0; int j = 0; row = (CUX90POOrderDateilsVORowImpl)vo.first(); //定位记录指针到第一条 while (row != null) { // String checkFlag = row.getCheckFlag(); if (poNumber.equals(row.getDocumentNum())) { j = j + 1; } if (vo.hasNext()) { row = (CUX90POOrderDateilsVORowImpl)vo.next(); } else { break; } } if (j != 0) { Number[] params = new Number[j]; //iface_line_id row = (CUX90POOrderDateilsVORowImpl)vo.first(); //定位记录指针到第一条 while (row != null) { if (poNumber.equals(row.getDocumentNum())) { Number lineId = row.getLineId(); System.out.println("lineId:"+lineId); params[i] = lineId; // param = param + lineId + ","; i = i + 1; } if (vo.hasNext()) { row = (CUX90POOrderDateilsVORowImpl)vo.next(); } else { break; } } //获取XMLClob。 getXMLClob_req(pageContext, webBean, params,poNumber); } }
然后看一下获取选择数据的xmlClob的方法getXMLClob_req
/** * (有多选框版本)调用AM执行PLSQL返回CLOB类型 * @param pageContext * @param webBean */ public static void getXMLClob_req(OAPageContext pageContext, OAWebBean webBean, Number[] params,String poNumber) { OAApplicationModule am = pageContext.getApplicationModule(webBean); Serializable[] methodParams = { params }; Class[] methodParamTypes = { params.getClass() }; CLOB tempClob = (CLOB)am.invokeMethod("getXmlColb", methodParams, methodParamTypes); //在EBS中定义好之后报表需要输出的RTF模板,写入模板名称。 String templateName = "CUXEBSPODOCUMENTRPT"; //调用打印PDF的方法,将xml数据对象以及数据模板作为参数传入 PrintPDF_req(pageContext, webBean, tempClob,templateName,poNumber); }
可以看一下AM中调用getXmlColb的方法,其中大概就是使用OAF调用获取xml数据的程序包,将参数传入,然后将XML数据返回,跟做xml报表并无区别,只是将xml作为CLOB数据返回,具体就不细看了。
/** * 执行PLSQL 返回CLOB类型数据 * @param params 数值类型参数,存放选择数据的LINE_ID * @return */ public CLOB getXmlColb(Number[] params) { String result = null; String num = null; CLOB tempClob = null; OADBTransaction oadbtransaction = getOADBTransaction(); OracleConnection oracleConnection = (OracleConnection)oadbtransaction.getJdbcConnection(); if (params[0] != null) { ARRAY vdrArray = null; try { ArrayDescriptor tableOfNumber = oracle.sql.ArrayDescriptor.createDescriptor("FND_TABLE_OF_NUMBER", oracleConnection); vdrArray = new ARRAY(tableOfNumber, oracleConnection, params); String sql = "BEGIN cux_ebs_po_equipment_unitrpt.main(errbuf => :1, retcode=>:2, p_order_type=>:3, p_id_arr=>:4, x_out_xml=>:5);end;"; OracleCallableStatement oraclecallablestatement = (OracleCallableStatement)oadbtransaction.createCallableStatement(sql, 1); //PLSQL 输入参数 oraclecallablestatement.setString(3,"POORDER"); oraclecallablestatement.setARRAY(4, vdrArray); //PACKAGE 输出参数 oraclecallablestatement.registerOutParameter(1, OracleTypes.VARCHAR); oraclecallablestatement.registerOutParameter(2, OracleTypes.VARCHAR); oraclecallablestatement.registerOutParameter(5, OracleTypes.CLOB); //实行SQL oraclecallablestatement.execute(); //获取值 tempClob = oraclecallablestatement.getCLOB(5); } catch (Exception ex) { ex.printStackTrace(); } } return tempClob; }
接下来看一下调用PrintPDF_req打印PDF文件的方法。
/** * 调用模板生成PDF文件 * @param pageContext * @param webBean * @param xmlClob PLSQL返回的CLOB类型参数 * @param templateName 系统中模板的名称 * @param poNumber 订单编号 */ public static void PrintPDF_req(OAPageContext pageContext, OAWebBean webBean, CLOB xmlClob, String templateName,String poNumber) { // HttpServletResponse response = // (HttpServletResponse)pageContext.getRenderingContext().getServletResponse(); OAApplicationModule am = pageContext.getApplicationModule(webBean); OADBTransaction oadbTransaction = am.getOADBTransaction(); String fileName = "PurchaseOrder_"+poNumber+".pdf"; try { Reader inputReader = xmlClob.getCharacterStream(); //定义一个接收数据的输出流,将PDF的文件流输出。 ByteArrayOutputStream pdfFile = new ByteArrayOutputStream(); OADBTransactionImpl oaTrans = (OADBTransactionImpl)pageContext.getApplicationModule(webBean).getOADBTransaction(); // 参数--应用缩写,模板名称 TemplateHelper.processTemplate(oaTrans.getAppsContext(), "CUX", templateName, "zh", "CN", inputReader, TemplateHelper.OUTPUT_TYPE_PDF, null, pdfFile); byte[] bytes = pdfFile.toByteArray(); //定义一个输入流,将PDF文件流输入进去 InputStream in= new ByteArrayInputStream(bytes); //调用程序包,将blob放进数据库。 OADBTransaction oadbtransaction = am.getOADBTransaction(); OracleConnection oracleConnection = (OracleConnection)oadbtransaction.getJdbcConnection(); String sql = "BEGIN apps.cux_ebs_po_oacreatepo_pkg.update_file(errbuf => :1, retcode=>:2,p_file_name=>:3,p_blob=>:4,x_file_id=>:5,p_po_number=>:6);end;"; OracleCallableStatement oraclecallablestatement = (OracleCallableStatement)oadbtransaction.createCallableStatement(sql, 1); //PLSQL 输入参数 oraclecallablestatement.setString(3, fileName); oraclecallablestatement.setBlob(4,in); oraclecallablestatement.setString(6,poNumber); //PACKAGE 输出参数 oraclecallablestatement.registerOutParameter(1, OracleTypes.VARCHAR); oraclecallablestatement.registerOutParameter(2, OracleTypes.VARCHAR); oraclecallablestatement.registerOutParameter(5, OracleTypes.VARCHAR); //执行SQL oraclecallablestatement.execute(); String resultError = oraclecallablestatement.getString(1); System.out.println("resultError:"+resultError); String retcode = oraclecallablestatement.getString(2); System.out.println("retcode:"+retcode); String fileId=oraclecallablestatement.getString(5); System.out.println("fileId:"+fileId); } catch (Exception e) { // response.setContentType("text/html"); throw new OAException(e.getMessage(), OAException.ERROR); } }
接下里看一下程序包中接收BLOB之后的处理
/*================================================== Procedure Name : update_file Description: 将获取到的PDF文件输入流插入fnd_lobs表中,生成一条唯一的记录,并使用API生成超链接更新进传OA的接口表中。 Argument: errbuf : concurrent return message buffer retcode : concurrent return status code 0 success / 1 warning / 2 error x_file_id :OAF调试中每次生成的file_id p_file_name :文件名称 p_blob :接收到的文件BLOB p_po_number :订单编号 History: 1.00 2019-08-22 kaikai.zhang Creation ==================================================*/ PROCEDURE update_file(errbuf OUT VARCHAR2 ,retcode OUT VARCHAR2 ,x_file_id OUT VARCHAR2 ,p_file_name IN VARCHAR2 ,p_blob IN BLOB ,p_po_number IN VARCHAR2) IS l_return_status VARCHAR2(30); l_msg_count NUMBER; l_msg_data VARCHAR2(2000); l_file_id NUMBER; l_url VARCHAR2(240); BEGIN retcode := '0'; SELECT fnd_lobs_s.nextval INTO l_file_id FROM dual; --插入文件内容到附件表 INSERT INTO fnd_lobs (file_id ,file_name ,file_content_type ,file_data ,upload_date ,expiration_date ,program_name ,program_tag ,LANGUAGE ,file_format) VALUES (l_file_id ,p_file_name ,'application/pdf' --SELECT * FROM fnd_mime_types 查询文件类型 ,p_blob ,SYSDATE ,SYSDATE ,'ERPTOOAORDER' ,'XDO:10' ,'ZHS' ,'binary'); x_file_id := l_file_id; ------------------------------------------------------------------------- /* 使用file_id生成唯一的URL */ ------------------------------------------------------------------------- l_url := fnd_gfm.construct_download_url(fnd_web_config.gfm_agent, l_file_id, TRUE); ------------------------------------------------------------------------- /* 将生成的超链接更新进接口表中 */ ------------------------------------------------------------------------- IF l_url IS NOT NULL THEN UPDATE cux_oa_po_approval_iface t SET t.attchment = l_url ,t.attchment_flag = 'Y' WHERE 1 = 1 AND t.document_num = p_po_number; ELSE UPDATE cux_oa_po_approval_iface t SET t.attchment_flag = 'N' WHERE 1 = 1 AND t.document_num = p_po_number; END IF; COMMIT; EXCEPTION WHEN fnd_api.g_exc_error THEN cux_30_fnd_conc_utl.log_message_list; retcode := '1'; fnd_msg_pub.count_and_get(p_encoded => fnd_api.g_false, p_count => l_msg_count, p_data => l_msg_data); IF l_msg_count > 1 THEN l_msg_data := fnd_msg_pub.get_detail(p_msg_index => fnd_msg_pub.g_first, p_encoded => fnd_api.g_false); END IF; errbuf := NULL; errbuf := l_msg_data; WHEN fnd_api.g_exc_unexpected_error THEN cux_30_fnd_conc_utl.log_message_list; retcode := '2'; fnd_msg_pub.count_and_get(p_encoded => fnd_api.g_false, p_count => l_msg_count, p_data => l_msg_data); IF l_msg_count > 1 THEN l_msg_data := fnd_msg_pub.get_detail(p_msg_index => fnd_msg_pub.g_first, p_encoded => fnd_api.g_false); END IF; errbuf := NULL; errbuf := l_msg_data; WHEN OTHERS THEN fnd_msg_pub.add_exc_msg(p_pkg_name => g_pkg_name, p_procedure_name => 'MAIN', p_error_text => substrb(SQLERRM, 1, 240)); cux_30_fnd_conc_utl.log_message_list; retcode := '2'; errbuf := NULL; errbuf := SQLERRM; END update_file;
这样超链接就生成到传OA的接口表中,每次OA只需从接口表中获取对应记录的链接就可以获取相应的PDF报表
实战为王,记录在工作中技术使用的点点滴滴