spring-boot - Spring Boot 和 configureMessageConverters
问题描述
我面临与 Spring Boot + 数据转换器相关的问题。所以,基本上我想针对到达名为
/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>-->
休息端点
@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 插件)
@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 进行验证?
更新 1 号
似乎这个问题很相似,但由于某种原因它不起作用......
解决方案
[糟糕的解决方案开始]
好的,所以我所做的是
步骤 1
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 步重构您的端点以接受字符串并返回字符串
@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 验证
[糟糕的解决方案结束]
所有需要做的就是
在我定义 jaxb2Marshaller 的块中添加 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
}
解决方案基于这篇文章Spring RestTemplate not accepting JAXBElement
更新 1 号
Spring Boot 2.4.0 不需要@EnableWebMvc
,可以跳过
推荐阅读
- reactjs - 在上传之前在客户端压缩图像是个好主意吗
- linux - 无法在 Kali linux 中构建和安装 binutils
- flutter - Flutter & Textfield:如何通过自动删除该空间来限制我的用户使用文本字段中的空间?
- python - 从 VS CODE 收到一条奇怪的消息
- twilio - 暮光之城 使用插件部署时出错
- wpf - 图像图标和字符串不出现在 WPF 的 Listview 中
- java - 这在实现多个接口时是否仍然遵循依赖倒置原则?
- python - 在 tkinter GUI 中嵌入 matplotlib
- c# - SyntaxFactory.ParseStatement 生成额外的空格
- php - Laravel如何在分类帖子上添加分页