Spring Rest web service return File as Resource

19,497

This is how I fixed the issue

@Bean
public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() {
    MappingJackson2HttpMessageConverter messageConverter = new MappingJackson2HttpMessageConverter();

    ObjectMapper objectMapper = new ObjectMapper();
    objectMapper.registerModule(new Hibernate4Module());
    objectMapper.configure(FAIL_ON_UNKNOWN_PROPERTIES, false);
    objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);

    messageConverter.setObjectMapper(objectMapper);
    return messageConverter;
}


@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
    converters.add(mappingJackson2HttpMessageConverter());
    converters.add(new ResourceHttpMessageConverter());
    super.configureMessageConverters(converters);
}

I added a ResourceHttpMessageConverter to the list of converters.

Here is the resource:

@RequestMapping(value="/file/{uniqueKey}", method = RequestMethod.GET)
@ResponseBody
public FileSystemResource getUserFile(HttpServletResponse response, @PathVariable String uniqueKey){

    Map<String, String> metadata = authService.getUserFileMetadataByUniqueKey(uniqueKey);

    final File file = new File(metadata.get("filePath"));
    response.setContentType(metadata.get("contentType"));
    response.setHeader("Content-Disposition", "attachment; filename="+metadata.get("fileUniqueName"));

    return new FileSystemResource(file);
}
Share:
19,497
luca
Author by

luca

Updated on June 14, 2022

