この記事では、フロントエンドに表示されたデータをスプリングブートでEXCELテーブルファイルにエクスポートする方法を紹介します。この方法はRuoyiRuoyiによるものです。
コンテンツ
2.3 exportExcel(リストリスト、文字列sheetName)方法
2.3.2 creteExcelField()メソッドの呼び出し
エクスポート方法のロードマップ
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();
}
}
}
}