我正面临一个与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
,所以可以跳过