目录

      • 需求:
      • 准备:
  • 文件、流之间的转换
    • MultipartFile 转 inputstream(输入流)
    • outputStream(输出流)转为 inputstream(输入流)
    • inputstream (输入流)转 ByteArrayOutputStream
    • MultipartFile 文件直接转输入流上传和生成摘要
    • MultipartFile 文件需要转为pdf 再进行上传和生成摘要
    • 文件上传源码
        • 文件hash 摘要算法
        • docx或doc转pdf
        • 文件上传

需求:

通过MultipartFile 上传文件到文件服务器,上传前要把文件转为pdf格式进行上传,并生成文件摘要用来验证服务器中的文件是否被篡改。

准备:

需要涉及到 inputstream(输入流)或outputStream(输出流)要使用两次 。
一、如果该文件本身就是pdf格式则直接进行上传。第一次是通过输入流去上传文件;第二次是通过输入流去生成文件摘要。

二、如果该文件不是pdf则需要工具类把文件转为pdf再上传。转pdf的工具类 返回的为outputStream(输出流)。上传的工具类以及生成摘要的工具类则需要inputstream(输入流)。
则需要把输出流进行转化变为输入流,然后再第一次是通过输入流去上传文件;第二次是通过输入流去生成文件摘要

注:流读过一次就不能再读了,而InputStream对象本身不能复制

文件、流之间的转换

MultipartFile 转 inputstream(输入流)

 byte [] byteArr=file.getBytes(); InputStream inputStream = new ByteArrayInputStream(byteArr);

outputStream(输出流)转为 inputstream(输入流)

 ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); InputStream inputStream2 = new ByteArrayInputStream(outputStream.toByteArray());

inputstream (输入流)转 ByteArrayOutputStream

 //InputStream 转 ByteArrayOutputStream //获取到一个inputstream后,可能要多次利用它进行read的操作。由于流读过一次就不能再读了,而InputStream对象本身不能复制,而且它也没有实现Cloneable接口 public static ByteArrayOutputStream cloneInputStream(InputStream input) {try {ByteArrayOutputStream baos = new ByteArrayOutputStream();byte[] buffer = new byte[1024];int len;while ((len = input.read(buffer)) > -1) {baos.write(buffer, 0, len);}baos.flush();return baos;} catch (IOException e) {e.printStackTrace();return null;}}

MultipartFile 文件直接转输入流上传和生成摘要

通过file 转字节数组,因为流不能重复读,所以要new成两个输入流。

 //获取并生成以pdf为后缀的文件名称String fileName = StringUtils.substringBeforeLast(originalFilename,"."); fileName = fileName +".pdf"; //如果上传的为pdf 则直接进行上传 不需要转换 if(originalFilename.endsWith(".pdf")){ //文件转字节数组 byte [] byteArr=file.getBytes(); //输入流1 InputStream inputStream = new ByteArrayInputStream(byteArr); //输入流2 InputStream inputStream2 = new ByteArrayInputStream(byteArr); //文件上传 url = CephUtils.uploadInputStreamReturnUrl("/" + Constants.CEPH_BUCK_NAME, fileName, inputStream); //生成文档hash 摘要 hash = FileHahUtil.hashAbstractByInputStream(inputStream2);}

MultipartFile 文件需要转为pdf 再进行上传和生成摘要

 //转换为pdf 后的输出流 ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); //原文件 byte [] byteArr=file.getBytes();InputStream inputStream = new ByteArrayInputStream(byteArr);//要转为pdf 文档Word2PdfUtil.convert2PdfStream(inputStream,outputStream);//输出流转输入流ByteArrayOutputStream baosPdf = (ByteArrayOutputStream) outputStream ;InputStream inputStream2 = new ByteArrayInputStream(baosPdf.toByteArray());//inputStream 只能用来读取一次所以进行copy一个新的 用来生成摘要InputStream inputStream3 = new ByteArrayInputStream(baosPdf.toByteArray());//生成文档hash 摘要hash = FileHahUtil.hashAbstractByInputStream(inputStream3);//上传文件url = fileService.uploadFileByInputStream(inputStream2,fileName);

