后台主要工作是解析XML定义的标签文件,并获取到数据集,放入到Map中,然后调用Jacob.jar中提供的相关方法来实现替换。首先想多说一句就是jacob会每次生成word报告时都会启动一个office word进程,替换完毕之后 需要关闭掉这个进程,如果有死掉的word进程有可能会影响word的生成。这些具体调试或运行过程中就会发现这个问题的。
还需要说明一点,解析XML有很多种方式,自己挑选自己熟悉的就行了,我采用jdom,当时想的没有这么负责,所以写代码也没有怎么重构,需要重新整理,主要方法我会贴出来。
那么我就从头到尾的说一下,调用生成报告时,后台的整个调用过程是怎么样的,是如何运转的?
首先访问web应用地址:http://192.16.3.22/demo/DocInfo!createDoc.action 这样我提交一个方法 action方法,这个方法首先是在web应用服务器上的,然后进入action中的createDoc方法,同时你需要获取到从方法传过来的相关参数,比如:sql中定义的那个查询条件,报告类型等参数。
(在去调用生成报告的方法中,可能你还需要加入一些判断,如是否已经生成过报告啊,或者最新报告的版本啊,因为我们都是既保存word报告文档又会在数据库中插入一条记录,方便查询),这样就开始了:
首先是action的createDoc方法:
/**
* 通过HttpCient调用报告服务器的方法生成报告 DOC
*/
public String createDoc() throws Exception {
//定义放回成功与否的判断码
String prMsg="";
// 获取当前登录的用户
UserVo userVo = CommonUtils.getUserMessage();
//获取模版类型
docType = Struts2Utils.getParameter("docType");
//重新创建文档
String creatOrnot = Struts2Utils.getParameter("creatOrnot");
//获取组组编号参数
workgroupId = Struts2Utils.getParameter("workgroupId");
//获取评估用例实例ID参数
evtcaseInstId = Struts2Utils.getParameter("evtcaseInstId");
if(CommonUtils.isNotNull(docType)){
//获取项目Id
projectId = Struts2Utils.getParameter("projectId");
if(!CommonUtils.isNotNull(projectId)){
if(CommonUtils.isNotNull(this.getIdFromSession("PM_PROJECTID"))){
projectId = this.getIdFromSession("PM_PROJECTID").toString();
}else{
Struts2Utils.getRequest().setAttribute("msg", "请先选择项目!");
}
}
if(CommonUtils.isNotNull(projectId)){
prMsg = infoSystemDescService.downloadFileByUrl(projectId, userVo.getUserId(), workgroupId, evtcaseInstId, docType, creatOrnot);
}
}
return "docList";
}
注:在我贴出来的代码中,能看懂就行了,有些不用管他(可能是其他业务方面的判断),关于最后返回的prMsg---代表各种状态 主要表示成功与否或者是出错的信息。
接着我贴出service层的方法downloadFileByUrl
/** * 功能: * 1.(生成报告文档) * 2.保存指定URL的源文件到指定路径下 * @param projectId * @param userId * @param workgroupId * @param evtcaseInstId * @param docType * @param creatOrnot * @return * @throws Exception */ @SuppressWarnings("deprecation") public synchronized String downloadFileByUrl(String projectId,String userId,String workgroupId,String evtcaseInstId,String docType,String creatOrnot) throws Exception { String msg = "1";//"1":默认为创建成功的提示信息 "2":标识创建失败 String srcUrl = ""; //报告服务器的执行路径 HttpResponse response = null; FileOutputStream out = null; HttpClient httpclient = null; HttpGet httpget = null; long time1 = System.currentTimeMillis(); //获取保存后的路径 TProjDoc projDoc = projectDocDao.findFileByType(userId, Integer.parseInt(docType), Long.parseLong(projectId), workgroupId,evtcaseInstId); if(projDoc == null || (projDoc != null && CommonUtils.isNotNull(creatOrnot) && creatOrnot.equals("1"))){ //FT_任务编号_[FID] try { //获取报告服务器的执行路径 srcUrl = xmlPathDef.getActionUrl(docType, projectId,userId,workgroupId,evtcaseInstId); HttpParams httpParams = new BasicHttpParams(); // 设置最大连接数 ConnManagerParams.setMaxTotalConnections(httpParams, 1); // 设置获取连接的最大等待时间 //ConnManagerParams.setTimeout(httpParams, 6000); // 设置每个路由最大连接数 ConnPerRouteBean connPerRoute = new ConnPerRouteBean(1); ConnManagerParams.setMaxConnectionsPerRoute(httpParams,connPerRoute); // 设置连接超时时间 HttpConnectionParams.setConnectionTimeout(httpParams, 6000); // 设置读取超时时间 if(docType.toString().equals(XmlPathDef.SPOTTEST_DOC) && docType.toString().equals(XmlPathDef.FTEST_DOC)){ HttpConnectionParams.setSoTimeout(httpParams, 2400000); }else{ HttpConnectionParams.setSoTimeout(httpParams, 600000); } SchemeRegistry registry = new SchemeRegistry(); registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80)); registry.register(new Scheme("https", SSLSocketFactory.getSocketFactory(), 443)); ClientConnectionManager connectionManager = new ThreadSafeClientConnManager(httpParams, registry); httpclient = new DefaultHttpClient(connectionManager, httpParams); httpget = new HttpGet(srcUrl); //执行返回 response = httpclient.execute(httpget); //如果是本机既当服务器,又当报表服务器,那么就只生成一遍 String ipvalues = xmlPathDef.getRepUrl(); if(CommonUtils.isNotNull(ipvalues)){ if(ipvalues.indexOf(":") != -1){ ipvalues = ipvalues.substring(0,ipvalues.lastIndexOf(":")); } } HttpEntity entity = response.getEntity(); //获取保存后的路径 projDoc = projectDocDao.findFileByType(userId,Integer.parseInt(docType), Long.parseLong(projectId), workgroupId,evtcaseInstId); String filePath = ""; if(projDoc != null) filePath = projDoc.getPath(); if(CommonUtils.isNotNull(filePath)){ String basepath = XmlPathDef.getBasePath(); String outFilePath = (basepath + filePath).replaceAll("\\\\", "\\/"); XmlPathDef.isExists(outFilePath); File wdFile = new File(outFilePath); out = new FileOutputStream(wdFile); int l; byte[] tmp = new byte[2048]; while ((l = instream.read(tmp)) != -1) { out.write(tmp, 0, l); } out.flush(); out.close(); System.out.println("****************************** "); System.out.println(""); System.out.println("*************** 恭喜! 报告创建成功 结束 ***************"); System.out.println(""); }else{ msg = "8";//说明word创建成功,但是数据没有保存成功 response = null; } }else{ msg = "2"; } } catch (ClientProtocolException e) { msg = "7"; e.printStackTrace(); } catch (IOException e) { msg = "7"; logger.error("数据库报告服务器地址配置错误或网络不通!!2.连接是否超时" + e.getMessage()); e.printStackTrace(); }finally{ if(out!=null){ try { out.close(); } catch (IOException e) { msg = "7"; logger.error("数据库报告服务器地址配置错误或网络不通!!2.连接是否超时" + e.getMessage()); e.printStackTrace(); } } } } long time2 = System.currentTimeMillis(); long numTime = time2 - time1; if(docType.toString().equals(XmlPathDef.SPOTTEST_DOC) && docType.toString().equals(XmlPathDef.FTEST_DOC)){ if(numTime >= 2401000){ msg = "9"; } }else{ if(numTime >= 601000){ msg = "9"; } } System.out.println(""); String loggerinfo = "********* 报告类型为 :" + docType + " 执行时间为: " + (time2 - time1) /1000 + " 秒!***************"; System.out.println(loggerinfo); System.out.println(""); System.out.println("*****************************"); logger.info(loggerinfo); return msg; }
这个方法还有待优化和调整,现在我主要说明他的作用:
首先使用了synchronized 关键字 意思说使用同步的方式,让每次只有一个线程运行这个方法(其实如果是大数量的并发,就不能这样写了,自己去摸索吧)。然后在方法体中,使用了一个httpclient技术,这个主要是调用远程的服务返回对象流,在我这里就是调用另外一个服务器的代码,去生成报告,
然后将word报告的流返回来就ok,如果不明白httpclient的用法,请上网学一下,具体我就不说了。(下节我会贴出相应的代码)
最后通过httpclient的返回流写成word文档就行了(其实里面还有一些判断什么的,比如:最后返回流是否是word流啊,什么的 都需要判断的,我都去掉了,代码太多),返回一个状态码给action就完毕。
(未完待续)