vue使用ntko控件完成word上传、html上传

前言

新项目前端用的是vue框架,后端用的是struts1框架(没错,就是struts1)。客户要求增加word上传的功能,这个功能在以前老项目里面已经存在,只需将jsp改造成vue。实际上,在改造过程中遇到了很多问题,记录下。

步骤

  1. ntko需要传递一些参数,我把它们写在props上,父组件使用时只需传递这些参数就可以了。
    props: {
      settings: {
        docId: '',  // 文档id,同时是文档名称
        docFolder: '',  // 文件夹名称,
        fileExt: '.doc', // 文件扩展名:默认为.doc,如果你只上传word文档,这个不用改
        width: '700',   // 控件宽度
        height: '500'  // 控件高度
      }
    }
  1. ntko是activex控件来着,使用方式如下:
<!--
xxxx:根据自己的情况填写
:width:绑定宽度
:height:绑定高度
-->
<object id='TANGER_OCX' classid='clsid:xxxxxxxxxxxx'
        codebase='../../../../public/lib/ntko-office/OfficeControl.cab#version=5,0,4,1'
        :width='settings.width' :height='settings.height'>
  <param name='TitleBar' value='0'>
  <param name="NoExpireKey" value="xxxxxxxxxxxxxxxxxxxxx">
  <param name="MakerCaption" value="xxxxxxxxxxxxxxxxxxxxx">
  <param name="MakerKey" value="xxxxxxxxxxxxxxxxxxxxx">
  <param name="ProductCaption" value="xxxxxxxxxxxxxxxxxxxxx">
  <param name="ProductKey" value="xxxxxxxxxxxxxxxxxxxxx">
  <span style="color: red;display: inline-block">当前浏览器不能装载文档控件,
    请在检查浏览器的选项中检查浏览器的安全设置。</span>
