实现从一个类中的实体对象获取所有属性值注入到另一个不同类的实体对象的对应属性中

背景:

由于dao层的可视化对象(bean)跟service层以及controller层的bean对象是分开的,也就是同一业务流水线中,在controller层是跟界面或者接口的交互bean,而到了操作数据库层则用的匹配数据库表的实体bean。该俩个bean之间类名可能相同,属性也可能完全一致,就是包路径不一样,为了确保这个过程能够正常对接上,就需要有一个转换的工作名,而这个工作就交给了service层去处理,假若一个bean对象的属性数量相对少的时候,我们可以采取笨方法,挨个getset赋值转换,但假若一个bean对象的属性数量相对庞大,且该项目里存在大量该情况的bean的时候,就需要换个思路,能不能实现自动转换的工具类,因此才有了该工具并并记录于此,希望能够给相同处境的朋友提供上帮助

import org.springframework.util.StringUtils;

import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Objects;
import com.test.User;
import com.test.UserB;

public class ConvertUtil {

    /**
     * 对象转换,前提是俩个对象的属性字段要相同
     *
     * @param tClass 目标class
     * @param object 需要被转换的对象
     * @param <T>    T
     * @return 目标对象
     */
    public static <T> T convertObj(Class<T> tClass, Object object) throws IllegalAccessException, InstantiationException {
        Class<?> aClass = object.getClass();
        Field[] objDeclaredFields = aClass.getDeclaredFields();
        AccessibleObject.setAccessible(objDeclaredFields, true);
        T tObj = tClass.newInstance();
        Arrays.stream(objDeclaredFields).forEach(field -> {
            try {
                String name = field.getName();
                if (name.equals("serialVersionUID")) {
                    // 现在大部分bean都包含序列号,忽略该值
                    return;
                }
                // 该属性对应的值
                Object value = field.get(object);
                if (Objects.isNull(value) || StringUtils.isEmpty(value.toString().trim()) || isBaseDefaultValue(value)) {
                    // 无值或空字符串或是基础类型的默认值(如:int型默认值为0,double默认值为0.0,以此类推)
                    return;
                }
                // 属性名改成大驼峰
                name = name.substring(0, 1).toUpperCase() + name.substring(1);
                Method declaredMethod = tClass.getDeclaredMethod("set" + name, new Class[]{value.getClass()});
                declaredMethod.invoke(tObj, value);
            } catch (IllegalAccessException | NoSuchMethodException | InvocationTargetException e) {
                e.printStackTrace();
            }
        });
        return tObj;
    }

    /**
     * 判断是否为基本类型的默认值
     *
     * @param object
     * @return
     */
    public static boolean isBaseDefaultValue(Object object) {
        Class className = object.getClass();
        if (className.equals(java.lang.Integer.class)) {
            return (int) object == 0;
        } else if (className.equals(java.lang.Byte.class)) {
            return (byte) object == 0;
        } else if (className.equals(java.lang.Long.class)) {
            return (long) object == 0L;
        } else if (className.equals(java.lang.Double.class)) {
            return (double) object == 0.0d;
        } else if (className.equals(java.lang.Float.class)) {
            return (float) object == 0.0f;
        } else if (className.equals(java.lang.Character.class)) {
            return (char) object == '\u0000';
        } else if (className.equals(java.lang.Short.class)) {
            return (short) object == 0;
        } else if (className.equals(java.lang.Boolean.class)) {
            return (boolean) object == false;
        }
        return false;
    }

    public static void main(String[] args) throws InstantiationException, IllegalAccessException {
        User user = new User();
        user.setId("123456");
        user.setName("name");
        UserB userB = convertObj(UserB.class, user);
        // user的num属性这里没有赋值,但是因为其实基础类型自带默认值, 因此要忽略掉
        // UserB(name=name, id=123456, num=null)
        System.out.println(userB);
    }
}

实体类A 和B (类中的属性名必须保持一致,声明类型如果是基础数据类型,另一个实体类该属性可以是对应的包装类)

