多个场景@RequestMapping与Accept或ResponseEntity一起生成JSON / XML

时间:2014-10-31 14:06:31

标签: spring rest spring-mvc spring-3 spring-4

我正在使用Spring 4.0.7

关于Spring MVC,出于研究目的,我有以下内容:

@RequestMapping(value="/getjsonperson", 
                method=RequestMethod.GET, 
                produces=MediaType.APPLICATION_JSON_VALUE)
public @ResponseBody Person getJSONPerson(){
    logger.info("getJSONPerson - getjsonperson");
    return PersonFactory.createPerson();
}

@RequestMapping(value="/getperson.json", method=RequestMethod.GET)
public @ResponseBody Person getPersonJSON(){
    logger.info("getPerson - getpersonJSON");
    return PersonFactory.createPerson();
}

每个人都可以正常工作,同时观察JSON,有无扩展名:

  • / getjsonperson
  • /getperson.json

XML

相同
@RequestMapping(value="/getxmlperson",
                method=RequestMethod.GET,
                produces=MediaType.APPLICATION_XML_VALUE
                )
public @ResponseBody Person getXMLPerson(){
    logger.info("getXMLPerson - getxmlperson");
    return PersonFactory.createPerson();
}

@RequestMapping(value="/getperson.xml", method=RequestMethod.GET)
@ResponseBody
public Person getPersonXML(){
    logger.info("getPerson - getpersonXML");
    return PersonFactory.createPerson();
}

每个都可以正常工作,观察XML,有无扩展名:

  • / getxmlperson
  • /getperson.xml

现在关于 Restful 我有以下内容:

@RequestMapping(value="/person/{id}/", 
                method=RequestMethod.GET,
                produces={MediaType.APPLICATION_JSON_VALUE, 
                          MediaType.APPLICATION_XML_VALUE})
public ResponseEntity<Person> getPersonCustomizedRestrict(@PathVariable Integer id){
    Person person = personMapRepository.findPerson(id);
    return new ResponseEntity<>(person, HttpStatus.FOUND);//302     
}

观察MediaType,它是混合的,用于JSON和XML

通过 RestTemplate ,我可以指出Accept

    if(type.equals("JSON")){
        logger.info("JSON");
        headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
    }
    else if(type.equals("XML")){
        logger.info("XML");
        headers.setAccept(Arrays.asList(MediaType.APPLICATION_XML));
    }
    ….

    ResponseEntity<Person> response =
                restTemplate.exchange("http://localhost:8080/spring-utility/person/{id}/customizedrestrict",
                                      HttpMethod.GET,
                                      new HttpEntity<Person>(headers),  
                                      Person.class,
                                       id
                                     ); 

在此之前,我可以使用一个URL / URI来获取XML或JSON格式的数据。它工作正常

我的问题在于Spring MVC ......只需考虑

@RequestMapping(value="/{id}/person", 
                method=RequestMethod.GET,
                produces={MediaType.APPLICATION_JSON_VALUE,  
                          MediaType.APPLICATION_XML_VALUE})
public @ResponseBody Person getPerson(@PathVariable Integer id){
    return personMapRepository.findPerson(id);
}

我可以通过:

