通过上一篇文章: Java导入Excel文档到数据库
我们了解到了有关使用Java操作Excel文件的基本流程及相关的类。
那么现在我们就要做一下将相关的数据导出成Excel文件给用户了。
导入的流程我们已经清楚了:
读取Excel文件生成工作簿(Workbook)对象
获取表(Sheet)对象
遍历行所有的单元格(Cell)
获取一行数据(Row)
生成一个相应的对象
数据库存储
重复上述操作,直至遍历完所有的行。
大致可以理解为将表里的所有Row变为一个List
那么导出的逻辑就很简单了,反过来就行了:
List变为表里面所有Row
1、数据库操作获取一个List
2、创建一个Workbook对象
3、由Workbook获取一个Sheet对象
4、遍历List集合
为每一个对象创建一个Row对象遍历属性集合,为每一个属性值创建一个Cell将对象里的值设置进Cell中
测试结果
这里就不对使用到类再进行赘述了,前言里提到的Java导入Excel文档到数据库一文中,已经说过了。相关的类也在里面,代码部分我只放测试与工具类,其他的在导入里面。
导出结果 - 默认排序
指定顺序
import org.apache.poi.ss.usermodel.*;import java.io.*;
import java.lang.reflect.InvocationTargetException;
import java.util.*;/*** @author 三文鱼先生* @title* @description* @date 2022/8/11**/
public class TestForParseExcel {public static void main(String[] args) throws ClassNotFoundException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchMethodException, IOException {Map<String , String> map &#61; new HashMap<>();//表头与键值对的映射关系map.put("学号", "id");map.put("姓名" , "name");map.put("科目" , "subject");map.put("分数" , "grade");map.put("班级" , "className");map.put("任课教师" , "teacher");map.put("是否缺课" , "cutClass");List<Student> list &#61; null;try(//这里面的对象会自动关闭InputStream in &#61; new FileInputStream(new File("F:\\学习记录\\测试数据\\Student.xlsx"));//用流来构建工作簿对象Workbook workbook &#61; ExcelImportSheet.getTypeFromExtends(in , "Student.xlsx")) {//根据名称获取单张表对象 也可以使用getSheetAt(int index)获取单张表的对象 获取第一张表Sheet sheet &#61; workbook.getSheetAt(0);list &#61; ExcelImportSheet.getListFromExcel(sheet , Student.class , map);for (Student student : list) {//底层数据库操作 insert什么的System.out.println(student.toString());}}catch(IOException exception) {exception.printStackTrace();} catch (Exception e) {e.printStackTrace();}finally {//写着好看的}Map<String , String> map1 &#61; new HashMap<>();//表头与键值对的映射关系map1.put("id", "学号");map1.put("name" , "姓名");map1.put("subject" , "科目");map1.put("grade" , "分数");map1.put("className" , "班级");map1.put("teacher" , "任课老师");map1.put("cutClass" , "是否缺课");//这里是指定表头顺序 记得把方法参数的null改为orderList
// List
// orderList.add("id");
// orderList.add("name");
// orderList.add("subject");
// orderList.add("grade");
// orderList.add("className");
// orderList.add("teacher");
// orderList.add("cutClass");//导出逻辑 这里的list是从导入里面哪来的 map1与map不一样 orderList这里为空Workbook workbook &#61; ExcelExportUtil.createWorkbook(list , map1 , 1 , "学生信息表" , null);System.out.println("导出文件位置为&#xff1a;" &#43; ExcelExportUtil.store("F:\\学习记录\\测试数据\\导出excel测试" , workbook , 1));}}
ExcelExportUtil.class
导出工具类&#xff0c;这里值得注意的是:
Map的映射方式是 属性-表头名称
&#xff0c;而导入的映射方式是&#xff1a;表头名称 - 属性。
Map中的Key是不一样的。
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;import java.io.*;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.text.SimpleDateFormat;
import java.util.*;/*** &#64;author 三文鱼先生* &#64;title* &#64;description 用于导出数据* &#64;date 2022/8/23**/
public class ExcelExportUtil {/*** &#64;description 考虑到下载方式的不同 这里细化成只获取一个workBook 格式为默认 无格式* &#64;author 三文鱼先生* &#64;date 10:47 2022/8/26* &#64;param list 需要存储为excel的对象集合* &#64;param map 键值对映射 属性 - 表头字段 类似于: name - 姓名* &#64;param type 生成workbook的类型* &#64;param tableName 生成Sheet的名称* &#64;param orderList 表头顺序对应的属性list* &#64;return org.apache.poi.ss.usermodel.Workbook**/public static <T>Workbook createWorkbook(List<T> list , //数据库查询的返回ListMap<String , String> map , //表头映射Integer type , //生成workbook的类型 0 - xls 其他-xlsxString tableName , //表名List<String> orderList //排序的List 为空 则使用默认的顺序) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException {//工作簿Workbook workbook &#61; getWorkbookByType(type);//单个表Sheet sheet &#61; workbook.createSheet(tableName);//orderList 表头顺序&#xff0c;可以为空if(orderList &#61;&#61; null || orderList.size() &#61;&#61; 0) {orderList &#61; new ArrayList<>();//获取map映射的顺序for (Map.Entry<String, String> mapEntry : map.entrySet()) {orderList.add(mapEntry.getKey());}}//每列对应的属性参数List<Class> typeClassList &#61; getParamsType(list.get(0).getClass(), orderList);//设置表头的值Row headRow &#61; sheet.createRow(0);for (int i &#61; 0; i < orderList.size(); i&#43;&#43;) {Cell cell &#61; headRow.createCell(i);//设置单元格的属性cell.setCellType(CellType.STRING);cell.setCellValue(map.get(orderList.get(i)));}int index &#61; 1;//单元行Row dataRow &#61; null;//单元格Cell dataCell &#61; null;//遍历Listfor (T t : list) {//获取一行dataRow &#61; sheet.createRow(index);//遍历表头对应属性&#xff0c;给一行数据设置值for (int j &#61; 0; j < orderList.size(); j&#43;&#43;) {//获取一个单元格dataCell &#61; dataRow.createCell(j);//根据对应列的属性 设置对应的值类型及值setCellValueTypeAndValue(dataCell , typeClassList.get(j) ,t.getClass().getMethod(getGetterMethodName(orderList.get(j)) , new Class[]{}).invoke(t , new Class[]{}));}//行下标后移index&#43;&#43;;}//设置值return workbook;}/*** &#64;description 存储到对应的文件夹下* &#64;author 三文鱼先生* &#64;date 10:44 2022/8/26* &#64;param path 文件夹路径* &#64;param workbook 存储的工作簿对象* &#64;param type 存储的类型* &#64;return void**/public static String store(String path , Workbook workbook , Integer type) throws IOException {path &#61; path &#43;File.separator &#43;getNowDate()&#43; workbook.getSheetName(0) &#43; getExtensionByType(type);try(OutputStream outputStream &#61; new FileOutputStream(new File(path))){workbook.write(outputStream);} catch (FileNotFoundException e) {e.printStackTrace();}catch (Exception e) {e.printStackTrace();} finally {workbook.close();}return path;}/*** &#64;description 根据type获取对应文件后缀 0-xls 其他xlsx 默认为xls* &#64;author 三文鱼先生* &#64;date 10:43 2022/8/26* &#64;param type 类型* &#64;return java.lang.String**/public static String getExtensionByType(Integer type) {if(type &#61;&#61; null || type &#61;&#61; 0)return ".xls";elsereturn ".xlsx";}/*** &#64;description 根据所给的type获取对应的工作簿 0-HSSFWorkbook 其他-XSSFWorkbook* &#64;author 三文鱼先生* &#64;date 10:41 2022/8/26* &#64;param type 类型* &#64;return org.apache.poi.ss.usermodel.Workbook**/public static Workbook getWorkbookByType(Integer type) {if(type &#61;&#61; null || type &#61;&#61; 0)return new HSSFWorkbook();elsereturn new XSSFWorkbook();}/*** &#64;description 根据属性名称获取对应的get方法* &#64;author 三文鱼先生* &#64;date 10:38 2022/8/26* &#64;param param 属性名称* &#64;return java.lang.String**/public static String getGetterMethodName(String param) {char[] chars &#61; param.toCharArray();//首字母大写if(Character.isLowerCase(chars[0])) {chars[0] -&#61; 32;}//拼接get方法return "get" &#43; new String(chars);}/*** &#64;description 根据属性的List获取对应的类型List* &#64;author 三文鱼先生* &#64;date 10:37 2022/8/26* &#64;param cs 对应的类* &#64;param paramsList 对应的属性list* &#64;return java.util.List
}
遇到的问题
boolean属性自动生成的get方法问题。自动生成的方法为&#xff1a;getIs属性名&#xff0c;而不是我以为的get属性名称。
自己写一个该属性的get方法即可
cell.setCellValue()的方法是需要具体的类型的
他没有cell.setCellValue(Object o)方法&#xff0c;而是需要具体的类型。
我没找到使用Class和Object&#xff0c;将一个对象强转为指定Class对象的方法。
将强转和设置单元格类型&#xff0c;放到一起。也就是这样
也是不难&#xff0c;不过需要时间。上述需要最应该优化的地方应该是在&#xff0c;
设置单元格的风格&#xff1a;
表头字体可能需要加粗&#xff0c;
字符串包括什么敏感字符&#xff0c;单元格需要标红&#xff0c;
又或者是数字类型的数据超过什么值&#xff0c;需要显示黄色等等
但是由于每个人风格不一样&#xff0c;
所以还是读取完数据&#xff0c;生成了workbook,再拿workbook对象来设置好了。
另一个点就是&#xff0c;没有存储图片文件。不过估计也不难。