Spring Boot and configureMessageConverters



我正面临一个与Spring Boot +数据转换器相关的问题。所以,基本上我想针对到达端点的XSD验证应用程序/xml请求/request/test .

我的配置文件

package com.my.package.configuration;
import com.test.AcceptMessageRequestType;
import com.test.AcceptMessageResultType;
import com.test.ObjectFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.format.FormatterRegistry;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.xml.MarshallingHttpMessageConverter;
import org.springframework.jms.config.DefaultJmsListenerContainerFactory;
import org.springframework.jms.connection.CachingConnectionFactory;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.oxm.jaxb.Jaxb2Marshaller;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import javax.jms.Session;
import java.util.List;
@Configuration
@EnableWebMvc
public class ReqConfiguration implements WebMvcConfigurer {
    private static final Logger LOG =
            LoggerFactory.getLogger(ReqConfiguration.class);

    @Override
    public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
        converters.add(customConverter());
    }
/* NOT WORKING
    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        try {
            converters.add(customConverter());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
*/
    @Bean
    public HttpMessageConverter<Object> customConverter() {
        MarshallingHttpMessageConverter xmlConverter = new MarshallingHttpMessageConverter();
        xmlConverter.setSupportedMediaTypes(List.of(MediaType.APPLICATION_XML));
        xmlConverter.setMarshaller(jaxb2Marshaller());
        xmlConverter.setUnmarshaller(jaxb2Marshaller());
        return xmlConverter;
    }

    @Bean
    public Jaxb2Marshaller jaxb2Marshaller() {
        Jaxb2Marshaller jaxb2Marshaller = new Jaxb2Marshaller();
        jaxb2Marshaller.setSchemas(
                new ClassPathResource("/MyMessageResponse.xsd"),
                new ClassPathResource("/MyMessageRequest.xsd"));
        jaxb2Marshaller.setClassesToBeBound(MyMessageRequest.class,
                MyMessageResponse.class);
        jaxb2Marshaller.setValidationEventHandler(event -> {
            event.getMessage();
            LOG.info("Do something");
        });
        jaxb2Marshaller.afterPropertiesSet();
        return jaxb2Marshaller;
    }
}

我的pom文件的相关部分

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-oxm</artifactId>
    </dependency>
    <!--<dependency> WORKS BUT NOT bypasses jaxb2Marshaller and no validation happens
        <groupId>com.fasterxml.jackson.dataformat</groupId>
        <artifactId>jackson-dataformat-xml</artifactId>
    </dependency>-->

Rest端点

@PostMapping(path = "/request/test", consumes = MediaType.APPLICATION_XML_VALUE,
        produces = MediaType.APPLICATION_XML_VALUE)
public @ResponseBody MyResponseMessage acceptMessage(@RequestBody MyRequestMessage message) {
   return null;
}

xsd生成的类(cxf-xjc-plugin plugin)

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "MyResponseMessage", propOrder = {
    "result",
    "uuid",
    "accepted"
})
public class MyResponseMessage implements Serializable {
    @XmlElement(required = true)
    protected Result result = new Result();
    @XmlElement(required = true)
    protected String uuid;
    protected boolean accepted;
     <... setter / getter cut out ...>
}
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "result", propOrder = {
    "result",
    "desc"
})
public class Result implements Serializable {
    protected int code;
    @XmlElement(required = true)
    protected String desc;
<... setter / getter cut out ...>
}
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "AcceptMessageRequestType", propOrder = {
    "id",
    "name",
    "state"
})
public class MyRequestMessage implements Serializable {
@XmlElement(required = true)
protected String id;
@XmlElement(required = true)
protected String name;
@XmlElement(required = true)
protected String state;
   <... setters / getters cut out...>
}

所以,我得到的要么是415(不支持的类型),要么是如果我使用jackson,我得到响应,但是传入请求的验证没有针对xsd进行验证。如何使进料XML请求将根据xsd进行验证?更新第一

这个问题似乎是类似的,但由于某种原因它不起作用…

