反射机制的简单示例

一个使用反射机制的简单示例,这个示例将展示如何使用反射来实现一个通用的数据导出功能。

首先,让我们创建必要的项目结构和文件:

  1. 首先修改 pom.xml 添加依赖:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>cn.yam</groupId>
    <artifactId>reflection-demo</artifactId>
    <version>1.0-SNAPSHOT</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.0</version>
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.5.2</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.30</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
    </dependencies>
</project>
  1. 创建实体类:
package cn.yam.entity;

import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;

@Data
@TableName("user")
public class User {
    private Long id;
    private String username;
    private String email;
    private Integer age;
}
  1. 创建一个自定义注解,用于标记需要导出的字段:
package cn.yam.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ExportField {
    String value() default "";
}
  1. 更新实体类,添加注解:
package cn.yam.entity;

import cn.yam.annotation.ExportField;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;

@Data
@TableName("user")
public class User {
    private Long id;
    
    @ExportField("用户名")
    private String username;
    
    @ExportField("邮箱")
    private String email;
    
    @ExportField("年龄")
    private Integer age;
}
  1. 创建通用的导出工具类:
package cn.yam.util;

import cn.yam.annotation.ExportField;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;

public class ExportUtil {
    
    public static <T> List<String[]> exportData(List<T> dataList) {
        List<String[]> result = new ArrayList<>();
        if (dataList == null || dataList.isEmpty()) {
            return result;
        }

        // 使用反射获取类的所有字段
        Class<?> clazz = dataList.get(0).getClass();
        Field[] fields = clazz.getDeclaredFields();
        
        // 获取标题行
        List<Field> exportFields = new ArrayList<>();
        List<String> headers = new ArrayList<>();
        
        for (Field field : fields) {
            ExportField exportField = field.getAnnotation(ExportField.class);
            if (exportField != null) {
                exportFields.add(field);
                headers.add(exportField.value());
            }
        }
        
        // 添加标题行
        result.add(headers.toArray(new String[0]));
        
        // 添加数据行
        for (T data : dataList) {
            List<String> rowData = new ArrayList<>();
            for (Field field : exportFields) {
                try {
                    field.setAccessible(true);
                    Object value = field.get(data);
                    rowData.add(value == null ? "" : value.toString());
                } catch (IllegalAccessException e) {
                    rowData.add("");
                }
            }
            result.add(rowData.toArray(new String[0]));
        }
        
        return result;
    }
}
  1. 创建 Service 和 Controller:
package cn.yam.service;

import cn.yam.entity.User;
import com.baomidou.mybatisplus.extension.service.IService;

public interface UserService extends IService<User> {
}
package cn.yam.service.impl;

import cn.yam.entity.User;
import cn.yam.mapper.UserMapper;
import cn.yam.service.UserService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
}
package cn.yam.controller;

import cn.yam.entity.User;
import cn.yam.service.UserService;
import cn.yam.util.ExportUtil;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.util.List;

@RestController
@RequestMapping("/user")
public class UserController {

    @Resource
    private UserService userService;

    @GetMapping("/export")
    public List<String[]> exportUsers() {
        List<User> users = userService.list();
        return ExportUtil.exportData(users);
    }
}
  1. 创建 Mapper 接口:
package cn.yam.mapper;

import cn.yam.entity.User;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface UserMapper extends BaseMapper<User> {
}
  1. 最后更新主类:
package cn.yam;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
@MapperScan("cn.yam.mapper")
public class Main {
    public static void main(String[] args) {
        SpringApplication.run(Main.class, args);
    }
}

在这里插入图片描述

详细剖析实现细节

好的,我来详细解读 ExportUtil 的实现细节:

  1. 首先看方法签名:
public static <T> List<String[]> exportData(List<T> dataList)
  • 这是一个静态泛型方法,<T> 表示可以接收任意类型的列表
  • 返回类型是 List<String[]>,即字符串数组的列表,每个数组代表一行数据
  1. 输入检查:
List<String[]> result = new ArrayList<>();
if (dataList == null || dataList.isEmpty()) {
    return result;
}
  • 创建结果集容器
  • 如果输入列表为空或null,直接返回空结果集
  1. 获取类的字段信息:
