自定义HTTP消息转换器实战
在上一篇教程中,我们学习了如何创建自定义的HTTP消息转换器。本篇教程,我们将更进一步,创建一个能够将包含YAML内容的请求体转换为用户定义的对象,反之亦然的HTTP消息转换器。我们将使用SnakeYAML,这是一个基于Java的YAML数据解析器。
创建控制器
首先,我们创建一个控制器ExampleController
,它将处理YAML格式的请求和响应。
@Controller
public class ExampleController {
@RequestMapping(
value = "/newEmployee",
consumes = "text/yaml",
produces = MediaType.TEXT_PLAIN_VALUE,
method = RequestMethod.POST)
@ResponseBody
@ResponseStatus(HttpStatus.OK)
public String handleRequest(@RequestBody Employee employee) {
System.out.printf("In handleRequest method, employee: %s%n", employee);
String s = String.format("Employee saved: " + employee.getName());
System.out.println(s);
return s;
}
@RequestMapping(
value = "/employee",
produces = "text/yaml",
method = RequestMethod.GET)
@ResponseStatus(HttpStatus.OK)
public Employee handleRequest2(@RequestParam String id) {
// 创建一个测试员工
return new Employee(id, "Tina", "111-111-1111");
}
}
public class Employee {
private String id;
private String name;
private String phoneNumber;
// 省略其他字段和getter/setter方法
}
创建转换器
接下来,我们创建一个YamlHttpMessageConverter
类,继承自AbstractHttpMessageConverter
,用于处理YAML格式的转换。
public class YamlHttpMessageConverter<T> extends AbstractHttpMessageConverter<T> {
public YamlHttpMessageConverter() {
super(new MediaType("text", "yaml"));
}
@Override
protected boolean supports(Class<?> clazz) {
return true;
}
@Override
protected T readInternal(Class<? extends T> clazz, HttpInputMessage inputMessage)
throws IOException, HttpMessageNotReadableException {
Yaml yaml = new Yaml();
T t = yaml.loadAs(inputMessage.getBody(), clazz);
return t;
}
@Override
protected void writeInternal(T t, HttpOutputMessage outputMessage)
throws IOException, HttpMessageNotWritableException {
Yaml yaml = new Yaml();
OutputStreamWriter writer = new OutputStreamWriter(outputMessage.getBody());
yaml.dump(t, writer);
writer.close();
}
}
注册转换器
然后,我们需要在Spring的配置类中注册这个转换器。
@EnableWebMvc
@ComponentScan("com.logicbig.example")
public class AppConfig extends WebMvcConfigurerAdapter {
@Override
public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(new YamlHttpMessageConverter<>());
}
}
使用JUnit测试
最后,我们使用JUnit来测试我们的控制器。
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration(classes = AppConfig.class)
public class ControllerTest {
@Autowired
private WebApplicationContext wac;
private MockMvc mockMvc;
public void setup() {
DefaultMockMvcBuilder builder = MockMvcBuilders.webAppContextSetup(this.wac);
this.mockMvc = builder.build();
}
@Test
public void testConsumerController() throws Exception {
MockHttpServletRequestBuilder builder =
MockMvcRequestBuilders.post("/newEmployee")
.contentType("text/yaml")
.accept(MediaType.TEXT_PLAIN_VALUE)
.content(getNewEmployeeInYaml());
this.mockMvc.perform(builder)
.andExpect(MockMvcResultMatchers.status().isOk())
.andExpect(MockMvcResultMatchers.content().string("Employee saved: Tina"))
.andDo(MockMvcResultHandlers.print());
}
public String getNewEmployeeInYaml() {
return "id: 1\nname: Tina\nphoneNumber: 111-111-1111\n";
}
}
输出示例
当测试通过时,你将看到如下输出:
In handleRequest method, employee: Employee{id='1', name='Tina', phoneNumber='111-111-1111}
Employee saved: Tina
项目依赖和技术
- Spring Web MVC 4.3.8.RELEASE
- Spring TestContext Framework 4.3.8.RELEASE
- Java Servlet API 3.0.1
- JUnit 4.12
- SnakeYAML 1.18
- JDK 1.8
- Maven 3.3.9