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

聊聊springboot项目中使用jackson的一些小技巧

ruisui883个月前 (02-04)技术分析15

前言

在我们前后端联调时,很经常以json作为数据的交互格式,今天我们就来聊聊在开发springboot项目中,使用jackson进行数据渲染一些小技巧

场景一:枚举-JSON互转

在日常开发中我们为了避免过多的魔法值,使用枚举类来封装一些静态的状态代码。
但是在将这些枚举的意思正确而全面的返回给前端却并不是那么顺利,比如有个状态枚举类

public enum StatusEnums {

    NORMAL(1,"正常"),

    LOCK(2,"锁定"),

    DELETE(3,"删除");

    private Integer code;

    private String desc;

    StatusEnums(Integer code, String desc) {
        this.code = code;
        this.desc = desc;
    }


    public Integer getCode() {
        return code;
    }

    public void setCode(Integer code) {
        this.code = code;
    }

    public String getDesc() {
        return desc;
    }

    public void setDesc(String desc) {
        this.desc = desc;
    }



}

如果我们直接使用Jackson对枚举进行序列化,将只能简单的输出枚举的String名称

new ObjectMapper().writeValueAsString(StatusEnums.NORMAL);

输出结果为枚举名称:

NORMAL

而我们希望将枚举转为JSON对象,像下面这样:

{"code":200,"desc":"正常"}

那如何达到以上效果

方法一:使用@JsonValue 注解

我们通过@JsonValue注解,来控制枚举序列化结果

    @JsonValue
    public Integer getCode() {
        return code;
    }

比如StatusEnums.NORMAL最后最终序列化的值:

1

同样我们也可以通过@JsonValue注解进行反序列化,最终1反序列化的值为

NORMAL

方法二:通过自定义序列化/反序列器

a、 自定义序列化器以及反序列化器

public class StatusEnumsJsonSerializer extends JsonSerializer {

    @Override
    public void serialize(StatusEnums value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
        gen.writeString(value.getCode().toString());
    }
}
public class StatusEnumsJsonDerializer extends JsonDeserializer {


    @Override
    public StatusEnums deserialize(JsonParser p, DeserializationContext ctx) throws IOException, JsonProcessingException {
         if(p.getText() != null){
             return StatusEnums.getByCode(Integer.valueOf(p.getText()));
         }
        return null;
    }
}

b、在枚举类上加上自定义序列化、反序列化注解

 @JsonSerialize(using = StatusEnumsJsonSerializer.class)
 @JsonDeserialize(using =  StatusEnumsJsonDerializer.class)
    private StatusEnums status;

除了以上方法,还可以通过@JsonCreator来达到上述效果,因为demo没实现,这边就不演示了

场景二:规避前端JavaScript接收后端Long属性值,精度丢失问题

示例演示

后端示例代码

  @GetMapping("get")
    @ResponseBody
    public User getUser(){
       return User.builder().name("张三")
                .password("123456")
                .status(StatusEnums.NORMAL)
                .id(987654321123456789L).build();
    }

前端示例代码


浏览器访问结果


可以发现精度丢失了

方法一:通过@JsonSerialize注解,将long序列化为字符串

注: 直接通过jackson自带的序列化器

示例

@JsonSerialize(using = ToStringSerializer.class)
    private Long id;

加上该注解后,通过浏览器查看效果

可以发现精度没有丢失了

场景三:数据脱敏

敏感数据脱敏展示,应该是挺通用需求,我们可以通过自定义序列化器实现这一效果

1、自定义脱敏序列化器

RequiredArgsConstructor
public class SensitiveJsonSerializer extends JsonSerializer implements ContextualSerializer {

    private final DesensitizedUtil.DesensitizedType desensitizedType;

    public SensitiveJsonSerializer(){
        this.desensitizedType = DesensitizedUtil.DesensitizedType.CLEAR_TO_EMPTY;
    }



    @Override
    public void serialize(String value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
            gen.writeString(DesensitizedUtil.desensitized(value,desensitizedType));
    }

    @Override
    public JsonSerializer createContextual(SerializerProvider prov, BeanProperty property) throws JsonMappingException {
        Sensitive sensitive = property.getAnnotation(Sensitive.class);
        if (sensitive != null){
            return new SensitiveJsonSerializer(sensitive.type());
        }

        return prov.findValueSerializer(property.getType(), property);
    }
}

2、自定义脱敏注解

@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@JacksonAnnotationsInside
@JsonSerialize(using = SensitiveJsonSerializer.class)
public @interface Sensitive {

