MybatisPlus实体类属性与Json自动转换

实现思路
2023年8月11日
MybatisPlus自带更好的实现方案,@TableName和@TableField就可以满足...
所以,以下都是废代码...

1、获取要自动转换的实体类,需要有一个标识告诉程序
2、继承BaseTypeHandler,构造方法传入需要实现的实体类,从而实现数据库json格式的字段自动转换为实体类对象
具体实现代码如下,逻辑可能有误。
1,实体类定义
@TableName("connect_info")
@Slf4j
public class ConnectInfo implements Serializable {

    private static final long serialVersionUID = 1L;

    @TableId
    private String pkId;

    /**
     * 连接类型
     */
    private String connectType;

    /**
     * 连接元数据,据此可创建数据库连接
     */
    //@TableField(typeHandler = FastjsonTypeHandler.class,jdbcType = JdbcType.VARCHAR)
    private DataSourceBase connectMetaData;

    public String getPkId() {
        return pkId;
    }

    public void setPkId(String pkId) {
        this.pkId = pkId;
    }

    public String getConnectType() {
        return connectType;
    }

    public void setConnectType(String connectType) {
        this.connectType = connectType;
    }

    public JSONObject getConnectMetaData() {
        try {
            return JsonMetaDataFactory.getMetaDataFromTarget(connectMetaData);
        } catch (Exception e) {
            log.error("获取失败:{}-{}",this.getClass().getName(),this.getPkId(),e);
            throw new RuntimeException(""+e.getMessage());
        }
    }

    public void setConnectMetaData(DataSourceBase connectMetaData) {
        this.connectMetaData = connectMetaData;
    }
}
@Data
@JsonMetaData
public class DataSourceBase {
    private String user;
    private String password;
    private String url;
    private DataSourceBaseAAA aaa;	
}

@Data
public class DataSourceBaseAAA {
    private String name;
    private int age;
}
2,扫描实体类
//这一步的实现思路参考了ClassPathMapperScanner
//需要实现json与实体互转的标识
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
public @interface JsonMetaData {
}

public interface JsonMetaDataSource {
}
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
@Import(ScanConfigImport.class)
public @interface EnableScanConfig {
    String[] value() default {};
}
public class ScanConfigImport implements ImportBeanDefinitionRegistrar {
    @Override
    public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
        Map<String, Object> annotationAttributes = metadata.getAnnotationAttributes(EnableScanConfig.class.getName());
        String[] value = (String [])annotationAttributes.get("value");
        BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(ScanConfig.class);
        builder.addPropertyValue("packages", Sets.newHashSet(value));
        builder.addConstructorArgValue(registry);
        registry.registerBeanDefinition(ScanConfig.class.getName(),builder.getBeanDefinition());
    }
}
/**
 * 扫描符合指定条件的类
 */
public class ScanConfig
        extends ClassPathBeanDefinitionScanner
        implements BeanDefinitionRegistryPostProcessor{
    @Setter
    private Set<String> packages;

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {

    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        packages.addAll(AutoConfigurationPackages.get(beanFactory));
        Map<String, TypeFilterNotMatch> beansOfType = beanFactory.getBeansOfType(TypeFilterNotMatch.class);

        if(!CollectionUtils.isEmpty(beansOfType)){
            //清空默认设置
            super.resetFilters(false);
            beansOfType.values().forEach(super::addIncludeFilter);
            this.doScan(packages.toArray(new String[0]));
        }
    }

    public ScanConfig(BeanDefinitionRegistry registry) {
        //继承自ClassPathBeanDefinitionScanner
        super(registry);
    }
}
/**
 * 这里是为了扫描出来一些需要的信息,并非是创建bean,所以不需要返回true
 */
public abstract class TypeFilterNotMatch implements TypeFilter {

    abstract public void check(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException;


    @Override
    public boolean match(MetadataReader metadataReader,
                         MetadataReaderFactory metadataReaderFactory) throws IOException {
        check(metadataReader,metadataReaderFactory);
        return false;
    }
}
@Component
@Slf4j
public class JsonMetaDataFilter extends TypeFilterNotMatch implements ResourceLoaderAware {
    private ClassLoader classLoader;

