2015-12-16 88 views
3

我正在使用Spring MVC 4.1.5,它的REST支持試圖獲得使用google協議緩衝區消息格式的web服務。我看到很多帖子都提到這個問題與JSON格式,但沒有與谷歌協議緩衝區格式。 我也沒有看到Spring框架文檔有protobufs(低於更多),我的代碼在這裏張貼在githubspring mvc rest protocol buffers http 406不可接受的錯誤

這裏是我的控制器代碼(使用或不使用的MediaType產生=「應用xprotobuf」不做區別 - 這裏同樣406不接受錯誤)

@RestController 
@RequestMapping("/ws") 
@EnableWebMvc 
public class CustomerRestController { 
    @Autowired 
    private CustomerRepository customerRepository; 
    //@RequestMapping(value="/customers/{id}", method = RequestMethod.GET, produces="application/x-protobuf") 
    @RequestMapping(value="/customers/{id}", method = RequestMethod.GET) 
    public CustomerProtos.Customer customer(@PathVariable Integer id) { 
     return this.customerRepository.findById(id); 
    } 

    @Bean 
    ProtobufHttpMessageConverter protobufHttpMessageConverter() { 
     return new ProtobufHttpMessageConverter(); 
    } 

    private CustomerProtos.Customer customer(int id, String f, String l, Collection<String> emails) { 
     String emailAddressString = "[email protected]"; 
     for (String email : emails) { 
      emailAddressString = email; 
      break; 
     } 

     EmailAddress emailAddress = CustomerProtos.Customer.EmailAddress.newBuilder() 
       .setType(CustomerProtos.Customer.EmailType.PROFESSIONAL).setEmail(emailAddressString).build(); 

     return CustomerProtos.Customer.newBuilder().setFirstName(f).setLastName(l).setId(id).addEmail(emailAddress) 
       // .addAllEmail(emailAddresses) 
       .build(); 
    } 

    @Bean 
    CustomerRepository customerRepository() { 
     return new CustomerRepositoryImpl(); 
    } 
} 

是我的web.xml

<?xml version="1.0" encoding="UTF-8"?> 
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5"> 
    <display-name>demo</display-name> 
    <welcome-file-list> 
    <welcome-file>index.html</welcome-file> 
    <welcome-file>index.htm</welcome-file> 
    <welcome-file>index.jsp</welcome-file> 
    <welcome-file>default.html</welcome-file> 
    <welcome-file>default.htm</welcome-file> 
    <welcome-file>default.jsp</welcome-file> 
    </welcome-file-list> 


<servlet> 
    <servlet-name>rest</servlet-name> 
    <servlet-class> 
     org.springframework.web.servlet.DispatcherServlet 
    </servlet-class> 
    <load-on-startup>1</load-on-startup> 
</servlet> 