    DesensitizedUtil.DesensitizedType type();
}

3、在需要脱敏的字段上,加上脱敏注解

@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class User {

    @JsonSerialize(using = ToStringSerializer.class)
    private Long id;

    @Sensitive(type = DesensitizedUtil.DesensitizedType.CHINESE_NAME)
    private String name;

    @Sensitive(type = DesensitizedUtil.DesensitizedType.PASSWORD)
    private String password;
    }

a、 未加脱敏注解时,通过浏览器访问


发现没有脱敏,现在我们针对名字和密码进行脱敏

b、 名字和密码加上脱敏注解

    @Sensitive(type = DesensitizedUtil.DesensitizedType.CHINESE_NAME)
    private String name;

    @Sensitive(type = DesensitizedUtil.DesensitizedType.PASSWORD)
    private String password;

观察浏览器

总结

本文介绍枚举和json转换、long精度问题、数据脱敏三种我们日常开发比较常用的场景,但不知道大家发现没,这三种场景本质上都是通过json的序列化和反序列化实现,因此我们可以通过定制全局json序列化、反序列化器来实现。核心代码如下

    @Bean
    @ConditionalOnMissingBean
    public Jackson2ObjectMapperBuilderCustomizer customJackson2ObjectMapperBuilderCustomizer(){
        return jacksonObjectMapperBuilder -> jacksonObjectMapperBuilder
                .serializerByType(Long.class,ToStringSerializer.instance)
                .serializerByType(StatusEnums.class,new StatusEnumsJsonSerializer())
                .deserializerByType(StatusEnums.class,new StatusEnumsJsonDerializer());

    }

demo链接

https://github.com/lyb-geek/springboot-learning/tree/master/springboot-json-render

扫描二维码推送至手机访问。

版权声明:本文由ruisui88发布,如需转载请注明出处。

本文链接:http://www.ruisui88.com/post/1659.html

标签: objectmapper
分享给朋友:

“聊聊springboot项目中使用jackson的一些小技巧” 的相关文章

快速上手React

web前端三大主流框架1、Angular大家眼里比较牛的框架,甚至有人说三大框架中只有它能称得上一个完整的框架,因为它包含的东西比较完善,包含模板,数据双向绑定,路由,模块化,服务,过滤器,依赖注入等所有功能。对于刚开始学习使用框架的小伙伴们,可以推荐这个框架,学会之后简直能颠覆之前你对前端开发的认...

GitLab-创建分支

描述分支是独立的生产线,是开发过程的一部分。分支的创建涉及以下步骤。创建一个分支步骤1-登录您的GitLab帐户,然后转到“ 项目”部分下的项目。步骤2-要创建分支,请单击“ 存储库”部分下的“ 分支”选项,然后单击“ 新建分支”按钮。步骤3-在“ 新建分支”屏幕中,输入分支的名称,然后单击“ 创建...

快速掌握 Git:程序员必会的版本控制技巧

在现代软件开发中,版本控制系统(VCS)是开发人员不可或缺的工具。无论是个人项目,还是多人协作的团队开发,良好的版本控制都能确保代码管理的高效性与稳定性。而在版本控制系统中,Git 凭借其分布式、灵活性和高效性,成为了最流行的工具之一。几乎所有的开发团队都在使用 Git 来管理代码版本、协作开发和追...

编码 10000 个小时后,开发者悟了:“不要急于发布!”

【CSDN 编者按】在软件开发的道路上,时间是最好的老师。根据“一万小时定律”,要成为某个领域的专家,通常需要大约一万小时的刻意练习。本文作者身为一名程序员,也经历了一万小时的编程,最终悟出了一个道理:慢即是快,重视架构设计和代码质量,确保每一行代码都经得起时间的考验。作者 | Sotiris Ko...

15款测试html5响应式的在线工具

手机、平板灯手持设备的增多,网站要顺应变化,就必须要做响应式开发,响应式网站最大的特点在于可以在不同设备下呈现不同的布局,是基于html5+css3技术,目前越来越多的网站开始采用了响应式设计,而下面15款工具可以方便测试你的html5响应式效果。Responsinatorhttp://www.re...

佳能 EOS R8 深度评测

佳能 EOS R8 的定位是入门级全画幅无反光镜可换镜头相机。尽管在产品阵容中处于这一位置,R8 仍然是一个强大的相机,配备了先进的 R6 II 同款成像传感器、快速处理器和令人难以置信的自动对焦系统,体积小、重量轻、价格低。这款相机是发烧友、旅行者、家庭以及任何想要全画幅传感器相机的人的绝佳选择。...