|
@@ -1,14 +1,36 @@
|
|
|
package com.chelvc.framework.database.handler;
|
|
|
|
|
|
+import java.io.IOException;
|
|
|
+import java.lang.reflect.AnnotatedElement;
|
|
|
+import java.lang.reflect.Method;
|
|
|
+import java.lang.reflect.Parameter;
|
|
|
+import java.lang.reflect.ParameterizedType;
|
|
|
import java.lang.reflect.Type;
|
|
|
import java.sql.CallableStatement;
|
|
|
import java.sql.PreparedStatement;
|
|
|
import java.sql.ResultSet;
|
|
|
import java.sql.SQLException;
|
|
|
import java.sql.Types;
|
|
|
+import java.util.List;
|
|
|
+import java.util.Set;
|
|
|
|
|
|
import com.chelvc.framework.common.util.JacksonUtils;
|
|
|
import com.chelvc.framework.common.util.ObjectUtils;
|
|
|
+import com.chelvc.framework.database.annotation.Sensitive;
|
|
|
+import com.chelvc.framework.database.context.DatabaseContextHolder;
|
|
|
+import com.fasterxml.jackson.core.JsonGenerator;
|
|
|
+import com.fasterxml.jackson.core.JsonParser;
|
|
|
+import com.fasterxml.jackson.core.JsonProcessingException;
|
|
|
+import com.fasterxml.jackson.core.Version;
|
|
|
+import com.fasterxml.jackson.databind.AnnotationIntrospector;
|
|
|
+import com.fasterxml.jackson.databind.DeserializationContext;
|
|
|
+import com.fasterxml.jackson.databind.JavaType;
|
|
|
+import com.fasterxml.jackson.databind.JsonDeserializer;
|
|
|
+import com.fasterxml.jackson.databind.JsonSerializer;
|
|
|
+import com.fasterxml.jackson.databind.ObjectMapper;
|
|
|
+import com.fasterxml.jackson.databind.SerializerProvider;
|
|
|
+import com.fasterxml.jackson.databind.introspect.Annotated;
|
|
|
+import com.fasterxml.jackson.databind.type.CollectionType;
|
|
|
import lombok.NonNull;
|
|
|
import org.apache.ibatis.executor.result.ResultMapException;
|
|
|
import org.apache.ibatis.type.JdbcType;
|
|
@@ -21,9 +43,195 @@ import org.apache.ibatis.type.TypeReference;
|
|
|
*
|
|
|
* @param <T> 对象类型
|
|
|
* @author Woody
|
|
|
- * @date 2024/1/30
|
|
|
+ * @date 2024/4/3
|
|
|
*/
|
|
|
public interface JsonTypeHandler<T> extends TypeHandler<T> {
|
|
|
+ /**
|
|
|
+ * 敏感字符串序列化处理器
|
|
|
+ */
|
|
|
+ class SensitiveSerializer extends JsonSerializer<String> {
|
|
|
+ @Override
|
|
|
+ public void serialize(String value, JsonGenerator generator, SerializerProvider provider) throws IOException {
|
|
|
+ if (DatabaseContextHolder.isSensitiveWritable()) {
|
|
|
+ value = DatabaseContextHolder.encrypt(value, true);
|
|
|
+ }
|
|
|
+ generator.writeString(value);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 敏感字符串集合序列化处理器
|
|
|
+ */
|
|
|
+ class SensitiveSetSerializer extends JsonSerializer<Set<String>> {
|
|
|
+ @Override
|
|
|
+ public void serialize(Set<String> value, JsonGenerator generator, SerializerProvider provider)
|
|
|
+ throws IOException {
|
|
|
+ if (DatabaseContextHolder.isSensitiveWritable()) {
|
|
|
+ value = DatabaseContextHolder.encrypt(value, true);
|
|
|
+ }
|
|
|
+ generator.writeObject(value);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 敏感字符串列表序列化处理器
|
|
|
+ */
|
|
|
+ class SensitiveListSerializer extends JsonSerializer<List<String>> {
|
|
|
+ @Override
|
|
|
+ public void serialize(List<String> value, JsonGenerator generator, SerializerProvider provider)
|
|
|
+ throws IOException {
|
|
|
+ if (DatabaseContextHolder.isSensitiveWritable()) {
|
|
|
+ value = DatabaseContextHolder.encrypt(value, true);
|
|
|
+ }
|
|
|
+ generator.writeObject(value);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 敏感字符串数组序列化处理器
|
|
|
+ */
|
|
|
+ class SensitiveArraySerializer extends JsonSerializer<String[]> {
|
|
|
+ @Override
|
|
|
+ public void serialize(String[] value, JsonGenerator generator, SerializerProvider provider)
|
|
|
+ throws IOException {
|
|
|
+ if (DatabaseContextHolder.isSensitiveWritable()) {
|
|
|
+ value = DatabaseContextHolder.encrypt(value, true);
|
|
|
+ }
|
|
|
+ generator.writeObject(value);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 敏感字符串反序列化处理器
|
|
|
+ */
|
|
|
+ class SensitiveDeserializer extends JsonDeserializer<String> {
|
|
|
+ @Override
|
|
|
+ public String deserialize(JsonParser parser, DeserializationContext context)
|
|
|
+ throws IOException, JsonProcessingException {
|
|
|
+ return DatabaseContextHolder.decrypt(parser.getValueAsString(), true);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 敏感字符串集合反序列化处理器
|
|
|
+ */
|
|
|
+ class SensitiveSetDeserializer extends JsonDeserializer<Set<String>> {
|
|
|
+ private static final com.fasterxml.jackson.core.type.TypeReference<Set<String>> TYPE =
|
|
|
+ new com.fasterxml.jackson.core.type.TypeReference<Set<String>>() {
|
|
|
+ };
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Set<String> deserialize(JsonParser parser, DeserializationContext context)
|
|
|
+ throws IOException, JsonProcessingException {
|
|
|
+ Set<String> values = parser.readValueAs(TYPE);
|
|
|
+ return DatabaseContextHolder.decrypt(values, true);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 敏感字符串列表反序列化处理器
|
|
|
+ */
|
|
|
+ class SensitiveListDeserializer extends JsonDeserializer<List<String>> {
|
|
|
+ private static final com.fasterxml.jackson.core.type.TypeReference<List<String>> TYPE =
|
|
|
+ new com.fasterxml.jackson.core.type.TypeReference<List<String>>() {
|
|
|
+ };
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public List<String> deserialize(JsonParser parser, DeserializationContext context)
|
|
|
+ throws IOException, JsonProcessingException {
|
|
|
+ List<String> values = parser.readValueAs(TYPE);
|
|
|
+ return DatabaseContextHolder.decrypt(values, true);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 敏感字符串数组反序列化处理器
|
|
|
+ */
|
|
|
+ class SensitiveArrayDeserializer extends JsonDeserializer<String[]> {
|
|
|
+ private static final com.fasterxml.jackson.core.type.TypeReference<String[]> TYPE =
|
|
|
+ new com.fasterxml.jackson.core.type.TypeReference<String[]>() {
|
|
|
+ };
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public String[] deserialize(JsonParser parser, DeserializationContext context)
|
|
|
+ throws IOException, JsonProcessingException {
|
|
|
+ String[] values = parser.readValueAs(TYPE);
|
|
|
+ return DatabaseContextHolder.decrypt(values, true);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 对象JSON序列化/反序列化处理器实例
|
|
|
+ */
|
|
|
+ ObjectMapper mapper = JacksonUtils.initializeSerializer().setAnnotationIntrospector(new AnnotationIntrospector() {
|
|
|
+ @Override
|
|
|
+ public Version version() {
|
|
|
+ return Version.unknownVersion();
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Object findSerializer(Annotated am) {
|
|
|
+ if (!am.hasAnnotation(Sensitive.class)) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ JavaType type = am.getType();
|
|
|
+ Class<?> raw = am.getRawType();
|
|
|
+ if (raw == String.class) {
|
|
|
+ return SensitiveSerializer.class;
|
|
|
+ } else if (raw.isArray() && raw.getComponentType() == String.class) {
|
|
|
+ return SensitiveArraySerializer.class;
|
|
|
+ } else if (type instanceof CollectionType && type.getContentType().getRawClass() == String.class) {
|
|
|
+ if (Set.class.isAssignableFrom(type.getRawClass())) {
|
|
|
+ return SensitiveSetSerializer.class;
|
|
|
+ }
|
|
|
+ return SensitiveListSerializer.class;
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Object findDeserializer(Annotated am) {
|
|
|
+ if (!am.hasAnnotation(Sensitive.class)) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ AnnotatedElement element = am.getAnnotated();
|
|
|
+ if (element instanceof Method) {
|
|
|
+ Parameter[] parameters = ((Method) element).getParameters();
|
|
|
+ if (ObjectUtils.notEmpty(parameters) && parameters.length > 0) {
|
|
|
+ Type type = parameters[0].getParameterizedType();
|
|
|
+ if (type == String.class) {
|
|
|
+ return SensitiveDeserializer.class;
|
|
|
+ } else if (type instanceof ParameterizedType) {
|
|
|
+ Type raw = ((ParameterizedType) type).getRawType();
|
|
|
+ Type arg = ((ParameterizedType) type).getActualTypeArguments()[0];
|
|
|
+ if (raw == Set.class && arg == String.class) {
|
|
|
+ return SensitiveSetDeserializer.class;
|
|
|
+ } else if (raw == List.class && arg == String.class) {
|
|
|
+ return SensitiveListDeserializer.class;
|
|
|
+ }
|
|
|
+ } else if (type instanceof Class<?> && ((Class<?>) type).isArray()
|
|
|
+ && ((Class<?>) type).getComponentType() == String.class) {
|
|
|
+ return SensitiveArrayDeserializer.class;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ JavaType type = am.getType();
|
|
|
+ Class<?> raw = am.getRawType();
|
|
|
+ if (raw == String.class) {
|
|
|
+ return SensitiveDeserializer.class;
|
|
|
+ } else if (raw.isArray() && raw.getComponentType() == String.class) {
|
|
|
+ return SensitiveArrayDeserializer.class;
|
|
|
+ } else if (type instanceof CollectionType && type.getContentType().getRawClass() == String.class) {
|
|
|
+ if (Set.class.isAssignableFrom(type.getRawClass())) {
|
|
|
+ return SensitiveSetDeserializer.class;
|
|
|
+ }
|
|
|
+ return SensitiveListDeserializer.class;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
/**
|
|
|
* 获取对象类型
|
|
|
*
|
|
@@ -99,7 +307,7 @@ public interface JsonTypeHandler<T> extends TypeHandler<T> {
|
|
|
if (ObjectUtils.isBlank(parameter)) {
|
|
|
ps.setNull(i, Types.VARCHAR);
|
|
|
} else {
|
|
|
- ps.setString(i, JacksonUtils.serialize(parameter));
|
|
|
+ ps.setString(i, JacksonUtils.serialize(mapper, parameter));
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -113,7 +321,7 @@ public interface JsonTypeHandler<T> extends TypeHandler<T> {
|
|
|
*/
|
|
|
@SuppressWarnings("unchecked")
|
|
|
default T getNullableResult(ResultSet rs, String columnName) throws SQLException {
|
|
|
- return (T) JacksonUtils.deserialize(rs.getString(columnName), this.getRawType());
|
|
|
+ return (T) JacksonUtils.deserialize(mapper, rs.getString(columnName), this.getRawType());
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -126,7 +334,7 @@ public interface JsonTypeHandler<T> extends TypeHandler<T> {
|
|
|
*/
|
|
|
@SuppressWarnings("unchecked")
|
|
|
default T getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
|
|
|
- return (T) JacksonUtils.deserialize(rs.getString(columnIndex), this.getRawType());
|
|
|
+ return (T) JacksonUtils.deserialize(mapper, rs.getString(columnIndex), this.getRawType());
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -139,7 +347,7 @@ public interface JsonTypeHandler<T> extends TypeHandler<T> {
|
|
|
*/
|
|
|
@SuppressWarnings("unchecked")
|
|
|
default T getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
|
|
|
- return (T) JacksonUtils.deserialize(cs.getString(columnIndex), this.getRawType());
|
|
|
+ return (T) JacksonUtils.deserialize(mapper, cs.getString(columnIndex), this.getRawType());
|
|
|
}
|
|
|
|
|
|
/**
|