谢谢大家牺牲自己宝贵的时间阅读拙作,这是在下的第一篇博客,若有疏忽和不当之处,请多多指正,谢谢,下面进入正题。
工作中我们可能会遇到要将多个对象作为sheet表导入excel的情况,下面就是我应对这种情况对poi进行的一次简单封装。
需要引入的pom:
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>3.17</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.18</version>
<scope>provided</scope>
</dependency>
ps:事实上我们只需要poi就足够完成所有功能的实现,lombok的引入是为了提高编写的效率和代码的可读性,作为个人来说,如果为了练习的话不建议使用lombok。
首先,为了简化导出表时对于列的操作,我们可以先对需要导出的对象添加一个注解标签,以便于之后的操作,此处就使用ExcelAttribute作为注解名称:
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ExcelAttribute {
//列名
String name();
//列序号
int column();
//是否需要导出
boolean isExport() default true;
//单元格是否需要自适应
boolean isAdaptive() default false;
}
本次我是以Map的方式传递参数的,因为使用key值作为sheet名称会显得更加直观一些,如果有需要可以再添加一个ExcelSheet的注解,标记在所需要导出的类的类名上
以List<List<?>>的形式传递参数,如果需要使用,只需要在抓取list<?>的泛型后扫描该注解即可,本次就为了节省篇幅就不作介绍了。
我们建立完注解,便可以进行工具类的编写,此处导出为2003版的excel:
/**
* @param datas 导出报表,以key值作为表名
* @return
*/
public static Workbook exportExcelByMaps(Map<String,List<?>> datas){
HSSFWorkbook hssfWorkbook = new HSSFWorkbook();
//遍历Map
for(Map.Entry<String, List<?>> map : datas.entrySet()){
List<?> list = map.getValue();
//将key值设为sheet名称
HSSFSheet sheet = hssfWorkbook.createSheet(map.getKey());
//判断map的值是否为空
if(null == map.getValue() || map.getValue().size() == 0)
continue;
//使用反射抓取list的泛型
Type type = list.getClass().getGenericSuperclass();
ParameterizedType p = (ParameterizedType)type;
Class cls = (Class)p.getActualTypeArguments()[0];
//可能有即便list可能传递为空,也需要导出到表格的情况发生,所以弃置定位取类型的方法
//Field[] fields = list.get(0).getClass().getDeclaredFields();
Field[] fields = cls.getDeclaredFields();
Row titleRow = sheet.createRow(0);
for (int i = 0, m = fields.length; i < m; i++){
//判断该属性是否是需要导出的列,不是则直接跳过
if(!fields[i].isAnnotationPresent(ExcelAttribute.class)){
continue;
}
//获取属性的对应注解
ExcelAttribute excelAttribute = fields[i].getAnnotation(ExcelAttribute.class);
if(excelAttribute.isExport()) {
int colum = excelAttribute.column() - 1;
Cell cell = titleRow.createCell(colum);
cell.setCellValue(excelAttribute.name());
if(excelAttribute.isAdaptive()) {
sheet.autoSizeColumn(colum);
}
}
continue;
}
//遍历list
int startIndex = 0;
int endIndex = list.size();
Row row = null;
Cell cell = null;
for(int i = startIndex; i < endIndex; i++){
row = sheet.createRow(i+1-startIndex);
//如果list为空或者size为0则跳过
if(list.size() == 0 || null == list){
continue;
}
Object o = list.get(i);
for(int m = 0;m<fields.length;m++){
Field field = fields[m];
if(!field.isAnnotationPresent(ExcelAttribute.class)){
continue;
}
field.setAccessible(true);
ExcelAttribute attr = field.getAnnotation(ExcelAttribute.class);
try{
//判断该属性在现有需求下是否需要导出
if(attr.isExport()){
//让列的宽度自适应
if(attr.isAdaptive()){
sheet.autoSizeColumn(attr.column() - 1);
}
cell = row.createCell(attr.column() - 1);
cell.setCellValue(field.get(o) == null? "":String.valueOf(field.get(o)));
}
} catch (Exception e){
e.printStackTrace();
}
}
}
}
return hssfWorkbook;
}
完成了工具类的编写之后我们需要设定下导出的方式,一般来说,我们经常使用的就是指定路径导出或者以流的方式附加在HttpServletResponse中
/**
* 将workbook附加在response中
*/
public static void export2Response(Workbook workbook , String fileName,HttpServletResponse response){
try{
response.setContentType("application/vnd.ms-excel;charset=utf-8");
response.setHeader("Content-Disposition",
"attachment;filename=" + new String((fileName + ".xls").getBytes("GBK"), "iso-8859-1"));
workbook.write(response.getOutputStream());
} catch (Exception e){
e.printStackTrace();
}
}
/**
* 将excel输出至本地路径
*/
public static void export2Path(Workbook workbook , String fileName,String path){
File dir = new File(path);
//路径不存在则创建
if(!dir.exists()||!(dir.isDirectory())){
dir.mkdir();
}
String filePath = path.concat(fileName).concat(".xls");
File file = new File(filePath);
FileOutputStream out = null;
try {
out = new FileOutputStream(file);
workbook.write(out);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException ioe){
ioe.printStackTrace();
} finally {
//关闭流
if(null != out) {
try {
out.flush();
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
测试用实体类:
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class UserInfo {
@ExcelAttribute(column = 1,name = "姓名",isAdaptive = true)
private String name;
@ExcelAttribute(column = 2,name = "年龄",isAdaptive = true)
private String age;
@ExcelAttribute(column = 3,name = "性别",isAdaptive = true)
private String gender;
@ExcelAttribute(column = 4,name = "注释",isExport = false)
private String mark;
}
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class DogeInfo {
@ExcelAttribute(column = 4,name = "姓名a",isAdaptive = true)
private String name;
@ExcelAttribute(column = 3,name = "年龄a",isAdaptive = true)
private String age;
@ExcelAttribute(column = 1,name = "性别a",isAdaptive = true)
private String gender;
@ExcelAttribute(column = 2,name = "注释a",isExport = false)
private String mark;
}
测试片段:
public static Workbook exportExcel(){
Map<String, List<?>> temp = new HashMap<>();
UserInfo tempUser1 = new UserInfo("alien","11","1","clone");
UserInfo tempUser2 = new UserInfo("寿限无寿限无EWQEWQEWQEWQE","2222222","22","dsadsa");
UserInfo tempUser3 = new UserInfo("dwqdwqdw","222","2","2");
DogeInfo dogeInfo1 = new DogeInfo("alien","11","1","clone");
DogeInfo dogeInfo12 = new DogeInfo("寿限无寿限无EWQEWQEWQEWQE","2222222","22","dsadsa");
DogeInfo dogeInfo13 = new DogeInfo("dwqdwqdw","222","2","2");
List<UserInfo> users = new ArrayList<UserInfo>(){{add(tempUser1);add(tempUser2);add(tempUser3);}};
List<DogeInfo> dogeInfos = new ArrayList<DogeInfo>(){{add(dogeInfo13);add(dogeInfo12);add(dogeInfo1);}};
List<DogeInfo> dogeInfos1 = new ArrayList<>();
temp.put("user",users);
temp.put("doge",dogeInfos);
temp.put("doge2",dogeInfos1);
temp.put("doge3",null);
Workbook workbook = ExcelUtils.exportExcelByMaps(temp);
return workbook;
}
public static void main(String[] args){
System.out.print(args.toString());
Workbook workbook = exportExcel();
ExcelUtils.export2Path(workbook,"temp","D:/File/");
}
由于时间关系,写的略有仓促,请见谅,如果有什么纰漏之处,万望指正,谢谢。
代码git地址:https://github.com/yangzan0816/ExcelExport.git