предисловие
История началась так: Компания дала несколько дней на завершение разработки 2-х функциональных модулей. Один из сценариев таков: импорт данных из Excel требует, чтобы данные не повторялись. Пользователи могут загружать файлы Excel, которые не удалось импортировать.
Итак, есть 2 реализации
- Храните ошибочные данные в базе данных и создавайте загрузку Excel, когда вам нужно ее загрузить.
- Создайте файл Excel из ошибочных данных и сохраните его на файловом сервере, а затем верните ссылку для скачивания.
Начальник попросил действовать по второму плану. Что ж, экспорт в Excel — очень распространенная функция, но я всегда чувствовал, что она недостаточно элегантна, чтобы писать ее раньше, поэтому я решил сделать простой пакет для адаптации к экспорту в Excel простых сценариев.
выполнить
Источником данных, экспортируемым Excel, обычно являются данные, запрашиваемые в базе данных. В объектно-ориентированном дизайне Java-разработки данные обычно заполняются коллекциями с объектами в качестве носителей. Таким образом, один из входных параметров разработан как класс коллекции Collection.
Экспортированный Excel обычно нуждается в заголовке, чтобы объяснить значение каждого столбца данных.Здесь мы планируем использовать аннотацию + отражение для его определения. Excel либо черезHttpServletResponseвсе ещеFileStorage — это, по сути, операция потока ввода-вывода.
Конкретная реализация выглядит следующим образом:
pom.xml
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>4.1.2</version>
</dependency>
Определение аннотации
Эта аннотация добавляется к полю, определяет, какие поля необходимо экспортировать в Excel, и добавляет описание заголовка.
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ExcelHeader {
/**
* 表头
* @return
*/
String value() default "";
/**
* 列索引
* @return
*/
int columnIndex() default 0;
}
класс сущности
Согласно аннотациям в следующих классах сущностей, поле возраста не нужно экспортировать в Excel.
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
@ExcelHeader(value = "账号")
private String username;
@ExcelHeader(value = "密码")
private String password;
@ExcelHeader(value = "生日")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime birthday;
// 该字段没有添加注解, Excel不导出
private Integer age;
public User(String username, String password, LocalDateTime birthday) {
this.username = username;
this.password = password;
this.birthday = birthday;
}
}
модульный тест
Комментарии достаточно ясны, чтобы не повторяться здесь слишком много.
@Slf4j
class IdcPoiApplicationTests {
@Test
void contextLoads() throws NoSuchFieldException, IllegalAccessException, IOException {
// 创建模拟数据
User user1 = new User("admin", "123456", LocalDateTime.now());
User user2 = new User("test", "123456", LocalDateTime.now());
List<User> users = Arrays.asList(user1, user2);
// 文件路径
String basePath = "/Users/cuishiying/Documents/spring-cloud-learning/idc-poi/oss/";
String fileName = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()).toString() +".xls";
// 将Excel写入文件
HSSFWorkbook workbook = exportExcel(users, User.class);
workbook.setSheetName(0,"sheetName");//设置sheet的Name
// 无论是通过HttpServletResponse导出还是导出到本地磁盘,本质都是IO操作,所以这里将IO操作提取到外层。
workbook.write(new File(basePath + File.separator + fileName));
}
/**
*
* @param data 需要导出的数据
* @param clz 数据对应的实体类
* @param <T> 泛型
* @return Excel文件
* @throws NoSuchFieldException
* @throws IllegalAccessException
*/
public <T> HSSFWorkbook exportExcel(List<T> data, Class<T> clz) throws NoSuchFieldException, IllegalAccessException {
Field[] fields = clz.getDeclaredFields();
List<String> headers = new LinkedList<>();
List<String> variables = new LinkedList<>();
// 创建工作薄对象
HSSFWorkbook workbook=new HSSFWorkbook();//这里也可以设置sheet的Name
// 创建工作表对象
HSSFSheet sheet = workbook.createSheet();
// 创建表头
Row rowHeader = sheet.createRow(0);
// 表头处理
for (int h = 0; h < fields.length; h++) {
Field field = fields[h];
if (field.isAnnotationPresent(ExcelHeader.class)) {
// 表头
ExcelHeader annotation = field.getAnnotation(ExcelHeader.class);
headers.add(annotation.value());
rowHeader.createCell(h).setCellValue(annotation.value());
// 字段
variables.add(field.getName());
}
}
// 数据处理
for (int i = 0; i < data.size() ; i++) {
//创建工作表的行(表头占用1行, 这里从第二行开始)
HSSFRow row = sheet.createRow(i + 1);
// 获取一行数据
T t = data.get(i);
Class<?> aClass = t.getClass();
// 填充列数据
for (int j = 0; j < variables.size(); j++) {
Field declaredField = aClass.getDeclaredField(variables.get(j));
declaredField.setAccessible(true);
String key = declaredField.getName();
Object value = declaredField.get(t);
row.createCell(j).setCellValue(value.toString());
}
}
log.info("Excel文件创建成功");
return workbook;
}
}
Суммировать
Вышеприведенный случай предназначен только для выражения основных дизайнерских идей, а не строго. Пожалуйста, подумайте, используете ли вы его в своем проекте. На этом статья заканчивается, спасибо за прочтение. Если вы считаете, что это хорошо, обратите внимание на публичный аккаунт [Когда я встретил вас], чтобы поддержать его.