java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > Jackson自定义序列化反序列化注解

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

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

您可能感兴趣的文章:
阅读全文