Java:SpringBoot返回json数据时间格式、命名风格、忽略字段返回

简介: Java:SpringBoot返回json数据时间格式、命名风格、忽略字段返回

SpringBoot返回json数据是很常见的需求,我们可以通过配置来控制实体对象的输出形式

目录

版本依赖

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.7.7</version>
    <relativePath/> <!-- lookup parent from repository -->
</parent>

通过一个简单的SpringBoot项目测试json数据返回格式

对象实体

package com.example.demo.dto;
import lombok.Data;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.Date;
@Data
public class User {
    private String name;
    private Integer age;
    private String password;
    private Date birthday;
    private LocalDateTime localDateTime;
    private LocalDate localDate;
    private LocalTime localTime;
    private LocalDateTime localDateTimeFormat;
}

控制器

package com.example.demo.controller;
import com.example.demo.dto.User;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.Date;
@RestController
public class UserController {
    @GetMapping("/user")
    @ResponseBody
    public User getUser(){
        User user = new User();
        user.setAge(20);
        user.setName("tom");
        user.setPassword("123456");
        user.setBirthday(new Date());
        user.setLocalDateTime(LocalDateTime.now());
        user.setLocalDate(LocalDate.now());
        user.setLocalTime(LocalTime.now());
        user.setLocalDateTimeFormat(LocalDateTime.now());
        return user;
    }
}

默认返回

没有任何配置,直接输出对象,可以得到一个如下的json数据(前端看了想打人)

{
    "name":"tom",
    "age":20,
    "password":"123456",
    "birthday":1677250587064,
    "localDateTime":[ 2023, 2, 24, 22, 56, 27, 64000000],
    "localDate":[ 2023, 2, 24],
    "localTime":[ 22, 56, 27, 64000000],
    "localDateTimeFormat":[ 2023, 2, 24, 22, 56, 27, 64000000]
}

或者(测试几次发现日期格式输出竟然不固定)

{
    "name": "tom",
    "age": 20,
    "password": "123456",
    "birthday": "2023-02-24T23:24:08.956+00:00",
    "localDateTime": "2023-02-25T07:24:08.956",
    "localDate": "2023-02-25",
    "localTime": "07:24:08.956",
    "localDateTimeFormat": "2023-02-25T07:24:08.956"
}

默认返回数据有几个问题:

  1. 密码字段password不需要返回
  2. 时间格式Date 返回的是13位时间戳
  3. 时间格式LocalDateTimeLocalDateLocalTime返回的是数组格式
  4. 字段名是小驼峰个格式,大部分情况需要返回蛇形的下划线小写格式

通过配置格式化

添加配置 application.yml

spring:
  jackson:
    date-format: yyyy-MM-dd HH:mm:ss
    time-zone: GMT+8

返回数据

{
    "name": "tom",
    "age": 20,
    "password": "123456",
    "birthday": "2023-02-25 07:25:56",
    "localDateTime": "2023-02-25T07:25:56.509",
    "localDate": "2023-02-25",
    "localTime": "07:25:56.51",
    "localDateTimeFormat": "2023-02-25T07:25:56.51"
}

可以看到,只有Date类型的birthday参数生效了

通过注解实现属性设置

通过几个注解,实现实体对象转为json的属性设置

注解 作用
@JsonIgnoreProperties 批量设置转 JSON 时忽略的属性
@JsonIgnore 转 JSON 时忽略当前属性
@JsonProperty 修改转换后的 JSON 的属性名
@JsonFormat 转 JSON 时格式化属性的值

返回对象实体

package com.example.demo.dto;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.Date;
@Data
public class User {
    private String name;
    private Integer age;
    // 忽略属性
    @JsonIgnore
    private String password;
    // 修改属性名
    @JsonProperty("birthDay")
    private Date birthday;
    private LocalDateTime localDateTime;
    private LocalDate localDate;
    private LocalTime localTime;
    // 格式化
    @JsonFormat(pattern = "yyyy年MM月dd日")
    private LocalDateTime localDateTimeFormat;
}