    @Override
    public void setResourceLoader(ResourceLoader resourceLoader) {
        classLoader = resourceLoader.getClassLoader();
    }

    @Getter
    private final Set<Class<?>> setClass = new HashSet<>();

    @Override
    public void check(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) {
        String className = metadataReader.getClassMetadata().getClassName();
        boolean contains1 = metadataReader.getAnnotationMetadata()
                .getAnnotationTypes().contains(JsonMetaData.class.getName());
        if(contains1){
            addClass(className);
            return;
        }
        List<String> list = Lists.newArrayList(metadataReader.getClassMetadata().getInterfaceNames());
        boolean contains2 = list.contains(JsonMetaDataSource.class.getName());
        if(contains2){
            addClass(className);
        }
    }

    private void addClass(String className){
        try {
            Class<?> aClass = ClassUtils.forName(className, classLoader);
            setClass.add(aClass);
        }catch (Exception e){
            log.error("JsonMetaDataFilter-addClass-加载失败:{}",className,e);
        }
    }
}
3,实体和JSON互转
public class JsonMetaDataTypeHandler<T> extends BaseTypeHandler<T> {
    private final Class<T> cls;

    public JsonMetaDataTypeHandler(Class<T> cls){
        this.cls = cls;
    }


    @Override
    public void setNonNullParameter(PreparedStatement preparedStatement, int i, T t, JdbcType jdbcType) throws SQLException {
        String value = "";
        try {
            value = JsonMetaDataFactory.getMetaDataFromTarget(t)
                    .toString(SerializerFeature.DisableCircularReferenceDetect);
        }catch (Exception e){
            throw new RuntimeException(e.getMessage());
        }

        preparedStatement.setString(i,value);
    }

    @Override
    public T getNullableResult(ResultSet resultSet, String columnName) throws SQLException {
        String json = resultSet.getString(columnName);
        T targetByJsonMetaData = null;
        try {
            targetByJsonMetaData =
                    JsonMetaDataFactory.getTargetByJsonMetaData(cls, JSONObject.parseObject(json));
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }
        return targetByJsonMetaData;
    }

    @Override
    public T getNullableResult(ResultSet resultSet, int columnIndex) throws SQLException {
        String json = resultSet.getString(columnIndex);
        T targetByJsonMetaData = null;
        try {
            targetByJsonMetaData =
                    JsonMetaDataFactory.getTargetByJsonMetaData(cls, JSONObject.parseObject(json));
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }
        return targetByJsonMetaData;
    }

    @Override
    public T getNullableResult(CallableStatement callableStatement, int columnIndex) throws SQLException {
        String json = callableStatement.getString(columnIndex);
        T targetByJsonMetaData = null;
        try {
            targetByJsonMetaData =
                    JsonMetaDataFactory.getTargetByJsonMetaData(cls, JSONObject.parseObject(json));
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }
        return targetByJsonMetaData;
    }
}

public class JsonMetaDataFactory {

    //实体对象是否保存原来的json信息
    private static boolean saveMetaData = false;

    /**
     * 从json格式的元数据中获取目标对象
     * 元数据来源可以是数据库字段值
     */
    public static <T> T getTargetByJsonMetaData(@NonNull  Class<T> cls,
                                             @NonNull  JSONObject metaData) throws Exception{
        T t = metaData.toJavaObject(cls);
        if(!saveMetaData){
            return t;
        }
        JsonMetaDataTarget<T> jsonMetaDataTarget = new JsonMetaDataTarget<>(t,metaData);
        ProxyFactory factory = new ProxyFactory();
        factory.setProxyTargetClass(true);
        factory.setTarget(t);
        factory.addAdvice(jsonMetaDataTarget);

        return cls.cast(factory.getProxy());
    }

