找回密码
 立即注册
首页 业界区 业界 扩展若依@Excel注解,使其对字段的控制是否导出更加便捷 ...

扩展若依@Excel注解,使其对字段的控制是否导出更加便捷

仄谦 2025-7-8 16:37:47
基于若依框架实现按角色控制 Excel 字段导出功能

一、背景介绍

在我们的项目开发中,采用了若依(RuoYi)的 Java Spring 框架进行系统搭建。若依框架提供了 @Excel 注解,通过在实体类的字段上添加该注解,能够方便地实现 Excel 数据的导出功能。然而,在实际业务场景中,领导提出了根据用户角色来控制某些字段是否导出的需求。但遗憾的是,若依自带的 @Excel 注解并不支持这一功能。为了满足这一业务需求,我们决定自行开发一套解决方案。
二、解决方案思路

为了实现按角色控制 Excel 字段导出的功能,我们的核心思路是自定义一个注解和一个导出工具类。具体步骤如下:

  • 自定义注解:创建一个新的注解 RoleExcel,该注解能够标识出需要导出的字段,并且可以指定允许导出该字段的角色列表。
  • 编写导出工具类:开发一个新的导出工具类 RoleExcelUtil,该工具类会根据当前用户的角色信息,过滤掉没有权限导出的字段,然后将有权限导出的字段数据导出到 Excel 文件中。
  • 实体类注解应用:在需要导出和进行角色控制的实体类 JiheHandledRate 的相应字段上添加 RoleExcel 注解。
  • 控制器调用:在控制器 JiheStationCommonController 的 exportHandledRate 方法中调用 RoleExcelUtil 工具类的导出方法,完成数据的导出操作。
三、具体实现步骤

3.1 自定义 RoleExcel 注解

首先,我们定义了一个 RoleExcel 注解,用于标识需要导出的字段,并支持按角色控制导出。以下是 RoleExcel 注解的代码实现:
  1. package com.sdhs.common.annotation;
  2. import java.lang.annotation.*;
  3. /**
  4. * 扩展Excel注解,支持按角色控制导出字段
  5. */
  6. @Target({ElementType.FIELD})
  7. @Retention(RetentionPolicy.RUNTIME)
  8. @Documented
  9. public @interface RoleExcel {
  10.     // 字段显示名称(同若依@Excel的name)
  11.     String name();
  12.     // 列宽(默认20)
  13.     int width() default 20;
  14.     // 日期格式(如"yyyy-MM-dd HH:mm:ss")
  15.     String dateFormat() default "";
  16.     // 允许导出该字段的角色标识列表(如"admin","audit_role")
  17.     String[] roles() default {};
  18.     // 是否允许所有角色导出(默认false)
  19.     boolean allowAll() default false;
  20.     // 权限标识(支持按权限控制,如"jihe:export:vehplate")
  21.     String[] permissions() default {};
  22. }
复制代码
在这个注解中,我们定义了字段显示名称、列宽、日期格式、允许导出的角色列表、是否允许所有角色导出以及权限标识等属性。
3.2 编写 RoleExcelUtil 导出工具类