返回结果

{
    "name": "tom",
    "age": 20,
    "localDateTime": "2023-02-25T07:32:57.637",
    "localDate": "2023-02-25",
    "localTime": "07:32:57.637",
    "localDateTimeFormat": "2023年02月25日",
    "birthDay": "2023-02-25 07:32:57"
}

通过以上配置,我们实现了

  1. 不返回密码字段password
  2. 自定义了字段localDateTimeFormat的时间格式
  3. 自定义了字段birthday的命名风格改为了小驼峰形式birthDay

目前为止,localDateTimelocalTime还没有处理到

全局配置

继承WebMvcConfigurationSupport类,覆写方法

protected void extendMessageConverters(List<HttpMessageConverter<?>> converters){}

WebMvcConfig

package com.example.demo.config;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
import java.util.List;
@Configuration
@Slf4j
public class WebMvcConfig extends WebMvcConfigurationSupport {
    /**
     * 扩展消息转换器
     *
     * @param converters
     */
    @Override
    protected void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
        // 创建消息转换器对象
        MappingJackson2HttpMessageConverter messageConverter = new MappingJackson2HttpMessageConverter();
        // 设置对象转换器
        messageConverter.setObjectMapper(new JacksonObjectMapper());
        // 添加到mvc框架消息转换器中,优先使用自定义转换器
        converters.add(0, messageConverter);
    }
}

JacksonObjectMapper

package com.example.demo.config;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategies;
import com.fasterxml.jackson.databind.deser.std.DateDeserializers;
import com.fasterxml.jackson.databind.ser.std.DateSerializer;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import static com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES;
/**
 * 对象映射器:基于jackson将Java对象转为json,或者将json转为Java对象
 * 将JSON解析为Java对象的过程称为 [从JSON反序列化Java对象]
 * 从Java对象生成JSON的过程称为 [序列化Java对象到JSON]
 */
public class JacksonObjectMapper extends ObjectMapper {
    private static final String DEFAULT_DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
    private static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd";
    private static final String DEFAULT_TIME_FORMAT = "HH:mm:ss";
    public JacksonObjectMapper() {
        super();
        // 收到未知属性时不报异常
        this.configure(FAIL_ON_UNKNOWN_PROPERTIES, false);
        // 统一返回数据的输出风格 转为蛇形命名法
        this.setPropertyNamingStrategy(new PropertyNamingStrategies.SnakeCaseStrategy());
        // 反序列化时,属性不存在的兼容处理
        this.getDeserializationConfig()
                .withoutFeatures(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
        // 格式化时间
        JavaTimeModule module = new JavaTimeModule();
        module.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT)))
                .addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT)))
                .addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT)))
                .addDeserializer(Date.class, new DateDeserializers.DateDeserializer())
                // .addSerializer(BigInteger.class, ToStringSerializer.instance)
                // .addSerializer(Long.class, ToStringSerializer.instance)
                .addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT)))
                .addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT)))
                .addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT)))
                .addSerializer(Date.class, new DateSerializer(false, new SimpleDateFormat(DEFAULT_DATE_TIME_FORMAT)))
                ;
        // 注册功能模块 添加自定义序列化器和反序列化器
        this.registerModule(module);
    }
}

最终效果

{
    "name": "tom",
    "age": 20,
    "local_date_time": "2023-02-25 07:56:22",
    "local_date": "2023-02-25",
    "local_time": "07:56:22",
    "local_date_time_format": "2023年02月25日",
    "birthDay": "2023-02-25 07:56:22"
}

至此,我们解决了一开始的几个格式问题

完整代码: https://mouday.github.io/spring-boot-demo/#/SpringBoot-JSON/README

参考


