什么会写Easypoi
以前的以前(岁月真TMD的快)我虽然写了不少代码但还是很少写poi,然后跳到一家公司之后就和业务人员聊上了,来这个需要个报表,这个报表样式是这样的,这个表头是这样的,就这样我写了大量的poi代码,每次都是大量的篇幅,copy to copy,无聊的一逼,然后加入了jeecg,jeecg中有一个小的工具类,虽然我也不知道是谁写的,然是可以用注解搞定最简单的导出,突然豁然开朗,我可以完善,让我从报表的苦海当中脱离出来,这样我花了一周的时间做了第一个版本支持导入导出放到了jeecg,发现还是不错的,慢慢的用的人越来越多,我就把这块独立出来了,再然后有人提出了模板,然后就加入了模板功能,提出了word的需求,加入了word的功能,后来工作忙了虽然没再参与jeecg,但还是一直维持这easypoi的更新,根据见识的增长也不断的重构这代码,直到现在
独特的功能
小白如何开始
Easypoi 为谁而开发
都可以使用easypoi
Easypoi的目标是什么
Easypoi的目标不是替代poi,而是让一个不懂导入导出的快速使用poi完成Excel和word的各种操作,而不是看很多api才可以完成这样工作
1.3 使用
如果不使用spring mvc的便捷福利,直接引入easypoi-base 就可以了,easypoi-annotation
1.4 测试项目
测试这个事情真不是个容易的事情
测试项目包括两块 Junit 的常见测试和spring 的view测试
1.spring view测试
运行application就可以了,访问界面,然后看到界面
对应的代码在view下面
2.Junit的测试目录结构如下
目前的测试覆盖率
2. Excel 注解版
2.1 Excel导入导出
Excel的导入导出是Easypoi的核心功能,前期基本也是围绕这个打造的,主要分为三种方式的处理,其中模板和Html目前只支持导出,因为支持Map.class其实导入应该是怎样都支持的
下面分别就这三种方式进行讲解
2.2 注解
注解介绍
easypoi起因就是Excel的导入导出,最初的模板是实体和Excel的对应,model--row,filed--col 这样利用注解我们可以和容易做到excel到导入导出
经过一段时间发展,现在注解有5个类分别是
注解中的ID的用法
这个ID算是一个比较独特的例子,比如
@ExcelTarget("teacherEntity") public class TeacherEntity implements java.io.Serializable { /** name */ @Excel(name="主讲老师_teacherEntity,代课老师_absent", orderNum="1", mergeVertical=true,needMerge=true,isImportField="true_major,true_absent") private String name;
这里的@ExcelTarget 表示使用teacherEntity这个对象是可以针对不同字段做不同处理
同样的ExcelEntity 和ExcelCollection 都支持这种方式
当导出这对象时,name这一列对应的是主讲老师,而不是代课老师还有很多字段都支持这种做法
@Excel
这个是必须使用的注解,如果需求简单只使用这一个注解也是可以的,涵盖了常用的Excel需求,需要大家熟悉这个功能,主要分为基础,图片处理,时间处理,合并处理几块,name_id是上面讲的id用法,这里就不累言了
属性类型默认值功能name
String
null
列名,支持name_id
needMerge
boolean
fasle
是否需要纵向合并单元格(用于含有list中,单个的单元格,合并list创建的多个row)
orderNum
String
"0"
列的排序,支持name_id
replace
String[]
{}
值得替换 导出是{a_id,b_id} 导入反过来
savePath
String
"upload"
导入文件保存路径,如果是图片可以填写,默认是upload/className/ IconEntity这个类对应的就是upload/Icon/
type
int
1
导出类型 1 是文本 2 是图片,3 是函数,10 是数字 默认是文本
width
double
10
列宽
height
double
10
列高,后期打算统一使用@ExcelTarget的height,这个会被废弃,注意
isStatistics
boolean
fasle
自动统计数据,在追加一行统计,把所有数据都和输出
这个处理会吞没异常,请注意这一点
isHyperlink
boolean
false
超链接,如果是需要实现接口返回对象
isImportField
boolean
true
校验字段,看看这个字段是不是导入的Excel中有,如果没有说明是错误的Excel,读取失败,支持name_id
exportFormat
String
""
导出的时间格式,以这个是否为空来判断是否需要格式化日期
importFormat
String
""
导入的时间格式,以这个是否为空来判断是否需要格式化日期
format
String
""
时间格式,相当于同时设置了exportFormat 和 importFormat
databaseFormat
String
"yyyyMMddHHmmss"
导出时间设置,如果字段是Date类型则不需要设置 数据库如果是string 类型,这个需要设置这个数据库格式,用以转换时间格式输出
numFormat
String
""
数字格式化,参数是Pattern,使用的对象是DecimalFormat
imageType
int
1
导出类型 1 从file读取 2 是从数据库中读取 默认是文件 同样导入也是一样的
suffix
String
""
文字后缀,如% 90 变成90%
isWrap
boolean
true
是否换行 即支持\n
mergeRely
int[]
{}
合并单元格依赖关系,比如第二列合并是基于第一列 则{0}就可以了
mergeVertical
boolean
fasle
纵向合并内容相同的单元格
fixedIndex
int
-1
对应excel的列,忽略名字
isColumnHidden
boolean
false
导出隐藏列
@ExcelTarget
限定一个到处实体的注解,以及一些通用设置,作用于最外面的实体
属性类型默认值功能value
String
null
定义ID
height
double
10
设置行高
fontSize
short
11
设置文字大小
@ExcelEntity
标记是不是导出excel 标记为实体类,一遍是一个内部属性类,标记是否继续穿透,可以自定义内部id
属性类型默认值功能id
String
null
定义ID
@ExcelCollection
一对多的集合注解,用以标记集合是否被数据以及集合的整体排序
属性类型默认值功能id
String
null
定义ID
name
String
null
定义集合列名,支持nanm_id
orderNum
int
0
排序,支持name_id
type
Class<?>
ArrayList.class
导入时创建对象使用
@ExcelIgnore
忽略这个属性,多使用需循环引用中,无需多解释吧^^
2.3 注解导出,导入
2.3.1 对象定义
注解介绍了这么多,大家基本上也了解我们的注解是如何定义Excel的了吧,下面我们来跟着路飞实战吧
这天老师吧路飞叫到了办公室,让给给老师实现一个报表的需求,就是从教育平台把某个班级的人员导出来
需求是,导出我们班的所有学生的姓名,性别,出生日期,进校日期
正巧路飞刚看到Easypo,就打算用Easypoi来实现,实现方法如下:
首先定义一个我们导出的对象,为了节省篇幅,统一忽略getter,setter
public class StudentEntity implements java.io.Serializable { /** * id */ private String id; /** * 学生姓名 */ @Excel(name="学生姓名", height=20, width=30, isImportField="true_st") private String name; /** * 学生性别 */ @Excel(name="学生性别", replace={ "男_1", "女_2" }, suffix="生", isImportField="true_st") private int sex; @Excel(name="出生日期", databaseFormat="yyyyMMddHHmmss", format="yyyy-MM-dd", isImportField="true_st", width=20) private Date birthday; @Excel(name="进校日期", databaseFormat="yyyyMMddHHmmss", format="yyyy-MM-dd") private Date registrationDate; }
这里设置我们的4列分别是学生姓名,学生性别,出生日期,进校日期
其中学生姓名定义了我们的列的行高,学生性别因为我们基本上都是存在数据库都是数字所以我们转换下,两个日期我们都是进行了格式化输出了,这样我们就完成了业务对我们Excel的样式需求,后面只有把这个学生列表输出就可以了
生成Excel代码如下
Workbook workbook=ExcelExportUtil.exportExcel(new ExportParams("计算机一班学生","学生"), StudentEntity .class, list);
这样我们就得到的一个java中的Excel,然后把这个输出就得到我们的Excel了https://static.oschina.net/uploads/space/2017/0622/212811_uh7e_1157922.png
2.3.2 集合定义
路飞很快的完成了老师的任务,花了也就是喝杯茶的时间,就交差了,但过了一会就又被老师叫去了,让他给出一个某个班级选择选择某些课的学生以及对应的老师
路飞又很快的想到了Easypoi,其中有一对多的导出,这不正是一对多的体现吗,然后他继续定义实体:
一个课程对应一个老师
一个课程对应N个学生
课程的实体
@ExcelTarget("courseEntity") public class CourseEntity implements java.io.Serializable { /** 主键 */ private String id; /** 课程名称 */ @Excel(name="课程名称", orderNum="1", width=25) private String name; /** 老师主键 */ @ExcelEntity(id="absent") private TeacherEntity mathTeacher; @ExcelCollection(name="学生", orderNum="4") private List<StudentEntity> students; }
教师的实体
@ExcelTarget("teacherEntity") public class TeacherEntity implements java.io.Serializable { private String id; /** name */ @Excel(name="主讲老师_major,代课老师_absent", orderNum="1", isImportField="true_major,true_absent") private String name;
这里在课程这个实体里面就完成了一堆多的导出,达到了我们基础需求,同时使用了orderNum对我们的列进行了排序,满足老师的需求,导出代码如下
Workbook workbook=ExcelExportUtil.exportExcel(new ExportParams("2412312", "测试", "测试"), CourseEntity.class, list);
这样我们就完成了老师的需求,效果如图2.3.2-1
但是课程名和代课老师没有合并,不太美观
路飞又果断给课程名称和代课老师加了needMerge=true的属性,就可以完成单元格的合并
/** 课程名称 */ @Excel(name="课程名称", orderNum="1", width=25,needMerge=true) private String name; //-------------------------------- /** name */ @Excel(name="主讲老师_major,代课老师_absent", orderNum="1",needMerge=true, isImportField="true_major,true_absent")
效果如图2.3.2-2
到这里,路飞就完美的完成了老师的任务,快乐的去交差了
图2.3.2-1
图2.3.2-2
2.3.3 图片的导出
在日常运作中不可避免的会遇到图片的导入导出,这里提供了两种类型的图片导出方式
@Excel(name="公司LOGO", type=2 ,width=40 , height=20,imageType=1) private String companyLogo;
@Excel(name="公司LOGO", type=2 ,width=40 , height=20,imageType=1) private byte[] companyLogo;
效果如下
List<CompanyHasImgModel> list; @Before public void initData() { list=new ArrayList<CompanyHasImgModel>(); list.add(new CompanyHasImgModel("百度", "imgs/company/baidu.png", "北京市海淀区西北旺东路10号院百度科技园1号楼")); list.add(new CompanyHasImgModel("阿里巴巴", "imgs/company/ali.png", "北京市海淀区西北旺东路10号院百度科技园1号楼")); list.add(new CompanyHasImgModel("Lemur", "imgs/company/lemur.png", "亚马逊热带雨林")); list.add(new CompanyHasImgModel("一众", "imgs/company/one.png", "山东济宁俺家")); } @Test public void exportCompanyImg() throws Exception { File savefile=new File("D:/excel/"); if (!savefile.exists()) { savefile.mkdirs(); } Workbook workbook=ExcelExportUtil.exportExcel(new ExportParams(), CompanyHasImgModel.class, list); FileOutputStream fos=new FileOutputStream("D:/excel/ExcelExportHasImgTest.exportCompanyImg.xls"); workbook.write(fos); fos.close(); }
运行效果
2.3.3 -1
2.3.4 Excel导入介绍
有导出就有导入,基于注解的导入导出,配置配置上是一样的,只是方式反过来而已,比如类型的替换 导出的时候是1替换成男,2替换成女,导入的时候则反过来,男变成1 ,女变成2,时间也是类似
导出的时候date被格式化成 2017-8-25 ,导入的时候2017-8-25被格式成date类型
下面说下导入的基本代码,注解啥的都是上面讲过了,这里就不累赘了
@Test public void test2() { ImportParams params=new ImportParams(); params.setTitleRows(1); params.setHeadRows(1); long start=new Date().getTime(); List<MsgClient> list=ExcelImportUtil.importExcel( new File(PoiPublicUtil.getWebRootPath("import/ExcelExportMsgClient.xlsx")), MsgClient.class, params); System.out.println(new Date().getTime() - start); System.out.println(list.size()); System.out.println(ReflectionToStringBuilder.toString(list.get(0))); }
基本是写法也很简单,ImportParams 参数介绍下
属性类型默认值功能titleRows
int
0
表格标题行数,默认0
headRows
int
1
表头行数,默认1
startRows
int
0
字段真正值和列标题之间的距离 默认0
keyIndex
int
0
主键设置,如何这个cell没有值,就跳过 或者认为这个是list的下面的值
这一列必须有值,不然认为这列为无效数据
startSheetIndex
int
0
开始读取的sheet位置,默认为0
sheetNum
int
1
上传表格需要读取的sheet 数量,默认为1
needSave
boolean
false
是否需要保存上传的Excel
needVerfiy
boolean
false
是否需要校验上传的Excel
saveUrl
String
"upload/excelUpload"
保存上传的Excel目录,默认是 如 TestEntity这个类保存路径就是
upload/excelUpload/Test/yyyyMMddHHmss* 保存名称上传时间五位随机数
verifyHanlder
IExcelVerifyHandler
null
校验处理接口,自定义校验
lastOfInvalidRow
int
0
最后的无效行数,不读的行数
readRows
int
0
手动控制读取的行数
importFields
String[]
null
导入时校验数据模板,是不是正确的Excel
keyMark
String
":"
Key-Value 读取标记,以这个为Key,后面一个Cell 为Value,多个改为ArrayList
readSingleCell
boolean
false
按照Key-Value 规则读取全局扫描Excel,但是跳过List读取范围提升性能
仅仅支持titleRows + headRows + startRows 以及 lastOfInvalidRow
dataHanlder
IExcelDataHandler
null
数据处理接口,以此为主,replace,format都在这后面
2.3.5 Excel导入小功能
2.3.6 图片的导入
有图片的导出就有图片的导入,导入的配置和导出是一样的,但是需要设置保存路径
1.设置保存路径saveUrl 默认为"upload/excelUpload"
可以手动修改 ImportParams 修改下就可以了
@Test public void test() { try { ImportParams params=new ImportParams(); params.setNeedSave(true); List<CompanyHasImgModel> result=ExcelImportUtil.importExcel( new File(PoiPublicUtil.getWebRootPath("import/imgexcel.xls")), CompanyHasImgModel.class, params); for (int i=0; i < result.size(); i++) { System.out.println(ReflectionToStringBuilder.toString(result.get(i))); } Assert.assertTrue(result.size()==4); } catch (Exception e) { e.printStackTrace(); } } }
导入日志
16:35:43.081 [main] DEBUG c.a.e.e.imports.ExcelImportServer - Excel import start ,class is class cn.afterturn.easypoi.test.entity.img.CompanyHasImgModel 16:35:43.323 [main] DEBUG c.a.e.e.imports.ExcelImportServer - start to read excel by is ,startTime is 1503650143323 16:35:43.344 [main] DEBUG c.a.e.e.imports.ExcelImportServer - end to read excel by is ,endTime is 1503650143344 16:35:43.429 [main] DEBUG c.a.e.e.imports.ExcelImportServer - end to read excel list by pos ,endTime is 1503650143429 cn.afterturn.easypoi.test.entity.img.CompanyHasImgModel@1b083826[companyName=百度,companyLogo=upload/CompanyHasImgModel/pic88273295062.PNG,companyAddr=北京市海淀区西北旺东路10号院百度科技园1号楼] cn.afterturn.easypoi.test.entity.img.CompanyHasImgModel@105fece7[companyName=阿里巴巴,companyLogo=upload/CompanyHasImgModel/pic22507938183.PNG,companyAddr=北京市海淀区西北旺东路10号院百度科技园1号楼] cn.afterturn.easypoi.test.entity.img.CompanyHasImgModel@3ec300f1[companyName=Lemur,companyLogo=upload/CompanyHasImgModel/pic86390457892.PNG,companyAddr=亚马逊热带雨林] cn.afterturn.easypoi.test.entity.img.CompanyHasImgModel@482cd91f[companyName=一众,companyLogo=upload/CompanyHasImgModel/pic69566571093.PNG,companyAddr=山东济宁俺家]
2.3.5-1
2.3.7 Excel多Sheet导出
目前单Sheet和单Class的方式比较多,对于多Sheet的方式还是一片空白,这里做一下说明:
导出基本采用ExportParams 这个对象,进行参数配置;
我们需要进行多Sheet导出,那么就需要定义一个基础配置对象
public class ExportView { public ExportView(){ } private ExportParams exportParams; private List<?> dataList; private Class<?> cls; public ExportParams getExportParams() { return exportParams; } public void setExportParams(ExportParams exportParams) { this.exportParams=exportParams; } public Class<?> getCls() { return cls; } public void setCls(Class<?> cls) { this.cls=cls; } public List<?> getDataList() { return dataList; } public void setDataList(List<?> dataList) { this.dataList=dataList; } public ExportView(Builder builder) { this.exportParams=builder.exportParams; this.dataList=builder.dataList; this.cls=builder.cls; } public static class Builder { private ExportParams exportParams=null; private List<?> dataList=null; private Class<?> cls=null; public Builder() { } public Builder exportParams(ExportParams exportParams) { this.exportParams=exportParams; return this; } public Builder dataList(List<?> dataList) { this.dataList=dataList; return this; } public Builder cls(Class<?> cls) { this.cls=cls; return this; } public ExportView create() { return new ExportView(this); } } }
对象主要有三个属性:
// 该注解配置的导出属性
这里没有用泛型,因为多Sheet导出时,会引用到不同的注解对象;
定义基础配置的集合
public class ExportMoreView { private List<ExportView> moreViewList=Lists.newArrayList(); public List<ExportView> getMoreViewList() { return moreViewList; } public void setMoreViewList(List<ExportView> moreViewList) { this.moreViewList=moreViewList; } }
最后在实现调用的方法中,对整个集合进行配置和解析
List<Map<String, Object>> exportParamList=Lists.newArrayList(); //该行主要用于获取业务数据,请根据具体的情况进行修改和调整 ExportMoreView moreView=this.getBaseTransferService().mergeExportView(templateTypeCode); //迭代导出对象,将对应的配置信息写入到实际的配置中 for(ExportView view:moreView.getMoreViewList()){ Map<String, Object> valueMap=Maps.newHashMap(); valueMap.put(NormalExcelConstants.PARAMS,view.getExportParams()); valueMap.put(NormalExcelConstants.DATA_LIST,view.getDataList()); valueMap.put(NormalExcelConstants.CLASS,view.getCls()); exportParamList.add(valueMap); } //实现导出配置 modelMap.put(NormalExcelConstants.FILE_NAME,new DateTime().toString("yyyyMMddHHmmss")); //将转换完成的配置接入到导出中 modelMap.put(NormalExcelConstants.MAP_LIST,exportParamList); return NormalExcelConstants.JEECG_EXCEL_VIEW;
如果不是采用的MVC的方式,请将转换的配置采用以下的方式实现:
参见ExcelExportUtil
2.4 注解变种-更自由的导出
这天老师又把路飞喊道的办公室,要求路飞导出班级学生的整体信息
@Excel(name="学生姓名", height=20, width=30, isImportField="true_st") private String name; @Excel(name="学生性别", replace={ "男_1", "女_2" }, suffix="生", isImportField="true_st") private int sex; @Excel(name="出生日期", databaseFormat="yyyyMMddHHmmss", format="yyyy-MM-dd", isImportField="true_st", width=20) private Date birthday; @Excel(name="进校日期", databaseFormat="yyyyMMddHHmmss", format="yyyy-MM-dd") private Date registrationDate;
路飞飞快的用到上面的学到的知识搞定了,这这时有一个老师把路飞叫去,说想要导出一个不要出生日期的Excel,感觉用户需求很无奈,路飞又造两个一个bean,把这个注解去掉了,来导出
@Excel(name="学生姓名", height=20, width=30, isImportField="true_st") private String name; @Excel(name="学生性别", replace={ "男_1", "女_2" }, suffix="生", isImportField="true_st") private int sex; @Excel(name="进校日期", databaseFormat="yyyyMMddHHmmss", format="yyyy-MM-dd") private Date registrationDate;
虽然解决了老师的需求,但这个并不是一个完美的解决方案,下面介绍一个更自由的解决方案
注解的导出,规定我们必须把model写好,并且注解写好,每次导出的Excel都是固定的,无法动态控制导出的列,虽然可以通过id来处理一个案例,但是自由度远远不够,这里介绍个变种支持,基本支持注解所有的功能
基于List<ExcelExportEntity> 的导出,ExcelExportEntity是注解经过处理翻译成的实体类,两者几乎是一对的,所以如果我们要动态自定义导出列,我们只要动态拼装ExcelExportEntity就可以了
下面我们看下这个类
/** * 如果是MAP导出,这个是map的key */ private Object key; private double width=10; private double height=10; /** * 图片的类型,1是文件,2是数据库 */ private int exportImageType=0; /** * 排序顺序 */ private int orderNum=0; /** * 是否支持换行 */ private boolean isWrap; /** * 是否需要合并 */ private boolean needMerge; /** * 单元格纵向合并 */ private boolean mergeVertical; /** * 合并依赖 */ private int[] mergeRely; /** * 后缀 */ private String suffix; /** * 统计 */ private boolean isStatistics; private String numFormat; private List<ExcelExportEntity> list;
基本上是和注解对应的, List<ExcelExportEntity> list 这个是对应的一对多的导出,相当于集合,其他基本上都是和注解保持一致
下面给出正常的demo
public void test() { try { List<ExcelExportEntity> entity=new ArrayList<ExcelExportEntity>(); //构造对象等同于@Excel ExcelExportEntity excelentity=new ExcelExportEntity("姓名", "name"); excelentity.setNeedMerge(true); entity.add(excelentity); entity.add(new ExcelExportEntity("性别", "sex")); excelentity=new ExcelExportEntity(null, "students"); List<ExcelExportEntity> temp=new ArrayList<ExcelExportEntity>(); temp.add(new ExcelExportEntity("姓名", "name")); temp.add(new ExcelExportEntity("性别", "sex")); //构造List等同于@ExcelCollection excelentity.setList(temp); entity.add(excelentity); List<Map<String, Object>> list=new ArrayList<Map<String, Object>>(); //把我们构造好的bean对象放到params就可以了 Workbook workbook=ExcelExportUtil.exportExcel(new ExportParams("测试", "测试"), entity, list); FileOutputStream fos=new FileOutputStream("D:/excel/ExcelExportForMap.tt.xls"); workbook.write(fos); fos.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } }
路飞想到了这个方案,并且用上面做了测试可以完美解决所以他把之前的代码改为了(代码有删减,基本上都是和注解对应的)
List<ExcelExportEntity> beanList=new ArrayList<ExcelExportEntity>(); beanList .add(new ExcelExportEntity(new ExcelExportEntity("学生姓名", "name")); beanList .add(new ExcelExportEntity("学生性别", "sex")); beanList .add(new ExcelExportEntity("进校日期", "registrationDate")); if(needBirthday()){ beanList .add(new ExcelExportEntity("出生日期", "birthday")); } Workbook workbook=ExcelExportUtil.exportExcel(new ExportParams("测试", "测试"), beanList , list);
用同一套代买完美了支持了老师的需求,心满意足的回宿舍了^^
2.5 Map导入,自由发挥
这天,老师把路飞叫到办公室,总是被叫,能者的悲哀啊,让他临时导入一批数据,到数据库,但是中间需要处理一些字段逻辑没办法直接导入到数据库,
这时路飞首先想到构造一个bean然后标记注解,导入处理对象,但是想想一次的对象太过于浪费,不如用map试试,获取map处理map也是一样的
导入的逻辑就变成了
ImportParams params=new ImportParams(); params.setDataHanlder(new MapImportHanlder()); long start=new Date().getTime(); List<Map<String, Object>> list=ExcelImportUtil.importExcel( new File(PoiPublicUtil.getWebRootPath("import/check.xls")), Map.class, params);
导入后,处理每个map,然后入库完美的解决了老师的需求,简单更快捷,和bean导入基础没有区别,省去了bean的构造时间
PS:这个作者也只是在临时方案中或者一次性活当中使用,一般还是推荐注解这种方式,拥有更高的代码阅读性
!!!测试了时间的,最好导入使用文本格式,可以获取时间格式可能无法获取
2.6 Excel的样式自定义
"路飞,来办公室一趟",就这样路飞又被叫到了办公室,这次老师的需求是,想要一个漂亮点的Excel,希望路飞可以点缀下Excel,思来想去还是需要用poi的style来解决,但是如果每个都写style是不是太麻烦,而且Excel的styler数量是有限制的,这里就需要尽量复用已经创造的style,看看之前的Excel表格,大体上可以分为[标题,表头,表体],那可以说的就是创建一个接口每次调用这三个接口就可以了不说干就干
public interface IExcelExportStyler { /** * 列表头样式 * @param headerColor * @return */ public CellStyle getHeaderStyle(short headerColor); /** * 标题样式 * @param color * @return */ public CellStyle getTitleStyle(short color); /** * 获取样式方法 * @param Parity * @param entity * @return */ public CellStyle getStyles(boolean Parity, ExcelExportEntity entity); }
实现类尽量复用已经创建的Styler,切记
这样路飞先造了一个带边框的styler ,ExcelExportStylerBorderImpl
效果如下
然后路飞又手痒写了个带换行颜色的 ExcelExportStylerColorImpl
效果如下
客官看到这里应该就大体理解了我们的实现方法了吧,
最后路飞实现了一个复杂的按照老师要求的样式交差了
styler接口用法
上面两个表头和标题样式不用解释
后面这个是传入当前列的以及奇偶行,用户可以根据需求实现业务,包括去掉Excel的小箭头(也就是设置数字为数字格式的Cell),完成居中,字体等等各式各样的需求
但是这里无法实现特别没的Excel,如果有这种需求可以使用模板来实现,在Excel点点就可以完美实现
获取源码方式 转发+【关注】,私信回复【eypoi】,即可免费获取源码地址
家好,接下来几篇文章我将分享基于SSM整合POI实现Excel的导入导出,并介绍如何采用MVC三层模式体验企业级JavaWeb应用的开发流程。而这些功能我进行了整理并录制了一套完整的视频教程,具体的功能列表如下:
1、SSM的整合流程;
2、POI导入导出Excel;
3、增加、删除、修改、搜索功能。
其中,我对整个项目进行了两种方式的整合:第一种是采用传统的往lib目录丢jar包;第二种是采用maven的方式进行整合;而视频教程中采用的是第一种方式。当然啦,这两种方式的源码我这里都有!感兴趣的童鞋可以私聊!
大家也可以搜索“程序员实战基地”,关于poi实现Excel导入导出介绍视频链接如下:
http://list.youku.com/albumlist/show/id_51818026.html
在开发前端这块大多使用 SpringMVC,EasyPOI 也提供了 对 SpringMVC 的支持;
EasypoiBigExcelExportView 大数据量导出
EasypoiMapExcelView map 列表导出
EasypoiPDFTemplateView pdf导出
EasypoiSingleExcelView 注解导出
EasypoiTemplateExcelView 模板导出
EasypoiTemplateWordView word模板导出
MapGraphExcelView 图表导出
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
<%@include file="/WEB-INF/views/head.jsp" %>
</head>
<body>
<span style="color: red">${count}</span>
<!-- 上传请配置enctype -->
<form action="/import/xlsx" method="post" enctype="multipart/form-data">
<input class="easyui-filebox" name="xlsxFile" data-options="prompt:'选择一个文件...'" style="width:80%">
<button class="easyui-linkbutton" type="submit">确定</button>
</form>
</body>
</html>
@Controller
@RequestMapping("/import")
public class ImportController extends BaseController {
@Autowired
private IEmployeeService employeeService;
@Autowired
private IDepartmentService departmentService;
//跳转到导入页面
@RequestMapping("/index")
public String index(){
return "import";
}
//跳转到导入页面
@RequestMapping("/xlsx")
public String importXlsx(MultipartFile xlsxFile, HttpServletRequest request, HttpServletResponse response) throws Exception{
ImportParams params=new ImportParams();
params.setTitleRows(1); //注意:这里有两个表头
List<Employee> list=ExcelImportUtil.importExcel(
xlsxFile.getInputStream(),
Employee.class, params);
for (Employee employee : list) {
employee.setPassword("123"); //默认密码123
if(employee.getDepartment()!=null) {
Department department=departmentService.findByName(employee.getDepartment().getName());
employee.setDepartment(department);
}
employeeService.save(employee);
}
return "import";
}
}
自定义验证需要实现IExcelVerifyHandler接口
*请认真填写需求信息,我们会在24小时内与您取得联系。