Pārlūkot izejas kodu

Excel导出子对象支持多个字段

RuoYi 5 gadi atpakaļ
vecāks
revīzija
d76c57a691

+ 1 - 1
ruoyi-common/src/main/java/com/ruoyi/common/annotation/Excel.java

@@ -17,7 +17,7 @@ public @interface Excel
     /**
      * 导出到Excel中的名字.
      */
-    public String name();
+    public String name() default "";
 
     /**
      * 日期格式, 如: yyyy-MM-dd

+ 18 - 0
ruoyi-common/src/main/java/com/ruoyi/common/annotation/Excels.java

@@ -0,0 +1,18 @@
+package com.ruoyi.common.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Excel注解集
+ * 
+ * @author ruoyi
+ */
+@Target(ElementType.FIELD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Excels
+{
+    Excel[] value();
+}

+ 202 - 131
ruoyi-common/src/main/java/com/ruoyi/common/utils/poi/ExcelUtil.java

@@ -1,7 +1,47 @@
 package com.ruoyi.common.utils.poi;
 
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.math.BigDecimal;
+import java.text.DecimalFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+import org.apache.poi.hssf.usermodel.HSSFDateUtil;
+import org.apache.poi.hssf.usermodel.HSSFFont;
+import org.apache.poi.hssf.util.HSSFColor.HSSFColorPredefined;
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.CellStyle;
+import org.apache.poi.ss.usermodel.CellType;
+import org.apache.poi.ss.usermodel.DataValidation;
+import org.apache.poi.ss.usermodel.DataValidationConstraint;
+import org.apache.poi.ss.usermodel.DataValidationHelper;
+import org.apache.poi.ss.usermodel.DateUtil;
+import org.apache.poi.ss.usermodel.FillPatternType;
+import org.apache.poi.ss.usermodel.Font;
+import org.apache.poi.ss.usermodel.HorizontalAlignment;
+import org.apache.poi.ss.usermodel.Row;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.usermodel.VerticalAlignment;
+import org.apache.poi.ss.usermodel.Workbook;
+import org.apache.poi.ss.usermodel.WorkbookFactory;
+import org.apache.poi.ss.util.CellRangeAddressList;
+import org.apache.poi.xssf.streaming.SXSSFWorkbook;
+import org.apache.poi.xssf.usermodel.XSSFDataValidation;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import com.ruoyi.common.annotation.Excel;
 import com.ruoyi.common.annotation.Excel.Type;
+import com.ruoyi.common.annotation.Excels;
 import com.ruoyi.common.config.Global;
 import com.ruoyi.common.core.domain.AjaxResult;
 import com.ruoyi.common.core.text.Convert;
@@ -9,25 +49,10 @@ import com.ruoyi.common.exception.BusinessException;
 import com.ruoyi.common.utils.DateUtils;
 import com.ruoyi.common.utils.StringUtils;
 import com.ruoyi.common.utils.reflect.ReflectUtils;
-import org.apache.poi.hssf.usermodel.HSSFDateUtil;
-import org.apache.poi.hssf.usermodel.HSSFFont;
-import org.apache.poi.hssf.util.HSSFColor.HSSFColorPredefined;
-import org.apache.poi.ss.usermodel.*;
-import org.apache.poi.ss.util.CellRangeAddressList;
-import org.apache.poi.xssf.streaming.SXSSFWorkbook;
-import org.apache.poi.xssf.usermodel.XSSFDataValidation;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import java.io.*;
-import java.lang.reflect.Field;
-import java.lang.reflect.Method;
-import java.math.BigDecimal;
-import java.text.DecimalFormat;
-import java.util.*;
 
 /**
  * Excel相关处理
- *
+ * 
  * @author ruoyi
  */
 public class ExcelUtil<T>
@@ -94,7 +119,7 @@ public class ExcelUtil<T>
 
     /**
      * 对excel表单默认第一个索引名转换成list
-     *
+     * 
      * @param input 输入流
      * @return 转换后集合
      */
@@ -105,7 +130,7 @@ public class ExcelUtil<T>
 
     /**
      * 对excel表单指定表格索引名转换成list
-     *
+     * 
      * @param sheetName 表格索引名
      * @param input 输入流
      * @return 转换后集合
@@ -153,7 +178,6 @@ public class ExcelUtil<T>
                     cellMap.put(null, i);
                 }
             }
-
             // 有数据时才处理 得到类的所有field.
             Field[] allFields = clazz.getDeclaredFields();
             // 定义一个map用于存放列的序号和field.
@@ -251,7 +275,7 @@ public class ExcelUtil<T>
 
     /**
      * 对list数据源将其里面的数据导入到excel表单
-     *
+     * 
      * @param list 导出数据集合
      * @param sheetName 工作表的名称
      * @return 结果
@@ -264,7 +288,7 @@ public class ExcelUtil<T>
 
     /**
      * 对list数据源将其里面的数据导入到excel表单
-     *
+     * 
      * @param sheetName 工作表的名称
      * @return 结果
      */
@@ -276,7 +300,7 @@ public class ExcelUtil<T>
 
     /**
      * 对list数据源将其里面的数据导入到excel表单
-     *
+     * 
      * @return 结果
      */
     public AjaxResult exportExcel()
@@ -289,65 +313,31 @@ public class ExcelUtil<T>
             for (int index = 0; index <= sheetNo; index++)
             {
                 createSheet(sheetNo, index);
-                Cell cell = null; // 产生单元格
 
                 // 产生一行
                 Row row = sheet.createRow(0);
+                int excelsNo = 0;
                 // 写入各个字段的列头名称
-                for (int i = 0; i < fields.size(); i++)
+                for (int column = 0; column < fields.size(); column++)
                 {
-                    Field field = fields.get(i);
-                    Excel attr = field.getAnnotation(Excel.class);
-                    // 创建列
-                    cell = row.createCell(i);
-                    // 设置列中写入内容为String类型
-                    cell.setCellType(CellType.STRING);
-                    CellStyle cellStyle = wb.createCellStyle();
-                    cellStyle.setAlignment(HorizontalAlignment.CENTER);
-                    cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
-                    if (attr.name().indexOf("注:") >= 0)
+                    Field field = fields.get(column);
+                    if (field.isAnnotationPresent(Excel.class))
                     {
-                        Font font = wb.createFont();
-                        font.setColor(HSSFFont.COLOR_RED);
-                        cellStyle.setFont(font);
-                        cellStyle.setFillForegroundColor(HSSFColorPredefined.YELLOW.getIndex());
-                        sheet.setColumnWidth(i, 6000);
+                        Excel excel = field.getAnnotation(Excel.class);
+                        createCell(excel, row, column);
                     }
-                    else
+                    if (field.isAnnotationPresent(Excels.class))
                     {
-                        Font font = wb.createFont();
-                        // 粗体显示
-                        font.setBold(true);
-                        // 选择需要用到的字体格式
-                        cellStyle.setFont(font);
-                        cellStyle.setFillForegroundColor(HSSFColorPredefined.LIGHT_YELLOW.getIndex());
-                        // 设置列宽
-                        sheet.setColumnWidth(i, (int) ((attr.width() + 0.72) * 256));
-                        row.setHeight((short) (attr.height() * 20));
-                    }
-                    cellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
-                    cellStyle.setWrapText(true);
-                    cell.setCellStyle(cellStyle);
-
-                    // 写入列名
-                    cell.setCellValue(attr.name());
-
-                    // 如果设置了提示信息则鼠标放上去提示.
-                    if (StringUtils.isNotEmpty(attr.prompt()))
-                    {
-                        // 这里默认设了2-101列提示.
-                        setXSSFPrompt(sheet, "", attr.prompt(), 1, 100, i, i);
-                    }
-                    // 如果设置了combo属性则本列只能选择不能输入
-                    if (attr.combo().length > 0)
-                    {
-                        // 这里默认设了2-101列只能选择不能输入.
-                        setXSSFValidation(sheet, attr.combo(), 1, 100, i, i);
+                        Excels attrs = field.getAnnotation(Excels.class);
+                        Excel[] excels = attrs.value();
+                        // 写入列名
+                        Excel excel = excels[excelsNo++];
+                        createCell(excel, row, column);
                     }
                 }
                 if (Type.EXPORT.equals(type))
                 {
-                    fillExcelData(index, row, cell);
+                    fillExcelData(index, row);
                 }
             }
             String filename = encodingFilename(sheetName);
@@ -389,12 +379,12 @@ public class ExcelUtil<T>
 
     /**
      * 填充excel数据
-     *
+     * 
      * @param index 序号
      * @param row 单元格行
      * @param cell 类型单元格
      */
-    public void fillExcelData(int index, Row row, Cell cell)
+    public void fillExcelData(int index, Row row)
     {
         int startNo = index * sheetSize;
         int endNo = Math.min(startNo + sheetSize, list.size());
@@ -407,56 +397,131 @@ public class ExcelUtil<T>
             row = sheet.createRow(i + 1 - startNo);
             // 得到导出对象.
             T vo = (T) list.get(i);
-            for (int j = 0; j < fields.size(); j++)
+            int excelsNo = 0;
+            for (int column = 0; column < fields.size(); column++)
             {
                 // 获得field.
-                Field field = fields.get(j);
+                Field field = fields.get(column);
                 // 设置实体类私有属性可访问
                 field.setAccessible(true);
-                Excel attr = field.getAnnotation(Excel.class);
-                try
+                if (field.isAnnotationPresent(Excel.class))
                 {
-                    // 设置行高
-                    row.setHeight((short) (attr.height() * 20));
-                    // 根据Excel中设置情况决定是否导出,有些情况需要保持为空,希望用户填写这一列.
-                    if (attr.isExport())
-                    {
-                        // 创建cell
-                        cell = row.createCell(j);
-                        cell.setCellStyle(cs);
-                        if (vo == null)
-                        {
-                            // 如果数据存在就填入,不存在填入空格.
-                            cell.setCellValue("");
-                            continue;
-                        }
+                    addCell(field.getAnnotation(Excel.class), row, vo, field, column, cs);
+                }
+                if (field.isAnnotationPresent(Excels.class))
+                {
+                    Excels attrs = field.getAnnotation(Excels.class);
+                    Excel[] excels = attrs.value();
+                    Excel excel = excels[excelsNo++];
+                    addCell(excel, row, vo, field, column, cs);
+                }
+            }
+        }
+    }
 
-                        // 用于读取对象中的属性
-                        Object value = getTargetValue(vo, field, attr);
-                        String dateFormat = attr.dateFormat();
-                        String readConverterExp = attr.readConverterExp();
-                        if (StringUtils.isNotEmpty(dateFormat) && StringUtils.isNotNull(value))
-                        {
-                            cell.setCellValue(DateUtils.parseDateToStr(dateFormat, (Date) value));
-                        }
-                        else if (StringUtils.isNotEmpty(readConverterExp) && StringUtils.isNotNull(value))
-                        {
-                            cell.setCellValue(convertByExp(String.valueOf(value), readConverterExp));
-                        }
-                        else
-                        {
-                            cell.setCellType(CellType.STRING);
-                            // 如果数据存在就填入,不存在填入空格.
-                            cell.setCellValue(StringUtils.isNull(value) ? attr.defaultValue() : value + attr.suffix());
-                        }
-                    }
+    /**
+     * 创建单元格
+     */
+    public Cell createCell(Excel attr, Row row, int column)
+    {
+        // 创建列
+        Cell cell = row.createCell(column);
+        // 设置列中写入内容为String类型
+        cell.setCellType(CellType.STRING);
+        // 写入列名
+        cell.setCellValue(attr.name());
+        CellStyle cellStyle = createStyle(attr, row, column);
+        cell.setCellStyle(cellStyle);
+        return cell;
+    }
+
+    /**
+     * 创建表格样式
+     */
+    public CellStyle createStyle(Excel attr, Row row, int column)
+    {
+        CellStyle cellStyle = wb.createCellStyle();
+        cellStyle.setAlignment(HorizontalAlignment.CENTER);
+        cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
+        if (attr.name().indexOf("注:") >= 0)
+        {
+            Font font = wb.createFont();
+            font.setColor(HSSFFont.COLOR_RED);
+            cellStyle.setFont(font);
+            cellStyle.setFillForegroundColor(HSSFColorPredefined.YELLOW.getIndex());
+            sheet.setColumnWidth(column, 6000);
+        }
+        else
+        {
+            Font font = wb.createFont();
+            // 粗体显示
+            font.setBold(true);
+            // 选择需要用到的字体格式
+            cellStyle.setFont(font);
+            cellStyle.setFillForegroundColor(HSSFColorPredefined.LIGHT_YELLOW.getIndex());
+            // 设置列宽
+            sheet.setColumnWidth(column, (int) ((attr.width() + 0.72) * 256));
+            row.setHeight((short) (attr.height() * 20));
+        }
+        cellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
+        cellStyle.setWrapText(true);
+        // 如果设置了提示信息则鼠标放上去提示.
+        if (StringUtils.isNotEmpty(attr.prompt()))
+        {
+            // 这里默认设了2-101列提示.
+            setXSSFPrompt(sheet, "", attr.prompt(), 1, 100, column, column);
+        }
+        // 如果设置了combo属性则本列只能选择不能输入
+        if (attr.combo().length > 0)
+        {
+            // 这里默认设了2-101列只能选择不能输入.
+            setXSSFValidation(sheet, attr.combo(), 1, 100, column, column);
+        }
+        return cellStyle;
+    }
+
+    /**
+     * 添加单元格
+     */
+    public Cell addCell(Excel attr, Row row, T vo, Field field, int column, CellStyle cs)
+    {
+        Cell cell = null;
+        try
+        {
+            // 设置行高
+            row.setHeight((short) (attr.height() * 20));
+            // 根据Excel中设置情况决定是否导出,有些情况需要保持为空,希望用户填写这一列.
+            if (attr.isExport())
+            {
+                // 创建cell
+                cell = row.createCell(column);
+                cell.setCellStyle(cs);
+
+                // 用于读取对象中的属性
+                Object value = getTargetValue(vo, field, attr);
+                String dateFormat = attr.dateFormat();
+                String readConverterExp = attr.readConverterExp();
+                if (StringUtils.isNotEmpty(dateFormat) && StringUtils.isNotNull(value))
+                {
+                    cell.setCellValue(DateUtils.parseDateToStr(dateFormat, (Date) value));
                 }
-                catch (Exception e)
+                else if (StringUtils.isNotEmpty(readConverterExp) && StringUtils.isNotNull(value))
                 {
-                    log.error("导出Excel失败{}", e);
+                    cell.setCellValue(convertByExp(String.valueOf(value), readConverterExp));
+                }
+                else
+                {
+                    cell.setCellType(CellType.STRING);
+                    // 如果数据存在就填入,不存在填入空格.
+                    cell.setCellValue(StringUtils.isNull(value) ? attr.defaultValue() : value + attr.suffix());
                 }
             }
         }
+        catch (Exception e)
+        {
+            log.error("导出Excel失败{}", e);
+        }
+        return cell;
     }
 
     /**
@@ -484,7 +549,7 @@ public class ExcelUtil<T>
 
     /**
      * 设置某些列的值只能输入预制的数据,显示下拉框.
-     *
+     * 
      * @param sheet 要设置的sheet.
      * @param textlist 下拉框显示的内容
      * @param firstRow 开始行
@@ -518,7 +583,7 @@ public class ExcelUtil<T>
 
     /**
      * 解析导出值 0=男,1=女,2=未知
-     *
+     * 
      * @param propertyValue 参数值
      * @param converterExp 翻译注解
      * @return 解析后值
@@ -547,7 +612,7 @@ public class ExcelUtil<T>
 
     /**
      * 反向解析值 男=0,女=1,未知=2
-     *
+     * 
      * @param propertyValue 参数值
      * @param converterExp 翻译注解
      * @return 解析后值
@@ -585,7 +650,7 @@ public class ExcelUtil<T>
 
     /**
      * 获取下载路径
-     *
+     * 
      * @param filename 文件名称
      */
     public String getAbsoluteFile(String filename)
