保存结构化 JSON 对象的错误请求 [英] Bad Request from saving structured JSON object

查看:41
本文介绍了保存结构化 JSON 对象的错误请求的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我创建了一个简单的 Web REST 应用程序,它必须保存更改票".到数据库.但是在我尝试使用 JSON 作为正文创建 POST 请求后,我收到一个错误:

I have created a simple web REST application that has to save a "change ticket" to database. But after I try to create a POST request with JSON as body I get an error:

2020-11-28 14:06:10.449 DEBUG 14864 --- [nio-8080-exec-2] o.s.web.servlet.DispatcherServlet        : Completed 400 BAD_REQUEST
2020-11-28 14:06:10.453 DEBUG 14864 --- [nio-8080-exec-2] o.s.web.servlet.DispatcherServlet        : "ERROR" dispatch for POST "/error", parameters={}
2020-11-28 14:06:10.455 DEBUG 14864 --- [nio-8080-exec-2] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped to org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController#error(HttpServletRequest)
2020-11-28 14:06:10.464 DEBUG 14864 --- [nio-8080-exec-2] o.s.w.s.m.m.a.HttpEntityMethodProcessor  : Using 'application/json', given [*/*] and supported [application/json, application/*+json, application/json, application/*+json]
2020-11-28 14:06:10.464 DEBUG 14864 --- [nio-8080-exec-2] o.s.w.s.m.m.a.HttpEntityMethodProcessor  : Writing [{timestamp=Sat Nov 28 14:06:10 CET 2020, status=400, error=Bad Request, message=, path=/change/save}]
2020-11-28 14:06:10.476 DEBUG 14864 --- [nio-8080-exec-2] o.s.web.servlet.DispatcherServlet        : Exiting from "ERROR" dispatch, status 400

我使用 Spring Boot 2、MySQL 作为 DB 和 MapStruct 将 DTO 转换为实体,反之亦然.我也使用 Project lombok 来摆脱一些样板代码

I am using Spring Boot 2, MySQL as DB and MapStruct to convert DTO to entities and vice versa. Also I use Project lombok to get rid of some boilerplate code

我的控制器 POST 方法如下所示:

My controller POST method is depicted here:

@RestController
@Slf4j
@RequestMapping({"/change"})
public class ChangeTicketController { 
@PostMapping(value = "/save", consumes = MediaType.APPLICATION_JSON_VALUE)
    public ResponseEntity<String> save(@RequestBody @Validated ChangeTicketDto changeTicketDto){
        ChangeTicket mappedChangeTicket = changeTicketMapper.changeTicketDtoToChangeTicket(changeTicketDto);
        ChangeTicket savedTicket = changeService.save(mappedChangeTicket);
        return ResponseEntity.created(URI.create(BASE_URL + "/save/" + savedTicket.getChangeId()))
                .body("Change Ticket has been saved");
    }
}

我保存的实体如下所示:

My entity which I am saving looks like this:

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Entity
public class ChangeTicket extends BaseItem{

    //some constructor

    @NotBlank
    private String changeId;    // public ID set by user

    @NotNull
    @Enumerated(value = EnumType.STRING)
    private ChangeType changeType;


    @NotBlank
    @Size(min = 15, max = 500)
    @Column(length = 500)
    private String description;

}

超类:

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@MappedSuperclass
public class BaseItem {

    @JsonIgnore
    @Id
    @GeneratedValue(generator="system-uuid")
    @GenericGenerator(name="system-uuid", strategy = "uuid")
    private String id;      // Secret ID generated by DB

    @Enumerated(value = EnumType.STRING)
    @NotNull
    @Column(name = "item_status")
    private ItemStatus itemStatus;

    @CreationTimestamp
    @Column(name = "created_at", updatable = false)
    private Timestamp createdAt;

    @UpdateTimestamp
    @Column(name = "updated_at",updatable = true)
    private Timestamp updatedAt;

    @Column(name = "closed_at", updatable = false)
    private Timestamp closedAt;


    @OneToOne(cascade = CascadeType.ALL)
    @JoinColumn(name = "incidentSolver_id", referencedColumnName = "id")   // owning side
    private IncidentSolver incidentSolver;


    @OneToOne(cascade = CascadeType.ALL)
    @JoinColumn(name = "user_id", referencedColumnName = "id")
    private User user;
}

这是我通过 POSTMAN 作为 POST 请求发送到的示例 JSON 代码:http://localhost:8080/change/save

And here is the sample JSON code I am sending via POSTMAN to as POST request to: http://localhost:8080/change/save

{
    "changeId": "86edd7ea-4c37-4dd9-a55c-aeea171e0b42",
    "changeType": "OS_SETTINGS_CHANGE",
    "description": "description",
    "itemStatus": "OPEN",
    "createdAt": "2020-11-28T12:51:58+00:00",
    "updatedAt": "2020-11-28T12:55:08+00:00",
    "closedAt":"",
    "incidentSolver": [
        {
            "incidentId": "015f3e95-de08-4035-9052-9d40ad2b7af6",
            "userName": "ThisDude"
        }
    ],
    "user": [
        {
            "userId": "3d00339a-5757-4ada-a316-6705ff603d96",
            "userType": "CUSTOMER",
            "userName": "WednesdayDude"
        }
    ]
}

我不知道 Jackson 不知道如何反序列化/序列化子对象和父对象是否有问题,或者我是否错误地构建了 Json.如果您需要查看我的服务类存储库,我将编辑这篇文章以显示它们.

I don't know if it is a problem with Jackson not knowing how to deserialize/serialize child and parent objects or If I am building my Json wrongly. If you will need to see my repositories of service classes I will edit this post to show them.

添加 ChangeTicketDTO

adding ChangeTicketDTO

@Getter
@Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ChangeTicketDto extends BaseItemDto {

    private String changeId;    // public ID set by user

    private ChangeType changeType;
    private String description;
}

BaseItemDTO

BaseItemDTO

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class BaseItemDto {

    private ItemStatus itemStatus;
    private Timestamp createdAt;
    private Timestamp updatedAt;
    private Timestamp closedAt;
    private IncidentSolver incidentSolver;
    private User user;
}

谢谢大家的帮助

推荐答案

我回来了一个对我有用的解决方案.我曾尝试测试并查看可能导致此问题的原因,结果是当您错误地构建 JSON 请求正文时会出现此问题.

I am back with a solution that worked for me. I have tried to test and see what can cause this problem and it turned out, that this problem occurs when you construct your JSON request body wrong.

正如您在我的帖子中看到的那样,我正在使用 JSON 正文向我的控制器发送 POST 请求.但是,我想到编写一个测试方法,将我的对象转换为 JSON,因此我将确保我的 JSON 以正确的方式构建.你可以在这里看到:

I was sending POST request to my controller with JSON body as you can see up in my post. But than I got the idea to write a test method that will transform my object to JSON so I will be sure that my JSON is constructed in a proper way. You can see it here:

@ExtendWith(MockitoExtension.class)
class ChangeServiceImplTest {

    ChangeTicketDto changeTicketDto;


    @Test
    public void testConversionOfObject() throws JsonProcessingException {

        changeTicketDto = changeTicketDto.builder().changeId("StringID")
                .description("SOME TEXT")
                .changeType(ChangeType.INSTALLATION_OF_OS)
                .incidentSolver(IncidentSolver.builder().userName("DUDE").id("ID").build())
                .user(User.builder().userName("USERNAME").userType(UserType.USER).build())
                .closedAt(Timestamp.from(Instant.now()))
                .createdAt(Timestamp.from(Instant.now()))
                .updatedAt(Timestamp.from(Instant.now()))
                .itemStatus(ItemStatus.OPEN)
                .build();

        ObjectMapper objectMapper = new ObjectMapper();
        String json = objectMapper.writeValueAsString(changeTicketDto);
        System.out.println(json);
    }

}

此方法返回一个简单的 JSON 字符串,如下所示:

This method returned a simple JSON string that looked like this:

{
  "itemStatus": "OPEN",
  "createdAt": 1607031646362,
  "updatedAt": 1607031646362,
  "closedAt": 1607031646361,
  "incidentSolver": {
    "incidentId": null,
    "userName": "DUDE"
  },
  "user": {
    "userId": null,
    "userType": "USER",
    "userName": "USERNAME"
  },
  "changeId": "StringID",
  "changeType": "INSTALLATION_OF_OS",
  "description": "SOME TEXT"
}

所以我创建了另一个到同一个 URL 的 POST 请求并且成功了!!!所以现在我知道,如果我将创建一个与我的对象(及其父超类)不对应的错误 JSON,我将收到此类错误.非常感谢

So I have created another POST request to the same URL and it worked!!! So now I know that if I will create a bad JSON that is not corresponding to my objectt(and its parent super class) I will get this kind of error. Thanks a lot

这篇关于保存结构化 JSON 对象的错误请求的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