</object>
  1. ntko的操作api需要一个ntko对象,所以需要一个属性存储ntko对象
    data() {
      return {
        officeObj: null  // ntko对象
      }
    }
  1. 初始化
      /**
       * 初始化文档控件,主要做以下操作:
       * 1. 封装ntko对象
       * 2. 判断docId是否为空,如果为空,则创建一个新的word文档;
       *     否则,根据docId去下载文档并显示出来
       */
      initDoc(){
        // 获取控件对象
        this.officeObj = document.getElementById("TANGER_OCX")

        if (this.officeObj == null) {
          return
        }
        if (this.settings.docId == null || this.settings.docId === '') {
          // 打开一个空白文档
          this.officeObj.CreateNew('Word.Document')
        } else {
          // 下载文档
          this.httpDownload()
        }
      }
  1. 下载word文档:注意,这里下载的都是word文档,下载其他文档需要另作处理
      /**
       * 下载office控件
       */
      httpDownload() {
        let fileName = this.settings.docId + '.doc'

        let fileUrl = "/downloadOfficeOcx.do?fileName=" + fileName + "&docFolder=" + this.settings.docFolder
        return this.officeObj.OpenFromURL(fileUrl, false)
      }
  1. 上传word文档
      /**
       * 上传word文档
       */
      httpUpload() {
        let myUrl = "/uploadOfficeOcx.do"
        let fileName = this.settings.docId + '.doc'

        let params = "docFolder=" + this.settings.docFolder

        /**
         * officeFile:文件域的id,类似
        return this.officeObj.saveToURL(myUrl, "officeFile", params, fileName, 0)
      }
  1. 上传html文档
      /**
       * doc转HTML:会先上传word文档,然后再转换为html,再上传html文档
       */
      saveDocAsHTML()  {
        //上传office文件
        this.httpUpload()
        //把文件保存到服务器
        let htmlFileName = this.settings.docId + ".html"
        let myUrl = "/uploadHtmlOcx.do?docId=" + this.settings.docId + "&docFolder=" + this.settings.docFolder

        //发布成html文件
        return this.officeObj.PublishAsHTMLToURL(myUrl, "uploadHtml", null, htmlFileName, 0)
      }
  1. 后台操作逻辑
	/* office和html的上传路径:根据实际情况写,一般从配置文件中读取 */
	private String officeUploadPath = "xxx/xxx/xxx";
	private String htmlUploadPath = "xxx/xxx/xxx";
	
	/**
	 * 功能:下载office编辑文档信息
	 */
	public ActionForward downloadOfficeOcx(ActionMapping mapping,
			ActionForm form, HttpServletRequest request,
			HttpServletResponse response) throws Exception {
		String fileName = request.getParameter("fileName");
		InputStream inStream = null;
		try {
			String docFolder = request.getParameter("docFolder");
			String filePath = officeUploadPath + "/" + docFolder + "/"
					+ fileName;
			// 设置输出的格式
			response.reset();
			response.setContentType("bin");
			response.addHeader("Content-Disposition", "attachment; filename=\""
					+ fileName + "\"");

			File file = new File(filePath);
			if (!file.exists()) {// doc文档不存在时则创建一个
				return null;
			}

			// 读到流中
			inStream = new FileInputStream(filePath);// 文件的存放路径
			// 循环取出流中的数据
			byte[] b = new byte[100];
			int len;
			while ((len = inStream.read(b)) > 0)
				response.getOutputStream().write(b, 0, len);
			inStream.close();
		} catch (Exception e) {
			throw e;
		} finally {
			IOUtils.closeQuietly(inStream);
		}
		return null;
	}
	/**
	 * 上传文档
	 */
	public ActionForward uploadOfficeOcx(ActionMapping mapping,
			ActionForm form, HttpServletRequest request,
			HttpServletResponse response) throws Exception {
		OfficeUploadForm officeUploadForm = (OfficeUploadForm) form;
		Hashtable<Object, Object> files = officeUploadForm
				.getMultipartRequestHandler().getFileElements();
		TreeMap<Object, Object> tree = new TreeMap<Object, Object>(files);
		// 上传文件
		StringBuffer message = new StringBuffer();
		if (!files.isEmpty()) {
			for (Object it : tree.keySet()) {
				FormFile formFile = (FormFile) files.get(it.toString());
				FileOutputStream fos = null;
				try {
					String docFolder = request.getParameter("docFolder");
					File file = new File(officeUploadPath + File.separator
							+ docFolder);
					if (!file.exists()) {
						file.mkdirs();// 文件夹找不到,创建文件夹
					}
					String officePath = officeUploadPath + File.separator
							+ docFolder + File.separator
							+ formFile.getFileName();
					fos = new FileOutputStream(new File(officePath));
					// 上传
					fos.write(formFile.getFileData());
					message.append("上传文件成功!");
				} catch (IOException e) {
					e.printStackTrace();
					message.append("上传文件失败!");
				} finally {
					IOUtils.closeQuietly(fos);
				}
			}
		}
		// 响应编码格式为gbk
		response.setCharacterEncoding("gbk");
		response.getWriter().print(message.toString());
		return null;
	}
	/**
	 * 功能:保存为html文档
	 */
	public void uploadHtmlOcx(ActionMapping mapping, ActionForm form,
			HttpServletRequest request, HttpServletResponse response)
			throws Exception {
		String docFolder = request.getParameter("docFolder");
		String docId = request.getParameter("docId");
		String path = htmlUploadPath + File.separator + docFolder + File.separator + docId;
		try {
			DiskFileItemFactory factory = new DiskFileItemFactory();
			ServletFileUpload servletFileUpload = new ServletFileUpload(factory);
			List<FileItem> fileItems = servletFileUpload.parseRequest(request);

			for (FileItem fileItem : fileItems) {
				if (fileItem.isFormField()) {
					String FieldName = fileItem.getFieldName();
					// getName()返回的是文件名字普通域没有文件返回NULL
					String Content = fileItem.getString("UTF-8");
					request.setAttribute(FieldName, Content);
				} else {
					String nm = fileItem.getName().substring(
							fileItem.getName().lastIndexOf("\\") + 1);
					File file = new File(path);
					if (!file.exists()) {
						file.mkdirs();// 文件夹找不到,创建文件夹
					}
					File mkr = new File(path, nm);
					if (nm.indexOf(".html") > 0) {
						String html = getReadToString(
								fileItem.getInputStream(), "gb2312");
						StringBuilder sb = new StringBuilder();
						try {
							Parser parser = new Parser();
							parser.setInputHTML(html);
							parser.setEncoding("gb2312");

							NodeIterator it = parser.elements();

							while (it.hasMoreNodes()) {
								Node node = it.nextNode();
								node.accept(new NodeVisitor() {
									public void visitTag(Tag tag) {
										if (tag instanceof LinkTag) {
											LinkTag link = (LinkTag) tag;

											link.setAttribute("target",
													"_blank");

										}
									}
								});
								sb.append(node.toHtml());
							}
						} catch (Exception e) {
							e.printStackTrace();
						}
						FileWriter fw = new FileWriter(mkr);
						fw.write(sb.toString());
						fw.close();
					} else {
						fileItem.write(mkr);
					}
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	private String getReadToString(InputStream is, String type) {
		StringBuffer data = new StringBuffer(1000);
		Reader reader = null;
		BufferedReader bufferReader = null;
		try {
			reader = new InputStreamReader(is, Charset.forName(type));
			bufferReader = new BufferedReader(reader);
			String line;
			while ((line = bufferReader.readLine()) != null) {
				data.append(line);
				data.append("\r\n");
			}
		} catch (Exception e) {
			e.printStackTrace();
			closeStream(is, bufferReader, reader);
			return "";
		} finally {
			closeStream(is, bufferReader, reader);

			return data.toString();
		}
	}

	/**
	 * @param is
	 * @param bufferReader
	 * @param reader
	 */
	public static void closeStream(InputStream is, BufferedReader bufferReader,
			Reader reader) {
		try {
			if (bufferReader != null) {
				bufferReader.close();
			}
		} catch (IOException e1) {
			e1.printStackTrace();
		}
		try {
			if (reader != null) {
				reader.close();
			}
		} catch (IOException e1) {
			e1.printStackTrace();
		}
		try {
			if (is != null) {
				is.close();
			}
		} catch (IOException e1) {
			e1.printStackTrace();
		}
	}
	
/**
 * word文件接收form
 */
public class OfficeUploadForm extends BaseStrutsForm implements Serializable {
	private static final long serialVersionUID = -8000290643668685995L;
	private FormFile officeFile;

	public FormFile getOfficeFile() {
		return officeFile;
	}
	public void setOfficeFile(FormFile officeFile) {
		this.officeFile = officeFile;
	}

}

采坑(问题)

  1. 父组件settings改变,为何子组件没有响应改变?原来以前都是监听值的改变,由于settings是对象,不能使用之前的办法监听了,所以采用以下做法。Object.assign的作用是合并两个对象。
    watch: {
      settings: {
        handler(val){
          this.settings = Object.assign(this.settings, val)
        },
        deep:true
      }
    }
  1. uploadOfficeOcx方法为什么后台接收不到文件?这里涉及到struts1的用法了,使用ActionForm的时候一定要记得在xml中配置
  <form-beans>
      <form-bean name="officeUploadForm" type="xxx.xxx.xxx.OfficeUploadForm" />
  form-beans>  
  
  <action name="officeUploadForm" path="//uploadOfficeOcx" parameter="uploadOfficeOcx" scope="request"
    type="org.springframework.web.struts.DelegatingActionProxy">
  action>
  <action name="officeUploadForm" path="/downloadOfficeOcx" parameter="downloadOfficeOcx" scope="request"
    type="org.springframework.web.struts.DelegatingActionProxy">
  action>
  <action path="/uploadHtmlOcx" parameter="uploadHtmlOcx" scope="request"
    type="org.springframework.web.struts.DelegatingActionProxy">
  action>
  1. 上传单文件没问题,但是如果html中带有图片资源,相当于多文件上传,后台为什么只拿到最后一个文件?还有,我改成其他方法(ServletFileUpload),为什么一个文件也接收不了?

第一个问题:这种问题出现在使用OfficeUploadForm去接收多个文件,由于上传时html和图片资源的name值都是一样的,struts1根据name值获取文件,由于只有一个name值,后来者把前面的都覆盖了,所以只有一个文件。

第二个问题:网上很多人推荐使用ServletFileUpload获取多文件,很方便强大。但是遇到struts1这个老顽固,就得小心了。因为ActionForm和ServletFileUpload不能同时存在,否则会接收不到文件。所以需要在xml中去掉uploadHtmlOcx的name值,同时把uploadHtmlOcx的返回值设为void。

  1. 我使用了弹框组件,为什么会被ntko控件覆盖?怎么解决?

这个问题在官网有记录,主要思路是:用一个iframe把整个ntko覆盖,设置iframe的z-index为一个很小的值,然后在iframe上弹框。但是有个问题:iframe怎么设置透明,各位大佬,给我个思路。




.shade-iframe {
   position:absolute;
   top:0px;
   left:0px;
   width:5000px;
   height:5000px;
   z-index:100;
   border-width:0px;
   background: #ff0000;
   opacity:0;
 }

总结

ntko坑很多,使用时建议结合旧项目(if exist)和ntko文档来,有问题记得上官网查询、或者百度。最后我想说的是:我不是针对ntko,我是针对在座的各位office web控件,都是垃圾!

你可能感兴趣的:(框架,前端)