    /**
     * 从目标对象中获取Json格式的元数据,这个元数据会被存储进数据库
     */
    public static <T> JSONObject getMetaDataFromTarget(@NonNull T t) throws Exception{
        JsonMetaDataTarget<?> advice = ProxyFactoryUtils.getAdvisor(
                ProxyFactoryUtils.getProxyFactory(t),JsonMetaDataTarget.class);
        if(advice != null){
            JSONObject metaData = advice.getMetaData();
            JSONObject targetJson = (JSONObject)JSONObject.toJSON(advice.getTarget());
            metaData.putAll(targetJson);
            return metaData;
        }else {
            return (JSONObject)JSONObject.toJSON(t);
        }
    }
}
public class JsonMetaDataTarget<T> implements MethodInterceptor {
    @Getter
    private final T target;
    @Getter
    private final JSONObject metaData;

    public JsonMetaDataTarget(T target, JSONObject metaData) {
        this.target = target;
        this.metaData = metaData;
    }

    @Nullable
    @Override
    public Object invoke(@Nonnull MethodInvocation invocation) throws Throwable {
        Method method = invocation.getMethod();
        Object[] arguments = invocation.getArguments();
        return method.invoke(target,arguments);
    }
}

public class ProxyFactoryUtils {
    private static volatile Field CGLIB$CALLBACK_0 = null;
    private static final Object SYNC_CGLIB$CALLBACK_0 = new Object();
    private static volatile Field ADVISED = null;
    private static final Object SYNC_ADVISED = new Object();


    public static <T> ProxyFactory getProxyFactory(T t) throws Exception {
        if(AopUtils.isCglibProxy(t)){
            if(CGLIB$CALLBACK_0 == null){
                synchronized (SYNC_CGLIB$CALLBACK_0){
                    if(CGLIB$CALLBACK_0 == null){
                        Field cglib$CALLBACK_0 = ReflectionUtils.findField(t.getClass(), "CGLIB$CALLBACK_0");
                        if(cglib$CALLBACK_0 != null){
                            ReflectionUtils.makeAccessible(cglib$CALLBACK_0);
                            CGLIB$CALLBACK_0 = cglib$CALLBACK_0;
                        }
                    }
                }
            }
            if(CGLIB$CALLBACK_0 == null){
                return null;
            }
            Object fieldValue = CGLIB$CALLBACK_0.get(t);

            if(ADVISED == null){
                synchronized (SYNC_ADVISED){
                    if(ADVISED == null){
                        Field advised = ReflectionUtils.findField(fieldValue.getClass(), "advised");
                        if(advised != null){
                            ReflectionUtils.makeAccessible(advised);
                            ADVISED = advised;
                        }
                    }
                }
            }
            if(ADVISED == null){
                return null;
            }

            fieldValue = ADVISED.get(fieldValue);

            if(fieldValue instanceof ProxyFactory){
                return (ProxyFactory)fieldValue;
            }
        }
        return null;
    }

    public static <T extends Advice> T getAdvisor(ProxyFactory factory, Class<T> cls){
        if(factory != null){
            Advisor[] advisors = factory.getAdvisors();
            for(Advisor advisor : advisors){
                if(advisor.getAdvice().getClass() == cls){
                    return cls.cast(advisor.getAdvice());
                }
            }
        }
        return null;
    }
}
4,注册到Mybatis

@Configuration
@EnableScanConfig
public class MybatisConfig {
    private List<SqlSessionFactory> sqlSessionFactories;

    @Autowired
    private JsonMetaDataFilter jsonMetaDataFilter;

    @Autowired
    public void setSqlSessionFactories(ObjectProvider<List<SqlSessionFactory>> sqlSessionFactories) {
        this.sqlSessionFactories = sqlSessionFactories.getIfAvailable();
    }

    @PostConstruct
    public void init(){
        if(CollectionUtils.isEmpty(sqlSessionFactories)){
            return;
        }
        for(SqlSessionFactory factory : sqlSessionFactories){
            org.apache.ibatis.session.Configuration configuration = factory.getConfiguration();
            TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry();
            typeHandlerRegistry.register(JSONObject.class, JdbcType.VARCHAR, FastjsonTypeHandler.class);

            jsonMetaDataFilter.getSetClass().forEach(x->{
                typeHandlerRegistry.register(x,(TypeHandler)new JsonMetaDataTypeHandler<>(x));
            });
        }
    }

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值