Apache POI 实现报表导入和导出
生活随笔
收集整理的這篇文章主要介紹了
Apache POI 实现报表导入和导出
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
1、POI概述
在企業級應用開發中,Excel報表是一種最常見的報表需求。Excel報表開發一般分為兩種形式:
- 基于Excel報表批量上傳數據
- 通過Java代碼生成Excel報表
Java中常見的用來操作Excel的方式一般有2種:JXL和POI
- JXL只能對Excel進行操作,屬于比較老的框架,它只支持到Excel 95-2000的版本。現在已經停止更新和維護。
- POI是Apache的項目,可對微軟的Word、Excel、PPT進行操作:包括office2003和2007,Excl2003和2007。POI現在一直有更新。
Apache POI是Apache軟件基金會的開源項目,由Java編寫的免費開源的跨平臺的 Java API,Apache POI提供API給Java語言操作Microsoft Office的功能。使用場景:
- 數據報表生成
- 數據備份
- 數據批量上傳
2、準備工作
2.1、創建項目導入依賴
<dependencies><dependency><groupId>org.apache.poi</groupId><artifactId>poi</artifactId><version>4.0.1</version></dependency><dependency><groupId>org.apache.poi</groupId><artifactId>poi-ooxml</artifactId><version>4.0.1</version></dependency><dependency><groupId>org.apache.poi</groupId><artifactId>poi-ooxml-schemas</artifactId><version>4.0.1</version></dependency> </dependencies>2.2、POI常用API介紹
2.3、自定義工具類
自定義生成Excel報表文件有很多不盡如意的地方,特別是針對復雜報表頭,單元格樣式,字體等操作。手寫這些代碼不僅費時費力,有時候效果還不太理想。怎么樣才能更方便的對報表樣式,報表頭進行處理呢?答:使用已經準備好的Excel模板,只需要關注模板中的數據即可。
2.3.1、準備模板文件,比如:
2.3.2、自定義注解
// 用來修飾實體類的字段:指定屬性用來封裝excel表的哪一列數據 @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public @interface ExcelAttribute {/** 對應的列名稱 */String name() default "";/** 列序號 */int sort();/** 字段類型對應的格式 */String format() default ""; }2.3.3、創建實體類
// 用來封裝數據庫的每條記錄:對應excel的一條記錄 public class Employee {// 編號@ExcelAttribute(sort = 0)private String id;// 姓名@ExcelAttribute(sort = 1)private String username;// 手機@ExcelAttribute(sort = 2)private String mobile;// 最高學歷@ExcelAttribute(sort = 3)private String edu;// 籍貫@ExcelAttribute(sort = 4)private String province;// 生日@ExcelAttribute(sort = 5)private String birthday;// 入職時間@ExcelAttribute(sort = 6)private Date joinDate;// 省略setters & getters }2.3.4、導出工具類
// 基本模板的Excel導出工具類 public class ExcelExportUtil<T> {// 寫入數據的起始行private int rowIndex;// 需要提取樣式所在的行號private int styleIndex;// 對象的字節碼private Class clazz;// 對象中的所有屬性private Field fields[];// 構造方法public ExcelExportUtil(Class clazz,int rowIndex,int styleIndex) {this.clazz = clazz;this.rowIndex = rowIndex;this.styleIndex = styleIndex;fields = clazz.getDeclaredFields();}/*** 基于注解導出* response:響應對象,用于往瀏覽器導出數據(文件下載)* is:模板文件對應的輸入流* objs:要導出的數據,即從數據庫中查詢的對象數據集合* fileName:導出的文件名(文件下載名)*/public void export(HttpServletResponse response,InputStream is, List<T> objs,String fileName) throws Exception {// 根據模板創建工作簿XSSFWorkbook workbook = new XSSFWorkbook(is);// 獲得工作表Sheet sheet = workbook.getSheetAt(0);// 獲取公共樣式CellStyle[] styles = getTemplateStyles(sheet.getRow(styleIndex));AtomicInteger datasAi = new AtomicInteger(rowIndex);// 遍歷集合for (T t : objs) {// 創建每一行對象Row row = sheet.createRow(datasAi.getAndIncrement());for(int i=0;i <styles.length; i++) {// 創建一個單元格對象(每一列)Cell cell = row.createCell(i);// 設置列的樣式cell.setCellStyle(styles[i]);// 遍歷成員變量對象for (Field field : fields) {// 判斷成員變量上是否使用了ExcelAttribute注解if(field.isAnnotationPresent(ExcelAttribute.class)){// 暴露反射field.setAccessible(true);// 獲得注解對象ExcelAttribute ea = field.getAnnotation(ExcelAttribute.class);if(i == ea.sort()) {// 設置單元格內容cell.setCellValue(field.get(t).toString());}}}}}// 將excel文件導出到瀏覽器fileName = URLEncoder.encode(fileName, "UTF-8");response.setContentType("application/octet-stream");response.setHeader("content-disposition", "attachment;filename=" + new String(fileName.getBytes("ISO8859-1")));response.setHeader("filename", fileName);workbook.write(response.getOutputStream());}/*** 獲得指定行的單元格樣式*/public CellStyle[] getTemplateStyles(Row row) {CellStyle [] styles = new CellStyle[row.getLastCellNum()];for(int i=0;i<row.getLastCellNum();i++) {styles[i] = row.getCell(i).getCellStyle();}return styles;}// 省略 setters & getters .................. }2.3.5、導入工具類
// 基于注解實現Excel報表數據導入 public class ExcelImportUtil<T> {// 對象的字節碼private Class clazz;// 對象的所有屬性private Field fields[];public ExcelImportUtil(Class clazz) {this.clazz = clazz;fields = clazz.getDeclaredFields();}/*** 基于注解讀取excel文檔數據* is:上傳文件的字節輸入流* rowIndex:讀取數據的起始行* cellIndex:讀取數據的起始單元格索引*/public List<T> readExcel(InputStream is, int rowIndex,int cellIndex) {// 創建集合:用來每一行記錄(對象)List<T> list = new ArrayList<T>();// 實體對象T entity = null;try {// 根據字節輸入流創建工作簿XSSFWorkbook workbook = new XSSFWorkbook(is);//獲得工作表Sheet sheet = workbook.getSheetAt(0);// 獲得總行數int rowLength = sheet.getLastRowNum();// 遍歷每行數據for (int rowNum = rowIndex; rowNum <= sheet.getLastRowNum(); rowNum++) {// 獲得每一行的行對象Row row = sheet.getRow(rowNum);// 通過反射創建實體對象:一行對應一個實體對象entity = (T) clazz.newInstance();// 遍歷每一列for (int j = cellIndex; j < row.getLastCellNum(); j++) {// 獲得單元格對象Cell cell = row.getCell(j);// 遍歷成員變量對象for (Field field : fields) {// 判斷成員變量上是否使用了注解:ExcelAttributeif(field.isAnnotationPresent(ExcelAttribute.class)){// 暴露反射field.setAccessible(true);// 獲得ExcelAttribute注解對象ExcelAttribute ea = field.getAnnotation(ExcelAttribute.class);if(j == ea.sort()) {// 給對象的成員變量賦值field.set(entity, covertAttrType(field, cell));break;}}}}// 將對象添加到集合中list.add(entity);}} catch (Exception e) {e.printStackTrace();}// 返回集合return list;}/*** 類型轉換 將cell 單元格格式轉為 字段類型*/private Object covertAttrType(Field field, Cell cell) throws Exception {String fieldType = field.getType().getSimpleName();if ("String".equals(fieldType)) {return getValue(cell);}else if ("Date".equals(fieldType)) {return new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").parse(getValue(cell)) ;}else if ("int".equals(fieldType) || "Integer".equals(fieldType)) {return Integer.parseInt(getValue(cell));}else if ("double".equals(fieldType) || "Double".equals(fieldType)) {return Double.parseDouble(getValue(cell));}else {return null;}}/*** 格式轉為String* @param cell* @return*/public String getValue(Cell cell) {if (cell == null) {return "";}switch (cell.getCellType()) {case STRING:return cell.getRichStringCellValue().getString().trim();case NUMERIC:if (DateUtil.isCellDateFormatted(cell)) {Date dt = DateUtil.getJavaDate(cell.getNumericCellValue());return new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").format(dt);} else {// 防止數值變成科學計數法String strCell = "";Double num = cell.getNumericCellValue();BigDecimal bd = new BigDecimal(num.toString());if (bd != null) {strCell = bd.toPlainString();}// 去除 浮點型 自動加的 .0if (strCell.endsWith(".0")) {strCell = strCell.substring(0, strCell.indexOf("."));}return strCell;}case BOOLEAN:return String.valueOf(cell.getBooleanCellValue());default:return "";}}// 省略 setters & getters .................. }3、報表導入和導出測試
/*** 導出Excel,導出員工*/ @RequestMapping(value = "/emp/export", method = RequestMethod.GET) public void export() throws Exception {// 1.構造數據List<Employee> list = null; // 查詢數據庫獲得數據// 2.加載模板數據Resource resource = new ClassPathResource("excel.xlsx");FileInputStream fis = new FileInputStream(resource.getFile());// 3. 導出數據new ExcelExportUtil(Employee.class,2,2).export(response,fis,list,"員工報表.xlsx"); }/*** 導入Excel,添加員工*/ @RequestMapping(value="/emp/import",method = RequestMethod.POST) public Result importUser(@RequestParam(name="file") MultipartFile file) throws Exception {// 1.解析ExcelList<Employee> list = new ExcelImportUtil(Employee.class).readExcel(file.getInputStream(),1,1)// 2.批量保存員工employeeService.saveAll(lis);return new Result(ResultCode.SUCCESS); }?
總結
以上是生活随笔為你收集整理的Apache POI 实现报表导入和导出的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Python实例---抽屉热搜榜前端代码
- 下一篇: 智能网关能够实现哪些功能