Class<?> clazz = dataList.get(0).getClass();
Field[] fields = clazz.getDeclaredFields();
  • 通过第一个对象获取类的Class对象
  • getDeclaredFields() 获取该类声明的所有字段(不包括继承的字段)
  1. 处理标题行:
List<Field> exportFields = new ArrayList<>();
List<String> headers = new ArrayList<>();

for (Field field : fields) {
    ExportField exportField = field.getAnnotation(ExportField.class);
    if (exportField != null) {
        exportFields.add(field);
        headers.add(exportField.value());
    }
}
  • 创建两个列表:一个存储要导出的字段,一个存储表头
  • 遍历所有字段,检查是否有 @ExportField 注解
  • 如果有注解,将字段添加到 exportFields,将注解的value值添加到headers
  1. 添加标题行到结果集:
result.add(headers.toArray(new String[0]));
  • 将headers转换为字符串数组并添加为结果集的第一行
  1. 处理数据行:
for (T data : dataList) {
    List<String> rowData = new ArrayList<>();
    for (Field field : exportFields) {
        try {
            field.setAccessible(true);
            Object value = field.get(data);
            rowData.add(value == null ? "" : value.toString());
        } catch (IllegalAccessException e) {
            rowData.add("");
        }
    }
    result.add(rowData.toArray(new String[0]));
}
  • 外层循环遍历每个数据对象
  • 内层循环遍历要导出的字段
  • field.setAccessible(true) 允许访问私有字段
  • field.get(data) 获取字段值
  • 将字段值转换为字符串,如果为null则转换为空字符串
  • 如果访问出错(比如没有访问权限),添加空字符串
  • 将每行数据转换为字符串数组并添加到结果集

让我用一个具体例子来说明整个过程:

// 示例类
public class User {
    @ExportField("姓名")
    private String name;
    
    @ExportField("年龄")
    private int age;
    
    private String password; // 不导出
}

// 使用示例
List<User> users = Arrays.asList(
    new User("张三", 20),
    new User("李四", 25)
);

List<String[]> result = ExportUtil.exportData(users);

执行过程:

  1. 首先获取User类的所有字段(name, age, password)
  2. 找到带有@ExportField注解的字段(name, age)
  3. 生成标题行 [“姓名”, “年龄”]
  4. 处理第一行数据 [“张三”, “20”]
  5. 处理第二行数据 [“李四”, “25”]

最终结果:

[
    ["姓名", "年龄"],     // 标题行
    ["张三", "20"],      // 数据行1
    ["李四", "25"]       // 数据行2
]

这个示例展示了如何使用反射机制实现一个通用的数据导出功能:

  1. 我们创建了一个 @ExportField 注解,用于标记需要导出的字段。
  2. ExportUtil 类中,我们使用反射机制:
    • 获取类的所有字段 (clazz.getDeclaredFields())
    • 获取字段上的注解 (field.getAnnotation(ExportField.class))
    • 动态访问对象的字段值 (field.get(data))

这样的设计有以下优点:

  1. 通用性强:可以用于任何带有 @ExportField 注解的实体类
  2. 可扩展性好:只需要在实体类的字段上添加注解就可以控制导出
  3. 维护方便:导出逻辑集中在一个工具类中

要运行这个示例,你需要:

  1. 创建对应的数据库和表
  2. 在 application.yml 中配置数据库连接信息
  3. 启动应用并访问 http://localhost:8080/user/export 接口

这个示例展示了反射机制在实际业务中的应用,通过反射我们可以在运行时动态获取类的信息,实现更加灵活和通用的功能。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/971977.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Qt:多元素控件

目录 多元素控件介绍 QListWidget QTableWidget QTreeWidget 多元素控件介绍 多元素控件表示这个控件中包含了很多的元素&#xff0c;元素可能指的是字符串&#xff0c;也可以指的是更加复杂的数据结构、图片等等 Qt 中提供的多元素控件有: QListWidgetQListViewQTableW…

