首页 > 其他分享 >反射操作ReflectionUtils

反射操作ReflectionUtils

时间:2024-10-09 10:33:06浏览次数:1  
标签:反射 return ReflectionUtils param clazz public static 操作 Class

ReflectionUtilsSpring框架中的反射工具类,它提供了一系列静态方法,可以方便地进行类、对象、方法、字段等反射操作。

工具类

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

/**
 * 反射工具类
 * 定义工具方法使用反射创建对象,调用方法。好处:一次编写多次调用(一劳永逸)
 */
public class ReflectUtils {

    public static final String SERIALVERSIONUID = "serialVersionUID";
    public static final String UPDATE_TIME = "update_time";
    public static final String ID = "id";

    /**
     * 定义静态工具方法,使用反射创建对象
     * 步骤:
     * 1 调用Class.forName(className)方法,获取Class对象。反射入口
     * 2 调用Class的getDeclaredConstructor方法获取构造器
     * 3 调用构造器的newInstance方法创建对象
     * @param className 以字符串表示的类名称,通常是包名+类名
     * @param <T> 该方法支持泛型
     * @return 泛型(不确定的类型)
     */
    public static <T> T createObject(String className) throws Exception {
        Class<?> clazz = Class.forName(className);
        Constructor<?> structor = clazz.getDeclaredConstructor();
        return (T)structor.newInstance();
    }

    /**
     * 使用反射创建带有参数对象
     * @param className 以字符串表示的类名称,通常是包名+类名
     * @param params 参数类型列表
     * @param values 参数实际值列表
     * @param <T> 方法支持泛型
     * @return 返回结果是泛型(不确定的类型)
     */
    public static <T> T createObject(String className,Class<?>[] params,Object... values) throws Exception{
        Class<?> clazz = Class.forName(className);
        Constructor<?> struct = clazz.getDeclaredConstructor(params);
        return (T)struct.newInstance(values);
    }

    /**
     *
     * 使用反射完成方法调用(无参)
     * 步骤:
     * 1 根据方法名称获取方法签名(信息)
     * 2 使用反射调用方法
     * @param  type 对象的实例
     * @param  methodName 方法名称
     * 备注:该方法支持两个泛型
     *  T 参数是一个泛型类型
     *  R 返回值是一个泛型
     */
    public static <T,R>  R invokeMethod(T type,String methodName) throws Exception {
        Class<?> clazz = type.getClass();
        // 根据方法名称获取方法签名
        Method method = clazz.getDeclaredMethod(methodName);
        return (R)method.invoke(type);
    }

    /**
     * 使用反射调用带有参数的方法
     * 步骤:
     * 1 获取Class对象
     * 2 根据方法名称获取方法签名
     * 3 调用Method的invoke方法,完成方法调用,并填写参数类型和参数名称
     * 4 返回方法调用的结果
     * @param obj 反射创建的对象
     * @param methodName 方法名称
     * @param params 参数类型列表
     * @param value 参数值列表
     * @param <T> 参数支持泛型
     * @param <R> 返回值支持泛型
     * @return 返回方法调用的结果
     */
    public static <T,R> R invokeMethod(T obj,String methodName,Class[] params,Object...value) throws Exception{
        Class<?> clazz = obj.getClass();
        Method method = clazz.getDeclaredMethod(methodName, params);
        // 编译错误:invoke方法返回Object类型,但是我定义的方法返回R,需要将返回类型强制转换为R类型
        // return method.invoke(type,value);
        return (R) method.invoke(obj,value);
    }

    /**
     * 使用反射访问私有属性(暴力破解)
     * 步骤:
     * 1 获取Class对象
     * 2 根据属性名称获取属性签名Field
     * 3 设置属性签名的可访问性为true
     * 4 调用set方法访问私有属性(为私有属性赋值)
     * @param obj 对象
     * @param fieldName 属性名称
     * @param value 属性值
     * @param <T> 参数支持泛型,此时表示参数类型不确定
     * @throws Exception
     */
    public static <T> void accessField(T obj,String fieldName,String value) throws Exception {
        Class<?> clazz = obj.getClass();
        Field stuNameField = clazz.getDeclaredField(fieldName);
        // 设置属性可访问性为true,就能够访问私有属性
        stuNameField.setAccessible(true);
        // 为私有属性赋值
        stuNameField.set(obj,value);
    }