@@ -601,7 +666,7 @@ public class ExcelUtil<T>
 
     /**
      * 获取bean中的属性值
-     *
+     * 
      * @param vo 实体对象
      * @param field 字段
      * @param excel 注解
@@ -632,7 +697,7 @@ public class ExcelUtil<T>
 
     /**
      * 以类的属性的get方法方法形式获取值
-     *
+     * 
      * @param o
      * @param name
      * @return value
@@ -657,31 +722,37 @@ public class ExcelUtil<T>
     {
         this.fields = new ArrayList<Field>();
         List<Field> tempFields = new ArrayList<>();
-        Class<?> tempClass = clazz;
+        tempFields.addAll(Arrays.asList(clazz.getSuperclass().getDeclaredFields()));
         tempFields.addAll(Arrays.asList(clazz.getDeclaredFields()));
-        while (tempClass != null)
+        for (Field field : tempFields)
         {
-            tempClass = tempClass.getSuperclass();
-            if (tempClass != null)
+            // 单注解
+            if (field.isAnnotationPresent(Excel.class))
             {
-                tempFields.addAll(Arrays.asList(tempClass.getDeclaredFields()));
+                putToField(field, field.getAnnotation(Excel.class));
+            }
+
+            // 多注解
+            if (field.isAnnotationPresent(Excels.class))
+            {
+                Excels attrs = field.getAnnotation(Excels.class);
+                Excel[] excels = attrs.value();
+                for (Excel excel : excels)
+                {
+                    putToField(field, excel);
+                }
             }
         }
-        putToFields(tempFields);
     }
 
     /**
      * 放到字段集合中
      */
