门户项目中准备用web service获取现有的制作好的报表进行展示。遂去研究了下,研究的过程也是满纠结的,总算根据多方资料,将demo跑通了。
本文参考了网上的一些资料,做一下总结而已。讲解下如何配置,成功的获取到相关报表。
biee的web service的介绍我就不说了了,官方文档如下:
http://download.oracle.com/docs/cd/E21764_01/bi.1111/e16364/soa_overview.htm
提供的服务如下:
http://download.oracle.com/docs/cd/E12096_01/books/AnyWebServ/AnyWebServTOC.html
使用axis生成WEB service的客户端代码:
步骤参考:
http://gerardnico.com/wiki/ide/eclipse/eclipse_how_to_consume_a_webservice_with_wtp
需要指定包名为:com.siebel.analytics.web.soap.v5
客户端代码生成后,在eclipse下由于下载了插件依赖包都是有的,所以可以直接写一个java程序去测试下是否调用web service成功。
如果用maven生成工程,或者最终发布的话,需要在pom。xml中增加如下的依赖配置:
<dependency> <groupId>org.apache.axis</groupId> <artifactId>axis</artifactId> <version>1.4</version> </dependency> <dependency> <groupId>javax.xml</groupId> <artifactId>jaxrpc</artifactId> <version>1.1</version> </dependency> <dependency> <groupId>commons-discovery</groupId> <artifactId>commons-discovery</artifactId> <version>0.2</version> </dependency> <dependency> <groupId>wsdl4j</groupId> <artifactId>wsdl4j</artifactId> <version>1.6.2</version> </dependency> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.1-beta1</version> </dependency>
测试代码如下:
public class TestReadCatalog { public static void main(String[] args) { String sessionID = ""; SAWSessionServiceSoapProxy myPort = new SAWSessionServiceSoapProxy(); try { sessionID = myPort.logon("jianchen", "jianchen"); } catch (RemoteException e) { // TODO Auto-generated catch block e.printStackTrace(); } //测试获取目录结构 WebCatalogServiceSoapProxy catalogService = new WebCatalogServiceSoapProxy(); try { CatalogObject catalogItems = catalogService.readObject("/shared", false, sessionID); System.out.println(catalogItems.getItemInfo().getPath()); ItemInfo[] items = catalogService.getSubItems("/shared", "*", false, null, sessionID); for (ItemInfo item : items) { System.out.println(item.getCaption()); } } catch (RemoteException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
这里我用的登录账号是:rpd的账号。登录成功后会返回一个sessionID。跟服务器的交互必须要有sessionID作为参数。
执行后,的确能够获取到返回的catalog目录,输出目录名称。
最关键的来了,就是如何把biee中做好的报表展示到web页面上呢。biee提供了HtmlViewService,支持对biee report进行访问。
测试代码如下:
public class TestReadReport { /** * @param args */ public static void main(String[] args) { String sessionID = ""; SAWSessionParameters sessionparams = new SAWSessionParameters(); SAWSessionServiceSoapProxy myPort = new SAWSessionServiceSoapProxy(); try { sessionID = myPort.logon("jianchen", "jianchen"); } catch (RemoteException e) { // TODO Auto-generated catch block e.printStackTrace(); } HtmlViewServiceSoapProxy viewService = new HtmlViewServiceSoapProxy(); ReportRef reportRef = new ReportRef(); reportRef.setReportPath("/shared/"); StartPageParams startPageParams = new StartPageParams(); startPageParams.setIdsPrefix("beijixing"+Math.round(Math.random()*1000000)); startPageParams.setDontUseHttpCookies(false); try { String pageID = viewService.startPage(startPageParams, sessionID); viewService.addReportToPage(pageID, "beijixing", reportRef, null, null, null, sessionID); StringBuffer reportHTML = new StringBuffer(); /* reportHTML.append(viewService.getHeadersHtml(pageID, sessionID)); reportHTML.append(viewService.getHtmlForReport(pageID, "beijixing", sessionID));*/ reportHTML.append(viewService.getHtmlForPageWithOneReport("beijixing", reportRef, null, null, null, null, sessionID)); System.out.println(reportHTML.toString()); } catch (RemoteException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
测试是能够获取到html代码的。但是在页面上展示这段代码时,只会出现一个“等待”,而没有真正的获取报表内容。
分析页面源代码:发现页面里的js以及css等资源的路径都是:“missing_xxx.css”之类的。说明获取的那些资源没有加载到。
还有一个很关键的点,在某篇老外的博客上提到:
所以在登录服务器前,需要有如下代码段:
SAWLocale sawlocale = new SAWLocale(); sawlocale.setLanguage(request.getLocale().getLanguage()); sawlocale.setCountry(request.getLocale().getCountry()); SAWSessionParameters sessionparams = new SAWSessionParameters(); sessionparams.setUserAgent(request.getHeader("User-Agent")); sessionparams.setLocale(sawlocale); sessionparams.setAsyncLogon(false);
后仔细阅读文档,内容如下:
To avoid these issues, use the setBridge() method to modify callback URLs to point to the third-party Web server. Be aware that a Web component executed by the third-party Web server to re-route requests to Oracle BI Web Services is not provided. This function would need to be fulfilled by the third-party application. For more information about the setBridge() method, read setBridge() Method.
就是说这些静态资源需要用桥接的方式向真正的服务器发起请求,返回给浏览器。
桥接的实现,可以利用servlet,该servlet里要干的事情如下:
Make a URLConnection to the URL and read the content.
Write to the output stream.
当时为了立即看到效果,该bridge的代码我是借用了别人的(代码有点bug,比如连接未关闭,不能复用的bug),等正式开发用的时候可以考虑重新改写下,优化下性能。还是贴出来吧,方便下大众。
public class MyBridge extends HttpServlet { private static final long serialVersionUID = 1L; /** * Default constructor. */ public MyBridge() { // TODO Auto-generated constructor stub } /** * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse * response) */ @SuppressWarnings("unchecked") protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String relatedtUrl = request.getParameter("RedirectURL"); relatedtUrl = relatedtUrl.replaceAll("NoAuthGo", "Go"); StringBuffer url = new StringBuffer("").append(relatedtUrl); System.out.println("relatedtUrl>>>>>*****>>>>>>>>>>" + relatedtUrl); List<NameValuePair> nvps = new ArrayList<NameValuePair>(); Map parameterMap = request.getParameterMap(); for (Iterator iterator = parameterMap.keySet().iterator(); iterator .hasNext();) { String parameterName = (String) iterator.next(); String[] parameterValues = (String[]) parameterMap .get(parameterName); if (parameterValues != null && parameterValues.length > 0) { if (parameterName.equals("RedirectURL")) { continue; } for (int i = 0; i < parameterValues.length; i++) { NameValuePair pair = new BasicNameValuePair(parameterName, parameterValues[i]); nvps.add(pair); } } } HttpClient client = new DefaultHttpClient(); if (!url.toString().endsWith(".js") && !url.toString().endsWith(".css") && !url.toString().endsWith(".png") && !url.toString().endsWith(".gif")) { List<NameValuePair> tmp = new ArrayList<NameValuePair>(); NameValuePair pair = new BasicNameValuePair("NQUser", "jianchen"); NameValuePair pair1 = new BasicNameValuePair("NQPassword", "jianchen"); tmp.add(pair); tmp.add(pair1); HttpPost lpost = new HttpPost(url.toString()); lpost.setEntity(new UrlEncodedFormEntity(tmp, "GBK")); HttpResponse lresp = client.execute(lpost); System.out.println("登陆结果:"+lresp.getStatusLine().getStatusCode()); lpost.abort(); } if(url.toString().indexOf("?Go")<0 || url.toString().indexOf("?DocPart")>0){ HttpPost post = new HttpPost(url.toString()); post.setEntity(new UrlEncodedFormEntity(nvps,"GBK")); post.addHeader("Content-Type", "binary/data"); post.addHeader("User-Agent", request.getHeader("USER-AGENT")); HttpResponse resp = client.execute(post); HttpEntity entity = resp.getEntity(); InputStream in = entity.getContent(); if(url.toString().indexOf("?DocPart")>0){ FileOutputStream fout=new FileOutputStream("e:\\aaa.jpg"); byte buffer1[] = new byte[1024 * 128]; int k = 0; while ((k = in.read(buffer1)) != -1) { fout.write(buffer1, 0, k); } fout.flush(); fout.close(); } ServletOutputStream out = response.getOutputStream(); byte buffer1[] = new byte[1024 * 128]; int k = 0; while ((k = in.read(buffer1)) != -1) { out.write(buffer1, 0, k); } in.close(); out.close(); } else { HttpPost post = new HttpPost(url.toString()); post.setEntity(new UrlEncodedFormEntity(nvps,"GBK")); post.addHeader("Content-Type", "binary/data"); post.addHeader("User-Agent", request.getHeader("USER-AGENT")); HttpResponse resp = client.execute(post); HttpEntity entity = resp.getEntity(); InputStream in = entity.getContent(); InputStreamReader isr = new InputStreamReader(in); BufferedReader br = new BufferedReader(isr); StringBuffer sb = new StringBuffer(); String r = br.readLine(); sb.append(r); while (r != null) { r = br.readLine(); sb.append(r); } String html = sb.toString();//TODO 本地 InputStream sin = new ByteArrayInputStream(html.getBytes()); ServletOutputStream out = response.getOutputStream(); byte buffer1[] = new byte[1024 * 128]; int k = 0; while ((k = sin.read(buffer1)) != -1) { out.write(buffer1, 0, k); } sin.close(); out.close(); post.abort(); } } /** * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse * response) */ protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
web.xml中配置servlet如下:
<servlet> <description> </description> <display-name>MyBridge</display-name> <servlet-name>MyBridge</servlet-name> <servlet-class>com.taobao.service.kunshuo.webservice.MyBridge</servlet-class> </servlet> <servlet> <display-name>Apache-Axis Servlet</display-name> <servlet-name>AxisServlet</servlet-name> <servlet-class>org.apache.axis.transport.http.AxisServlet</servlet-class> </servlet> <servlet> <display-name>Axis Admin Servlet</display-name> <servlet-name>AdminServlet</servlet-name> <servlet-class>org.apache.axis.transport.http.AdminServlet</servlet-class> <load-on-startup>100</load-on-startup> </servlet> <servlet-mapping> <servlet-name>MyBridge</servlet-name> <url-pattern>/MyBridge</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>AxisServlet</servlet-name> <url-pattern>/servlet/AxisServlet</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>AxisServlet</servlet-name> <url-pattern>*.jws</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>AxisServlet</servlet-name> <url-pattern>/services/*</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>AdminServlet</servlet-name> <url-pattern>/servlet/AdminServlet</url-pattern> </servlet-mapping>
至此,将获取到的报表html增加到要展示的页面里,比如jsp,就可以直接展示报表了。
后面的获取xml结果,自己可以进行处理展示结果。还有待后续研究。
有几个开发同学跟我要源代码,都是通过邮箱发送的,这里我把我当时的demo发上来作为附件吧。
可以在附件中进行下载