世间万物,始于心,终于行
想要了解本章内容,你得先了解自定义注解.
目录
java.lang.annotation 提供了四种元注解,专门注解其他的注解(在自定义注解的时候,需要使用到元注解):
@Documented – 注解是否将包含在JavaDoc中 @Retention – 什么时候使用该注解 @Target –
注解用于什么地方 @Inherited – 是否允许子类继承该注解1.)@Retention – 定义该注解的生命周期 ● RetentionPolicy.SOURCE : 在编译阶段丢弃。这些注解在编译结束之后就不再有任何意义,所以它们不会写入字节码。@Override,
@SuppressWarnings都属于这类注解。 ● RetentionPolicy.CLASS :
在类加载的时候丢弃。在字节码文件的处理中有用。注解默认使用这种方式 ● RetentionPolicy.RUNTIME :
始终不会丢弃,运行期也保留该注解,因此可以使用反射机制读取该注解的信息。我们自定义的注解通常使用这种方式。2.)Target – 表示该注解用于什么地方。默认值为任何元素,表示该注解用于什么地方。可用的ElementType 参数包括 ● ElementType.CONSTRUCTOR: 用于描述构造器 ● ElementType.FIELD:
成员变量、对象、属性(包括enum实例) ● ElementType.LOCAL_VARIABLE: 用于描述局部变量 ●
ElementType.METHOD: 用于描述方法 ● ElementType.PACKAGE: 用于描述包 ●
ElementType.PARAMETER: 用于描述参数 ● ElementType.TYPE: 用于描述类、接口(包括注解类型)
或enum声明3.)@Documented – 一个简单的Annotations 标记注解,表示是否将注解信息添加在java 文档中。
4.)@Inherited – 定义该注释和子类的关系
@Inherited 元注解是一个标记注解,@Inherited 阐述了某个被标注的类型是被继承的。如果一个使用了@Inherited 修饰的annotation
类型被用于一个class,则这个annotation 将被用于该class 的子类。
接下来就是自定义注解
package com.yuan.testExcel;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* excel 表格 列名注解
*
* @author yuanzixiang
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ExcelRow {
/**
* Excel 对应列名
* @return
*/
String name();
/**
* excel 列名备注
* @return
*/
String note() default "";
}
ExcelRow 该注解使用在属性上.
package com.yuan.testExcel;
import java.lang.annotation.ElementType; import
java.lang.annotation.Retention; import
java.lang.annotation.RetentionPolicy; import
java.lang.annotation.Target;/** * excel 表格 列名注解 * * @author yuanzixiang */
@Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public
@interface ExcelRow {/** * Excel 对应列名 * @return */ String name(); /** * excel 列名备注 * @return */ String note() default ""; }
背景
最近在面试的时候被问到有没有用过java操作Excel,直接就是当场尬住,所以这几天狠狠研究了一下这个东西。
所用依赖
如果版本有不同有冲突,请自行去maven仓库拉取
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>4.1.1</version>
</dependency>
/**
* workbook
* @param titleList
* @return
*/
public static HSSFWorkbook getWorkBook(List<String> titleList){
//第一步,创建一个workbook,对应一个Excel文件
HSSFWorkbook wb = new HSSFWorkbook();
// 一个sheet
HSSFSheet sheet = wb.createSheet("工作表名");
// 第一行 标题
HSSFRow rowTitle = sheet.createRow(0);
// 设置标题
for (int i = 0; i < titleList.size(); i++) {
HSSFCell cell = rowTitle.createCell(i);
cell.setCellValue(titleList.get(i));
}
//合并单元格CellRangeAddress构造参数依次表示起始行,截至行,起始列, 截至列
/*sheet.addMergedRegion(new CellRangeAddress(0,0,0,4));
sheet.addMergedRegion(new CellRangeAddress(titleList.size()-1,titleList.size()-1,titleList.size()-1,titleList.size()+1));*/
return wb;
}
public static <T> HSSFWorkbook getWorkBook(List<String> titleList , List<T> dataList) throws IntrospectionException, IllegalAccessException, InvocationTargetException {
if (CollectionUtils.isNotEmpty(dataList)) {
T t1 = dataList.get(0);
Class<?> t1Class = t1.getClass();
EnableExcel enableExcel = t1Class.getAnnotation(EnableExcel.class);
if (enableExcel == null) {
throw new IllegalArgumentException("EnableExcel 注解没有在实体类启用");
}
Field[] fields = t1Class.getDeclaredFields();
if (fields != null && fields.length > 0) {
Map<String , Integer> titleMap = new HashMap<>(titleList.size()); // 存放属性名称对应的下标
int fieldExcelSize = 0; // 类中ExcelRow 注解的数量
for (Field field : fields) {
field.setAccessible(true);
String fieldName = field.getName();
ExcelRow excelRow = field.getAnnotation(ExcelRow.class);
if (excelRow != null) {
String name = excelRow.name();
if (StringUtils.isEmpty(name)) {
throw new IllegalArgumentException("ExcelRow 注解name属性不能为空");
}
int index = titleList.indexOf(name.trim());
if (index != -1) {
fieldExcelSize++;
titleMap.put(fieldName , index);
}
}
}
if (!(titleList.size() == fieldExcelSize)) {
throw new IllegalArgumentException("ExcelRow 注解name属性对应的列数不对");
}
HSSFWorkbook workBook = getWorkBook(titleList);
HSSFSheet sheet = workBook.getSheetAt(0);
for (T t : dataList) {
int lastRowNum = sheet.getLastRowNum();
HSSFRow row = sheet.createRow(lastRowNum + 1);
BeanInfo beanInfo = Introspector.getBeanInfo(t.getClass());
PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
String fieldName = propertyDescriptor.getName();
if (titleMap.containsKey(fieldName)) {
Method readMethod = propertyDescriptor.getReadMethod();
if (readMethod != null) {
Class<?> returnType = readMethod.getReturnType();
String simpleName = returnType.getSimpleName();
Object invoke = readMethod.invoke(t);
String value = "";
// 可以根据不同的类型返回不同的数据
if ("date".equalsIgnoreCase(simpleName)) {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
if (invoke != null) {
value = simpleDateFormat.format(invoke);
}
}
if (invoke != null && "".equals(value)) {
value = invoke.toString();
}
row.createCell(titleMap.get(fieldName)).setCellValue(value);
}
}
}
}
return workBook;
}
}
return null;
}
测试
/**
* 测试Excel表格导出
* @param args
*/
public static void main(String[] args) throws IllegalAccessException, IntrospectionException, InvocationTargetException, IOException {
List<String> titleList = new ArrayList<>();
titleList.add("哈");
titleList.add("哈哈");
titleList.add("Date");
List<ExcelEntity> userEntities = new ArrayList<>();
for (int i = 0; i < 10; i++) {
ExcelEntity excelEntity = new ExcelEntity();
excelEntity.setUsername("username"+i);
excelEntity.setPassword("password"+i);
excelEntity.setCreateDate(new Date());
userEntities.add(excelEntity);
}
HSSFWorkbook workBook = ExcelUtils.getWorkBook(titleList, userEntities);
if (workBook != null) {
File file = new File("D:\\1.xlsx");
workBook.write(file);
}
System.out.println("导出成功");
}