Comments

  • luca
    luca almost 2 years

    I'm trying to return a file stream from Rest web service deployed on server, and handle this stream from Rest web service on client. On the server I use this code:

    @Override
    @RequestMapping(value = "/file", method = RequestMethod.GET, produces = MediaType.APPLICATION_OCTET_STREAM_VALUE) 
    public @ResponseBody Resource getAcquisition(@RequestParam(value="filePath", required = true) String filePath) throws FileNotFoundException{
        // acquiring the stream
        File file= new File(filePath);
        InputStream stream = new FileInputStream(file);
        // counting the length of data
        final long contentLength = file.length() ;
    
        return new InputStreamResource(stream){
            @Override
            public long contentLength() throws IOException {
                return contentLength;
            }
        };
    }
    

    and, at the moment, on the client I use this (then I have to write the file on file system)

    @Override
    public void getFile(String serverIp, String toStorePath, String filePath) throws Exception{
        RestTemplate restTemplate = new RestTemplate();
        Resource resource  = restTemplate.getForObject(serverIp + "ATS/client/file/?filePath={filePath}",Resource.class, filePath);
        File file=resource.getFile();
        System.out.println(file.length());
    }
    

    But the server return this exception:

    ERROR com.controller.ErrorController - org.springframework.web.HttpMediaTypeNotAcceptableException: Could not find acceptable representation
    at org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor.writeWithMessageConverters(AbstractMessageConverterMethodProcessor.java:195)
    at org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor.writeWithMessageConverters(AbstractMessageConverterMethodProcessor.java:100)
    at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.handleReturnValue(RequestResponseBodyMethodProcessor.java:166)
    at org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite.handleReturnValue(HandlerMethodReturnValueHandlerComposite.java:80)
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:127)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:806)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:729)
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:959)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:893)
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970)
    at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:861)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:622)
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:291)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:219)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:142)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
    at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:616)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:518)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1091)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:673)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1526)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1482)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Thread.java:745)
    

    I tried even without MediaType buut it doesn't work. I post also my spring configuration:

    package com.config.core;
    
    import java.util.List;
    import java.util.Properties;
    
    import org.apache.commons.dbcp.BasicDataSource;
    import org.hibernate.jpa.HibernatePersistenceProvider;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.Import;
    import org.springframework.context.annotation.PropertySource;
    import org.springframework.core.env.Environment;
    import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
    import org.springframework.http.converter.HttpMessageConverter;
    import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
    import org.springframework.orm.jpa.JpaTransactionManager;
    import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
    import org.springframework.transaction.annotation.EnableTransactionManagement;
    import org.springframework.web.multipart.commons.CommonsMultipartResolver;
    import org.springframework.web.servlet.config.annotation.EnableWebMvc;
    import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
    import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
    import org.thymeleaf.spring4.SpringTemplateEngine;
    import org.thymeleaf.spring4.view.ThymeleafViewResolver;
    import org.thymeleaf.templateresolver.ServletContextTemplateResolver;
    
    import com.fasterxml.jackson.databind.ObjectMapper;
    import com.fasterxml.jackson.datatype.hibernate4.Hibernate4Module;
    
    
    /**
     * All the configuration bean
     *
     */
    @EnableWebMvc
    @Configuration
    @PropertySource(value = { "classpath:application.properties" })
    @ComponentScan({ "com.*" })
    @EnableTransactionManagement
    @Import({ SpringMvcInitializer.class })
    @EnableJpaRepositories("com.repository")
    public class AppConfig extends WebMvcConfigurerAdapter{
        @Autowired
        private Environment env;
    
        private static final String PROPERTY_NAME_DATABASE_DRIVER = "db.driver";
        private static final String PROPERTY_NAME_DATABASE_PASSWORD = "db.password";
        private static final String PROPERTY_NAME_DATABASE_URL = "db.url";
        private static final String PROPERTY_NAME_DATABASE_USERNAME = "db.username";
    
        private static final String PROPERTY_NAME_HIBERNATE_DIALECT = "hibernate.dialect";
    //  private static final String PROPERTY_NAME_HIBERNATE_SHOW_SQL = "hibernate.show_sql";
        private static final String PROPERTY_NAME_ENTITYMANAGER_PACKAGES_TO_SCAN = "entitymanager.packages.to.scan";
        private static final String PROPERTY_NAME_HIBERNATE_FORMAT_SQL = "hibernate.format_sql";
    
    
    /**
     * li utilizzavo prima quando facevo l'autenticazione, vedere come fare ora che ho messo nelle proprietà il percorso com.domain
     * @return
     */
    //  @Bean
    //  public SessionFactory sessionFactory() {
    //      LocalSessionFactoryBuilder builder = new LocalSessionFactoryBuilder(dataSource());
    //      builder
    //      .scanPackages(env.getRequiredProperty(PROPERTY_NAME_ENTITYMANAGER_PACKAGES_TO_SCAN))
    //      .addProperties(getHibernateProperties());
    //
    //      return builder.buildSessionFactory();
    //  }
    //  @Bean
    //  public HibernateTransactionManager txManager() {
    //      return new HibernateTransactionManager(sessionFactory());
    //  }
    
        /**
         * This and the next methods are used to avoid exception while jackson mapping the entity, so fields are setted with null value
         * unless use Hibernate.initialize
         * @return
         */
        public MappingJackson2HttpMessageConverter jacksonMessageConverter(){
            MappingJackson2HttpMessageConverter messageConverter = new MappingJackson2HttpMessageConverter();
    
            ObjectMapper mapper = new ObjectMapper();
            //Registering Hibernate4Module to support lazy objects
            mapper.registerModule(new Hibernate4Module());
    
            messageConverter.setObjectMapper(mapper);
            return messageConverter;
    
        }
    
        @Override
        public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
            //Here we add our custom-configured HttpMessageConverter
            converters.add(jacksonMessageConverter());
            super.configureMessageConverters(converters);
        }
    
        private Properties getHibernateProperties() {
            Properties properties = new Properties();
            properties.put(PROPERTY_NAME_HIBERNATE_DIALECT, env.getRequiredProperty(PROPERTY_NAME_HIBERNATE_DIALECT));
    //      properties.put(PROPERTY_NAME_HIBERNATE_SHOW_SQL, env.getRequiredProperty(PROPERTY_NAME_HIBERNATE_SHOW_SQL));
            properties.put(PROPERTY_NAME_HIBERNATE_FORMAT_SQL, env.getRequiredProperty(PROPERTY_NAME_HIBERNATE_FORMAT_SQL));
            properties.put("hibernate.enable_lazy_load_no_trans",true);
            return properties;
        }
    
        @Bean(name = "dataSource")
        public BasicDataSource dataSource() {
            BasicDataSource ds = new BasicDataSource();
            ds.setDriverClassName(env.getRequiredProperty(PROPERTY_NAME_DATABASE_DRIVER));
            ds.setUrl(env.getRequiredProperty(PROPERTY_NAME_DATABASE_URL));
            ds.setUsername(env.getRequiredProperty(PROPERTY_NAME_DATABASE_USERNAME));
            ds.setPassword(env.getRequiredProperty(PROPERTY_NAME_DATABASE_PASSWORD));
            return ds;
        }
    
        @Bean
        public ServletContextTemplateResolver TemplateResolver(){
            ServletContextTemplateResolver resolver = new ServletContextTemplateResolver();
            resolver.setPrefix("/WEB-INF/templates/pages/");
            resolver.setSuffix(".html");
            resolver.setTemplateMode("LEGACYHTML5");
            resolver.setCacheable(false);
            return resolver;
            /*ServletContextTemplateResolver resolver = new ServletContextTemplateResolver();
            resolver.setPrefix("/WEB-INF/pages/");
            resolver.setSuffix(".html");
            resolver.setTemplateMode("HTML5");
            return resolver;*/
        }
    
        @Bean
        public SpringTemplateEngine templateEngine(){
            SpringTemplateEngine templateEngine = new SpringTemplateEngine();
            templateEngine.setTemplateResolver(TemplateResolver());
            return templateEngine;
        }
    
    
        @Bean
        public ThymeleafViewResolver viewResolver() {
            ThymeleafViewResolver resolver = new ThymeleafViewResolver();
            resolver.setTemplateEngine(templateEngine());
            resolver.setOrder(1);
            resolver.setViewNames(new String[]{"*", "js/*", "template/*"});
            return resolver;
        }
    
        /**
         * Register multipartResolver for file upload
         * @return
         */
        @Bean
        public CommonsMultipartResolver multipartResolver() {
            CommonsMultipartResolver resolver=new CommonsMultipartResolver();
            resolver.setDefaultEncoding("utf-8");
            return resolver;    
        }
    
        /**
         * Allow use of bootstrap
         */
        @Override
        public void addResourceHandlers(ResourceHandlerRegistry registry) {
                registry.addResourceHandler("/static/**")
                        .addResourceLocations("/static/");
        }
    
        /**
         * Allow use of JPA
         */
        @Bean
        public JpaTransactionManager transactionManager() {
            JpaTransactionManager transactionManager = new JpaTransactionManager();
            transactionManager.setEntityManagerFactory(entityManagerFactory().getObject());
            return transactionManager;
        }
        @Bean
        public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
            LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
            entityManagerFactoryBean.setDataSource(dataSource());
            entityManagerFactoryBean.setPersistenceProviderClass(HibernatePersistenceProvider.class);
            entityManagerFactoryBean.setPackagesToScan(env.
            getRequiredProperty(PROPERTY_NAME_ENTITYMANAGER_PACKAGES_TO_SCAN));
            entityManagerFactoryBean.setJpaProperties(getHibernateProperties());
            return entityManagerFactoryBean;
    
        }
    }
    

    Do you know this problem?Thanks

    Update:

    @Override
    @RequestMapping(value = "/file", method = RequestMethod.GET) 
    public ResponseEntity<Resource> getAcquisition(HttpServletResponse resp,@RequestParam(value="filePath", required = true) String filePath) throws FileNotFoundException{
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.TEXT_PLAIN);
        resp.setContentType("application/octet-stream");
        File file= new File(filePath);
        InputStream stream = new FileInputStream(file);
        InputStreamResource inputStreamResource = new InputStreamResource(stream);
        return new ResponseEntity<Resource>(inputStreamResource, null, HttpStatus.OK);
    }
    

    but receive

    Could not write content: No serializer found for class java.io.FileDescriptor
    
  • luca
    luca over 8 years
    I obtain 'No serializer found for class java.io.FileDescriptor and no properties discovered to create BeanSerializer'. I tried also tried with return new ResponseEntity<FileSystemResource>(new FileSystemResource(new File(filePath)),null, HttpStatus.OK);
  • reos
    reos over 8 years
    Remove the produces and use ResponseEntity<Resource> instead ResponseEntity, also add the content type in the headers and response headers.setContentType(MediaType.IMAGE_GIF); response.setContentType("image/gif");
  • luca
    luca over 8 years
    I posted the updated method but receive an exception
  • reos
    reos over 8 years
    Inject the response in the method and then set the contenttype, and define the headers and also set the contenttype there.