406 Spring REST API中自定义接受/标头和返回类型的HTTP状态

时间:2018-05-14 10:23:16

标签: java xml spring rest jaxb

我有一个Spring REST API,它必须响应自定义的'accept:project / xml'标题。此外,我从REST方法返回自己的Response对象,然后应该转换为XML(因此所有响应都包含在标记内)。 因此,控制器看起来像:

@Controller("Project Controller")
@RequestMapping(value = "/wa", produces = "project/xml; charset=utf-8")
@ResponseBody
public class ProjectController {

    private final IProjectService projectService;

    @Autowired
    public ProjectController(IProjectService projectService) {
        this.projectService = projectService;
    }

    @RequestMapping(method = RequestMethod.GET)
    public Response projectInfo() {
        return new Response(projectService.listProjects());
    }

    @RequestMapping(value = "/start", method = RequestMethod.GET)
    public Response start() {
        return new Response(new JAXBElement<>(new QName("resource"), 
String.class, StaticConstants.STRING_START_TAG));
    }

    @RequestMapping(value = "/end", method = RequestMethod.GET)
    public ResponseEntity<String> end() {
        return ResponseEntity.ok(StaticConstants.STRING_END_TAG);
    }
}

这就是Response类的样子:

@XmlRootElement(name = "response")
@XmlAccessorType(XmlAccessType.FIELD)
@Data
@NoArgsConstructor
public class Response {

   @XmlAnyElement(lax=true)
   private List<Object> body;

   public Response(Object single) {
      if (body == null) {
          body = new ArrayList<>(1);
      }
      body.add(single);
   }
}

所有包含在Response中的Bean类也都标有@XmlRootElement和@XmlElement注释。

我还包括了所有的fastxml依赖项(即使是那些不必要的依赖项):

    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-annotations</artifactId>
        <version>${com.fasterxml.jackson.version}</version>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>${com.fasterxml.jackson.version}</version>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.dataformat</groupId>
        <artifactId>jackson-dataformat-xml</artifactId>
        <version>${com.fasterxml.jackson.version}</version>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-core</artifactId>
        <version>${com.fasterxml.jackson.version}</version>
    </dependency>

此外,我已将必要的bean添加到Spring配置中,如下所示:

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = "com.project")
public class BeanConfiguration {

    ...

    @Bean
    public HttpMessageConverter jsonMessageConverter() {
        return new MappingJackson2HttpMessageConverter();
    }
}

问题是我正在接收/ start端点的 406 Not Acceptable 状态,但是没有收到/ end端点的状态。 我从Postman发送的请求当然包含'Accept:project / xml'标题。

因此,如果我从Controller中删除'produce'并从Postman请求中删除'Accept'标题,则一切正常。 如果我将'produce'更改为'application / xml'并将请求标头更改为'application / xml'或没有任何标头,它也可以工作。

但是使用自定义标题只适用于 ResponseEntity 类,并且不适用于我自己的响应类。

我也试过让Response类扩展ResponseEntity,但没有效果。

我查看了许多解决方案和类似问题 - 没有任何帮助。没有其他人使用自己的自定义“接受”标题。

1 个答案:

答案 0 :(得分:0)

我最终设法通过下一个方式解决了这个问题。首先,添加了自己的消息转换器,扩展了Jaxb2RootElementHttpMessageConverter并调用setSupportedMediaTypes方法:

public class ProjectXmlMessageConverter extends Jaxb2RootElementHttpMessageConverter {

    public ProjectXmlMessageConverter() {
        super();
        setSupportedMediaTypes(Collections.singletonList(MediaType.valueOf("project/xml")));
}

}

其次,通过这种方式将我的转换器添加到已定义的转换器列表中:

@EnableWebMvc
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

    @Override
    public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
        converters.add(new ProjectXmlMessageConverter());
    }
}

现在它可以正常工作,我的API会响应请求,并接受:project / xml&#39;报头中。