DeepSeek 助力 Vue 开发:打造丝滑的范围选择器(Range Picker)

前言&#xff1a;哈喽&#xff0c;大家好&#xff0c;今天给大家分享一篇文章&#xff01;并提供具体代码帮助大家深入理解&#xff0c;彻底掌握&#xff01;创作不易&#xff0c;如果能帮助到大家或者给大家一些灵感和启发&#xff0c;欢迎收藏关注哦 &#x1f495; 目录 Deep…

STL —— 洛谷字符串(string库)入门题(蓝桥杯题目训练)(一)

目录 一、B2109 统计数字字符个数 - 洛谷 算法代码&#xff1a; 1. 引入库和命名空间 2. 主函数 3. 读取输入 4. 变量初始化 5. 遍历字符串 6. 输出结果 7. 返回值 总结 评测记录&#xff1a; 二、B2110 找第一个只出现一次的字符 - 洛谷 方法一&#xff1a;算法代…

Golang GORM系列:GORM并发与连接池

GORM 是一个流行的 Go 语言 ORM&#xff08;对象关系映射&#xff09;库&#xff0c;用于简化数据库操作。它支持连接池和并发访问功能&#xff0c;这些功能对于高性能、高并发的应用场景非常重要。本文结合示例详细介绍gorm的并发处理能力&#xff0c;以及如何是哟个连接池提升…

C#之上位机开发---------C#通信库及WPF的简单实践

〇、上位机&#xff0c;分层架构 界面层 要实现的功能&#xff1a; 展示数据 获取数据 发送数据 数据层 要实现的功能&#xff1a; 转换数据 打包数据 存取数据 通信层 要实现的功能&#xff1a; 打开连接 关闭连接 读取数据 写入数据 实体类 作用&#xff1a; 封装数据…

Ubuntu24安装MongoDB(解压版)

目录 0.需求说明1.环境检查2.下载软件2.1.下载MongoDB服务端2.2.下载MongoDB连接工具(可略过)2.3.检查上传或下载的安装包 3.安装MongoDB3.1.编辑系统服务3.2.启动服务3.3.客户端连接验证3.3.1.创建管理员用户 4.远程访问4.1.开启远程访问4.2.开放防火墙 0.需求说明 问&#x…

《DeepSeek-V3:人工智能大语言模型》

《DeepSeek-V3:人工智能大语言模型》 1. 引言 我们介绍了 DeepSeek-V3,这是一个强大的专家混合 (MoE) 语言模型,总共有 671B 个参数,每个令牌激活了 37B。 为了实现高效的推理和具有成本效益的训练,DeepSeek-V3 采用了多头潜在注意力 (MLA) 和 DeepSeekMoE 架构,这些…

解锁机器学习核心算法 | K -近邻算法:机器学习的神奇钥匙

一、引言 今天我们继续学习机器学习核心算法 —— K - 近邻&#xff08;K-Nearest Neighbors&#xff0c;简称 KNN&#xff09;算法。它就像是一位经验丰富的 “老江湖”&#xff0c;以其简单而又强大的方式&#xff0c;在众多机器学习任务中占据着不可或缺的地位。 K - 近邻…

算法分析—— 《归并排序》

《排序数组》 题目描述&#xff1a; 给你一个整数数组 nums&#xff0c;请你将该数组升序排列。 你必须在 不使用任何内置函数 的情况下解决问题&#xff0c;时间复杂度为 O(nlog(n))&#xff0c;并且空间复杂度尽可能小。 示例 1&#xff1a; 输入&#xff1a;nums [5,2…

linux云服务器部署deepseek,并通过网页访问

参考视频&#xff1a;https://www.douyin.com/root/search/linux%E5%AE%89%E8%A3%85%20deepseek?aid3aa2527c-e4f2-4059-b724-ab81a140fa8b&modal_id7468518885570940214&typegeneral 修改ollama配置文件 vim /etc/systemd/system/ollama.service 我的电脑硬盘只有4…

FastAdmin后端列表导入表格数据

后台添加数据的时候增加通过表格导入功能 如下图index.html页面增加导入和模板下载按钮代码如下 <div class"panel panel-default panel-intro">{:build_heading()}<div class"panel-body"><div id"myTabContent" class"ta…

