Jackson自定义序列化反序列化注解加解密字段详解

 更新时间:2023年11月06日 09:41:01   作者:LOOPY_Y  
这篇文章主要介绍了Jackson自定义序列化反序列化注解加解密字段详解,一些场景中,数据库字段用于存储json格式数据,处于安全的考虑,该json数据中,某些敏感信息字段需要做加密存储,例如身份证号、手机号等,需要的朋友可以参考下

1 问题场景

一些场景中,数据库字段用于存储json格式数据,处于安全的考虑,该json数据中,某些敏感信息字段需要做加密存储,例如身份证号、手机号等。如果将整个json数据进行加密处理,加密后的数据较大,只对需解密的字段进行加密处理更符合实际。

如何实现呢?

之前写过一篇脱敏注解,通过自定义序列化实现的,结合来看,其实可以复用之前的脱敏注解的模式,定义字段加解密注解,通过自定义序列化和反序列化实现。

2 代码实现

注解类

import com.test.jsonencrypt.EncryptJsonFiledDeSerializer;
import com.test.jsonencrypt.EncryptJsonFiledSerializer;
import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * <pre>
 * 加解密注解,标注在属性上
 * </pre>
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@JacksonAnnotationsInside
// 使用自定义的序列化实现
@JsonSerialize(using = EncryptJsonFiledSerializer.class)
// 使用自定义的序列化实现
@JsonDeserialize(using = EncryptJsonFiledDeSerializer.class)
public @interface EncryptJsonFiled {

}

自定义序列化实现类

import com.test.jsonencrypt.annotation.EncryptJsonFiled;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.BeanProperty;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.deser.ContextualDeserializer;
import com.test.util.EncryUtil;
import org.apache.commons.lang3.StringUtils;

import java.io.IOException;
import java.util.Objects;

/**
 * <pre>
 * 序列化注解自定义实现
 * JsonDeserializer<String>:指定String类型,deserialize()方法用于将修改后的数据载入
 * Jackson使用ContextualSerializer在序列化时获取字段注解的属性
 * </pre>
 */
public class EncryptJsonFiledDeSerializer extends JsonDeserializer<String> implements ContextualDeserializer {

    @Override
    public String deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
        String valueAsString = p.getValueAsString();
        // 数据不为空时解密数据
        if (StringUtils.isNotBlank(valueAsString)) {
            // EncryUtil为封装的加解密工具
            return EncryUtil.decrypt(valueAsString);
        }
        return valueAsString;
    }

    @Override
    public JsonDeserializer<?> createContextual(DeserializationContext ctxt, BeanProperty property) throws JsonMappingException {
        EncryptJsonFiled annotation = property.getAnnotation(EncryptJsonFiled.class);
        // 只针对String类型
        if (Objects.nonNull(annotation)&&Objects.equals(String.class, property.getType().getRawClass())) {
            return this;
        }
        return ctxt.findContextualValueDeserializer(property.getType(), property);
    }
}

自定义反序列化实现类

import com.test.jsonencrypt.annotation.EncryptJsonFiled;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.BeanProperty;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.ContextualSerializer;
import com.test.util.EncryUtil;
import org.apache.commons.lang3.StringUtils;

import java.io.IOException;
import java.util.Objects;

/**
 * <pre>
 * 序列化注解自定义实现
 * JsonSerializer<String>:指定String类型,serialize()方法用于将修改后的数据载入
 * Jackson使用ContextualSerializer在序列化时获取字段注解的属性
 * </pre>
 */
public class EncryptJsonFiledSerializer extends JsonSerializer<String> implements ContextualSerializer {

    @Override
    public void serialize(String value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
        // 数据不为空时加密数据
        if (StringUtils.isNotBlank(value)) {
            String encrypt = EncryUtil.encry(value);
            gen.writeString(encrypt);
            return;
        }
        gen.writeString(value);
    }

    @Override
    public JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty property) throws JsonMappingException {
        EncryptJsonFiled annotation = property.getAnnotation(EncryptJsonFiled.class);
        // 只针对String类型
        if (Objects.nonNull(annotation)&&Objects.equals(String.class, property.getType().getRawClass())) {
            return this;
        }
        return prov.findValueSerializer(property.getType(), property);
    }

}

