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自定义序列化反序列化注解内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Java抽象类与接口区别详解

    Java抽象类与接口区别详解

    这篇文章主要介绍了Java抽象类与接口区别详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-03-03
  • 使用java从乱码文本中解析出正确的文本

    使用java从乱码文本中解析出正确的文本

    这篇文章主要介绍了使用java从乱码文本中解析出正确的文本的方法,需要的朋友可以参考下
    2014-04-04
  • 为什么mybatis中的SqlSession一定要关闭

    为什么mybatis中的SqlSession一定要关闭

    这篇文章主要介绍了为什么mybatis中的SqlSession一定要关闭,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-12-12
  • win10操作系统下重启电脑java环境变量失效

    win10操作系统下重启电脑java环境变量失效

    这篇文章主要介绍了win10操作系统下重启电脑java环境变量失效,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-09-09
  • java 线程同步详细介绍及实例代码

    java 线程同步详细介绍及实例代码

    这篇文章主要介绍了java 线程同步详细介绍及实例代码的相关资料,需要的朋友可以参考下
    2017-02-02
  • 给Java菜鸟的一些建议_关于Java知识点归纳(J2EE and Web 部分)

    给Java菜鸟的一些建议_关于Java知识点归纳(J2EE and Web 部分)

    下面小编就为大家带来一篇给Java菜鸟的一些建议_关于Java知识点归纳(J2EE and Web 部分)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-05-05
  • 详解Java中的锁Lock和synchronized

    详解Java中的锁Lock和synchronized

    锁是Java并发编程中最重要的同步机制,Java提供了种类丰富的锁,每种锁因其特性的不同,在适当的场景下能够展现出非常高的效率。本文将详细介绍Lock和synchronized
    2021-06-06
  • Mybatis的TypeHandler加解密数据实现

    Mybatis的TypeHandler加解密数据实现

    在我们数据库中有些时候会保存一些用户的敏感信息,所以就需要对这些数据进行加密,那么本文就介绍了Mybatis的TypeHandler加解密数据实现,感兴趣的可以了解一下
    2021-06-06
  • Spring Cloud与分布式系统简析

    Spring Cloud与分布式系统简析

    这篇文章主要介绍了Spring Cloud与分布式系统的相关内容,具有一定参考价值,需要的朋友可以了解下。
    2017-09-09
  • springmvc中进行数据保存以及日期参数的保存过程解析

    springmvc中进行数据保存以及日期参数的保存过程解析

    这篇文章主要介绍了springmvc中进行数据保存以及日期参数的保存过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-09-09

最新评论