告别重复劳动!基于注解的通用列表导出组件设计与实现

亲爱的朋友们,热烈欢迎你们来到我的创意编程空间!能与你们在这里相聚,我感到无比激动和荣幸。在这个充满挑战与机遇的时代,我们每个人都在不断追求知识的深度与广度。而我的博客,正是一个激发灵感与分享智慧的乐园。在这里,你们不仅能够发现有趣的编程项目和实用的技术资源,还可以畅所欲言,分享你们的经验与想法。我真诚地期待着你们的到来,愿我们在这片小小的天地里携手前行,共同探索未知的领域。

------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

目录

引言

1、需求分析

1.1 核心需求

1.2 技术目标

 2、设计与实现

2.1 核心设计思路

 2.2 核心代码实现

2.2.1 定义注解

 2.2.2 切面逻辑

2.2.3 测试示例

3、总结


引言

在日常业务开发中,查询列表数据(如订单列表、购物车列表、待支付列表等)是一个非常常见的需求。而随着业务的发展,这些查询功能往往还需要支持数据导出(如导出为 Excel 文件)。传统的实现方式是为每个查询接口单独开发一个导出接口,导致大量重复代码和维护成本。为了解决这一问题,本文将介绍如何设计并实现一个 基于注解的通用列表导出组件,通过简单的配置即可为查询接口自动添加导出功能。

1、需求分析

1.1 核心需求

  • 在查询方法上添加注解,支持动态导出功能。

  • 通过请求参数标识是否执行导出操作。

  • 导出的字段通过注解配置,支持灵活扩展。

  • 导出文件名可通过参数动态指定。

1.2 技术目标

  • 减少重复代码,提升开发效率。

  • 提供友好的 API 设计,降低使用成本。

 2、设计与实现

2.1 核心设计思路

  • 注解驱动:通过自定义注解标记查询方法和导出字段。

  • AOP 拦截:利用 Spring AOP 拦截查询方法,根据请求参数动态切换导出逻辑。

  • 反射解析字段:通过反射机制解析实体类中的导出字段注解,动态生成 Excel 列。

  • 流式导出:使用 EasyExcel 实现高性能的流式导出,避免内存溢出。

 2.2 核心代码实现

2.2.1 定义注解
// 标记查询方法支持导出
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ExportExcel {
    //导出的文件名
    String fileName() default "导出列表.xlsx";
    //前端传参的导出标识
    String exportFlagParam() default "exportFlag";
}

// 标记导出字段
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ExportField {
    // 列名
    String name();
    // 列优先级顺序,值越小越优先
    int order();
}
 2.2.2 切面逻辑
@Aspect
@Component
public class ExportAspect {

    @Around("@annotation(exportExcel)")
    public Object aroundExport(ProceedingJoinPoint joinPoint, ExportExcel exportExcel) throws Throwable {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
        HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getResponse();
        // 判断是否触发导出
        boolean isExport = Boolean.parseBoolean(request.getParameter(exportExcel.exportFlagParam()));
        if (!isExport) {
            // 正常执行查询
            return joinPoint.proceed();
        }
        try {
            // 执行原方法获取数据
            JsonData result = (JsonData)joinPoint.proceed();
            if (ResultCodeEnum.SUCCESS.getCode().equals(result.getCode())){
                List dataList = (List)result.getData();
                // 生成Excel
                String fileName = exportExcel.fileName();
                ExcelUtil.exportExcel(dataList, fileName, response);
            }
        } catch (Throwable e) {
            throw new RuntimeException(e);
        }
        // 导出请求无需返回JSON
        return null;
    }
}
2.2.3 测试示例

@ExportField注解中name为导出excel的列名,order为导出excel的列顺序,@ExportExcel注解中fileName 为需要导出的文件名称,exportFlagParam为指定前端确定是否导出的入参。

@Data
public class TestDemoDTO {

    @ExportField(name = "姓名",order = 1)
    private String name;

    @ExportField(name = "年龄",order = 3)
    private Integer age;

    @ExportField(name = "性别",order = 2)
    private String sex;

    private String exportFlag;
}

@PostMapping(value = "/queryUserByName")
@ExportExcel(fileName = "导出Excel测试.xlsx",exportFlagParam = "export")
public JsonData> queryUserByName(String username,String export) {
    // 模拟从数据库获取用户信息
    List testDemoDTOs = new ArrayList<>();
    for (int i = 0; i < 10; i++) {
        TestDemoDTO testDemoDTO = new TestDemoDTO();;
        testDemoDTO.setAge(15+i/3);
        testDemoDTO.setName("张三"+i);
        testDemoDTO.setSex(i%2 == 0 ? "男" : "女");
        testDemoDTOs.add(testDemoDTO);
    }
    return JsonData.buildSuccess(testDemoDTOs);
}

测试示例中当传参export值为true时则为导出Excel

告别重复劳动!基于注解的通用列表导出组件设计与实现_第1张图片

告别重复劳动!基于注解的通用列表导出组件设计与实现_第2张图片

当传参export值为其他时则为查询列表

告别重复劳动!基于注解的通用列表导出组件设计与实现_第3张图片

3、总结

通过本文介绍的 基于注解的通用列表导出组件,我们可以显著减少重复代码,提升开发效率。该组件具有以下优势:

  • 低侵入性:通过注解和 AOP 实现,无需修改业务逻辑。

  • 高性能:基于 EasyExcel 的流式导出,支持大数据量场景。

  • 灵活扩展:支持动态配置导出字段和文件名,满足多样化需求。

希望本文能为大家在实际开发中提供有价值的参考,助力高效开发!

了解idea插件的开发流程及idea右键选择项目批量导出插件介绍-CSDN博客

深入讲解TransmittableThreadLocal工作原理,并手写一个精简版的功能组件-CSDN博客

如何快速实现一个简单的通用缓存工具?-CSDN博客

java实现接口反参JsonData<T>封装,并实现字符串与泛型对象JsonData<T>之间的快速转换-CSDN博客

你可能感兴趣的:(spring,boot,java)