    /**
     * 获取对象字段名、字段值
     */
    public static <T> Map<String, Object> getFieldNameValueMap(T t) {
        Field[] fields = ReflectUtil.getFields(t.getClass());
        Map<String, Object> map = new HashMap<>(16);
        Arrays.stream(fields).forEach(o -> {
            if (SERIALVERSIONUID.equals(o.getName()) || ID.equals(o.getName())) {
                return;
            }
            if (UPDATE_TIME.equals(o.getName())) {
                map.put(o.getName(), new Date());
                return;
            }
            map.put(o.getName(), ReflectUtil.getFieldValue(t, o));
        });
        return map;
    }

    /**
     * 获取字段名
     */
    public static <T> List<String> getFieldNameList(Class<T> clazz) {
        Field[] fields = ReflectUtil.getFields(clazz);
        return Arrays.stream(fields).map(Field::getName)
                .filter(name -> !SERIALVERSIONUID.equals(name)).collect(Collectors.toList());
    }

    /**
     * 获取多记录数据
     */
    public static <T> List<List<Object>> getFieldValueLists(List<String> fieldNameList, List<T> list) {
        List<List<Object>> dataList = new ArrayList<>(1000);
        list.forEach(o -> {
            List<Object> fieldValueList = new LinkedList<>();
            fieldNameList.forEach(name -> {
                if (UPDATE_TIME.equals(name)) {
                    fieldValueList.add(new Date());
                    return;
                }
                fieldValueList.add(ReflectUtil.getFieldValue(o, name));
            });
            dataList.add(fieldValueList);
        });
        return dataList;
    }

    /**
     * 获取实体表名
     */
    public static <T> String getTableName(T t) {
        if (t instanceof Class) {
            return AnnotationUtil.getAnnotationValue((Class) t, TableName.class).toString();
        }
        return AnnotationUtil.getAnnotationValue(t.getClass(), TableName.class).toString();
    }
}

使用 mybatis 批量插入

serviceImpl:

    /**
     * 批量插入
     *
     * @param list
     * @param clazz
     */
    @Override
    public <T> int batchSave(List<T> list, Class<T> clazz) {
        List<String> fieldNameList = ReflectUtils.getFieldNameList(clazz);
        List<List<Object>> fieldValueLists = ReflectUtils.getFieldValueLists(fieldNameList, list);
        String tableName = ReflectUtils.getTableName(clazz);
        return dataMapper.batchSave(fieldNameList, fieldValueLists, tableName);
    }

mapper:

int batchSave(@Param("fieldNameList") List<String> fieldNameList, @Param("fieldValueLists") List<List<Object>> fieldValueLists, @Param("tableName") String tableName);

xml:

    <insert id="batchSave">
        insert into
        ${tableName}
        <foreach collection="fieldNameList" item="item" index="index" open="(" separator="," close=")">${item}</foreach>
        values
        <foreach collection="fieldValueLists" item="item" separator=",">
            <foreach collection="item" item="valueItem" index="index" open="(" separator="," close=")">
                #{valueItem}
            </foreach>
        </foreach>
    </insert>

调用

// 查询需要批量插入数据总量 sum
// 计算插入的页数 (这里每次1000)
int pageNum = sum % 1000 == 0 ? sum / 1000 : sum / 1000 + 1;
Stream.iterate(1, no -> no + 1).limit(pageNum).forEach(no -> {
  // 批量插入
  int i = baseService.batchSave(data, Entity.class);
});

标签:反射,return,ReflectionUtils,param,clazz,public,static,操作,Class
From: https://www.cnblogs.com/1399z3blog/p/18453726

