自定义注解导出excel数据
利用自定义注解方式,对数据列表进行简单的导出操作。即在实体对象的属性域上添加导出标识的注解,在对实体进行导出时,利用自定义注解进行反射的方法,获取实体需要导出的属性及值。该导出功能由于进行了封装,所以只适用于简单的excel导出功能,如需对导出的excel进行格式上的美化或合并单元格之类的操作,则本功能未进行实现。
优点:
1、由于使用了自定义注解,在导出时,只需要给接口传实体对象类和数据的list以及一些条件参数即可,使用起来简单易懂。
2、由于对导出excel方法进行了封装,所以导出时不用在进行繁琐的excel表格代码的编写了。
3、使用自定义注解的方式进行方法的封装,可根据业务需要进行自定义注解的扩展,满足业务需求,即具有可扩展性。
4、自定义注解中封装了一个数组属性,用来进行导出对象属性的分组,如系统中不同页面显示的对象属性不同,这时可以根据需要进行属性的分组,在导出时传入分组的参数,对应导出分组的属性值。
缺点:
1、导出的excel表格样式比较单一简单,暂时不支持合并单元格、添加表格特殊样式功能。
部分代码介绍:
1、ExcelField.java自定义注解类介绍:
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface ExcelField {
/**
* 导出字段名(默认调用当前字段的“get”方法,如指定导出字段为对象,请填写“对象名.对象属性”,例:“area.name”、“office.name”)
*/
String value() default "";
/**
* 导出字段标题(需要添加批注请用“**”分隔,标题**批注,仅对导出模板有效)
*/
String title();
/**
* 字段类型(0:导出导入;1:仅导出;2:仅导入)
*/
int type() default 0;
/**
* 导出字段对齐方式(0:自动;1:靠左;2:居中;3:靠右)
*/
int align() default 0;
/**
* 导出字段字段排序(升序)
*/
int sort() default 0;
/**
* 如果是字典类型,请设置字典的type值
*/
String dictType() default "";
/**
* 反射类型
*/
Class<?> fieldType() default Class.class;
/**
* 字段归属组(根据分组导出导入)
*/
int[] groups() default {};
}
2、导出excel类代码简单介绍:
/**
* 构造函数
* @param title 表格标题,传“空值”,表示无标题
* @param cls 实体对象,通过annotation.ExportField获取标题
* @param type 导出类型(1:导出数据;2:导出模板)
* @param groups 导入分组
*/
public ExportExcel(String title, Class<?> cls, int type, int... groups){
// Get annotation field
Field[] fs = cls.getDeclaredFields();
for (Field f : fs){
ExcelField ef = f.getAnnotation(ExcelField.class);
if (ef != null && (ef.type()==0 || ef.type()==type)){
if (groups!=null && groups.length>0){
boolean inGroup = false;
for (int g : groups){
if (inGroup){
break;
}
for (int efg : ef.groups()){
if (g == efg){
inGroup = true;
annotationList.add(new Object[]{ef, f});
break;
}
}
}
}else{
annotationList.add(new Object[]{ef, f});
}
}
}
// Get annotation method
Method[] ms = cls.getDeclaredMethods();
for (Method m : ms){
ExcelField ef = m.getAnnotation(ExcelField.class);
if (ef != null && (ef.type()==0 || ef.type()==type)){
if (groups!=null && groups.length>0){
boolean inGroup = false;
for (int g : groups){
if (inGroup){
break;
}
for (int efg : ef.groups()){
if (g == efg){
inGroup = true;
annotationList.add(new Object[]{ef, m});
break;
}
}
}
}else{
annotationList.add(new Object[]{ef, m});
}
}
}
// 根据自定义注解中的sort进行排序
Collections.sort(annotationList, new Comparator<Object[]>() {
public int compare(Object[] o1, Object[] o2) {
return new Integer(((ExcelField)o1[0]).sort()).compareTo(
new Integer(((ExcelField)o2[0]).sort()));
};
});
// Initialize
List<String> headerList = Lists.newArrayList();
for (Object[] os : annotationList){
String t = ((ExcelField)os[0]).title();
// 如果是导出,则去掉注释
if (type==1){
String[] ss = StringUtils.split(t, "**", 2);
if (ss.length==2){
t = ss[0];
}
}
headerList.add(t);
}
initialize(title, headerList);
}
3、调用该接口代码介绍:
String fileName = "银行列表"+DateUtils.getDate("yyyyMMddHHmmss")+"."+fileType;
//分页查询导出数据
Page<InvestorBankCard> page = bankCardService.findPage(new Page<InvestorBankCard>(request, response, -1), investorBankCard);
//调用导出方法进行excel表格导出
new ExportExcel("银行卡数据", InvestorBankCard.class).setDataList(page.getList()).write(response, fileName);
return null;
总结
自定义注解可以灵活的对代码进行封装使用,通过本次excel表格数据的功能开发,对自定义注解有了一些新的认识,在一些特定的场景,使用自定义注解可以节省很大的代码量,并且具有重用性。避免大量的重复代码。由于导出涉及的excel表格比较简单,所以该功能还需要在进行完善,至少需要支持单元格的合并及一些表格样式或字体样式的设置,待后续业务需要或有空余时间在进行完善。