将数据库的数据转换为excel文件下载到本地的方法中遇到的困难及解决方案
以下是将数据库的数据转换为excel文件下载到本地的方法
@Autowired
private BooksService booksService;
@RequestMapping("/downloadBooksExcel")
public void downstudents(HttpServletRequest request, HttpServletResponse response)throws IOException {
String[] headers = { "序号", "作者", "出版社", "时间","项目编号","标题"};//导出的Excel头部,这个要根据自己项目改一下
List<TBooks> dataset = booksService.findAll();//查询出来的数据,根据自己项目改一下
for (TBooks books: dataset) {
}
//下面的完全不动就行了(Excel数据中不包含图片)
// 声明一个工作薄
HSSFWorkbook workbook = new HSSFWorkbook();
// 生成一个表格
HSSFSheet sheet = workbook.createSheet();
// 设置表格默认列宽度为15个字节
sheet.setColumnWidth(5,8000);
HSSFRow row = sheet.createRow(0);
for (int i = 0; i < headers.length; i++) {
HSSFCell cell = row.createCell(i);
HSSFRichTextString text = new HSSFRichTextString(headers[i]);
cell.setCellValue(text);
}
//遍历集合数据,产生数据行
Iterator it = dataset.iterator();
int index = 0;
while (it.hasNext()) {
index++;
row = sheet.createRow(index);
TBooks t = (TBooks) it.next();
//利用反射,根据javabean属性的先后顺序,动态调用getXxx()方法得到属性值
Field[] fields = t.getClass().getDeclaredFields();
for (int i = 0; i < fields.length; i++) {
Field field = fields[i];
String fieldName = field.getName();
String getMethodName = "get"
+ fieldName.substring(0, 1).toUpperCase()
+ fieldName.substring(1);
HSSFCell cell = row.createCell(i);
try {
Class tCls = t.getClass();
Method getMethod = tCls.getMethod(getMethodName,
new Class[]{});
System.out.println(getMethodName);
Object value = null;
if (getMethodName.equals("getStatus")) {
//sheet.removeMergedRegion(getMergedRegionIndex(sheet, 1, 1));
continue;//相当于清空了是数据
}
if (getMethodName.equals("getResultId")) {
continue;//相当于清空了是数据
}
//row.removeCell(cell);
value = getMethod.invoke(t, new Object[]{});
if (getMethodName.equals("getId")) {
cell.setCellValue(i+1);//如果是id列的话,直接将序号设置进去
}
System.out.println(value);
String textValue = null;
if (value instanceof Date) {
Date date = (Date) value;
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
textValue = sdf.format(date);
} else {
//其它数据类型都当作字符串简单处理
textValue = value.toString();
}
HSSFRichTextString richString = new HSSFRichTextString(textValue);
HSSFFont font3 = workbook.createFont();
font3.setColor(HSSFColor.BLUE.index);//定义Excel数据颜色
richString.applyFont(font3);
cell.setCellValue(richString);
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchMethodException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
response.setContentType("application/octet-stream");
response.setHeader("Content-disposition", "attachment;filename=createList.xls");//默认Excel名称
response.flushBuffer();
workbook.write(response.getOutputStream());
}
今天在生成excel文件的时候遇到一个bug,那就是我们在查询数据库的时候得到一个集合,但是这个集合里面有一些字段不是我们需要的,比如id,status(状态)等信息,这些信息我们不需要生成excel表格,然后让客户下载下来。那么问题来了,我们就需要把把这些数据删掉。
if (getMethodName.equals("getStatus")) {
continue;//相当于清空了是数据
}
if (getMethodName.equals("getResultId")) {
continue;//相当于清空了是数据
}
然后我就把数据删掉了,但是这样的话还是会存在问题,因为数据虽然删掉了,但是生成的列还存在
就如上图一样,我们的项目编号是空的,因为if (getMethodName.equals(“getResultId”)) {
continue;//相当于清空了是数据
}清空了数据但是,没有删除列
然后我尝试了很多方法进行删除列
比如:sheet.removeMergedRegion(getMergedRegionIndex(sheet, 1, 1));
但是这个方法getMergedRegionIndex缺少依赖,无法正常使用
又尝试了另一种方法
//deleteColumn(sheet,0,1);
private static void deleteColumn(HSSFSheet sheet, int columnStartIndex, int columnNum) {
Util.shiftCellsLeft(sheet, 0, columnStartIndex + columnNum, sheet.getPhysicalNumberOfRows() - 1, sheet.getRow(0).getPhysicalNumberOfCells() - 1, columnNum, true);
Util.shiftCellsLeft(sheet, 0, sheet.getRow(0).getPhysicalNumberOfCells(), sheet.getPhysicalNumberOfRows() - 1, sheet.getRow(0).getPhysicalNumberOfCells() + columnNum, columnNum, true);
}
这种方法是可以删除列的,但是本人比较笨,这个方法的源码有点不是很懂,源码如下:
public static void shiftCellsLeft(Sheet sheet, int startRow, int startCol, int endRow, int endCol, int shiftNumber, boolean removeSourceMergedRegion) {
Set mergedRegions = new HashSet();
for(int rowNum = startRow; rowNum <= endRow; ++rowNum) {
boolean doSetWidth = true;
Row row = sheet.getRow(rowNum);
if (row != null) {
for(int colNum = startCol; colNum <= endCol; ++colNum) {
Cell cell = row.getCell(colNum);
if (cell == null) {
cell = row.createCell(colNum);
doSetWidth = false;
}
int destColNum = colNum - shiftNumber;
Cell destCell = row.getCell(destColNum);
if (destCell == null) {
destCell = row.createCell(destColNum);
}
copyCell(cell, destCell, true);
updateMergedRegionInRow(sheet, mergedRegions, rowNum, colNum, destColNum, removeSourceMergedRegion);
if (doSetWidth) {
sheet.setColumnWidth(destCell.getColumnIndex(), getWidth(sheet, cell.getColumnIndex()));
}
}
}
}
}
最后数据是删除了,但是删除的结果不是我想要的,删除结果如下图
应该是参数的问题,或者是调用的方法放的位置不对
然后我想着既然我不能删除列,那我在创建列的时候不创建对应的列不就行了吗
HSSFCell cell = null;
if(!getMethodName.equals("getStatus")||!getMethodName.equals("getResultId"){
cell = row.createCell(i);
}
但是事与愿违,它还是生成了对应的列,没有办法,我只能另寻出路了
最后我把实体类的顺序更改了一下,就完成了这个功能
更改前的顺序
更改后的顺序,把resultId(get/set方法也放在后面)放到最后了,虽然还会生成空的resultId的列,但是这是在后面,对我们的结果没有影响,这样虽然没有实现真正的删除列,但是我们得到了数据又有什么影响呢?
还有就是id那一列,通过一下方法,将数据存入进去就行了
value = getMethod.invoke(t, new Object[]{});
if (getMethodName.equals("getId")) {
cell.setCellValue(i+1);//如果是id列的话,直接将序号设置进去
}
最后,访问网页http://localhost:8081/file/downloadBooksExcel就可以了
下载的数据如下图,大功告成
参考文献:https://blog.****.net/panpan96/article/details/76566475