<servlet-mapping> 
    <servlet-name>rest</servlet-name> 
    <url-pattern>/*</url-pattern> 
</servlet-mapping> 

    <context-param> 
     <param-name>contextConfigLocation</param-name> 
     <param-value>/WEB-INF/rest-servlet.xml</param-value> 
    </context-param> 

    <listener> 
     <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> 
    </listener> 

</web-app> 

,這裏是我的pom.xml,請注意,我確實有谷歌的protobuf libaries添加在這裏和他們的最終WEB-INF/lib目錄部署的.war文件的文件夾。

<?xml version="1.0" encoding="UTF-8"?> 
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 
    <modelVersion>4.0.0</modelVersion> 

    <groupId>org.test</groupId> 
    <artifactId>demo</artifactId> 
    <version>0.0.1-SNAPSHOT</version> 
    <packaging>war</packaging> 

    <parent> 
     <groupId>org.springframework.boot</groupId> 
     <artifactId>spring-boot-starter-parent</artifactId> 
     <version>1.3.0.RELEASE</version> 
    </parent> 

    <properties> 
     <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> 
     <start-class>demo.DemoApplication</start-class> 
     <java.version>1.8</java.version> 
     <jackson.version>2.5.3</jackson.version> 

    </properties> 

    <dependencies> 
     <dependency> 
      <groupId>org.springframework</groupId> 
      <artifactId>spring-webmvc</artifactId> 
      <version>4.2.0.RELEASE</version> 
     </dependency> 
     <dependency> 
      <groupId>org.springframework</groupId> 
      <artifactId>spring-tx</artifactId> 
      <version>4.2.0.RELEASE</version> 
     </dependency> 
     <dependency> 
      <groupId>com.fasterxml.jackson.core</groupId> 
      <artifactId>jackson-databind</artifactId> 
     </dependency> 
     <dependency> 
      <groupId>javax.servlet</groupId> 
      <artifactId>javax.servlet-api</artifactId> 
     </dependency> 
     <dependency> 
      <groupId>com.google.protobuf</groupId> 
      <artifactId>protobuf-java</artifactId> 
      <version>2.5.0</version> 
     </dependency> 
     <dependency> 
      <groupId>com.googlecode.protobuf-java-format</groupId> 
      <artifactId>protobuf-java-format</artifactId> 
      <version>1.2</version> 
     </dependency> 

     <dependency> 
      <groupId>org.springframework.boot</groupId> 
      <artifactId>spring-boot-starter-web</artifactId> 
     </dependency> 

     <dependency> 
      <groupId>org.springframework.boot</groupId> 
      <artifactId>spring-boot-starter-test</artifactId> 
      <scope>test</scope> 
     </dependency> 

     <dependency> 
      <groupId>org.springframework.boot</groupId> 
      <artifactId>spring-boot-legacy</artifactId> 
      <version>1.0.0.RELEASE</version> 
     </dependency> 
    </dependencies> 

    <build> 
     <plugins> 
      <plugin> 
       <groupId>org.springframework.boot</groupId> 
       <artifactId>spring-boot-maven-plugin</artifactId> 
      </plugin> 
     </plugins> 
    </build> 
</project> 

這裏是我的測試客戶端

package demo; 

import java.util.Arrays; 

import org.junit.Test; 
import org.junit.runner.RunWith; 
import org.springframework.beans.factory.annotation.Autowired; 
import org.springframework.boot.test.IntegrationTest; 
import org.springframework.boot.test.SpringApplicationConfiguration; 
import org.springframework.context.annotation.Bean; 
import org.springframework.context.annotation.Configuration; 
import org.springframework.http.ResponseEntity; 
import org.springframework.http.converter.protobuf.ProtobufHttpMessageConverter; 
import org.springframework.test.context.ContextConfiguration; 
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 
import org.springframework.web.client.RestTemplate; 

@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration 
public class DemoApplicationTests { 

    @Configuration 
    public static class RestClientConfiguration { 

     @Bean 
     RestTemplate restTemplate(ProtobufHttpMessageConverter hmc) { 
      return new RestTemplate(Arrays.asList(hmc)); 
     } 

     @Bean 
     ProtobufHttpMessageConverter protobufHttpMessageConverter() { 
      return new ProtobufHttpMessageConverter(); 
     } 
    } 

    @Autowired 
    private RestTemplate restTemplate; 

    @Test 
    public void contextLoaded() { 

     ResponseEntity<CustomerProtos.Customer> customer = restTemplate.getForEntity(
       "http://localhost:7001/demo-0.0.1-SNAPSHOT/ws/customers/2", CustomerProtos.Customer.class); 

     System.out.println("customer retrieved: " + customer.toString()); 

    } 

} 

當我使用MVN測試 從命令行運行客戶端,我得到以下錯誤

Tests run: 1, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 0.697 sec <<< FAILURE! - in demo.DemoApplicationTests 
contextLoaded(demo.DemoApplicationTests) Time elapsed: 0.037 sec <<< ERROR! 
org.springframework.web.client.HttpClientErrorException: 406 Not Acceptable 
     at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:91) 
     at org.springframework.web.client.RestTemplate.handleResponse(RestTemplate.java:641) 
     at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:597) 
     at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:557) 
     at org.springframework.web.client.RestTemplate.getForEntity(RestTemplate.java:289) 
     at demo.DemoApplicationTests.contextLoaded(DemoApplicationTests.java:42) 

我看到人們使用contentNegotiationManager

提示

在我的rest-servlet.xml中我有mvc:anno塔季翁驅動標籤

<?xml version="1.0" encoding="UTF-8"?> 
<beans xmlns="http://www.springframework.org/schema/beans" 
    xmlns:context="http://www.springframework.org/schema/context" 
    xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:p="http://www.springframework.org/schema/p" 
    xsi:schemaLocation=" 
     http://www.springframework.org/schema/beans  
     http://www.springframework.org/schema/beans/spring-beans-4.0.xsd 
     http://www.springframework.org/schema/context 
     http://www.springframework.org/schema/context/spring-context-4.0.xsd 
     http://www.springframework.org/schema/mvc 
     http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd"> 
    <context:component-scan base-package="demo" /> 
    <mvc:annotation-driven /> 
    </beans> 

而且我在webConfig.java已經下降在演示包

package demo; 

import org.springframework.context.annotation.Configuration; 
import org.springframework.http.MediaType; 
import org.springframework.web.servlet.config.annotation.ContentNegotiationConfigurer; 
import org.springframework.web.servlet.config.annotation.EnableWebMvc; 
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; 

@Configuration 
@EnableWebMvc 
public class WebConfig extends WebMvcConfigurerAdapter { 

    /** 
    * Total customization - see below for explanation. 
    */ 
    @Override 
    public void configureContentNegotiation(ContentNegotiationConfigurer configurer) { 
    configurer.favorPathExtension(false). 
      favorParameter(true). 
      parameterName("mediaType"). 
      ignoreAcceptHeader(true). 
      useJaf(false). 
      defaultContentType(MediaType.TEXT_PLAIN). 
      mediaType("xml", MediaType.APPLICATION_XML). 
      mediaType("json", MediaType.APPLICATION_JSON). 
      mediaType("x-protobuf", MediaType.ALL) 
      ; 
    } 
} 

