所有内容类型都不支持Spring REST Controller内容/类型

时间:2018-02-06 20:23:00

标签: java spring spring-mvc postman media-type

我正在尝试创建一个使用HTML的Web服务,以后用于使用iText创建PDF。

我正在使用Postman将请求发送到服务器但每次出现以下错误时,无论我选择哪种内容类型:

{
    "status": "CONFLICT",
    "code": 40902,
    "message": "Content type 'text/plain' not supported",
    "developerMessage": "null",
    "moreInfoUrl": "class org.springframework.web.HttpMediaTypeNotSupportedException",
    "throwable": null
}

根据所选的内容类型,消息会发生变化:

"message": "Content type 'text/xml' not supported"
"message": "Content type 'text/html' not supported"

这是我的终点:

@RequestMapping(path = "/reports/pdf", method = RequestMethod.POST, consumes = MediaType.TEXT_HTML_VALUE)
public ResponseEntity<byte[]> generatePdfReport(@RequestBody String html) throws Exception {
    byte[] pdfBytes = reportsService.generatePdf(html);
    ResponseEntity<byte[]> response = new ResponseEntity<byte[]>(pdfBytes, HttpStatus.OK);
    return response;
}

我已将consumes属性更改为:

  • MediaType.TEXT_PLAIN_VALUE
  • MediaType.TEXT_XML_VALUE

匹配我在Postman上发送的内容。

除了@dnault评论之外,还要从RequestMapping注释中完全删除它,结果相同。

我调查了类似的问题:

然而,上述和其他一些与我已经检查过的问题并不紧密相关的问题已经提供了解决此问题的答案。

我尝试发送到服务器的示例HTML是:

<table style="border: 1px solid black; font-size: 12px; margin-top: 1px; width: 900px;" id="table_direction">
    <tr>
        <td width="33%" colspan="2">
            <strong>Data1</strong>
        </td>
        <td width="33%" colspan="2">
            <strongData2</strong>
        </td>
        <td width="16%" colspan="1">Foo</td>
        <td width="16%" colspan="1">Bar</td>
    </tr>
    <tr>
        <td colspan="">ID</td>
        <td colspan="">123456</td>
        <td colspan="">Property 1</td>
        <td colspan="">Foo</td>
        <td colspan="">Property 2</td>
        <td colspan="">Bar</td>
    </tr>
</table>

我们的配置由Java配置类完成,如下所示:

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = "com.company.project")
@PropertySource("classpath:application.properties")

@EnableTransactionManagement // proxyTargetClass = true
@EnableJpaRepositories(basePackages = { "com.company.project.dao", "com.company.project.repository" })

public class HelloWorldConfiguration extends WebMvcConfigurerAdapter {

    @Inject
    Environment env;

    @Value("${jdbc.user}")
    private String userDB;

    @Value("${jdbc.password}")
    private String passDB;

    @Value("${jdbc.url}")
    private String urlDB;

    @Value("${jdbc.driverClassName}")
    private String driverClassName;

    @Bean
    public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
        return new PropertySourcesPlaceholderConfigurer();
    }

    @Bean
    public CommonsMultipartResolver multipartResolver() {
        return new CommonsMultipartResolver();
    }

    @Bean(name = "dataSource")
    public DriverManagerDataSource dataSource() {
        DriverManagerDataSource driverManagerDataSource = new DriverManagerDataSource();
        driverManagerDataSource.setDriverClassName(driverClassName);
        driverManagerDataSource.setUrl(urlDB);
        driverManagerDataSource.setUsername(userDB);
        driverManagerDataSource.setPassword(passDB);
        return driverManagerDataSource;
    }

    @Bean
    public LocalSessionFactoryBean sessionFactory() {
        LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
        sessionFactory.setDataSource(dataSource());
        sessionFactory.setPackagesToScan(new String[] { "com.company.project.model" });
        sessionFactory.setHibernateProperties(hibernateProperties());
        return sessionFactory;
    }

    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource dataSource,
            JpaVendorAdapter jpaVendorAdapter) {
        LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
        entityManagerFactoryBean.setDataSource(dataSource);
        entityManagerFactoryBean.setJpaVendorAdapter(jpaVendorAdapter);
        entityManagerFactoryBean.setPackagesToScan("com.company.project.model");
        entityManagerFactoryBean.setJpaProperties(hibernateProperties());
        return entityManagerFactoryBean;
    }

    private Properties hibernateProperties() {
        Properties jpaProperties = new Properties();
        jpaProperties.put("hibernate.hbm2ddl.auto", env.getProperty("hibernate.hbm2ddl.auto"));
        jpaProperties.put("hibernate.show_sql", env.getProperty("hibernate.show_sql"));
        jpaProperties.put("hibernate.dialect", env.getProperty("hibernate.dialect"));
        return jpaProperties;
    }

    @Bean
    public PlatformTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
        return new JpaTransactionManager(entityManagerFactory);
    }

    @Bean(name = "transactionManager2")
    @Autowired
    @Named("transactionManager2")
    public HibernateTransactionManager transactionManager2(SessionFactory s) {
        HibernateTransactionManager txManager = new HibernateTransactionManager();
        txManager.setSessionFactory(s);
        return txManager;
    }

    @Bean
    public JpaVendorAdapter jpaVendorAdapter() {
        HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
        vendorAdapter.setGenerateDdl(true);
        return vendorAdapter;
    }

    public MappingJackson2HttpMessageConverter jacksonMessageConverter(){
        MappingJackson2HttpMessageConverter messageConverter = new MappingJackson2HttpMessageConverter();

        ObjectMapper mapper = new ObjectMapper();
        Hibernate5Module module = new Hibernate5Module();
        module.disable(Hibernate5Module.Feature.USE_TRANSIENT_ANNOTATION);

        mapper.registerModule(module);

        messageConverter.setObjectMapper(mapper);
        return messageConverter;

    }

    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        converters.add(jacksonMessageConverter());
        super.configureMessageConverters(converters);
    }
}
@ControllerAdvice
public class GenericRepositoryRestExceptionHandler extends RepositoryRestExceptionHandler {