接下来,我们编写了 RoleExcelUtil 工具类,该工具类会根据用户角色过滤需要导出的字段,并将数据导出到 Excel 文件中。以下是 RoleExcelUtil 工具类的代码实现:
  1. package com.sdhs.common.utils.poi;
  2. import com.sdhs.common.annotation.RoleExcel;
  3. import com.sdhs.common.core.domain.entity.SysRole;
  4. import com.sdhs.common.core.domain.model.LoginUser;
  5. import com.sdhs.common.utils.SecurityUtils;
  6. import org.apache.poi.ss.usermodel.*;
  7. import org.apache.poi.xssf.streaming.SXSSFWorkbook;
  8. import javax.servlet.http.HttpServletResponse;
  9. import java.io.OutputStream;
  10. import java.lang.reflect.Field;
  11. import java.net.URLEncoder;
  12. import java.util.*;
  13. import java.util.stream.Collectors;
  14. /*
  15. * @description:支持角色权限的Excel工具类
  16. * @author: 龙谷情
  17. * @date: 2025-07-08 16:39:28
  18. **/
  19. public class RoleExcelUtil<T> {
  20.     private final Class<T> clazz;
  21.     private List<ExcelColumn> excelColumns;
  22.     public RoleExcelUtil(Class<T> clazz) {
  23.         this.clazz = clazz;
  24.         this.excelColumns = getFilteredColumns();
  25.     }
  26.     /**
  27.      * 获取过滤后的列(根据角色权限)
  28.      */
  29.     private List<ExcelColumn> getFilteredColumns() {
  30.         List<ExcelColumn> allColumns = new ArrayList<>();
  31.         Class<?> currentClass = clazz;
  32.         while (currentClass != Object.class) {
  33.             Field[] fields = currentClass.getDeclaredFields();
  34.             for (Field field : fields) {
  35.                 RoleExcel roleExcel = field.getAnnotation(RoleExcel.class);
  36.                 if (roleExcel == null) {
  37.                     continue;
  38.                 }
  39.                 if (hasExportPermission(roleExcel)) {
  40.                     allColumns.add(buildExcelColumn(field, roleExcel));
  41.                 }
  42.             }
  43.             currentClass = currentClass.getSuperclass();
  44.         }
  45.         return allColumns;
  46.     }
  47.     /**
  48.      * 检查当前用户是否有权限导出该字段
  49.      */
  50.     private boolean hasExportPermission(RoleExcel roleExcel) {
  51.         if (roleExcel.allowAll()) {
  52.             return true;
  53.         }
  54.         LoginUser loginUser = SecurityUtils.getLoginUser();
  55.         if (loginUser == null) {
  56.             return false;
  57.         }
  58.         // 检查角色权限
  59.         String[] allowRoles = roleExcel.roles();
  60.         if (allowRoles.length > 0) {
  61.             List<String> userRoleKeys = loginUser.getUser().getRoles().stream()
  62.                    .map(SysRole::getRoleKey)
  63.                    .collect(Collectors.toList());
  64.             for (String role : allowRoles) {
  65.                 if (userRoleKeys.contains(role) || loginUser.getUser().isAdmin()) {
  66.                     return true;
  67.                 }
  68.             }
  69.         }
  70.         return false;
  71.     }
  72.     /**
  73.      * 构建Excel列信息
  74.      */
  75.     private ExcelColumn buildExcelColumn(Field field, RoleExcel roleExcel) {
  76.         ExcelColumn column = new ExcelColumn();
  77.         column.setField(field);
  78.         column.setHeader(roleExcel.name());
  79.         column.setWidth(roleExcel.width());
  80.         column.setDateFormat(roleExcel.dateFormat());
  81.         return column;
  82.     }
  83.     /**
  84.      * 导出Excel文件
  85.      */
  86.     public void exportExcel(HttpServletResponse response, List<T> list, String title) {
  87.         try (Workbook workbook = new SXSSFWorkbook(500)) {
  88.             Sheet sheet = workbook.createSheet(title);
  89.             setSheetStyle(sheet);
  90.             // 创建表头
  91.             Row headerRow = sheet.createRow(0);
  92.             createHeader(headerRow);
  93.             // 填充数据
  94.             for (int i = 0; i < list.size(); i++) {
  95.                 Row dataRow = sheet.createRow(i + 1);
  96.                 fillDataRow(dataRow, list.get(i));
  97.             }
  98.             // 输出到客户端
  99.             response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
  100.             response.setCharacterEncoding("utf-8");
  101.             String fileName = URLEncoder.encode(title + ".xlsx", "UTF-8").replaceAll("\\+", "%20");
  102.             response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName);
  103.             try (OutputStream os = response.getOutputStream()) {
  104.                 workbook.write(os);
  105.                 os.flush();
  106.             }
  107.         } catch (Exception e) {
  108.             throw new RuntimeException("导出Excel失败", e);
  109.         }
  110.     }
  111.     /**
  112.      * 设置工作表样式
  113.      */
  114.     private void setSheetStyle(Sheet sheet) {
  115.         for (int i = 0; i < excelColumns.size(); i++) {
  116.             sheet.setColumnWidth(i, excelColumns.get(i).getWidth() * 256);
  117.         }
  118.     }
  119.     /**
  120.      * 创建表头
  121.      */
  122.     private void createHeader(Row headerRow) {
  123.         CellStyle headerStyle = headerRow.getSheet().getWorkbook().createCellStyle();
  124.         Font headerFont = headerRow.getSheet().getWorkbook().createFont();
  125.         headerFont.setBold(true);
  126.         headerStyle.setFont(headerFont);
  127.         headerStyle.setAlignment(HorizontalAlignment.CENTER);
  128.         for (int i = 0; i < excelColumns.size(); i++) {
  129.             Cell cell = headerRow.createCell(i);
  130.             cell.setCellValue(excelColumns.get(i).getHeader());
  131.             cell.setCellStyle(headerStyle);
  132.         }
  133.     }
  134.     /**
  135.      * 填充数据行
  136.      */
  137.     private void fillDataRow(Row dataRow, T obj) throws Exception {
  138.         for (int i = 0; i < excelColumns.size(); i++) {
  139.             ExcelColumn column = excelColumns.get(i);
  140.             Field field = column.getField();
  141.             field.setAccessible(true);
  142.             Cell cell = dataRow.createCell(i);
  143.             Object value = field.get(obj);
  144.             if (value == null) {
  145.                 cell.setCellValue("");
  146.                 continue;
  147.             }
  148.             // 处理日期类型
  149.             if (value instanceof Date && !column.getDateFormat().isEmpty()) {
  150.                 CellStyle style = dataRow.getSheet().getWorkbook().createCellStyle();
  151.                 DataFormat format = dataRow.getSheet().getWorkbook().createDataFormat();
  152.                 style.setDataFormat(format.getFormat(column.getDateFormat()));
  153.                 cell.setCellStyle(style);
  154.                 cell.setCellValue((Date) value);
  155.                 continue;
  156.             }
  157.             // 处理基本类型
  158.             cell.setCellValue(value.toString());
  159.         }
  160.     }
  161.     // ExcelColumn类定义
  162.     public static class ExcelColumn {
  163.         private Field field;
  164.         private String header;
  165.         private int width;
  166.         private String dateFormat;
  167.         // getters/setters
  168.         public Field getField() {
  169.             return field;
  170.         }
  171.         public void setField(Field field) {
  172.             this.field = field;
  173.         }
  174.         public String getHeader() {
  175.             return header;
  176.         }
  177.         public void setHeader(String header) {
  178.             this.header = header;
  179.         }
  180.         public int getWidth() {
  181.             return width;
  182.         }
  183.         public void setWidth(int width) {
  184.             this.width = width;
  185.         }
  186.         public String getDateFormat() {
  187.             return dateFormat;
  188.         }
  189.         public void setDateFormat(String dateFormat) {
  190.             this.dateFormat = dateFormat;
  191.         }
  192.     }
  193. }
