Java注解合泛型的小探索使用

  • 前言

最近整了个新的奇葩需求 在android中处理excel表,通过搜索找到了个

库apache的poi poi-3.12-android-a.jar 但是用起来非常多api都没有 就想着自己整一个 然后就用上了接触已久 但是从没自己写过的东西 注解

主要目的是为了把表格中的一行(Row)转换为一个Java对象来操作,整个表(Sheet)当成一个List,一行中的列(Cell)就当成对象中的属性字段。

1. 注解类

定义一个注解类 用在 类字段上面 后面可以用@ExcelColumn(name = “商品编号”, index = 0)来为一个类属性添加注解

1
2
3
4
5
6
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface ExcelColumn {
String name();
int index();
}

2.解析的类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
public class XlsxUtil {
private static final String TAG="XlsxUtil";

public static <T> List<T> bindObject(FileInputStream fis,Class<T> type, boolean skip_first) throws Exception {
ArrayList<T> rows = new ArrayList<>();

Workbook workbook = new XSSFWorkbook(fis);
Sheet sheetAt = workbook.getSheetAt(0);
for (Row row : sheetAt) {
if (skip_first && row.getRowNum() == 0) continue;
//使用反射 创建一个实例对象
T t = type.getDeclaredConstructor().newInstance();
//传入实例对象合row 在函数里面完成 row和对象的转换
bindRow2obj(row,t);
rows.add(t);
}
return rows;
}

public static <T> void bindRow2obj(Row row,T obj) throws IllegalAccessException {
//获取这个类的全部属性
Field[] declaredFields = obj.getClass().getDeclaredFields();
//遍历每个属性
for (Field declaredField : declaredFields) {
//jvm的优化 可以让对象属性可以直接修改
declaredField.setAccessible(true);

//单独为一个属性做操作 这里我默认使用row_index 来记录在excel中的行
if (declaredField.getName().equals("row_index")) {
//为属性赋值
declaredField.set(obj, row.getRowNum());
continue;
}

//判断是不是加了@ExcelColumn的注解
if (declaredField.isAnnotationPresent(ExcelColumn.class)) {
//取出注解
ExcelColumn annotation = declaredField.getAnnotation(ExcelColumn.class);
int index = annotation.index();
//从row中获取index的值 然后从row中获取出来
if (row.getCell(index) != null) {
String cellString = XlsxUtil.getCell2String(row.getCell(index));
//判断当前这个属性是什么类型的 然后进行解析 再调用declaredField.set进行赋值
switch (declaredField.getType().getSimpleName()) {
case "String":
declaredField.set(obj, cellString);
break;
case "int":
case "Integer":
//去除小数部分
declaredField.set(obj, Integer.valueOf(cellString.split("\\.")[0]));
break;
case "double":
declaredField.set(obj, Double.valueOf(cellString));
break;
}
}
}
}
}

public static String getCell2String(Cell cell){
if (cell.getCellType() == Cell.CELL_TYPE_NUMERIC) {
return String.valueOf(cell.getNumericCellValue());
} else if (cell.getCellType() == Cell.CELL_TYPE_STRING) {
return cell.getStringCellValue();
} else if (cell.getCellType() == Cell.CELL_TYPE_BOOLEAN) {
return String.valueOf(cell.getBooleanCellValue());
}
return "";
}
}

在这里我前面想使用一个实体XlsxUtil类来对应一张表(Sheet),泛型放到类上面去,后面想想这样也不太好,多了一个List的状态要管理,这样不好使用多线程或者后面的一些复杂的东西。所有目前的是方法式的泛型,单纯当一个工具类来使用 不需要管理任何的状态。

3. 具体使用的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public void initdata(){
File file = new File(this.getExternalFilesDir(null), "data.xlsx");

try {
FileInputStream fis = new FileInputStream(file);
boxInfos = XlsxUtil.bindObject(fis, BoxInfo.class, true);
for (BoxInfo boxInfo: boxInfos) {
Log.i("Main", "strings: " + boxInfo.toString());
}
fis.close();
} catch (Exception e) {
e.printStackTrace();
}
}

在BoxInfo中使用注解在字段上面就好了

1
2
3
4
5
6
@ExcelColumn(name = "商品编号", index = 0)
private int goods_code;

记得加上一个空构造
public BoxInfo() {
}


Java注解合泛型的小探索使用
https://wantoper.github.io/2024/12/10/old/java-anno/
作者
Wantoper
发布于
2024年12月10日
许可协议