-    private void putToFields(List<Field> fields)
+    private void putToField(Field field, Excel attr)
     {
-        for (Field field : fields)
+        if (attr != null && (attr.type() == Type.ALL || attr.type() == type))
         {
-            Excel attr = field.getAnnotation(Excel.class);
-            if (attr != null && (attr.type() == Type.ALL || attr.type() == type))
-            {
-                this.fields.add(field);
-            }
+            this.fields.add(field);
         }
     }
 
@@ -695,7 +766,7 @@ public class ExcelUtil<T>
 
     /**
      * 创建工作表
-     *
+     * 
      * @param sheetName,指定Sheet名称
      * @param sheetNo sheet数量
      * @param index 序号
@@ -716,7 +787,7 @@ public class ExcelUtil<T>
 
     /**
      * 获取单元格值
-     *
+     * 
      * @param row 获取的行
      * @param column 获取单元格列号
      * @return 单元格值

+ 9 - 5
ruoyi-system/src/main/java/com/ruoyi/system/domain/SysUser.java

@@ -1,12 +1,13 @@
 package com.ruoyi.system.domain;
 
+import java.util.Date;
+import java.util.List;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
 import com.ruoyi.common.annotation.Excel;
 import com.ruoyi.common.annotation.Excel.Type;
+import com.ruoyi.common.annotation.Excels;
 import com.ruoyi.common.core.domain.BaseEntity;
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
-import java.util.Date;
-import java.util.List;
 
 /**
  * 用户对象 sys_user
@@ -76,7 +77,10 @@ public class SysUser extends BaseEntity
     private Date loginDate;
 
     /** 部门对象 */