相关文章
|
1月前
|
JSON 前端开发 搜索推荐
关于商品详情 API 接口 JSON 格式返回数据解析的示例
本文介绍商品详情API接口返回的JSON数据解析。最外层为`product`对象,包含商品基本信息(如id、name、price)、分类信息(category)、图片(images)、属性(attributes)、用户评价(reviews)、库存(stock)和卖家信息(seller)。每个字段详细描述了商品的不同方面,帮助开发者准确提取和展示数据。具体结构和字段含义需结合实际业务需求和API文档理解。
|
28天前
|
JSON 缓存 API
解析电商商品详情API接口系列,json数据示例参考
电商商品详情API接口是电商平台的重要组成部分,提供了商品的详细信息,支持用户进行商品浏览和购买决策。通过合理的API设计和优化,可以提升系统性能和用户体验。希望本文的解析和示例能够为开发者提供参考,帮助构建高效、可靠的电商系统。
39 12
|
24天前
|
JavaScript Java 测试技术
基于Java+SpringBoot+Vue实现的车辆充电桩系统设计与实现(系统源码+文档+部署讲解等)
面向大学生毕业选题、开题、任务书、程序设计开发、论文辅导提供一站式服务。主要服务:程序设计开发、代码修改、成品部署、支持定制、论文辅导,助力毕设!
55 6
|
28天前
|
Java 应用服务中间件 API
【潜意识Java】javaee中的SpringBoot在Java 开发中的应用与详细分析
本文介绍了 Spring Boot 的核心概念和使用场景,并通过一个实战项目演示了如何构建一个简单的 RESTful API。
38 5
|
28天前
|
前端开发 Java 数据库连接
Java后端开发-使用springboot进行Mybatis连接数据库步骤
本文介绍了使用Java和IDEA进行数据库操作的详细步骤,涵盖从数据库准备到测试类编写及运行的全过程。主要内容包括: 1. **数据库准备**:创建数据库和表。 2. **查询数据库**:验证数据库是否可用。 3. **IDEA代码配置**:构建实体类并配置数据库连接。 4. **测试类编写**:编写并运行测试类以确保一切正常。
52 2
|
28天前
|
监控 Java API
【潜意识Java】使用SpringBoot构建高效的RESTfulAPI
本文介绍了使用Spring Boot构建RESTful API的完整流程,涵盖从项目创建到API测试的各个步骤。
47 1
|
设计模式 Java 关系型数据库
JAVA命名方式
JAVA命名方式
|
2天前
|
Java 程序员 开发者
Java社招面试题:一个线程运行时发生异常会怎样?
大家好,我是小米。今天分享一个经典的 Java 面试题:线程运行时发生异常,程序会怎样处理?此问题考察 Java 线程和异常处理机制的理解。线程发生异常,默认会导致线程终止,但可以通过 try-catch 捕获并处理,避免影响其他线程。未捕获的异常可通过 Thread.UncaughtExceptionHandler 处理。线程池中的异常会被自动处理,不影响任务执行。希望这篇文章能帮助你深入理解 Java 线程异常处理机制,为面试做好准备。如果你觉得有帮助,欢迎收藏、转发!
35 14
|
5天前
|
安全 Java 程序员
Java 面试必问!线程构造方法和静态块的执行线程到底是谁?
大家好,我是小米。今天聊聊Java多线程面试题:线程类的构造方法和静态块是由哪个线程调用的?构造方法由创建线程实例的主线程调用,静态块在类加载时由主线程调用。理解这些细节有助于掌握Java多线程机制。下期再见! 简介: 本文通过一个常见的Java多线程面试题,详细讲解了线程类的构造方法和静态块是由哪个线程调用的。构造方法由创建线程实例的主线程调用,静态块在类加载时由主线程调用。理解这些细节对掌握Java多线程编程至关重要。
34 13
|
6天前
|
安全 Java 开发者
【JAVA】封装多线程原理
Java 中的多线程封装旨在简化使用、提高安全性和增强可维护性。通过抽象和隐藏底层细节,提供简洁接口。常见封装方式包括基于 Runnable 和 Callable 接口的任务封装,以及线程池的封装。Runnable 适用于无返回值任务,Callable 支持有返回值任务。线程池(如 ExecutorService)则用于管理和复用线程,减少性能开销。示例代码展示了如何实现这些封装,使多线程编程更加高效和安全。