    @Autowired
    public GenericRepositoryRestExceptionHandler(MessageSource messageSource) {
        super(messageSource);
        // TODO Auto-generated constructor stub
    }

    @ResponseBody
    @ExceptionHandler(Exception.class)
    ResponseEntity<?> handleException(Exception e) {
        //  return response(HttpStatus.CONFLICT, 40902, e.getMessage());
        return response(HttpStatus.CONFLICT, 40902, e.getMessage(), e.getCause() + "", e.getClass() + "");
    }

    private ResponseEntity<RestError> response(HttpStatus status, int code, String msg) {
        return response(status, code, msg, "", "");
    }

    private ResponseEntity<RestError> response(HttpStatus status, int code, String msg, String devMsg, String moreInfo) {
        return new ResponseEntity<>(new RestError(status, code, msg, devMsg, moreInfo, null), status);
    }

}
public class CORSFilter implements Filter {

    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
        System.out.println("Filtering on...........................................................");

        SecurityContext ctx = SecurityContextHolder.getContext();
        HttpServletResponse response = (HttpServletResponse) res;
        response.setHeader("Access-Control-Allow-Origin", "*");
        response.setHeader("Access-Control-Allow-Methods", "POST, GET, PUT, OPTIONS, DELETE");
        response.setHeader("Access-Control-Max-Age", "3600");
        response.setHeader("Access-Control-Allow-Headers", "x-requested-with");
        chain.doFilter(req, res);
    }

    public void init(FilterConfig filterConfig) {}

    public void destroy() {}

}

2 个答案:

答案 0 :(得分:4)

因为这个

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

Spring MVC会跳过它本来会注册的所有默认转换器。 (如果你很好奇,可以在WebMvcConfigurationSupport#getMessageConverters(..)完成。)

您唯一的HttpMessageConverterMappingJackson2HttpMessageConverter只能阅读MediaType.APPLICATION_JSON内容,即。 application/json。因此,每个其他请求内容类型都将被拒绝。

您可以在configureMessageConverters覆盖中自行注册所有常规默认值(或者只需要阅读HTML表单,XML,纯文本等所需的默认值)。

或者,您可以覆盖extendMessageConverters来查找默认的MappingJackson2HttpMessageConverter实例,并将其配置为使用自定义ObjectMapper。例如,

public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
    ObjectMapper mapper = new ObjectMapper();
    // ...initialize...

    for (HttpMessageConverter<?> converter : converters) {
        if (converter instanceof MappingJackson2HttpMessageConverter) {
            MappingJackson2HttpMessageConverter m = (MappingJacksonHttpMessageConverter) converter;
            m.setObjectMapper(mapper);
        }
    } 
}

也许可以放弃关于依赖默认转换器列表的评论。

答案 1 :(得分:0)

我意识到OP的问题中提到的情况与我的情况略有不同,尽管我有相同的错误。 就我而言,它是在我开始使用其他ObjectMapper之后出现的。

最初我是使用

“ com.fasterxml.jackson.core.databind”作为我项目中的ObjectMapper。

我重构了一些代码,并在此过程中切换到org.codehaus.jackson作为ObjectMapper的源。

那时候一切都变得松散了,Spring将简单地拒绝每个请求,而不管Content-Type的错误消息与OP相同。

我花了3天的时间来解决这个问题,但是最终我只是简单地切换回ObjectMapper的“ databind”。在那之后,一切都变魔术了。

我在这里提到这是为了帮助别人。取消对我没有接触过MessageConverters或其他任何复杂操作的OP的操作。