调用或激活该处理程序方法(@RequestMapping
  1. jQuery使用Ajax,我能够指出Accept值(例如JSON)
  2. Poster,通过Headers按钮,我可以设置Accept
  3. 问题一:

    但是对于一个共同的链接?我如何设置Accept值?有可能吗?

    我想以其他方式解决这个问题。

    • http://localhost:8080/spring-utility/person/getpersonformat?format=json
    • http://localhost:8080/spring-utility/person/getpersonformat?format=xml

    观察:

    • ?format

    因此

    @RequestMapping(value="/getpersonformat", 
                    method=RequestMethod.GET,
                    produces={MediaType.APPLICATION_JSON_VALUE,  
                              MediaType.APPLICATION_XML_VALUE})
    public @ResponseBody Person getPerson(@RequestParam String format){
        return personMapRepository.findPerson(id);
    }
    

    问题二:

    必须添加上述方法的代码才能自定义返回类型格式? 我的意思是,JSON或XML,可能吗?

    我想到了以下几点:

    @RequestMapping(value="/getpersonformataltern",
            method=RequestMethod.GET
            produces={MediaType.APPLICATION_JSON_VALUE, 
                      MediaType.APPLICATION_XML_VALUE}
            )
    public ResponseEntity<Person> getPersonFormat(@RequestParam String format){
        logger.info("getPersonFormat - format: {}", format);
        HttpHeaders httpHeaders = new HttpHeaders();
        if(format.equals("json")){
            logger.info("Ok JSON");
            httpHeaders.setContentType(MediaType.APPLICATION_JSON);
        }
        else{
            logger.info("Ok XML");
            httpHeaders.setContentType(MediaType.APPLICATION_XML);
        }
        return new ResponseEntity<>(PersonFactory.createPerson(), httpHeaders, HttpStatus.OK);
    }
    

    但是:

    如果我执行网址:

    • http://localhost:8080/spring-utility/person/getpersonformataltern?format=json

    我得到了

    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <person>
        <id>1</id>
        <firstName>Manuel</firstName>
        <lastName>Jordan</lastName>
    …
    </person>
    

    XML 中的是!

    注意:我可以确认控制台打印Ok JSON

    如果我执行网址:

    • http://localhost:8080/spring-utility/person/getpersonformataltern?format=xml

    我得到了

    This XML file does not appear to have any style information associated with it. 
    The document tree is shown below.
    
    <person>
        <id>1</id>
        <firstName>Manuel</firstName>
        <lastName>Jordan</lastName> 
        …
    </person>
    

    问题三

    必须添加上述方法的哪些代码才能修复JSON输出? 我不知道出了什么问题或遗失了......

    有三个问题。

    谢谢

    α

    @Override
    public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
        Map<String,MediaType> mediaTypes = new LinkedHashMap<>();
        mediaTypes.put("json", MediaType.APPLICATION_JSON);
        mediaTypes.put("xml", MediaType.APPLICATION_XML);
        configurer.mediaTypes(mediaTypes);
        configurer.defaultContentType(MediaType.TEXT_HTML);
    }
    

3 个答案:

答案 0 :(得分:31)

使用Accept标头很容易从REST服务获取格式json或xml。

这是我的控制器,看看生产部分。

@RequestMapping(value = "properties", produces = {MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE}, method = RequestMethod.GET)
    public UIProperty getProperties() {
        return uiProperty;
    }

为了使用REST服务,我们可以使用下面的代码,其中header可以是MediaType.APPLICATION_JSON_VALUE或MediaType.APPLICATION_XML_VALUE

HttpHeaders headers = new HttpHeaders();
headers.add("Accept", header);

HttpEntity entity = new HttpEntity(headers);

RestTemplate restTemplate = new RestTemplate();
ResponseEntity<String> response = restTemplate.exchange("http://localhost:8080/properties", HttpMethod.GET, entity,String.class);
return response.getBody();

编辑01:

要使用application/xml,请添加此依赖项

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

答案 1 :(得分:2)

你所有的问题都在于你正在将内容类型协商与参数传递混合在一起。它们是不同层次的东西。更具体地说,对于您的问题2,您构建了包含要返回的媒体类型的响应标头。实际内容协商基于请求标头中的接受媒体类型,而不是响应标头。在执行到达getPersonFormat方法的实现时,我不确定内容协商是否已经完成。取决于实施。如果没有,并且您希望使事情有效,则可以使用要返回的内容覆盖请求标头接受类型。

返回新 ResponseEntity &lt;&gt;(PersonFactory.createPerson(),httpHeaders,HttpStatus.OK);

答案 2 :(得分:0)

我更喜欢使用params过滤器来实现以参数为中心的内容类型..我相信它应该与produce属性一起使用。

@GetMapping(value="/person/{id}/", 
            params="format=json",
            produces=MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Person> getPerson(@PathVariable Integer id){
    Person person = personMapRepository.findPerson(id);
    return ResponseEntity.ok(person);
} 
@GetMapping(value="/person/{id}/", 
            params="format=xml",
            produces=MediaType.APPLICATION_XML_VALUE)
public ResponseEntity<Person> getPersonXML(@PathVariable Integer id){
    return GetPerson(id); // delegate
}