(反正没人看到,那我就偷偷学一下)
导出数据库到模板的Excel
这个篇笔记主要是总结一下。
首先是敲了一个简单的导出数据,代码如下:
这是Controller层(注:reqBookService.exportExcel()里面就是只是select出所有数据)
@RequestMapping("/export") public void export(HttpServletResponse response,Model model) throws Exception { List<ReqBook> books = reqBookService.exportExcel(); Workbook workbook = new XSSFWorkbook();//XSSFWorkbook可以创建.xlsx格式的Excel,区别于上一篇的.xls格式 Sheet sheet = workbook.createSheet("sheeet0"); String[] titles = {"ISBN","名称","作者","出版社","数量"}; Row row = sheet.createRow(0); for (int i = 0;i< titles.length;i++) { Cell cell = row.createCell(i); cell.setCellValue(titles[i]); } for (int i = 0;i < books.size();i++){ row = sheet.createRow(i+1); ReqBook reqBook = books.get(i); Cell ISBNCell = row.createCell(0); ISBNCell.setCellValue(reqBook.getBookISBN()); Cell nameCell = row.createCell(1); nameCell.setCellValue(reqBook.getName()); Cell authorCell = row.createCell(2); authorCell.setCellValue(reqBook.getAuthor()); Cell publishingCell = row.createCell(3); publishingCell.setCellValue(reqBook.getPublishing()); Cell quantityCell = row.createCell(4); quantityCell.setCellValue(reqBook.getQuantity()); } String filename = URLEncoder.encode("图书表.xlsx","UTF-8"); response.setContentType("application/octet-stream");//设置输出类型 response.setHeader("content-disposition","attachment;filename=" + filename);//文件下载需要的 response.setHeader("filename",filename); workbook.write(response.getOutputStream()); }
这段是最初的代码,缺点很显然,太死,不够灵活,所以我封装了一下作为一个util类(注:还有一些欠缺:不能设置结束行,开始列,结束列)
自定义注解@ExcelAtrr
import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;/** * 自定义注解 * 用于导出Excel */@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.FIELD)public @interface ExcelAtrr { int sort();}
sort等于几就是导出Excel的第几列
import com.example.anno.ExcelAtrr;public class ReqBook { /** *id */ private Integer id; /** * ISBN */ @ExcelAtrr(sort = 3) private String bookISBN; /** * 书名 */ @ExcelAtrr(sort = 0) private String name; /** * 作者 */ @ExcelAtrr(sort = 1) private String author; /** * 出版社 */ @ExcelAtrr(sort = 2) private String publishing; /** * 数量 */ @ExcelAtrr(sort = 4) private Integer quantity;
封装的使用模板导出工具
import com.example.anno.ExcelAtrr;import com.example.entity.ReqBook;import org.apache.poi.ss.usermodel.*;import org.apache.poi.xssf.usermodel.XSSFWorkbook;import org.springframework.lang.NonNull;import javax.servlet.http.HttpServletResponse;import java.io.OutputStream;import java.lang.reflect.Field;import java.net.URLEncoder;import java.util.List;import java.util.Map;import java.util.Objects;/** * 导出Excel工具 * 需要objs、 path、 rowIndex、 response四个参数 * 数据类型 模板路径 开始行 response * @param <T> */public class ExportUtil<T> { public void exportExcelStyle(@NonNull Map<String, Object> params)throws Exception{ List<T> objs = (List<T>) params.get("objs");//设置泛型 String path = (String) params.get("path");//路径 Integer rowIndex = (Integer) params.get("rowIndex");//开始行// Integer cellIndex = (Integer) params.get("cellIndex");//开始列 HttpServletResponse response = (HttpServletResponse) params.get("response"); String filename = (String) params.get("filename"); Workbook workbook = new XSSFWorkbook(Objects.requireNonNull(ExportUtil.class.getClassLoader().getResourceAsStream(path))); Sheet sheet = workbook.getSheetAt(0); Row row1 = sheet.getRow(rowIndex); CellStyle[] cellStyles = new CellStyle[row1.getLastCellNum()]; for (int i = 0;i< cellStyles.length;i++) { cellStyles[i]=row1.getCell(i).getCellStyle(); } for (int i = 0;i < objs.size();i++){ Row row = sheet.createRow(i + rowIndex); T t = objs.get(i); Class<?> clazz = t.getClass(); Field[] fields = clazz.getDeclaredFields();//只要标了注解的 for (int j = 0; j<cellStyles.length; j++){//根据上面拿到的单元格属性添加 Cell cell = row.createCell(j); cell.setCellStyle(cellStyles[j]); //每找出一个有注解的字段,就填入 for (Field field: fields) { ExcelAtrr annotation = field.getAnnotation(ExcelAtrr.class); if (annotation!=null){ int sort = annotation.sort(); if (sort==j) { field.setAccessible(true); cell.setCellValue(field.get(t).toString()); } } } } } String fileName = URLEncoder.encode(filename+".xlsx","UTF-8");//下载为“.xlsx” response.setContentType("application/octet-stream");//设置输出类型 response.setHeader("content-disposition","attachment;filename=" + fileName);//文件下载需要的 response.setHeader("filename",fileName); workbook.write(response.getOutputStream()); }}
这样就可以用泛型写任何实体的Excel导出
eg:
/** * 使用模板导出Excel * @param response * @param model * @throws Exception */ @RequestMapping("/exportExcelStyle") public void exportExcelStyle(HttpServletResponse response,Model model) throws Exception { List<ReqBook> reqBooks = reqBookService.exportExcel(); ExportUtil<ReqBook> exportUtil = new ExportUtil<>(); Map<String,Object> params = new HashMap<>(); params.put("objs",reqBooks); params.put("path", "excel/test.xlsx");//模板的路径,我是放在resources下面 //导出的表要有表头否则可能会报错,我的表头是两行所以从第二行开始 params.put("rowIndex",2);//开始行,从0开始数// params.put("cellIndex",0);//开始列,默认从0开始 params.put("response",response); params.put("filename","导出的Excel"); exportUtil.exportExcelStyle(params); }
虽然缺点还很多但是目前导出一个如下的表还是够用了
这是模板
这是导出后的样子
做这些真的是废了我好长时间,很多莫名其妙的空指针异常,比如:getResourceAsStream()报异常拿不到path,有可能不是路径问题而是字段或者模板表和开始行有问题,我一直以为是我路径不对,是真的坑。
最后,我也是小白如有更好的建议或意见请多多评论指正,不胜感激。