当前位置:首页 > 技术 > 正文内容

Spring MVC 整合 Jackson 实现 JSON 转换

访客 技术 2026年5月25日 3
在 Spring MVC 架构中,Jackson 承担着 Java 对象与 JSON 数据之间双向转换的关键角色。框架借助 HttpMessageConverter 机制完成这一集成,其具体实现由 MappingJackson2HttpMessageConverter 负责。

核心机制解析

组件协作关系

整个转换体系涉及三个层级:

  • HttpMessageConverter:Spring 定义的消息转换契约,用于桥接 HTTP 报文体与 Java 类型
  • MappingJackson2HttpMessageConverter:基于 Jackson 的具体实现,封装了 ObjectMapper 的调用逻辑
  • ObjectMapper:Jackson 库的心脏,执行真正的编解码运算

响应阶段的数据流转

当接口需要返回 JSON 时,处理链路如下:

  1. 处理器方法返回 POJO 实例
  2. Spring 依据请求头 Accept: application/json 筛选匹配的转换器
  3. MappingJackson2HttpMessageConverter 被选中并触发 write() 操作
  4. 内部委托 ObjectMapper.writeValueAsBytes() 完成字节流输出

请求阶段的解析过程

接收 JSON 载荷时,@RequestBody 标注的参数会驱动 ObjectMapper.readValue() 执行反序列化,将字节数据还原为对象实例。

工程依赖引入

通过 Maven 引入核心库:

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.15.3</version>
</dependency>

采用 Spring Boot 时,spring-boot-starter-web 启动器已内嵌相关依赖,无需额外声明。

实践代码演示

服务端接口定义

@RestController
@RequestMapping("/api/customers")
public class CustomerController {

    @GetMapping("/{customerId}")
    public Customer fetchById(@PathVariable Long customerId) {
        return new Customer(customerId, "李明", 28);
    }

    @PostMapping
    public ResponseEntity<String> register(@RequestBody Customer payload) {
        // 执行业务持久化
        return ResponseEntity.status(HttpStatus.CREATED)
                   .body("注册完成: " + payload.getNickname());
    }
}

领域模型设计

public class Customer {
    private Long uid;
    private String nickname;
    private Integer yearsOld;

    public Customer(Long uid, String nickname, Integer yearsOld) {
        this.uid = uid;
        this.nickname = nickname;
        this.yearsOld = yearsOld;
    }

    // 访问器方法省略...
}

Jackson 的默认策略会采集所有公有属性以及具备 getter 方法的私有字段。

注解精细化操控

注解功能说明
@JsonIgnore排除字段不参与任何方向的转换
@JsonAlias指定反序列化时的兼容字段名
@JsonProperty("new_key")重命名输出键
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd")控制时间型数据的输出格式
@JsonInclude(JsonInclude.Include.NON_ABSENT)按条件忽略字段

标注示例

public class Customer {
    
    private Long uid;
    
    @JsonProperty("display_name")
    private String nickname;
    
    @JsonFormat(pattern = "yyyy-MM-dd", timezone = "Asia/Shanghai")
    private LocalDate birthDay;
    
    @JsonIgnore
    private String credential;
    
    @JsonInclude(JsonInclude.Include.NON_DEFAULT)
    private Integer score = 0;
    
    // ...
}

全局行为定制方案

配置属性方式(YAML)

spring:
  jackson:
    default-property-inclusion: non_null
    serialization:
      write-dates-as-timestamps: false
      fail-on-empty-beans: false
    deserialization:
      fail-on-unknown-properties: false
    date-format: yyyy-MM-dd HH:mm:ss
    time-zone: Asia/Shanghai

编程式配置

@Configuration
public class ObjectMapperCustomization {

    @Bean
    public ObjectMapper objectMapper() {
        ObjectMapper om = new ObjectMapper();
        
        om.setSerializationInclusion(JsonInclude.Include.NON_NULL);
        om.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
        om.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
        om.enable(SerializationFeature.INDENT_OUTPUT);
        
        // 扩展 JDK8 日期时间支持
        om.registerModule(new JavaTimeModule());
        
        return om;
    }
}

