【问题标题】:Why does @RequestBody require no arg constructor?为什么@RequestBody 不需要 arg 构造函数?
【发布时间】:2015-10-06 17:10:52
【问题描述】:

我只是在玩spring-boot,只是想用method = RequestMethod.POST创建一个控制器

我的控制器:

@RequestMapping(value = "/user/signup",
        method = RequestMethod.POST)
private String signUpNewUser(@Valid @RequestBody SignInUserForm userForm){
        // validation + logic
}

SignUpUserForm 类:

@Getter
@NoArgsConstructor
@AllArgsConstructor
public class SignInUserForm {
    @NotEmpty
    @Email
    private String email;

    @NotEmpty
    @Size(min = 8, max = 24)
    private String password;

    @NotEmpty
    @Size(min = 8, max = 24)
    private String repeatedPassword;
}

最后是我的测试:

@Test
    public void shouldCallPostMethod() throws Exception {

        SignInUserForm signInUserForm = new SignInUserForm("test@mail.com", "aaaaaaaa", "aaaaaaaa");

        String json = new Gson().toJson(signInUserForm);

        mockMvc.perform(
                MockMvcRequestBuilders.post("/user/signup")
                    .contentType(MediaType.APPLICATION_JSON_VALUE)
                    .content(json))
                .andDo(MockMvcResultHandlers.print())
                .andExpect(MockMvcResultMatchers.status().isCreated());
    }

就 SignUpControllerForm 包含无参数构造函数而言,一切正常,但一旦丢失,这就是我从MockMvcResultHandlers.print() 收到的内容:

MockHttpServletRequest:
         HTTP Method = POST
         Request URI = /user/signup
          Parameters = {}
             Headers = {Content-Type=[application/json]}

             Handler:
                Type = org.bitbucket.akfaz.gui.controller.SignUpController
              Method = private java.lang.String org.bitbucket.akfaz.gui.controller.SignUpController.signUpNewUser(org.bitbucket.akfaz.gui.model.SignInUserForm)

               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 = []

我想表达的是,HttpMessageNotReadableException 的异常描述性不够。不应该有任何与@RequestBody 相关的异常吗?这样可以节省很多时间。

Spring 究竟如何使用无参数构造函数将 JSON 转换为 java 对象(它不使用我检查过的 getter)?

【问题讨论】:

  • 启用调试日志。 Spring 在那里打印异常消息。
  • 所有可序列化的类都需要一个无参数的构造函数。这是 java 的基本规则,而不是 Spring 本身的限制。 (Jackson 容忍你不将类标记为可序列化的不能承受 :))

标签: java rest spring-boot


【解决方案1】:

正如@Sotitios 所说,您可以启用调试日志,您可以通过将 logback.xml(它也可以是 groovy)添加到您的资源文件夹来做到这一点。这是我的

<configuration>
    <appender name="FILE"
        class="ch.qos.logback.core.rolling.RollingFileAppender">
        <File>logFile.log</File>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <FileNamePattern>logFile.%d{yyyy-MM-dd}.log</FileNamePattern>
            <maxHistory>5</maxHistory>
        </rollingPolicy>

        <layout class="ch.qos.logback.classic.PatternLayout">
            <Pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{35} -
                %msg%n</Pattern>
        </layout>
    </appender>

    <root level="DEBUG">
        <appender-ref ref="FILE" />
    </root>

</configuration>

关于您对无参数构造函数的问题,您可以创建自己的构造函数并强制杰克逊使用它,我相信这是一个很好的做法,因为您可以更好地控制可变性

@JsonCreator
    public UserDto(
            @JsonProperty("id") Long id, 
            @JsonProperty("firstName") String firstName, 
            @JsonProperty("lastName") String lastName,
            @JsonProperty("emailAddress") String emailAddress,
            @JsonProperty("active") boolean active,
            @JsonProperty("position") String position,
            @JsonProperty("pendingDays") Integer pendingDays,
            @JsonProperty("taxUid")  String taxUid,
            @JsonProperty("userName") String userName,
            @JsonProperty("approver") boolean approver,
            @JsonProperty("startWorkingDate") Date startWorkingDate,
            @JsonProperty("birthDate") Date birthDate){

        this.id = id;
        this.firstName = firstName;
        this.lastName = lastName;
        this.taxUid = taxUid;
        this.userName = userName;
        this.emailAddress = emailAddress;
        this.pendingDays = pendingDays;
        this.position = position;
        this.active = active;
        //this.resourceUrl = resourceUrl;
        this.isApprover = approver;
        this.birthDate = birthDate;
        this.startWorkingDate = startWorkingDate;

    }

希望对你有帮助

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-02-25
    • 2020-03-10
    • 1970-01-01
    • 2018-06-02
    • 2021-08-12
    相关资源
    最近更新 更多