如何在spring-servlet.xml配置Jackson ObjectMapper实现@RequestBody转换
我来一步步帮你解决这个问题,咱们从错误根源到配置细节逐个梳理:
一、先搞定HTTP请求头解析错误
你遇到的"Error parsing HTTP request header..."错误,大概率是前端AJAX请求的姿势不对——把JSON数据直接拼到URL里了,或者没正确设置请求头。正确的AJAX应该把JSON放在请求体里,并且指定contentType为application/json,示例代码如下:
var form = { "order":"12r34e56e", "state":"open", "date1":"2024-01-01", "date2":"2024-01-31", "address":"北京市某某区" }; $.ajax({ url: "/order/get-unclosed-packages", // 你的Controller接口地址 type: "POST", contentType: "application/json; charset=utf-8", // 必须指定这个,告诉后端是JSON格式 data: JSON.stringify(form), // 把JS对象转成JSON字符串 dataType: "json", success: function(response) { // 把返回的数据传给DataTable渲染 $('#package-table').DataTable({ data: response, columns: [ { data: "packageId" }, { data: "packageState" }, { data: "createTime" }, // 其他你需要展示的字段 ] }); }, error: function(xhr, status, err) { console.log("请求失败:", err); } });
二、Controller正确配置:用@RequestBody接收JSON参数
首先要纠正一个误区:@RequestBody不能直接解析成PreparedStatement对象,它的作用是把请求体的JSON解析成你自定义的Java实体类(DTO)。因为你参数很多,自定义DTO是最清晰的方式。
1. 创建查询参数DTO
public class OrderQueryDTO { private String order; private String state; private String date1; private String date2; private String address; // 必须要有无参构造函数(Jackson默认用它实例化对象) public OrderQueryDTO() {} // 生成所有字段的getter和setter,或者用Lombok的@Data注解简化 public String getOrder() { return order; } public void setOrder(String order) { this.order = order; } // 其他字段的getter/setter同理 }
2. 编写Controller方法
@Controller @RequestMapping("/order") public class OrderPackageController { // 注入你的WebService客户端(假设已经封装好调用逻辑) @Autowired private PackageWebServiceClient packageWebService; @PostMapping(value = "/get-unclosed-packages", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) @ResponseBody public List<PackageVO> getUnclosedPackages(@RequestBody OrderQueryDTO queryDTO) { // 1. 用DTO里的参数调用WebService获取包裹列表 List<WsPackage> wsPackageList = packageWebService.getUnclosedPackages( queryDTO.getOrder(), queryDTO.getState(), queryDTO.getDate1(), queryDTO.getDate2(), queryDTO.getAddress() ); // 2. 把WebService返回的实体转换成前端DataTable需要的VO对象 List<PackageVO> packageVOList = convertToVO(wsPackageList); // 3. 返回JSON格式的数据,Spring会自动通过Jackson序列化 return packageVOList; } // 示例:WebService实体转前端VO private List<PackageVO> convertToVO(List<WsPackage> wsPackageList) { List<PackageVO> result = new ArrayList<>(); for (WsPackage wsPkg : wsPackageList) { PackageVO vo = new PackageVO(); vo.setPackageId(wsPkg.getPackageId()); vo.setPackageState(wsPkg.getStatus()); vo.setCreateTime(wsPkg.getCreateDate()); // 其他字段映射 result.add(vo); } return result; } }
三、spring-servlet.xml中配置Jackson的ObjectMapper
如果你需要自定义JSON序列化/反序列化规则(比如日期格式、忽略空字段等),可以在spring配置文件里手动配置Jackson的消息转换器:
<!-- 配置RequestMappingHandlerAdapter,指定自定义的Jackson转换器 --> <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"> <property name="messageConverters"> <list> <ref bean="jackson2HttpMessageConverter"/> </list> </property> </bean> <!-- 自定义Jackson消息转换器 --> <bean id="jackson2HttpMessageConverter" class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"> <property name="objectMapper"> <bean class="com.fasterxml.jackson.databind.ObjectMapper"> <!-- 配置日期格式化规则,适配前端传的date1/date2 --> <property name="dateFormat"> <bean class="java.text.SimpleDateFormat"> <constructor-arg value="yyyy-MM-dd"/> </bean> </property> <!-- 只序列化非空字段,减少返回数据体积 --> <property name="serializationInclusion" value="NON_NULL"/> <!-- 关闭日期转时间戳,返回格式化后的字符串 --> <property name="disable" value="WRITE_DATES_AS_TIMESTAMPS"/> </bean> </property> <!-- 指定支持的媒体类型 --> <property name="supportedMediaTypes"> <list> <value>application/json;charset=UTF-8</value> </list> </property> </bean>
四、常见问题排查
- Jackson依赖是否完整:确保pom.xml里包含了
jackson-databind、jackson-core、jackson-annotations三个核心依赖,版本要和你的Spring版本兼容(比如Spring 5.x对应Jackson 2.9+)。 - DTO字段名匹配:如果前端传的key和DTO字段名不一致,可以用
@JsonProperty注解指定,比如@JsonProperty("order") private String orderNo;。 - 是否开启了MVC注解驱动:如果你的spring-servlet.xml里有
<mvc:annotation-driven/>,它会自动注册Jackson转换器,但如果手动配置了上面的转换器,需要注意避免冲突。
内容的提问来源于stack exchange,提问作者fuvu




