Spring Boot接口报400错误:无法反序列化java.lang.Long类型值
解决POST接口/shop/order的400错误及库存扣减逻辑问题
一、400 Bad Request错误的根因与修复
控制台抛出的JSON parse error: Cannot deserialize value of type java.lang.Long from Object value明确指向:请求的JSON格式不匹配Controller接收的Map<String, Long>类型,某个值是对象结构而非预期的Long数值。
修复步骤:
修正请求体格式
确保Postman发送的JSON是componentId为键、购买数量(Long类型)为值的结构,示例:{ "COMP-001": 2, "COMP-002": 1 }禁止发送类似
{"COMP-001": {"count": 2}}这种值为嵌套对象的格式。检查请求头配置
确认Postman的Content-Type请求头设置为application/json,否则Spring无法正确解析JSON请求体。
二、Service层逻辑错误修复
当前Service代码存在两个致命问题:
- 把
List<PartDetails>强制转换为单个PartDetails对象,会直接抛出ClassCastException; - 注释掉了零件不存在的异常处理,若传入无效
componentId,后续代码会触发空指针或类型转换错误。
修复后的Service代码:
@Transactional public void placeOrder(Map<String, Long> orderDetails) { for (Map.Entry<String, Long> entry : orderDetails.entrySet()) { String componentId = entry.getKey(); Long requestedUnits = entry.getValue(); // 获取对应零件详情,不存在则抛出异常 PartDetails partStock = partRepository.findByComponentId(componentId) .stream() .findFirst() .orElseThrow(() -> new RuntimeException("Part stock not found with component ID: " + componentId)); Long currentUnits = partStock.getUnitInStock(); if (currentUnits < requestedUnits) { throw new RuntimeException("Insufficient units in stock for component ID: " + componentId); } partStock.setUnitInStock(currentUnits - requestedUnits); partRepository.save(partStock); } }
三、Repository层优化
修正主键泛型类型
PartDetails的主键id是Long类型,但当前Repository泛型写的是CrudRepository<PartDetails, String>,会导致主键操作时类型不匹配。修正为:public interface PartRepository extends CrudRepository<PartDetails, Long> { // 保留原有查询方法 @Query("SELECT p FROM PartDetails p WHERE p.carModelId = :carModelId") List<PartDetails> findByCarModelId(String carModelId); @Query("SELECT p FROM PartDetails p WHERE p.componentId = :componentId") List<PartDetails> findByComponentId(String componentId); }优化查询方法语义
如果componentId是唯一字段(每个ID对应一个零件),建议将findByComponentId改为返回Optional<PartDetails>,更符合业务逻辑:@Query("SELECT p FROM PartDetails p WHERE p.componentId = :componentId") Optional<PartDetails> findByComponentId(String componentId);此时Service层可简化为:
PartDetails partStock = partRepository.findByComponentId(componentId) .orElseThrow(() -> new RuntimeException("Part stock not found with component ID: " + componentId));
四、额外优化建议
- 精细化异常处理:Controller当前捕获所有Exception返回500,建议区分异常类型返回对应状态码,比如零件不存在返回404、库存不足返回400,前端能更精准处理错误;
- 使用DTO封装请求:创建
OrderRequest类代替Map<String, Long>,提升代码可读性和可维护性,示例:
然后Controller参数改为public class OrderRequest { private Map<String, Long> components; // 生成getter、setter }@RequestBody OrderRequest orderRequest。
内容的提问来源于stack exchange,提问作者Vishesh Dab
相关产品推荐
相关产品推荐