可调节图片参数,解决图片模糊及尺寸过小问题的工具

软件介绍 你是否正为图片模糊、尺寸太小而烦恼&#xff1f;别担心&#xff0c;有这样一款神器能帮你轻松解决。它能精准调节图片参数&#xff0c;即便原本模糊不清的图片&#xff0c;经它处理后也能变得高清锐利&#xff0c;瞬间让图片焕然一新。而且&#xff0c;它还具备导出…

Windows网络安全基础

随着互联网的发展和普及&#xff0c;Windows网络安全问题愈发严重。在本文中&#xff0c;我们将会介绍Windows网络安全的基本概念&#xff0c;包括网络攻击类型、网络安全威胁、网络安全防御措施等等&#xff0c;帮助初学者更好地了解Windows网络安全。 一、网络攻击类型 网络…

代码补全『三重奏』:EverEdit如何用上下文识别+语法感知+智能片段重构你的编码效率!

1 代码自动完成 1.1 应用场景 在编辑文档时&#xff0c;为了提高编辑效率&#xff0c;编辑器一般都会带有自动完成功能&#xff0c;比如&#xff1a;输入括号时自动补全另一半&#xff0c;输入文字时&#xff0c;自动补全剩下的部分。 1.2 使用方法 1.2.1 自动缩进 单击主菜…

vue,vue3 keepalive没有效果,无法缓存页面include无效,keep-alive

keepalive没有效果&#xff0c;无法缓存页面&#xff1f; 问题大概是组件的name值不对应&#xff0c;vue2修改组件文件的name值&#xff0c;vue3保持组件文件名称和路由页面配置的name一致就可以了&#xff0c;如果vue3不想保持一致&#xff0c;必须手动在文件后面添加export..…

栈回溯方案

注&#xff1a;栈回溯无法很好的定位到未调优化的函数&#xff0c;需要编译前使用 -fno-optimize-sibling-calls 选项禁止尾调优化。 基于unwind的栈回溯 在 arm 架构下&#xff0c;不少32位系统用的是 unwind 形式的栈回溯&#xff0c;这种栈回溯要复杂很多。首先需要程序有一…

【存储中间件API】MySQL、Redis、MongoDB、ES常见api操作及性能比较

常见中间件api操作及性能比较 ☝️ MySQL crud操作✌️ maven依赖✌️ 配置✌️ 定义实体类✌️ 常用api ☝️ Redis crud操作✌️ maven依赖✌️ 配置✌️ 常用api ☝️ MongoDB crud操作✌️ maven依赖✌️ 配置文件✌️ 定义实体类✌️ MongoDB常用api ☝️ ES crud操作 ⭐️…

解锁D3.js与PlantUML的交互奥秘:探索知识图谱数据可视化新领域

解锁D3.js与PlantUML的交互魔法&#xff1a;数据可视化新征程 在前端开发的广袤天地里&#xff0c;数据可视化一直是一颗璀璨的明珠&#xff0c;吸引着无数开发者探索其奥秘。而当D3.js这一强大的JavaScript库&#xff0c;遇上专注于创建UML图的PlantUML&#xff0c;一场奇妙的…

DeepSeek24小时写作机器人,持续创作高质量文案

内容创作已成为企业、自媒体和创作者的核心竞争力。面对海量的内容需求&#xff0c;人工创作效率低、成本高、质量参差不齐等问题日益凸显。如何在有限时间内产出高质量内容&#xff1f;DeepSeek写作机器人&#xff0c;一款24小时持续创作的智能工具&#xff0c;为企业和个人提…

使用html css js 来实现一个服装行业的企业站源码-静态网站模板

最近在练习 前端基础&#xff0c;html css 和js 为了加强 代码的 熟悉程序&#xff0c;就使用 前端 写了一个个服装行业的企业站。把使用的技术 和 页面效果分享给大家。 应用场景 该制衣服装工厂官网前端静态网站模板主要用于前端练习和编程练习&#xff0c;适合初学者进行 HT…