使用邮递员发布请求后,spring boot 服务器返回错误 400

Posted

技术标签:

【中文标题】使用邮递员发布请求后,spring boot 服务器返回错误 400【英文标题】:springboot server returns error 400 after post request using postman 【发布时间】:2021-12-22 08:19:36 【问题描述】:

每当我尝试通过邮递员发送此邮件时:


    "date": "2021-11-05 12:32:32",
    "start": "start",
    "destination": "destination",
    "provider": "provider",
    "driver":1,
    "vehicule":1

我收到错误 400,错误请求,我同时使用了 @restController 和 @requestBody 注释,同时还将内容类型设置为 json。

我在调试器上收到此错误:

2021-11-09 16:57:52.086  WARN 11748 --- [nio-8080-exec-1] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot deserialize value of type `java.util.Date` from String "2021-11-06 12:32:32.0": not a valid representation (error: Failed to parse Date value '2021-11-06 12:32:32.0': Cannot parse date "2021-11-06 12:32:32.0": while it seems to fit format 'yyyy-MM-dd'T'HH:mm:ss.SSSX', parsing fails (leniency? null)); nested exception is com.fasterxml.jackson.databind.exc.InvalidFormatException: Cannot deserialize value of type `java.util.Date` from String "2021-11-06 12:32:32.0": not a valid representation (error: Failed to parse Date value '2021-11-06 12:32:32.0': Cannot parse date "2021-11-06 12:32:32.0": while it seems to fit format 'yyyy-MM-dd'T'HH:mm:ss.SSSX', parsing fails (leniency? null))
 at [Source: (PushbackInputStream); line: 3, column: 17] (through reference chain: com.siam.HRAssistTool.Entity.Schedule["date"])]

我不明白我应该如何解决我认为与日期格式相关的问题

当我从 json 正文中删除时间并只留下日期时,我收到此错误:

2021-11-09 17:34:55.418  WARN 11748 --- [nio-8080-exec-4] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot construct instance of `com.siam.HRAssistTool.Entity.Vehicule` (although at least one Creator exists): no int/Int-argument constructor/factory method to deserialize from Number value (1); nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot construct instance of `com.siam.HRAssistTool.Entity.Vehicule` (although at least one Creator exists): no int/Int-argument constructor/factory method to deserialize from Number value (1)
 at [Source: (PushbackInputStream); line: 8, column: 20] (through reference chain: com.siam.HRAssistTool.Entity.Schedule["vehicule"])]

我的日程安排实体:

@Entity
public class Schedule implements Serializable 
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id ; 
    private Date date ; 
    private String Start; 
    private String destination;
    @OneToOne( fetch = FetchType.LAZY)
    private Staff driver; 
    @OneToOne(fetch = FetchType.LAZY)
    private Vehicule vehicule; 
    private String provider;
    //constructors, getters and setters 

我的控制器:

@RestController
public class ScheduleController 

    @Autowired
    ScheduleService scheduleService; 

    @PostMapping(value="/schedule/create")
    public @ResponseBody String createSchedule( @RequestBody Schedule schedule) 
        System.out.println(schedule.toString());

        return scheduleService.addSchedule(schedule);
        
    
//other crud operation

【问题讨论】:

请添加Controller 以及您的模型类,否则我们无能为力。谢谢! 【参考方案1】:

首先,将Date 替换为LocalDate,这是新Java Time API 的一部分。有了这个,您可以配置 Jackson 以轻松处理这种复杂类型的序列化和反序列化。添加以下依赖:

<dependency>
    <groupId>com.fasterxml.jackson.datatype</groupId>
    <artifactId>jackson-datatype-jsr310</artifactId>
    <version>2.11.0</version>
</dependency>

然后相应地配置 Jackson:

@Configuration
public class JacksonConfiguration 

    @Bean
    public ObjectMapper objectMapper() 
        ObjectMapper objectMapper = new ObjectMapper();
        JavaTimeModule javaTimeModule = new JavaTimeModule();
        objectMapper.registerModule(javaTimeModule);

    objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);

        return objectMapper;
    

那么,请避免在您的Controller 中使用实体作为响应或请求类型。相反,请使用 DTO,它是您的核心模型实体的特定表示。

public class ScheduleCreationDto 
    private LocalDate date; 
    private String Start; 
    private String destination;
    private Long driverId;      // I am guessing the ID is a Long
    private Long vehiculeId;    // I am guessing the ID is a Long
    private String provider;
    
    //constructors, getters and setters 

现在应该将其用作请求正文:

@RestController
public class ScheduleController 

    @Autowired
    ScheduleService scheduleService; 

    @PostMapping(value="/schedule/create")
    public @ResponseBody String createSchedule(@RequestBody ScheduleCreationDto scheduleCreationDto) 
        return scheduleService.addSchedule(schedule);
    
    
    //other crud operation

您还需要更改ScheduleService,以便它基于ScheduleCreationDto 创建一个Schedule。大多数属性需要简单的映射,但其他属性(driverIdvehiculeId)需要您使用提供的 ID 从数据库中实际获取这些实体。应该在您的ScheduleService 中完成类似以下的操作:

@Service
public class ScheduleService 

    @Autowired
    ScheduleRepository scheduleRepository; 

    @Autowired
    DriverRepository driverRepository; 

    @Autowired
    VehiculeRepository vehiculeRepository; 

    public String addSchedule(ScheduleCreationDto scheduleCreationDto) 
        Optional<Driver> driver = driverRepository.findById(scheduleCreationDto.getDriverId());
        Optional<Vehicule> vehicule = vehiculeRepository.findById(scheduleCreationDto.getVehiculeId());

        if (driver.isPresent() && vehicule.isPresent()) 
            Schedule schedule = new Schedule(scheduleCreationDto.getDate(), scheduleCreationDto.getStart(), 
                scheduleCreationDto.getDestination(), driver.get(), vehicule.get(), scheduleCreationDto.getProvider());
            scheduleRepository.save(schedule);    
        
    
        return // whatever String you want to return, you should actually return the created Schedule, but that is a different topic
    

    //other crud operation

【讨论】:

您认为有可能实施模型映射器来改善这一点吗? 类似于 mapstruct (mapstruct.org) 的东西?当然,但有一件事它不会为你做。从数据库中获取drivervehicule。我个人不太喜欢这些神奇的映射器,因为一旦你想做一些与标准不同的事情,它就会变得混乱。我更喜欢在代码中明确说明我需要的映射。但这只是我个人的口味。 感谢您进行了一些调整,这成功了,感谢您的帮助 太棒了!你改变了什么?这样我就可以更新我的答案并帮助可能遇到相同问题的其他人。谢谢! findById() 返回一个可选的,因此为了更好地处理这个问题,您必须在每个例外之后设置例外,我相信这就是我真正改变的全部。

以上是关于使用邮递员发布请求后,spring boot 服务器返回错误 400的主要内容,如果未能解决你的问题,请参考以下文章

在邮递员上发布请求但不在浏览器中(代码状态:415) - Spring Boot,thymeleaf

Spring Boot WebClient OAuth - 同时命中多个请求时超时

如何使用邮递员和 Spring Boot 发送 multipartFile 和 Json

Spring Boot 401 未经授权的邮递员

spring boot 应用程序只接受 6 个请求,为啥?

java - 如何从Java Spring Boot中的请求标头获取不记名令牌?