3 测试

用于测试的简易实体类

@Data
@Accessors(chain = true)
public class User {

    private String name;
    
    private int age;
    
    @EncryptJsonFiled
    private String idCard;

}

测试类

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

/**
 * <pre>
 * 测试加解密注解
 * </pre>
 */
@RunWith(SpringRunner.class)
@SpringBootTest
public class TestEntry {

    @Test
    public void test() throws JsonProcessingException {
        User user = new User().setAge(11)
                .setName("小明")
                .setIdCard("13523451124");
        // 注意使用Jackson的json工具
        ObjectMapper objectMapper = new ObjectMapper();
        String json = objectMapper.writeValueAsString(user);
        System.out.println("序列化后的json数据:" + json);

        User user1 = objectMapper.readValue(json, User.class);
        System.out.println("反序列化后的解密数据:" + user1.getIdCard());
    }

}

测试结果:

序列化后的json数据:{"name":"小明","age":11,"idCard":"2f3d8f692eeaac2cbc60423ed99aed63"}
反序列化后的解密数据:13523451124

到此这篇关于Jackson自定义序列化反序列化注解加解密字段详解的文章就介绍到这了,更多相关Jackson自定义序列化反序列化注解内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • @valid 无法触发BindingResult的解决

    @valid 无法触发BindingResult的解决

    这篇文章主要介绍了@valid 无法触发BindingResult的解决方案,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-12-12
  • SpringBoot之使用Feign实现微服务间的交互

    SpringBoot之使用Feign实现微服务间的交互

    这篇文章主要介绍了SpringBoot中使用Feign实现微服务间的交互,对微服务这方面感兴趣的小伙伴可以参考阅读本文
    2023-03-03
  • IDEA集成Sonar的完整流程

    IDEA集成Sonar的完整流程

    这篇文章主要介绍了IDEA集成Sonar的完整流程,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-06-06
  • Java后端调用微信支付和支付宝支付的详细步骤

    Java后端调用微信支付和支付宝支付的详细步骤

    这篇文章主要介绍了Java后端如何调用微信支付和支付宝支付,涵盖了基本概念、配置步骤、代码示例以及注意事项,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2025-04-04
  • 浅谈将子类对象赋值给父类对象

    浅谈将子类对象赋值给父类对象

    浅谈将子类对象赋值给父类对象...
    2006-12-12
  • SpringBoot实现热部署的三种方式

    SpringBoot实现热部署的三种方式

    本文主要介绍了SpringBoot实现热部署的三种方式,主要包括配置pom.xml文件,使用插件的执行命令mvn spring-boot:run启动项,使用springloader本地启动修改jvm参数,使用devtools工具包,感兴趣的可以了解一下
    2023-12-12
  • 从JVM的内存管理角度分析Java的GC垃圾回收机制

    从JVM的内存管理角度分析Java的GC垃圾回收机制

    这篇文章主要介绍了从JVM的内存管理角度分析Java的GC垃圾回收机制,带有GC是Java语言的重要特性之一,需要的朋友可以参考下
    2015-11-11
  • java 读取网页内容的实例详解

    java 读取网页内容的实例详解

    这篇文章主要介绍了java 读取网页内容的实例详解的相关资料,希望通过本文能帮助到大家,让大家学习理解这部分内容,需要的朋友可以参考下
    2017-09-09
  • Java本地缓存Caffeine的简单使用

    Java本地缓存Caffeine的简单使用

    这篇文章主要介绍了Java本地缓存Caffeine的简单使用,Caffeine 是基于 JAVA 8 的高性能本地缓存库,并且在 spring5后,spring 官方放弃了 Guava,而使用了性能更优秀的 Caffeine 作为默认缓存组件,需要的朋友可以参考下
    2023-12-12
  • java通过jacob实现office在线预览功能

    java通过jacob实现office在线预览功能

    这篇文章主要为大家详细介绍了java通过jacob实现office在线预览功能,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-08-08

最新评论