import lombok.AccessLevel;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;
import java.io.Serializable;
// 该注解是lombok插件,自动生成getset方法,可以忽略
@Data
public class User implements Serializable {
    @Getter(AccessLevel.NONE)
    @Setter(AccessLevel.NONE)
    private static final long serialVersionUID = 3843044389018289214L;

    String name;

    // int默认值0
    int num;

    String id;

}

类名可以不相同,看个人习惯,个人觉得类名区分开还是比较好的,避免后续开发引包引错

import lombok.AccessLevel;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;
import java.io.Serializable;
// 该注解是lombok插件,自动生成getset方法,可以忽略
@Data
public class UserB implements Serializable {
    @Getter(AccessLevel.NONE)
    @Setter(AccessLevel.NONE)
    private static final long serialVersionUID = 3843044389018289214L;

    String name;

    // int默认值0
    int num;

    String id;

}

工具类中核心思路是采用反射的getFileds去搜索字段是否有有赋值,之后采用getMethod去获取getset方法,最后利用set方法执行invoke 往实例中注入值,大体处理思路是这样,有兴趣的可以查阅相应反射资料

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
使用帮助:http://pan.baidu.com/s/1bnxOHGF 主要功能介绍: 功能: 一、数据库生成实体类. 1.配置 (1)本工具提供了3连接数据库的方式,分别是:MySql、Oracle、SqlServer,在界面上给出连接示例,方便进行复制和修改(减少因错误配置连接方式而带来了不能链接数据库问题)。配置正确后即可正确读取出数据库的相关表和表字段。 (2)生成的代码路径可根据需要进行灵活配置,如果没有配置默认为:d:\.LKGenerator\dest-beans (3)提供了根据数据表生成代码的相关配置,可以配置去掉表前缀(如t_),去掉表后缀,去掉表名内容下划线(业界习惯表命名用下划线区分单词),大写表名下划线后的第一个字母,去掉属性下划线并大写其后第一个字母,这样可以使生成的代码更符合业界代码命名习惯,如,用户和角色的关联关系表常被命名为:t_user_role,表字段有user_id和role_id,按上面的配置后生成的代码为UserRole.java类中属性为userId和roleId. 2.选择表 前置条件:本功能要求第一步配置数据库连接方式能正确连接到数据库。 本功能可列出所配置数据库的所有表,请选择所需生成代码的表后点击确认按钮(注:如果重新配置步骤1的数据库连接后需刷新列表)。 3.生成实体类代码 前置条件:步骤2选择了需要生成代码的表。 本功能可根据步骤2选择表进行实体Beans代码的生成,生成的代码默认包含AutoBean和AutoField的注解配置(AutoBean和AutoField注解非生成代码的必须项,如果配置了可以在生成代码时时为模版注入该配置,增强模版的扩展性)。 4.编译实体类 前置条件:系统安装JDK并配置JAVA_HOME环境变量 本功能可以对Java代码进行编译(注:本功能的使用不必要依赖步骤3的代码,可对任何正确的java代码进行编译,如果代码有引用第三方的jar,请将jar放置到d:\.LKGenerator\.lib文件夹下。) 5.导出数据到Excel 前置条件:执行第三步后已生成带注解的JavaBean. 本功能只要使用地三步的配置注解的JavaBean就能将数据表的数据导出。 6.从Excel导入到DB 前置条件:执行第三步后已生成带注解的JavaBean. 本功能只要使用地三步的配置注解的JavaBean就能将Excel的数据导入到数据表。 7.生成数据表文档 前置条件:步骤2选择了需要生成文档的表。 本功能可以根据步骤2选择的表进行excel文档的生成。 8.清空Beans代码目录。 本功能可以清空生成代码的文件夹,主要为了增强用户体验,让使用者方便打开Beans文件夹并对代码进行修改。 9.打开Beans代码目录 本功能可以打开生成代码的文件夹,主要为了增强用户体验,让使用者方便打开Beans文件夹并对代码进行修改。 二、实体类根据模版生成最终代码. 功能简介:根据实体类代码结合模版生成最终代码,代码模版规范参考模版框架velocity的规范和样例。 实现思路:加载实体类的class文件到classLoader,读取实体类属性和注解,将名、属性字段名、注解三者与模版进行结合生成最终的代码。 1.配置 (1)配置模版路径,这个配置可以配置用于生成代码的velocity模版路径,生成的代码将模版的特定符号见“模版可使用的变量”的描述。 (2)配置生成代码的固定文件路径,这个配置的文件将原样拷贝到最终生成的代码,主要适用于非文本文件如*.jpg *.jar等文件。 (3)配置引用jar路径,这个jar路径的配置是需要加载的class需要引用的jar. (4)注入模版的Bean(*.class)路径,这个路径下需放置实体Bean的class文件。 (5)配置生成代码的根路径,这个路径即最终生成代码的路径。 (6)配置注入模板的键,这个功能可以配置除默认注入到模版的变量之外的特殊变量,例:author=李坤,模板可用变量${author},base-package=com.tgb.lk,则模版可使用${base-package} (7)读取数据库的数据用于生成代码。 本配置主要控制是否开启读取配置数据库数据后作为模板的输入功能。开启本功能将自动将数据库的数据转换成JavaBean并将此JavaBean作为模板变量的输入用于生成代码。 模板可使用的通用变量: ${base-package}包名的默认变量,可在步骤(5)进行属性的设置,可以放到路径,路径使用时将把配置的点(.)转为路径分隔符(/)使用. ${beans}实体类名集合. ${bean}实体类名首字母变为小写. ${bean.Lname}同${bean},实体类名首字母变为小写. ${bean.Uname}实体类名首字母变为大写. ${bean.ALname}实体类名全部变为小写字母. ${bean.AUname}实体类名全部变为大写字母. 注:${bean},${bean.Lname},${bean.Uname},${bean.ALname},${bean.AUname},${base-package}可以用于模版也可以用于路径和文件的命名. 注解增强Bean属性,需配置@AutoBean(alias="xxx",table="xxx",args={"xxx","yyy"}): ${bean.alias}实体类注解的alias,如果实体类上没有配置,则默认为名.可配置文注释,生成代码时显示该注释. ${bean.table}实体类注解的table,对应数据库的表名. ${bean.argsLength},${bean.argsSize}bean注解的args参数数组配置的参数个数. ${bean.args[0]}bean注解的args参数数组配置的第一个. ${bean.fields}实体类的字段集合,可对其进行循环. ${field}实体类属性名. ${field}实体属性首字母变为小写. ${field.Lname}同${bean},实体类属性首字母变为小写. ${field.Uname}实体类属性首字母变为大写. ${field.ALname}实体类属性全部变为小写字母. ${field.AUname}实体类属性全部变为大写字母. 注解增强Field属性,需配置 @AutoField(alias = "序号", isKey = true , isRequired = true , type="String", combo = {"男","女"},args={"xxx","yyy"}) ${field.alias}实体属性注解的alias,默认为属性名.可配置文注释,生成代码时显示该注释. ${field.isKey}实体属性注解的isKey,boolean型,配置后可以使用${bean.key}变量. ${field.isRequired}实体属性的isRequired属性,该属性可以配置该字段是否为必填项. ${field.type}实体类属注解型,例如String,Integer... ${field.comboLength},${field.comboSize}实体属性注解combo参数数组配置的参数个数. ${field.combo[0]}实体属性注解combo参数数组配置的第一个. ${field.argsLength}}实体属性注解的args参数数组配置的参数个数. ${field.args[0]}实体属性注解args参数数组配置的第一个. ${bean.datasLength} = ${bean.datasSize}bean读取数据表的内容并转为对象,模板可以使用. #foreach($data in ${bean.datas}) ${data.uuid},${data.name}... #end 2.从实体类生成代码 前置条件:步骤1的(1)配置了可用的velocity模版,步骤1(4)有可用的*.class文件。 本功能用于生成代码。 3.打开生成代码目录 本功能可以打开生成代码的文件夹,主要为了增强用户体验,让使用者方便打开Beans文件夹并对代码进行修改。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值