文件上传源码

 //文件上传(文档转pdf)@ApiOperation(value = "文件上传(文档转pdf)", produces = "application/json")@ApiResponses(value = {@ApiResponse(code = 200, message = "文件上传(文档转pdf)")})@PostMapping(value = "/uploadWordFile")public BaseVo<Contract> uploadWordFile(HttpServletRequest request, MultipartFile file, HttpServletResponse response){long startTimeTotal = System.currentTimeMillis();BaseVo<Contract> baseVo = new BaseVo<Contract>();baseVo.setCodeMessage(CodeConstant.FAILURE_CODE);try {if(null != file){String originalFilename = file.getOriginalFilename();//文件上传后返回的地址String url = "";//文件摘要的hash值String hash = "";if (!originalFilename.endsWith(".docx") && !originalFilename.endsWith(".doc") && !originalFilename.endsWith(".pdf")) {//上传的文件格式不支持baseVo.setMessage("暂不支持当前文件格式上传!");}else {//生成新的文件名称String fileName = StringUtils.substringBeforeLast(originalFilename,".");fileName = fileName +".pdf";//如果上传的为pdf 则直接进行上传 不需要转换if(originalFilename.endsWith(".pdf")){byte [] byteArr=file.getBytes();InputStream inputStream = new ByteArrayInputStream(byteArr);InputStream inputStream2 = new ByteArrayInputStream(byteArr);url = CephUtils.uploadInputStreamReturnUrl("/" + Constants.CEPH_BUCK_NAME, fileName, inputStream);//生成文档hash 摘要hash = FileHahUtil.hashAbstractByInputStream(inputStream2);}else {ByteArrayOutputStream outputStream = new ByteArrayOutputStream();byte [] byteArr=file.getBytes();InputStream inputStream = new ByteArrayInputStream(byteArr);//要转为pdf 文档Word2PdfUtil.convert2PdfStream(inputStream,outputStream);ByteArrayOutputStream baosPdf = (ByteArrayOutputStream) outputStream ;InputStream inputStream2 = new ByteArrayInputStream(baosPdf.toByteArray());//inputStream 只能用来读取一次所以进行copy一个新的 用来生成摘要InputStream inputStream3 = new ByteArrayInputStream(baosPdf.toByteArray());//生成文档hash 摘要hash = FileHahUtil.hashAbstractByInputStream(inputStream3);url = fileService.uploadFileByInputStream(inputStream2,fileName);baosPdf.close();inputStream2.close();outputStream.close();}if(StringUtils.isNotEmpty(url)){// 保存合同信息 到数据库Contract contract = new Contract();//随机字符串String str = StringUtils.replace(UUID.randomUUID().toString(), "-", "");contract.setCode(CodeGenerator.getLongCode(str));contract.setContractUrl(url);contract.setName(fileName);contract.setHashCode(hash);contractService.saveOrUpdate(contract);//返回合同信息baseVo.setData(contract);baseVo.setCodeMessage(CodeConstant.SUCCESS_CODE);}}}}catch (Exception e){e.printStackTrace();MeUtils.info("uploadFile error",e);}long endTimeTotal = System.currentTimeMillis();MeUtils.info("uploadFile total time:" + (endTimeTotal - startTimeTotal));return baseVo;}

生成文件摘要用的是文件hash 摘要算法中的SHA-256,docx或doc转pdf用的是aspose 中提供的方法,文件上传用的Ceph分布式文件系统中的。这里暂时不详细介绍,只贴一些代码。后面再出详细文档,以及开发中遇到的坑。

文件hash 摘要算法
 /** * 生成文件hashCode值 */public static String hashAbstractByInputStream(InputStream fis) throws Exception {String sha256 = null;try {MessageDigest md = MessageDigest.getInstance("SHA-256");byte buffer[] = new byte[1024];int length = -1;while ((length = fis.read(buffer, 0, 1024)) != -1) {md.update(buffer, 0, length);}byte[] digest = md.digest();sha256 = byte2hexLower(digest);} catch (Exception e) {e.printStackTrace();throw new Exception("生成文件hash值失败");} finally {try {if (fis != null) {fis.close();}} catch (IOException e) {e.printStackTrace();}}return sha256;}
docx或doc转pdf
public static void convert2PdfStream(InputStream inputStream, ByteArrayOutputStream outputStream) {if (!getLicense()) { // 验证License 若不验证则转化出的pdf文档会有水印产生return;}try {long old = System.currentTimeMillis();Document doc = new Document(inputStream);//insertWatermarkText(doc, "测试水印"); //添加水印PdfSaveOptions pdfSaveOptions = new PdfSaveOptions();pdfSaveOptions.setSaveFormat(SaveFormat.PDF);// 设置3级doc书签需要保存到pdf的heading中pdfSaveOptions.getOutlineOptions().setHeadingsOutlineLevels(3);// 设置pdf中默认展开1级pdfSaveOptions.getOutlineOptions().setExpandedOutlineLevels(1);//doc.save(outputStream, pdfSaveOptions);// 全面支持DOC, DOCX, OOXML, RTF HTML, OpenDocument, PDF,EPUB, XPS, SWF 相互转换doc.save(outputStream, SaveFormat.PDF);long now = System.currentTimeMillis();System.out.println("共耗时:" + ((now - old) / 1000.0) + "秒"); // 转化用时} catch (Exception e) {e.printStackTrace();}}
文件上传
 /** * 上传InputStream文件 * * @param bucketName * @param fileName * @param input */public static String uploadInputStreamReturnUrl(String bucketName, String fileName, InputStream input) {//String path = bucketName + timeSuffix();PutObjectResult putObjectResult = conn.putObject(bucketName, fileName, input, new ObjectMetadata());String cephUrl = ENDPOINT + bucketName + "/" + fileName;return cephUrl;}