时间:2015-09-09 17:28:26

标签: java spring spring-mvc

我有以下设置:

@ControllerAdvice
public class GlobalBindingInitializer {

    @InitBinder
    public void initBinder(WebDataBinder binder) {
        binder.registerCustomEditor(ZonedDateTime.class, new ZonedDateTimeBinder());
    }
}

public class ZonedDateTimeBinder extends PropertyEditorSupport {

    public void setAsText(String value) {
        setValue(ZonedDateTime.parse(value));
    }

    public String getAsText() {
        return ((ZonedDateTime) getValue()).toString();
    }

}

@RequestMapping(value = "/bx", method = RequestMethod.POST)
public ResponseEntity<X> bx(@Valid @RequestBody MyForm form, BindingResult result) {
    .............
}

public class AddNewBookingPeriodForm {

    .....

    @NotNull
    private ZonedDateTime dateFrom;

    @NotNull
    private ZonedDateTime dateTo;

    .....

}

@Test
public void test_bx_valid() throws Exception {

    String content = "{" +
            "\"uuid\":\""+...+"\"," +
            "\"dateFrom\":\""+...+"\"," +
            "\"dateTo\":\""+...+"\"," +
            "\"ln\":\""+...+"\"," +
            "\"fn\":\""+...+"\"," +
            "\"p\":\""+...+"\"" +
            "}";

    mockMvc.perform(post("/b/bx")
            .contentType("application/json;charset=UTF-8")
            .content((content).getBytes()))
            .andDo(print())
            .andExpect(status().isCreated())
            .andExpect(content().contentType("application/json;charset=UTF-8"))
            .andExpect((jsonPath("$.", Matchers.hasSize(3))))
            .andDo(print());

}

问题在于,当我运行测试时,它会找到控制器处理程序方法,并说它因为正文而无法读取请求。我调试了已发送的消息并且它具有所需的表单,它是一个有效的JSON对象。问题在于两个ZonedDateTime字段。

我在另一个地方有类似的代码,但用于验证的表单只有一个ZonedDateTime,它可以工作。我认为问题可能是因为我有两个这种形式,但我无法弄清楚发生了什么。

我尝试将dateFromdateTo的类型从我的表单更改为String,一切正常,所以问题在于这两个。

有什么想法吗?

测试打印的此调试消息:

MockHttpServletRequest:
         HTTP Method = POST
         Request URI = /b/bx
          Parameters = {}
             Headers = {Content-Type=[application/json;charset=UTF-8]}

             Handler:
                Type = valid handler controller
              Method = valid handler method

               Async:
       Async started = false
        Async result = null

  Resolved Exception:
                Type = org.springframework.http.converter.HttpMessageNotReadableException

        ModelAndView:
           View name = null
                View = null
               Model = null

            FlashMap:

MockHttpServletResponse:
              Status = 400
       Error message = null
             Headers = {}
        Content type = null
                Body = 
       Forwarded URL = null
      Redirected URL = null
             Cookies = []

编辑1

这是一个有效的样本

{  
   "uuid":"e50b5cbf-c81a-40de-9eee-ceecd21ad179",
   "dateFrom":"2015-09-07T19:25:42+03:00",
   "dateTo":"2015-09-08T19:25:42+03:00",
   "ln":"ln",
   "fn":"fn",
   "p":"007"
}

我认为问题可能来自@RequestBody注释,因为在前面的行中我讨论的工作案例中,我使用了GET方法而没有@RequestBody注释,并且映射有效很好。

1 个答案:

答案 0 :(得分:1)

给定RequestBody,Spring将使用HttpMessageConverter将您的请求主体反序列化为您给定类型的实例。在这种情况下,它将使用MappingJackson2HttpMessageConverter作为JSON。此转换器根本不涉及您的PropertyEditorSupport

要正确反序列化ZonedDateTime,您需要注册适当的Jackson模块以映射java.time类型。一种可能性是jackson-datatype-jsr310。我相信它应该在类路径上找到时自动注册。如果不是,您需要手动注册,方法是使用适当创建的MappingJackson2HttpMessageConverter手动创建并注册ObjectMapper