-    @Excel(name = "部门名称", targetAttr = "deptName", type = Type.EXPORT)
+    @Excels({
+        @Excel(name = "部门名称", targetAttr = "deptName", type = Type.EXPORT),
+        @Excel(name = "部门负责人", targetAttr = "leader", type = Type.EXPORT)
+    })
     private SysDept dept;
 
     private List<SysRole> roles;

+ 3 - 2
ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml

@@ -33,6 +33,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 		<result property="parentId" column="parent_id"   />
 		<result property="deptName" column="dept_name"   />
 		<result property="orderNum" column="order_num"   />
+		<result property="leader"   column="leader"      />
 		<result property="status"   column="dept_status" />
 	</resultMap>
 	
@@ -47,7 +48,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 	
 	<sql id="selectUserVo">
         select  u.user_id, u.dept_id, u.login_name, u.user_name, u.email, u.phonenumber, u.sex, u.avatar, u.password, u.salt, u.status, u.del_flag, u.login_ip, u.login_date, u.create_time, u.remark,
-       		    d.dept_id, d.parent_id, d.dept_name, d.order_num, d.status as dept_status,
+       		    d.dept_id, d.parent_id, d.dept_name, d.order_num, d.leader, d.status as dept_status,
        		    r.role_id, r.role_name, r.role_key, r.role_sort, r.data_scope, r.status as role_status
 		from sys_user u
 			 left join sys_dept d on u.dept_id = d.dept_id
@@ -56,7 +57,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
     </sql>
 	
 	<select id="selectUserList" parameterType="SysUser" resultMap="SysUserResult">
-		select u.user_id, u.dept_id, u.login_name, u.user_name, u.email, u.phonenumber, u.password, u.sex, u.avatar, u.salt, u.status, u.del_flag, u.login_ip, u.login_date, u.create_by, u.create_time, u.remark, d.dept_name from sys_user u
+		select u.user_id, u.dept_id, u.login_name, u.user_name, u.email, u.phonenumber, u.password, u.sex, u.avatar, u.salt, u.status, u.del_flag, u.login_ip, u.login_date, u.create_by, u.create_time, u.remark, d.dept_name, d.leader from sys_user u
 		left join sys_dept d on u.dept_id = d.dept_id
 		where u.del_flag = '0'
 		<if test="loginName != null and loginName != ''">