【问题标题】:Spring Boot: MockMvc returning empty body for POST requestSpring Boot:MockMvc 为 POST 请求返回空正文
【发布时间】:2019-11-27 18:09:36
【问题描述】:

我正在使用 Spring Boot 和 Spring Data Rest 编写一个小型演示应用程序。我有以下模型和相应的存储库:

@Entity
public class Employee {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String firstName;
    private String lastName;
    private String jobTitle;

    public Employee() {
    }

    ... // getters and setters
}
@RepositoryRestResource(collectionResourceRel = "employees", path = "employees")
public interface EmployeeRepository extends PagingAndSortingRepository<Employee, Long> {
    @RestResource(path = "by-last-name", rel = "by-last-name")
    Page<Employee> findByLastNameIgnoreCase(Pageable pageable, @Param("lastName") String lastName);

    @RestResource(path = "by-job-title", rel = "by-job-title")
    Page<Employee> findByJobTitleIgnoreCase(Pageable pageable, @Param("jobTitle") String jobTitle);
}

如果我通过 Postman 提出以下请求:

POST localhost:8080/employees
{"firstName":"Test","lastName":"McTest","jobTitle":"Tester"}

我收到了包含新创建实体的完整响应正文:

{
  "firstName": "Test",
  "lastName": "McTest",
  "jobTitle": "Tester",
  "_links": {
    "self": {
      "href": "http://localhost:8080/employees/120"
    },
    "employee": {
      "href": "http://localhost:8080/employees/120"
    }
  }
}

但是,当我通过如下所示的测试发出相同的请求时,我得到一个空的响应正文:

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = Application.class)
@AutoConfigureMockMvc
public class EmployeeIntegrationTest {
    @Autowired
    private MockMvc mvc;

    @Autowired
    ObjectMapper objectMapper;

    @Test
    public void testAddEmployee() throws Exception {
        Employee employee = new Employee();
        employee.setFirstName("Test");
        employee.setLastName("McTest");
        employee.setJobTitle("Tester");

        MockHttpServletRequestBuilder requestBuilder = post("/employees")
                .contentType(APPLICATION_JSON)
                .content(objectMapper.writeValueAsString(employee));

        mvc
                .perform(requestBuilder)
                .andExpect(status().isCreated())
                .andExpect(jsonPath("$.firstName", Matchers.is("Test"))); // Fails, because content is empty. 
    }
}

不管怎样,如果我在测试中执行GET /employees,我确实会在响应正文中看到该实体,因此我知道它正在被创建。

我的期望是,我会通过任何一种方法得到相同的响应,可惜目前情况并非如此,而且似乎 POSTMockMvc 的请求没有返回正文。我是否可能在某处遗漏了配置设置?

【问题讨论】:

    标签: java spring spring-boot spring-data-rest


    【解决方案1】:

    我能够通过显式设置来解决问题

    @Override
    public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {
        config.setReturnBodyForPutAndPost(true);
    }
    

    在实现RepositoryRestConfigurer@Configuration类内部

    我的猜测是,这是为主要代码隐式设置的,而不是为测试设置的。

    【讨论】:

      【解决方案2】:

      在请求中设置 HTTP Accept 标头应该会导致返回响应正文:

      MockHttpServletRequestBuilder requestBuilder = post("/employees")
              .accept(APPLICATION_JSON)
              .contentType(APPLICATION_JSON)
              .content(objectMapper.writeValueAsString(employee));
      

      默认情况下,如果指定了 HTTP Accept 标头,Spring Data REST 只会返回响应正文。这种行为记录在Spring Data REST Reference Guide:

      POST 方法从给定的请求正文创建一个新实体。默认情况下,响应是否包含正文由随请求发送的 Accept 标头控制。如果发送了一个,则会创建一个响应正文。如果不是,则响应正文为空,并且可以通过以下链接获得所创建资源的表示形式,该链接包含在Location 响应标头中。可以通过相应地配置 RepositoryRestConfiguration.setReturnBodyOnCreate(…) 来覆盖此行为。

      我的猜测是您的 Postman 请求设置了“Accept”标头,这就是您在 Postman 中没有看到这种行为的原因。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-08-06
        • 2018-01-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多