How to convert an InputStream to a DataHandler?

后端 未结 7 726
挽巷
挽巷 2020-12-05 07:20

I\'m working on a java web application in which files will be stored in a database. Originally we retrieved files already in the DB by simply calling getBytes o

相关标签:
7条回答
  • 2020-12-05 07:32

    Here is an answer for specifically working with the Spring Boot org.springframework.core.io.Resource object which is I think how a lot of us are getting here. Note that you might need to modify the content type in the code below as I'm inserting a png file into an html formatted email.

    Note: As others have mentioned, merely attaching an InputStream isn't enough as it gets used multiple times, just mapping through to Resource.getInputStream() does the trick.

    public class SpringResourceDataSource implements DataSource {
        private Resource resource;
    
        public SpringResourceDataSource(Resource resource) {
            this.resource = resource;
        }
    
        @Override
        public InputStream getInputStream() throws IOException {
            return resource.getInputStream();
        }
    
        @Override
        public OutputStream getOutputStream() throws IOException {
            throw new UnsupportedOperationException("Not implemented");
        }
    
        @Override
        public String getContentType() {
            return "image/png";
        }
    
        @Override
        public String getName() {
            return "SpringResourceDataSource";
        }
    }   
    

    Usage of the class looks like this:

        PathMatchingResourcePatternResolver pathMatchingResourcePatternResolver = new PathMatchingResourcePatternResolver();
        Resource logoImage = pathMatchingResourcePatternResolver.getResource("/static/images/logo.png");
        MimeBodyPart logoBodyPart = new MimeBodyPart();
        DataSource logoFileDataSource = new SpringResourceDataSource(logoImage);
    
    
        logoBodyPart.setDataHandler(new DataHandler(logoFileDataSource));
    
    0 讨论(0)
  • (bugs_)code doesn't works for me. I use DataSource to create Attachments to email (from objects that have inputStream and name) and content of attachments lost. Looks like Stefan is right and new inputStream must be returned every time. At least in my specific case. Next implementation deals with problem:

    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);
                }
    
                buffer.flush();
                inputStream.close();
            } 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");
        }
    
    }
    
    0 讨论(0)
  • 2020-12-05 07:39

    An implementation of answer from "Kathy Van Stone":

    At first create helper class, which create DataSource from InputStream:

    public class InputStreamDataSource implements DataSource {
        private InputStream inputStream;
    
        public InputStreamDataSource(InputStream inputStream) {
            this.inputStream = inputStream;
        }
    
        @Override
        public InputStream getInputStream() throws IOException {
            return inputStream;
        }
    
        @Override
        public OutputStream getOutputStream() throws IOException {
            throw new UnsupportedOperationException("Not implemented");
        }
    
        @Override
        public String getContentType() {
            return "*/*";
        }
    
        @Override
        public String getName() {
            return "InputStreamDataSource";
        }
    }
    

    And then you can create DataHandler from InputStream:

    DataHandler dataHandler = new DataHandler(new InputStreamDataSource(inputStream))
    

    imports:

    import javax.activation.DataSource;
    import java.io.OutputStream;
    import java.io.InputStream;
    
    0 讨论(0)
  • 2020-12-05 07:39

    I've meet situation, when InputStream requested from DataSource twice: using Logging Handler together with MTOM feature. With this proxy stream solution my implementation works fine:

    import org.apache.commons.io.input.CloseShieldInputStream;
    import javax.activation.DataHandler;
    import javax.activation.DataSource;
    ...
    
    private static class InputStreamDataSource implements DataSource {
        private InputStream inputStream;
    
        @Override
        public InputStream getInputStream() throws IOException {
            return new CloseShieldInputStream(inputStream);
        }
    
        @Override
        public OutputStream getOutputStream() throws IOException {
            throw new UnsupportedOperationException("Not implemented");
        }
    
        @Override
        public String getContentType() {
            return "application/octet-stream";
        }
    
        @Override
        public String getName() {
            return "";
        }
    }
    
    0 讨论(0)
  • 2020-12-05 07:42

    I also ran into this issue. If your source data is a byte[] Axis already has a class that wraps the InputStream and creates a DataHandler object. Here is the code

    //this constructor takes byte[] as input
    ByteArrayDataSource rawData= new ByteArrayDataSource(resultSet.getBytes(1));
    DataHandler data= new DataHandler(rawData);
    yourObject.setData(data);
    

    Related imports

    import javax.activation.DataHandler;
    import org.apache.axiom.attachments.ByteArrayDataSource;
    

    Hope it helps!

    0 讨论(0)
  • 2020-12-05 07:46

    My approach would be to write a custom class implementing DataSource that wraps your InputStream. Then create the DataHandler giving it the created DataSource.

    0 讨论(0)
提交回复
热议问题