如何使用Spring REST消耗protobuf参数?

时间:2016-10-13 14:23:17

标签: spring protocol-buffers spring-restcontroller

我正在尝试将protobuf参数传递给REST端点,但我得到了

  

org.springframework.web.client.HttpServerErrorException:500 null

每次我尝试。我现在拥有的是这样的:

@RestController
public class TestTaskEndpoint {

    @PostMapping(value = "/testTask", consumes = "application/x-protobuf", produces = "application/x-protobuf")
    TestTaskComplete processTestTask(TestTask testTask) {
        // TestTask is a generated protobuf class
        return generateResult(testTask);
    }
}


@Configuration
public class AppConfiguration {

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

}

@SpringBootApplication
public class JavaConnectorApplication {

    public static void main(String[] args) {
        SpringApplication.run(JavaConnectorApplication.class, args);
    }
}

我的测试看起来像这样:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
@WebAppConfiguration
public class JavaConnectorApplicationTest {


    @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;

    private int port = 8081;

    @Test
    public void contextLoaded() {

        TestTask testTask = generateTestTask();

        final String url = "http://127.0.0.1:" + port + "/testTask/";
        ResponseEntity<TestTaskComplete> customer = restTemplate.postForEntity(url, testTask, TestTaskComplete.class);

        // ...

    }
}

我确信它是带参数的东西,因为如果我创建一个不采用protobuf参数但返回一个的变体,它就可以正常工作了。我尝试调试控制器代码,但执行没有到达方法所以问题可能在其他地方。如何正确地参数化此REST方法?

2 个答案:

答案 0 :(得分:0)

这是完整的答案

@SpringBootApplication
public class JavaConnectorApplication {

    public static void main(String[] args) {
        SpringApplication.run(JavaConnectorApplication.class, args);
    }
}

然后您需要提供正确的配置。

 @Configuration
    public class AppConfiguration {

         //You need to add in this list all the messageConverters you will use
         @Bean 
        RestTemplate restTemplate(ProtobufHttpMessageConverter hmc) {
            return new RestTemplate(Arrays.asList(hmc,smc));
        }

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

    }

最后是你的RestController。

@RestController
public class TestTaskEndpoint {

    @PostMapping(value = "/testTask")
    TestTaskComplete processTestTask(@RequestBody TestTask testTask) {
        // TestTask is a generated protobuf class
        return generateResult(testTask);
    }
}

@RequestBody注释:请求的主体通过HttpMessageConverter(您已定义)传递,以根据请求的内容类型解析方法参数

你的考试班:

@RunWith(SpringRunner.class)
@SpringBootTest
@WebAppConfiguration
public class JavaConnectorApplicationTest {

    @Autowired
    private RestTemplate restTemplate;

    private int port = 8081;

    @Test
    public void contextLoaded() {

        TestTask testTask = generateTestTask();

        final String url = "http://127.0.0.1:" + port + "/testTask/";
        ResponseEntity<TestTaskComplete> customer = restTemplate.postForEntity(url, testTask, TestTaskComplete.class);

        // Assert.assertEquals("dummyData", customer.getBody().getDummyData());

    }
}

答案 1 :(得分:0)

这是我的第一个堆栈溢出答案,但我在通过 http 和 spring 搜索带有 protobuf 的工作示例时感到非常沮丧。

来自 Jorge 的答案 https://stackoverflow.com/a/44592469/15705964 几乎是正确的。 就像评论中提到的:“这本身是行不通的。你至少需要在某处添加一个转换器。”

这样做:

@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Autowired
    ProtobufHttpMessageConverter protobufHttpMessageConverter;

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

}

ProtobufHttpMessageConverter 将自动完成他的工作并将对象添加到您的控制器方法中

@RestController
public class ProtobufController {

    @PostMapping(consumes = "application/x-protobuf", produces = "application/x-protobuf")
    public ResponseEntity<TestMessage.Response> handlePost(@RequestBody TestMessage.Request protobuf) {

    TestMessage.Response response = TestMessage.Response.newBuilder().setQuery("This is a protobuf server Response")
            .build();

    return ResponseEntity.ok(response);
}

发送和接收休息的工作示例看看:https://github.com/Chriz42/spring-boot_protobuf_example