利用注解和反射,实现Excel通用导出
注解
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface ExcelAnnotation {
String filedName();
}
导入入参类
在类中属性上方加上先前自定义的注解,标识该列为可导出列,注解中的属性即为导出后的列名
import lombok.Data;
import java.util.Date;
/**
* @ClassName ExportExcelDto
* @Author zhang jie
* @Date 2021/9/22 16:42
* @Version 1.0
*/
@Data
public class ImportExcelVo{
@ExcelAnnotation(filedName = "序号")
@ApiModelProperty("序号")
private Integer sequenceNumber;
@ExcelAnnotation(filedName = "题库")
@ApiModelProperty("所属题库名称")
private String examName;
@ExcelAnnotation(filedName = "内容")
@ApiModelProperty("内容")
private String content;
@ExcelAnnotation(filedName = "评分规则")
@ApiModelProperty("评分规则")
private String scoringRule;
@ExcelAnnotation(filedName = "权重")
@ApiModelProperty("权重")
private Integer weight;
@ExcelAnnotation(filedName = "单位")
@ApiModelProperty("单位")
private String grpname;
@ExcelAnnotation(filedName = "是否需要提交材料")
@ApiModelProperty("是否允许上传材料 中文")
private String upload;
@ApiModelProperty("操作用户ID")
private String operationUserId;
@ApiModelProperty("创建时间")
private Date createTime;
@ApiModelProperty("修改时间")
private Date updateTime;
}
导入工具类
利用反射获取传入类的所有类名以及类上方所添加的注解,把数据读取出来之后存到list里然后返回
package cn.bywin.assess.base.util;
import cn.bywin.assess.base.annotation.ExcelAnnotation;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import java.io.File;
import java.io.FileInputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.*;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.Row;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.multipart.MultipartFile;
/**
* @ClassName ImportExcelUtil
* @Author zhang jie
* @Date 2021/8/27 16:01
* @Version 1.0
*/
public class ImportExcelUtil<T> {
Class<T> clazz;
public ImportExcelUtil(Class<T> clazz) {
this.clazz = clazz;
}
public Collection<T> importExcel(MultipartFile file , String... pattern) {
Collection<T> dist = new ArrayList<>();
try {
/*
* 类反射得到调用方法
*/
// 得到目标目标类的所有的字段列表
Field[] filed = clazz.getDeclaredFields();
// 将所有标有Annotation的字段,也就是允许导入数据的字段,放入到一个map中
HashMap<String,Object> map = new HashMap<>();
// 循环读取所有字段
for (Field f : filed) {
// 得到单个字段上的Annotation
ExcelAnnotation exa = f.getAnnotation(ExcelAnnotation.class);
// 如果标识了Annotation的话
if (exa != null) {
// 构造设置了Annotation的字段的Setter方法
String fieldName = f.getName();
String setMethodName = "set"
+ fieldName.substring(0, 1).toUpperCase()
+ fieldName.substring(1);
// 构造调用的method,
Method setMethod = clazz.getMethod(setMethodName,
f.getType());
// 将这个method以Annotation的名字为key来存入。
map.put(exa.filedName(), setMethod);
}
}
/*
* excel的解析开始
*/
// 将传入的File构造为 FileInputStream;
File f = new File(Objects.requireNonNull(file.getOriginalFilename()));
FileCopyUtils.copy(file.getBytes(),f);
FileInputStream in = new FileInputStream(f);
// 得到工作表
HSSFWorkbook book = new HSSFWorkbook(in);
// 得到第一页
HSSFSheet sheet = book.getSheetAt(0);
// 得到第一面的所有行
Iterator<Row> row = sheet.rowIterator();
/*
* 标题解析
*/
// 得到第一行,也就是标题行
Row title = row.next();
// 得到第一行的所有列
Iterator<Cell> cellTitle = title.cellIterator();
// 将标题的文字内容放入到一个map中。
Map<Object,Object> titleMap = new HashMap<>();
// 从标题第一列开始
int i = 0;
// 循环标题所有的列
while (cellTitle.hasNext()) {
Cell cell = cellTitle.next();
String value = cell.getStringCellValue();
titleMap.put(i, value);
i = i + 1;
}
/*
* 解析内容行
*/
//用来格式化日期的 DateFormat
SimpleDateFormat sf;
if(pattern.length<1) {
sf=new SimpleDateFormat("yyyy-MM-dd");
} else{
sf=new SimpleDateFormat(pattern[0]);
}
while (row.hasNext()) {
// 标题下的第一行
Row rows = row.next();
// 行的所有列
Iterator<Cell> cellBody = rows.cellIterator();
// 得到传入类的实例
T tObject = clazz.newInstance();
int k = 0;
// 遍历一行的列
while (cellBody.hasNext()) {
Cell cell = cellBody.next();
// 这里得到此列的对应的标题
String titleString = (String) titleMap.get(k);
// 如果这一列的标题和类中的某一列的Annotation相同,那么则调用此类的的set方法,进行设值
if (map.containsKey(titleString)) {
Method setMethod = (Method) map.get(titleString);
//判断参数类型
if (cell.getCellType().equals(CellType.STRING)){
setMethod.invoke(tObject, cell.getStringCellValue());
}else if (cell.getCellType().equals(CellType.NUMERIC)){
setMethod.invoke(tObject, (int) cell.getNumericCellValue());
}else if (cell.getCellType().equals(CellType.BOOLEAN)){
setMethod.invoke(tObject, cell.getBooleanCellValue());
}
}
// 下一列
k = k + 1;
}
dist.add(tObject);
}
} catch (Exception e) {
e.printStackTrace();
return null;
}
return dist;
}
/*
public static void main(String[] args) {
ImportExcel<Loginfo> test = new ImportExcel(Loginfo.class);
File file = new File("D:\\testOne.xls");
Long befor = System.currentTimeMillis();
List<Loginfo> result = (ArrayList) test.importExcel(file);
Long after = System.currentTimeMillis();
System.out.println("此次操作共耗时:" + (after - befor) + "毫秒");
// for (int i = 0; i < result.size(); i++) {
// Loginfo loginfo=result.get(i);
// System.out.println("导入的信息为:"+loginfo.getLogInfo()+loginfo.getUserip()+loginfo.getUsername());
// }
System.out.println("共转化为List的行数为:" + result.size());
}
*/
}
调用
ImportExcelUtil<ImportExcelVo> importExcelUtil = new ImportExcelUtil<>(ImportExcelVo.class);
Collection<ImportExcelVo> importExcelVos = importExcelUtil.importExcel(file);
ArrayList<ImportExcelVo> list = (ArrayList<ImportExcelVo>) importExcelVos;
结束
ps:另外还有一个通用导出的工具类,实现原理跟这个完全相同,写在另一篇温州