我得到的406不接受錯誤與不webconfig.java(這是做的工作contentNegotationManager)。

我一直無法在Spring 4.1.3或甚至4.2.3 jars中找到MediaType.APPLICATION_XPROTOBUF。

所以我已經離開該值MediaType.ALL(我認爲這應該工作?)

當我運行測試客戶端我實際運行測試之前得到這個消息..

09:27:26.198 [main] DEBUG o.s.web.client.RestTemplate - Created GET request for "http://localhost:7001/demo-0.0.1-SNAPSHOT/ws/customers/2" 
09:27:26.199 [main] DEBUG o.s.web.client.RestTemplate - Setting request Accept header to [application/x-protobuf, text/plain, application/xml, application/json] 
09:27:26.245 [main] DEBUG o.s.web.client.RestTemplate - GET request for "http://localhost:7001/demo-0.0.1-SNAPSHOT/ws/customers/2" resulted in 406 (Not Acceptable); invoking error 
handler 

它清楚地顯示了它將accept頭設置爲包含「application-xprotobuf」值。 不知道我在這種情況下缺少什麼。

+0

你可以再試一次適當的Spring Boot應用程序(嘗試使用start.spring.io)。我可以在這裏看到多種氣味,這可能會導致很多問題:1)您不需要自己添加spring-mvc作爲依賴項,也不需要自己指定spring版本2)不應該有BootWebMvc註釋,因爲它是由Boot完成的。 3)web.xml和rest-servlet.xml文件不應該在那裏4)你應該刪除儘可能多的噪音,這裏不涉及你的問題 –

+0

我可以做的那些步驟,除了我需要保持網頁。 xml和rest-servlet.xml,因爲我試圖讓它在支持Java6的servlet 2.5容器上工作。我見過Spring啓動文檔提到如果我在一個servlet 2.5容器中運行,我將需要該web.xml ..將讓你張貼。 thx的迴應。 –

+0

預定義的MediaType常量只是一個便利功能。你可以創建你想要的媒體類型! 只需創建您自己的實例是這樣的: 新的MediaType(「應用程序/ x-protobuf的」) 還有一些其他的構造函數亞型,提供的字符集等。 –

回答

6

我的控制器與406: Not Acceptable失敗的問題相同。大量的跟蹤後,我在example想出聲明:

春天開機自動註冊HttpMessageConverter豆,所以我們只需要定義ProtobufHttpMessageConverter豆,它得到適當配置。

從字面上理解,因爲沒有彈簧啓動沒有轉換器註冊發生。 Bean 實例化的,但它從來沒有在HttpMessageConverters列表中註冊。

我已經明確地註冊ProtobufHttpMessageConverter實例解決了這個問題:

@Configuration 
@EnableWebMvc 
@ComponentScan 
public class AppConfig extends WebMvcConfigurerAdapter { 

    @Override 
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) { 
     converters.add(new ProtobufHttpMessageConverter()); 
     super.configureMessageConverters(converters); 
    } 
} 

你並不需要聲明一個單獨的bean爲它(除非你打算來顯式調用)。

另請注意,覆蓋configureMessageConverters()將禁用所有標準轉換器;如果您的意思是擴大庫存轉換器的列表而不是替換它,請改爲使用extendMessageConverters()

相關問題