SpringbootはEXCElメソッドをエクスポートします(インスタンスによる場合)

この記事では、フロントエンドに表示されたデータをスプリングブートでEXCELテーブルファイルにエクスポートする方法を紹介します。この方法はRuoyiRuoyiによるものです。

コンテンツ

1.関連する構成

1.1構成の注釈

1.2フィールドを追加する

1.3注釈を追加する

2.Excelメソッドクラス

エクスポート方法のロードマップ

2.1変数フィールドを定義する

2.2コントローラーレイヤー

2.3 exportExcel(リストリスト、文字列sheetName)方法

2.3.1 initメソッド(初期化)

2.3.2 creteExcelField()メソッドの呼び出し

2.3.3 createWorkbook()

2.4 exportExcel()


エクスポート方法のロードマップ

1.関連する構成

1.1環境の紹介

        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml</artifactId>
        </dependency>

EXCELファイルにデータをエクスポートする場合、行の高さ、日付形式、エクスポートタイプなど、多くの構成があります。コードの再利用と機能の多様性を実現するには、さまざまなエンティティクラスに注釈メソッドを使用し、個々の構成にさまざまなデータタイプを使用する必要があります。 。

1.2構成の注釈

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Excel
{
   
   

@Rententionは、アノテーションがどのように維持されるか、つまりライフサイクルを定義するために使用されます

RetentionPolicy.SOURCE アノテーションはソースファイルにのみ保持され、Javaファイルがクラスファイルにコンパイルされると、アノテーションは破棄されます。
RetentionPolicy.CLASS アノテーションはクラスファイルに保持されますが、JVMがクラスファイルをロードするときに破棄されます。これはデフォルトのライフサイクルです。
RetentionPolicy.RUNTIME アノテーションはクラスファイルに保存されるだけでなく、JVMがクラスファイルをロードした後も存在します。

@Targetは、注釈の使用範囲を記述するために使用されます。記述された注釈を使用できる場合は、パラメーター

1.3フィールドを追加する

EXCELテーブルに必要な構成

例えば:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Excel
{
   
     /**
     * 导出时在excel中排序
     */
    public int sort() default Integer.MAX_VALUE;

    /**
     * 导出到Excel中的名字.
     */
    public String name() default "";

    /**
     * 日期格式, 如: yyyy-MM-dd
     */
    public String dateFormat() default "";

    /**
     * 如果是字典类型,请设置字典的type值 (如: sys_user_sex)
     */
    public String dictType() default "";

    /**
     * 读取内容转表达式 (如: 0=男,1=女,2=未知)
     */
    public String readConverterExp() default "";

    /**
     * 分隔符,读取字符串组内容
     */
    public String separator() default ",";

    /**
     * BigDecimal 精度 默认:-1(默认不开启BigDecimal格式化)
     */
    public int scale() default -1;

    /**
     * BigDecimal 舍入规则 默认:BigDecimal.ROUND_HALF_EVEN
     */
    public int roundingMode() default BigDecimal.ROUND_HALF_EVEN;

    /**
     * 导出类型(0数字 1字符串)
     */
    public ColumnType cellType() default ColumnType.STRING;

    /**
     * 导出时在excel中每个列的高度 单位为字符
     */
    public double height() default 14;

    /**
     * 导出时在excel中每个列的宽 单位为字符
     */
    public double width() default 16;

    /**
     * 文字后缀,如% 90 变成90%
     */
    public String suffix() default "";

    /**
     * 当值为空时,字段的默认值
     */
    public String defaultValue() default "";

    /**
     * 提示信息
     */
    public String prompt() default "";

    /**
     * 设置只能选择不能输入的列内容.
     */
    public String[] combo() default {};

    /**
     * 是否导出数据,应对需求:有时我们需要导出一份模板,这是标题需要但内容需要用户手工填写.
     */
    public boolean isExport() default true;

    /**
     * 另一个类中的属性名称,支持多级获取,以小数点隔开
     */
    public String targetAttr() default "";

    /**
     * 是否自动统计数据,在最后追加一行统计数据总和
     */
    public boolean isStatistics() default false;

    /**
     * 导出字段对齐方式(0:默认;1:靠左;2:居中;3:靠右)
     */
    Align align() default Align.AUTO;

    public enum Align
    {
        AUTO(0), LEFT(1), CENTER(2), RIGHT(3);
        private final int value;

        Align(int value)
        {
            this.value = value;
        }

        public int value()
        {
            return this.value;
        }
    }

    /**
     * 字段类型(0:导出导入;1:仅导出;2:仅导入)
     */
    Type type() default Type.ALL;

    public enum Type
    {
        ALL(0), EXPORT(1), IMPORT(2);
        private final int value;

        Type(int value)
        {
            this.value = value;
        }

        public int value()
        {
            return this.value;
        }
    }

    public enum ColumnType
    {
        NUMERIC(0), STRING(1), IMAGE(2);
        private final int value;

        ColumnType(int value)
        {
            this.value = value;
        }

        public int value()
        {
            return this.value;
        }
    }

具体的な構成は必要に応じて決定され、列挙型は後で使用方法を判断するために使用されます。

1.4注釈を追加する

次に、エクスポートする必要のあるエンティティクラスのフィールドに注釈を追加する必要があります

例えば:

    /** 订单编号 */
    @Excel(name = "订单编号")
    private String orderId;

    /** 客户编号 */
    @Excel(name = "客户编号")
    private Long customerId;

    /** 姓名 */
    @Excel(name = "姓名")
    private String Person;

    @JsonFormat(pattern = "yyyy-MM-dd")
    @Excel(name = "时间", width = 30, dateFormat = "yyyy-MM-dd")
    private Date Time;

2.Excelメソッドクラス

エクスポート方法のロードマップ

2.1変数フィールドを定義する

テーブルの全体的な構成をこのクラスに追加する必要があります

/**
 * Excel相关处理
 * 
 * @author ruoyi
 */
public class ExcelUtil<T>
{
    private static final Logger log = LoggerFactory.getLogger(ExcelUtil.class);

    /**
     * Excel sheet最大行数,默认65536
     */
    public static final int sheetSize = 65536;

    /**
     * 工作表名称
     */
    private String sheetName;

    /**
     * 导出类型(EXPORT:导出数据;IMPORT:导入模板)
     */
    private Type type;

    /**
     * 工作薄对象
     */
    private Workbook wb;

    /**
     * 工作表对象
     */
    private Sheet sheet;

    /**
     * 样式列表
     */
    private Map<String, CellStyle> styles;

    /**
     * 导入导出数据列表
     */
    private List<T> list;

    /**
     * 注解列表
     */
    private List<Object[]> fields;

    /**
     * 最大高度
     */
    private short maxHeight;

    /**
     * 统计列表
     */
    private Map<Integer, Double> statistics = new HashMap<Integer, Double>();
    
    /**
     * 数字格式
     */
    private static final DecimalFormat DOUBLE_FORMAT = new DecimalFormat("######0.00");
    
    /**
     * 实体对象
     */
    public Class<T> clazz;

    public ExcelUtil(Class<T> clazz)
    {
        this.clazz = clazz;
    }

ワークブックと給与の違い:

新しいExcelを作成すると、システムはデフォルトでワークブックになります。このワークシートには、通常、sheet1、sheet2、sheet3の3つのワークシートがあります。とても簡単です。ブックには最大255のワークシートを含めることができ、シートには最大65536行を含めることができます

2.2コントローラーレイヤー

コントローラレイヤーでは、最初にデータをクエリしてから、ExcelUtilを初期化し、メソッドを呼び出す必要があります

List<Order> list=service.selectOrder(ids);  

ExcelUtil<Order> util = new ExcelUtil<Order>(Order.class);
 
return util.exportExcel(list, "Excel数据表");

2.3 exportExcel(List <T> list、String sheetName)方法

exportExcel(List <T> list、String sheetName)メソッドに入ります

/**
     * 对list数据源将其里面的数据导入到excel表单
     * 
     * @param list 导出数据集合
     * @param sheetName 工作表的名称
     * @return 结果
     */
    public AjaxResult exportExcel(List<T> list, String sheetName)
    {
        this.init(list, sheetName, Type.EXPORT);
        return exportExcel();
    }

2.3.1 initメソッド(初期化)

ご覧のとおり、最初にinitメソッド(初期化)が呼び出され、Type.EXPORTがエクスポートデータとして渡されます。

public void init(List<T> list, String sheetName, Type type)
    {
        if (list == null)
        {
            list = new ArrayList<T>();
        }
        this.list = list;
        this.sheetName = sheetName;
        this.type = type;
        createExcelField();
        createWorkbook();
    }

ロジックは、必要なエクスポートされたデータとファイル名、およびエクスポートとインポートを区別するタイプを変数に割り当てることです。

2.3.2 creteExcelField()メソッドの呼び出し

全体的なコード

    /**
     * 得到所有定义字段
     */
    private void createExcelField()
    {   this.fields = new ArrayList<Object[]>();
        List<Field> tempFields = new ArrayList<>();
        tempFields.addAll(Arrays.asList(clazz.getSuperclass().getDeclaredFields()));
        tempFields.addAll(Arrays.asList(clazz.getDeclaredFields()));
        for (Field field : tempFields)
        {
            // 单注解
            if (field.isAnnotationPresent(Excel.class))
            {
                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);
                }
            }
        }
        this.fields = this.fields.stream().sorted(Comparator.comparing(objects -> ((Excel) objects[1]).sort())).collect(Collectors.toList());
        this.maxHeight = getRowHeight();
    }

行ごとの紹介

/**
         * fields字段定义为存储所有注解的字段,为Object[]的数组
         * */
        this.fields = new ArrayList<Object[]>();

        List<Field> tempFields = new ArrayList<>();
/**
 * clazz字段存储的是实体类字段
* clazz.getSuperclass()为得到实体类的父类方法
* getDeclaredFields()为反射中的方法,获得某个类的所有声明的字段,即包括public,private            
* 和proteced,
* 但是不包括父类的申明字段,所以先获取了父类的声明字段,再获取当前类的声明字段
*
* Array.List()是将数组转化成List集合的方法,用此方法得到的List的长度是不可改变的,
*/

tempFields.addAll(Arrays.asList(clazz.getSuperclass().getDeclaredFields()));
tempFields.addAll(Arrays.asList(clazz.getDeclaredFields()));
 /**
         *遍历得到的所有字段
         */
        for (Field field : tempFields)
        {
            // 单注解
            /**
             * isAnnotationPresent() 判断该字段是否标注该注解
             */
            if (field.isAnnotationPresent(Excel.class))
            {
                /**
                 * 如果标注有@Excel注解,则调用该方法
                 */
                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);
                }
            }
        }
  /**
         * 根据注解中定义的顺序int大小来排序,默认为Integer.MAX_VALUE;
         */
        this.fields = this.fields.stream().sorted(Comparator.comparing(objects -> ((Excel) objects[1]).sort())).collect(Collectors.toList());

        this.maxHeight = getRowHeight();