深度定制转换器

在需要完全接管 JSON 处理逻辑的场景下,可手工装配消息转换器:

@Configuration
public class MessageConversionConfiguration {

    @Bean
    public MappingJackson2HttpMessageConverter tailoredConverter() {
        MappingJackson2HttpMessageConverter converter = 
            new MappingJackson2HttpMessageConverter();
        
        converter.setObjectMapper(tailoredMapper());
        
        // 限定支持的媒体类型与字符集
        List<MediaType> supported = Arrays.asList(
            MediaType.APPLICATION_JSON,
            new MediaType("application", "*+json")
        );
        converter.setSupportedMediaTypes(supported);
        
        return converter;
    }

    private ObjectMapper tailoredMapper() {
        ObjectMapper om = new ObjectMapper();
        // 注入特定模块或特性...
        return om;
    }
}

典型问题排查

现象根因与对策
LocalDateTime 输出为数字数组关闭 WRITE_DATES_AS_TIMESTAMPS 并确保 JavaTimeModule 已加载
空值字段残留于 JSON全局设置 NON_NULL 或在类/字段级应用 @JsonInclude
反序列化抛出异常确认目标类具备无参构造器,或采用 @JsonCreator 标注工厂方法
未知字段导致失败禁用 DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES

相关文章

Linux crontab 详解

1) crontab 是什么cron 是 Linux 的定时任务守护进程;crontab 是用来编辑/查看“按时间周期执行命令”的表(cron table)。常见两类:用户 crontab:每个用户一份(crontab -e 编辑)系统级 crontab / cron.d:可指定执行用户(/etc/crontab、/etc/cron.d/*)2) crontab 时间...

富文本里可以允许的 HTML 属性

一、所有标签默认允许的安全属性(极少)class        (可选)id           (通常建议禁用)title️ 注意:id 容易被滥用做锚点注入,很多系统直接禁用class 允许的话最好只允许固定前缀(如 editor-*)二、a 标签允许属性<a href="" t...

Mac 安装 Node.js 指南

方法一:通过官网安装包(最简单,适合初学者)如果你只是想快速安装并开始使用,这是最直接的方法。访问 Node.js 官网。页面会显示两个版本:LTS (Recommended For Most Users):长期支持版,最稳定。建议选这个。Current:最新特性版,包含最新功能但可能不够稳定。下载 .pkg 安装包并运行。按照安装向导点击“下一步”即可完成。方法二:使用 Homebrew 安装(...

Dom\HTML_NO_DEFAULT_NS 的副作用:自动加闭合标签

在使用Dom\HTMLDocument时,Dom\HTML_NO_DEFAULT_NS 将禁止在解析过程中设置元素的命名空间, 此设置是为了与DOMDocument向后兼容而存在的。当使用它时,已知的一个副作用就是:自动加闭合标签例如 </img> 为什么会这样?当你使用:Dom\HTML_NO_DEFAULT_NS文档会变成 无命名空间模式,此时内部更接近 XML...

Laravel 事件和监听器创建

在 Laravel 中,使用 Artisan 命令创建 Events(事件) 和 Listeners(监听器) 是非常高效的。你可以通过以下几种方式来实现:1. 手动创建单个 Event如果你只想创建一个事件类,可以使用 make:event 命令:Bashphp artisan make:event UserRegistered执行后,文件将生成在 app/Even...

自定义域名解析神器 dnsmasq

什么是 dnsmasq?dnsmasq 是一个轻量级、功能强大的网络服务工具,专为小型和中等规模网络设计。它是一个综合的网络基础设施解决方案[1]。dnsmasq 能做什么?功能说明应用场景DNS 转发与缓存将 DNS 查询转发到上游服务器(ISP、Google DNS 等),并在本地缓存结果加快 DNS 查询速度,减少外部 DNS 流量本地 DNS解析本地网络设备的主机名,无需编辑&n...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。