【问题标题】:Constructing a DataSource from an InputStream or Byte array从 InputStream 或 Byte 数组构造 DataSource
【发布时间】:2016-02-12 00:40:04
【问题描述】:

我正在编写一个小文件上传实用程序,作为一个更大项目的一部分。最初,我使用 Apache commons File 实用程序类从 servlet 处理这个问题。这是我为该服务编写的快速测试客户端的 sn-p:

public static void main(String[] args) {

  JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();

 factory.getInInterceptors().add(new LoggingInInterceptor());
 factory.getOutInterceptors().add(new LoggingOutInterceptor());
 factory.setServiceClass(FileUploadService.class);
 factory.setAddress("http://localhost:8080/FileUploadService/FileUploadService");
 FileUploadService client = (FileUploadService) factory.create();

 FileType file = new FileType();
 file.setName("statemo_1256144312279");
 file.setType("xls");

 DataSource source = new FileDataSource(new File("c:/development/statemo_1256144312279.xls"));
 file.setHandler(new DataHandler(source));
 Boolean ret = client.uploadFile(file);
 System.out.println (ret);
 System.exit(0);

}

这绝对没问题。现在,当我尝试替换 Apache 公共实用程序时,问题就来了。在上面的代码中,我从一个具有绝对路径名的文件创建一个数据源。但是,在我的 servlet 中,我无法获得绝对路径名,并且我通过网络发送的文件是空的。

这里是servlet代码:

 @SuppressWarnings("unchecked")
    protected void doPost (final HttpServletRequest request, final HttpServletResponse response) 
        throws ServletException, IOException {

    // form should have enctype="multipart/form-data" as an attribute
 if (!ServletFileUpload.isMultipartContent (request)) {
  LOG.info("Invalid form attribute");
  return;
 }

 //DataInputStream in = new DataInputStream(request.getInputStream());

 final DiskFileItemFactory factory = new DiskFileItemFactory ();
 factory.setSizeThreshold(FILE_THRESHOLD_SIZE);

 final ServletFileUpload sfu = new ServletFileUpload (factory);
 sfu.setSizeMax(MAX_FILE_SIZE);

 final HttpSession session = request.getSession();

 final List<FileItem> files = new ArrayList<FileItem>();

 final List<String> filesToProcess = new ArrayList<String>();

 try {
        final List<FileItem> items = sfu.parseRequest(request);

        for (final FileItem f : items) {
            if (!f.isFormField())
                files.add(f);
        }

        /*for (final FileItem f : files) {
         final String absoluteFileName = UPLOAD_DESTINATION + FilenameUtils.getName(f.getName());

            //f.write(new File (absoluteFileName));
            filesToProcess.add(absoluteFileName);
        }*/

        FileItem f = files.get(0);

        LOG.info("File: " + FilenameUtils.getName(f.getName()));
        LOG.info("FileBaseName: " + FilenameUtils.getBaseName(f.getName()));
        LOG.info("FileExtension: " + FilenameUtils.getExtension(f.getName()));

        FileUploadServiceClient client = new FileUploadServiceClient();

        DataSource source = new FileDataSource(new File(f.getName()));

        FileType file = new FileType();
        file.setHandler(new DataHandler(source));
        file.setName(FilenameUtils.getBaseName(f.getName()));
        file.setType(FilenameUtils.getExtension(f.getName()));

        Boolean ret = client.uploadFile(file);

        LOG.info("File uploaded - " + ret);

        filesToProcess.add(UPLOAD_DESTINATION + FilenameUtils.getName(f.getName()));
        session.setAttribute("filesToProcess", filesToProcess);

  final RequestDispatcher dispatcher = request.getRequestDispatcher("Validate");
        if (null != dispatcher) {
         dispatcher.forward(request, response);
        }
    } catch (FileUploadException e) {
        LOG.info("Exception " + e.getMessage());
        e.printStackTrace();
    } catch (Exception e) {
        LOG.info("Exception " + e.getMessage());
        e.printStackTrace();
    }

}

我今天早上的大部分时间都在努力解决这个问题,但我一无所获。即使我完全摆脱了 Apache commons 文件的内容并自己处理请求的解析,我仍然无法正确构造 DataSource。

谢谢!

【问题讨论】:

    标签: java servlets apache-commons


    【解决方案1】:

    这其实很简单,我只是将字节从 InputStream 复制到 DataSource:

    FileItem f = files.get(0);
    
    // there is a problem here where the file being created is empty, since we only have a
    // partial path:
    DataSource source = new FileDataSource(new File(f.getName()));
    
    // because of the above problem, we are going to copy over the data ourselves:
    byte[] sourceBytes = f.get();
    OutputStream sourceOS = source.getOutputStream();
    sourceOS.write(sourceBytes);
    

    【讨论】:

    • 没错。您需要发送文件 contents,而不仅仅是文件 handle ;)
    【解决方案2】:
    • This 是 commons-email ByteArrayDataSource 的代码
    • 尝试替换 apache commons 听起来很奇怪 - 除非你有充分的理由,否则不要这样做
    • 可以在 servlet 中获取绝对路径。您可以调用getServletContext().getRealPath("/"),它将返回您的应用程序的绝对路径,然后您可以获取相对于它的文件。

    【讨论】:

    • 是的,我不想替换 apache commons。我什至没有想过只是从上下文中获取路径并以这种方式获取文件。不过,该项目的其他部分会使这变得困难。
    • 我明天会看一下 ByteArrayDataSource 代码,可能会在我的解决方案中使用它。谢谢!
    【解决方案3】:

    在我们的应用程序中,有些对象具有 InputStream 和 Name 属性。我们正在使用下一个类来构造具有这些属性的 DataSource。

    public class InputStreamDataSource implements DataSource {
    
        ByteArrayOutputStream buffer = new ByteArrayOutputStream();
        private final String name;
    
        public InputStreamDataSource(InputStream inputStream, String name) {
            this.name = name;
            try {
                int nRead;
                byte[] data = new byte[16384];
                while ((nRead = inputStream.read(data, 0, data.length)) != -1) {
                  buffer.write(data, 0, nRead);
                }
                inputStream.close();
                buffer.flush();
            } catch (IOException e) {
                e.printStackTrace();
            }
    
        }
    
        @Override
        public String getContentType() {            
            return new MimetypesFileTypeMap().getContentType(name);
        }
    
        @Override
        public InputStream getInputStream() throws IOException {
                return new ByteArrayInputStream(buffer.toByteArray());
        }
    
        @Override
        public String getName() {
           return name;
        }
    
        @Override
        public OutputStream getOutputStream() throws IOException {
            throw new IOException("Read-only data");
        }
    
    }
    

    【讨论】:

    • 我认为这仍然会将整个流加载到内存中,还是我错了? (其他答案也是如此,或者他们在我只有一个 InputStream 时加载了一个文件)。
    猜你喜欢
    • 1970-01-01
    • 2011-01-06
    • 2015-04-18
    • 1970-01-01
    • 1970-01-01
    • 2015-03-16
    • 1970-01-01
    • 2012-05-20
    相关资源
    最近更新 更多