复制代码
在这个工具类中,getFilteredColumns 方法用于获取过滤后的列,hasExportPermission 方法用于检查当前用户是否有权限导出该字段,exportExcel 方法用于将数据导出到 Excel 文件中。
3.3 在 JiheHandledRate 实体类中添加注解

在 JiheHandledRate 实体类中,我们在需要导出和进行角色控制的字段上添加了 RoleExcel 注解。以下是 JiheHandledRate 实体类的部分代码示例:
  1. package com.sdhs.jihe.domain;
  2. import com.sdhs.common.annotation.RoleExcel;
  3. import com.sdhs.common.utils.CalculationUtils;
  4. import lombok.Data;
  5. import static com.sdhs.common.utils.CalculationUtils.divide;
  6. import static com.sdhs.common.utils.CalculationUtils.multiplyAndRound;
  7. @Data
  8. public class JiheHandledRate {
  9.     private static final long serialVersionUID = 1L;
  10.     /**
  11.      * 运管中心名称
  12.      */
  13.     @RoleExcel(name = "运管中心名称", allowAll = true)
  14.     private String ygcentername;
  15.     /**
  16.      * 总数量
  17.      */
  18.     @RoleExcel(name = "线索总数量", allowAll = true)
  19.     private Long totalCount;
  20. package com.sdhs.jihe.domain;
  21. import com.sdhs.common.annotation.RoleExcel;
  22. import com.sdhs.common.utils.CalculationUtils;
  23. import lombok.Data;
  24. import static com.sdhs.common.utils.CalculationUtils.divide;
  25. import static com.sdhs.common.utils.CalculationUtils.multiplyAndRound;
  26. @Data
  27. public class JiheHandledRate {
  28.     private static final long serialVersionUID = 1L;
  29.     /**
  30.      * 运管中心名称
  31.      */
  32.     @RoleExcel(name = "运管中心名称", allowAll = true)
  33.     private String ygcentername;
  34.     /**
  35.      * 总数量
  36.      */
  37.     @RoleExcel(name = "线索总数量", allowAll = true)
  38.     private Long totalCount;
  39.     /**
  40.      * 已处理数量
  41.      */
  42.     @RoleExcel(name = "已确认线索数量", allowAll = true)
  43.     private Long handledCount;
  44.     /**
  45.      * 待处理数量
  46.      */
  47.     @RoleExcel(name = "待确认线索数量", allowAll = true)
  48.     private Long unhandledCount;
  49.     /**
  50.      * 处理数量占比 描述
  51.      */
  52.     @RoleExcel(name = "线索确认占比", allowAll = true)
  53.     private String handledPercentDesc;
  54.     /**
  55.      * 工单发起数量
  56.      */
  57.     @RoleExcel(name = "工单发起数量", roles = {"internalAuditRole", "admin"})
  58.     private Long ticketCount;
  59.     /**
  60.      * 工单发起数量占比 描述
  61.      */
  62.     @RoleExcel(name = "工单发起数量占比", roles = {"internalAuditRole", "admin"})
  63.     private String ticketPercentDesc;
  64.     /**
  65.      * 应追缴金额
  66.      */
  67.     @RoleExcel(name = "工单合计漏征金额(元)", roles = {"internalAuditRole", "admin"})
  68.     private double owefeeYuan;
  69.     // 其他字段...
  70. }
复制代码
3.4 在 JiheStationCommonController 中调用导出方法

最后,在 JiheStationCommonController 的 exportHandledRate 方法中,我们调用了 RoleExcelUtil 工具类的 exportExcel 方法,完成数据的导出操作。以下是 exportHandledRate 方法的代码实现:
  1. /**
  2. * 导出处理率
  3. */
  4. @Log(title = "导出处理率", businessType = BusinessType.EXPORT)
  5. @PostMapping("/exportHandledRate")
  6. public void exportHandledRate(HttpServletResponse response, JiheStationCommon jiheStationCommon) {
  7.     //jiheStationCommon.setIsabnormal(2);
  8.     jiheStationCommon.setCurrentstatus("abnormal");
  9.     jiheStationCommon.setTicketcodeFlag(2);
  10.     List<JiheHandledRate> list = jiheStationCommonService.statisticHandledRate(jiheStationCommon);
  11.     RoleExcelUtil<JiheHandledRate> util = new RoleExcelUtil<>(JiheHandledRate.class);
  12.     util.exportExcel(response, list, "稽核车辆明细数据");
  13. }
复制代码
四、总结

通过自定义 RoleExcel 注解和 RoleExcelUtil 导出工具类,我们成功实现了在若依框架中按角色控制 Excel 字段导出的功能。这种实现方式不仅满足了业务需求,还具有良好的扩展性和可维护性。在实际项目中,我们可以根据具体需求对注解和工具类进行进一步的扩展和优化,以适应更多复杂的业务场景。
希望本文对大家在实现类似功能时有所帮助,如果你在实现过程中遇到任何问题,欢迎在评论区留言交流。

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册