putToField()メソッドを呼び出します 

fileds <Object []>に、Object [0]がフィールドで、Object [1]がアノテーションパラメータである場合、ループによって取得されたフィールドとアノテーションパラメータの合計を入力します。

/**
     * 放到字段集合中
     */
    private void putToField(Field field, Excel attr)
    {
        if (attr != null && (attr.type() == Type.ALL || attr.type() == type))
        {
            this.fields.add(new Object[] { field, attr });
        }
    }

およびgetRowHeight()メソッド

アノテーションパラメータの高さの値を1つずつ比較し、最大値を最終的な行の高さとして使用します

 /**
     * 根据注解获取最大行高
     */
    public short getRowHeight()
    {
        double maxHeight = 0;
        for (Object[] os : this.fields)
        {
            Excel excel = (Excel) os[1];
            maxHeight = maxHeight > excel.height() ? maxHeight : excel.height();
        }
        return (short) (maxHeight * 20);
    }

2.3.3 createWorkbook()

intiメソッドの最後のステップであるcreateWorkbook()メソッドを呼び出します

  /**
     * 创建一个工作簿
     */
    public void createWorkbook()
    {
        this.wb = new SXSSFWorkbook(500);
    }

2.4 exportExcel()

ロードマップを見る

initメソッドを呼び出した後、パラメーターなしでexportExcelメソッドを呼び出します

    /**
     * 对list数据源将其里面的数据导入到excel表单
     *
     * @return 结果
     */
    public AjaxResult exportExcel()
    {
        OutputStream out = null;
        try
        {
            // 取出一共有多少个sheet.
            double sheetNo = Math.ceil(list.size() / sheetSize);
            for (int index = 0; index <= sheetNo; index++)
            {
                createSheet(sheetNo, index);

                // 产生一行
                Row row = sheet.createRow(0);
                int column = 0;
                // 写入各个字段的列头名称
                for (Object[] os : fields)
                {
                    Excel excel = (Excel) os[1];
                    this.createCell(excel, row, column++);
                }
                if (Type.EXPORT.equals(type))
                {
                    fillExcelData(index, row);
                    addStatisticsRow();
                }
            }
            String filename = encodingFilename(sheetName);
            out = new FileOutputStream(getAbsoluteFile(filename));
            wb.write(out);
            return AjaxResult.success(filename);
        }
        catch (Exception e)
        {
            log.error("导出Excel异常{}", e.getMessage());
            throw new CustomException("导出Excel失败,请联系网站管理员!");
        }
        finally
        {
            if (wb != null)
            {
                try
                {
                    wb.close();
                }
                catch (IOException e1)
                {
                    e1.printStackTrace();
                }
            }
            if (out != null)
            {
                try
                {
                    out.close();
                }
                catch (IOException e1)
                {
                    e1.printStackTrace();
                }
            }
        }
    }

おすすめ

転載: blog.csdn.net/xsj5211314/article/details/123917816