试图解决方案

[BAD SOLUTION BEGIN]

好的,我所做的是

第一步

package com.my.package.configuration;
import com.test.AcceptMessageRequestType;
import com.test.AcceptMessageResultType;
import com.test.ObjectFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.format.FormatterRegistry;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.xml.MarshallingHttpMessageConverter;
import org.springframework.jms.config.DefaultJmsListenerContainerFactory;
import org.springframework.jms.connection.CachingConnectionFactory;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.oxm.jaxb.Jaxb2Marshaller;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import javax.jms.Session;
import java.util.List;
@Configuration
@EnableWebMvc
public class ReqConfiguration implements WebMvcConfigurer {
    private static final Logger LOG =
            LoggerFactory.getLogger(ReqConfiguration.class);

    @Override
    public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
        converters.add(customConverter());
    }
@Override //ADD THIS INSTEAD
public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
    try {
        converters.add(customConverter());
    } catch (Exception e) {
        e.printStackTrace();
    }
}

/* NOT WORKING
    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        try {
            converters.add(customConverter());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
*/
    @Bean
    public HttpMessageConverter<Object> customConverter() {
        MarshallingHttpMessageConverter xmlConverter = new MarshallingHttpMessageConverter();
        xmlConverter.setSupportedMediaTypes(List.of(MediaType.APPLICATION_XML));
        xmlConverter.setMarshaller(jaxb2Marshaller());
        xmlConverter.setUnmarshaller(jaxb2Marshaller());
        return xmlConverter;
    }

    @Bean
    public Jaxb2Marshaller jaxb2Marshaller() {
        Jaxb2Marshaller jaxb2Marshaller = new Jaxb2Marshaller();
        jaxb2Marshaller.setSchemas(
                new ClassPathResource("/MyMessageResponse.xsd"),
                new ClassPathResource("/MyMessageRequest.xsd"));
        jaxb2Marshaller.setClassesToBeBound(/*path to ObjectFactory.class(-es)*/);
        jaxb2Marshaller.setValidationEventHandler(event -> {
            event.getMessage();
            LOG.info("Do something");
        });
        //jaxb2Marshaller.afterPropertiesSet();
        return jaxb2Marshaller;
    }
}

步骤。1.5添加Maven条目

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-oxm</artifactId>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.dataformat</groupId>
        <artifactId>jackson-dataformat-xml</artifactId>
    </dependency>

步骤。2 .重构端点,使其接受String并返回String

@PostMapping(path = "/request/test", consumes = MediaType.APPLICATION_XML_VALUE,
        produces = MediaType.APPLICATION_XML_VALUE)
public @ResponseBody String acceptMessage(@RequestBody String message) {
        final XMLInputFactory inputFactory = XMLInputFactory.newInstance();
    final StringReader reader = new StringReader(message);
   jaxb2Marshaller.unmarshal(new StAXSource(inputFactory.createXMLStreamReader(reader)));
   return null;
}

现在应该用xsd

验证所有内容[BAD SOLUTION END]

所需要做的就是

中定义了jaxb2Marshaller add jaxb2Marshaller.setSupportJaxbElementClass(Boolean.TRUE);

并且只使用JAXBElement作为输入和相应的输出。

同时,删除maven依赖

    <dependency>
        <groupId>com.fasterxml.jackson.dataformat</groupId>
        <artifactId>jackson-dataformat-xml</artifactId>
    </dependency>

和控制器变成

@PostMapping(path = "/request/test", consumes = MediaType.APPLICATION_XML_VALUE,
        produces = MediaType.APPLICATION_XML_VALUE)
public @ResponseBody JAXBElement<OUTPUT.class> acceptMessage(@RequestBody JAXBElement<INPUT.class> message) {
// do something with a validated message object
}

解决方案是基于此post Spring RestTemplate不接受JAXBElement

更新第一

Spring Boot 2.4.0不需要@EnableWebMvc,所以可以跳过

相关内容

  • 没有找到相关文章

最新更新