相关文章

  • java中对比两个对象哪些字段不同(反射获取对象的字段和value值)
    场景:当需要对比两个对象的哪些字段的value值不同时,使用原理:通过反射来获取对象中每个字段的value值,进行对比1.获取需要比对对象的Class对象 比对的是obpPurQualityCheckTaskItem和obpPurQualityTaskItemExportDto对象,但因为他们是两个不同的类,所以都需要获取2.获取需要比......
  • 数据恢复篇:适用于 Windows 操作系统的 5 大数据恢复软件
    如今,数字空间正在快速发展。每个人都使用某种数字设备,如计算机、笔记本电脑、移动设备等来存储重要文档、照片、视频和其他重要文件。但事情并不总是一帆风顺。在很多情况下,技术会失败,您可能会遇到一些严重的问题,例如数据丢失。但是,有许多技术可以帮助您解决技术问题,例如数据恢......
  • Java反射
    Java反射参考文章:JAVA反序列化-反射机制Java反射(超详细!)Java反射(简单详细且易懂,快速入门)0准备一个User类packageorg.example.reflect;publicclassUser{publicStringname;privateintage;publicUser(){}privateUser(Stringname){......
  • Python字符串基本操作
    目录一、字符串的创建1.1转义字符1.2原始字符串二、字符串的访问与切片2.1字符访问2.2切片(Slicing)三、字符串的连接与重复四、字符串的格式化4.1百分号格式化4.2 str.format() 方法4.3f-字符串(Python3.6及以上)五、字符串的方法5.1大小写转换5.2去除空......
  • 使用标签实现MyBatis的基础操作
    目录前言1.配置MyBatis⽇志打印2.参数传递 2.1 #{}和${}区别 2.2传递多个参数 3.增删改查3.1增(Insert)3.2删(Delete)3.3改(Update) 3.4查(Select)前言 接下来我们会使用的数据表如下:对应的实体类为:UserInfoMapper所有的准备工作都在如下文章。MyBat......
  • javascript学习——CSS 操作总结
    CSS操作CSS与JavaScript是两个有着明确分工的领域,前者负责页面的视觉效果,后者负责与用户的行为互动。但是,它们毕竟同属网页开发的前端,因此不可避免有着交叉和互相配合。本章介绍如何通过JavaScript操作CSS。HTML元素的style属性操作CSS样式最简单的方法,就是......
  • D29【python 接口自动化学习】- python基础之输入输出与文件操作
    day29格式化输出学习日期:20241006学习目标:输入输出与文件操作﹣-41格式化输出:如何将执行结果通过屏幕输出?学习笔记:三种常用的格式化输出方式 百分号方式 format函数方式 总结1.格式化输出是为了让提示信息和输出的结果更人性化2.可以根据输出的复杂度和特点,......
  • D30【python 接口自动化学习】- python基础之输入输出与文件操作
    day30F-strings输出学习日期:20241007学习目标:输入输出与文件操作﹣-42F-strings-如何通过定义好的格式进行输出?学习笔记:F-strings介绍F-strings的计算功能F-strings宽度和精度调整练习#宽度为10个字符,不足补0print(f'{number:010}')#000123.456#指定类......
  • D31【python 接口自动化学习】- python基础之输入输出与文件操作
    day31文件的打开学习日期:20241008学习目标:输入输出与文件操作﹣-43常见常新:文件的打开学习笔记:文件的概念使用open()函数打开文件文件路径处理文件打开模式总结文件操作包括:打开,关闭,读取,写入类Unix系统中设备,虚拟设备,网络套接字等都被当作文件可以学......
  • 7-1单链表的基本操作
    题目:7-1单链表基本操作分数20作者朱允刚单位吉林大学请编写程序实现单链表插入、删除结点等基本算法。给定一个单链表和一系列插入、删除结点的操作序列,输出实施上述操作后的链表。单链表数据域值为整数。输入格式:输入第1行为1个正整数n,表示当前单链表长度;第2行为n个......