依賴

<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.poi.eg</groupId> <artifactId>java-poi</artifactId> <version>1.0-SNAPSHOT</version> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.5.RELEASE</version> <relativePath/> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> <fastjson.version>1.2.47</fastjson.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-logging</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>${fastjson.version}</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.16.16</version> </dependency> <!-- poi依賴--> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artifactId> <version>4.0.1</version> </dependency> <!-- poi對於excel 2007的支持依賴--> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml</artifactId> <version>4.0.1</version> </dependency> <!-- poi對於excel 2007的支持依賴--> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml-schemas</artifactId> <version>4.0.1</version> </dependency> </dependencies> <build> <plugins> <!--編譯插件--> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.1</version> <configuration> <source>${java.version}</source> <target>${java.version}</target> </configuration> </plugin> <!--單元測試插件--> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <version>2.12.4</version> <configuration> <skipTests>true</skipTests> </configuration> </plugin> </plugins> </build> </project>
Controller

package com.zhao.web; import com.zhao.common.util.DownloadUtils; import com.zhao.common.util.ExcelExportUtil; import com.zhao.common.util.ExcelImportUtil; import com.zhao.domain.User; import org.apache.poi.ss.usermodel.*; import org.apache.poi.xssf.usermodel.XSSFWorkbook; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.Resource; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; import javax.servlet.http.HttpServletResponse; import java.io.ByteArrayOutputStream; import java.io.FileInputStream; import java.io.IOException; import java.time.LocalDate; import java.util.ArrayList; import java.util.List; @RestController public class controller { /** * 使用抽取的Excel的工具類進行導入 基於模板 */ @PostMapping("ExcelUtilImport") public void ExcelUtilImport(@RequestParam(name = "file") MultipartFile file) throws Exception { List<User> list = new ExcelImportUtil(User.class).readExcel(file.getInputStream(), 1, 2); System.out.println(list); } /** * 使用抽取的Excel的工具類進行導出 基於模板 */ @GetMapping("ExcelUtilExport") public void ExcelUtilExport(HttpServletResponse response) throws Exception { //1.獲取數據 //人為構造的數據,實際是要從數據庫中查的 List<User> users=new ArrayList<>(); User user= new User(); for (int i = 0; i <3 ; i++) { user.setName("洪真英"); user.setPassword(123456); users.add(user); } //2.加載模板 Resource resource = new ClassPathResource("template-Excel/exceltUtilTemplate.xlsx"); FileInputStream fis = new FileInputStream(resource.getFile()); //3.通過 工具類下載文件 //因為內容樣式和要寫的內容都在下標2也就時excel中的第三行 new ExcelExportUtil(User.class,2,2) /** * 參數 1:HttpServletResponse * 2:文件輸入流 * 3:封裝好的對象 * 4:文件名 */ .export(response,fis,users,"反射的形式導出.xlsx"); } /** * 采用 提前制作好的excel模板導出 數據 */ @GetMapping("exportTemplate") public void exportTemplate(HttpServletResponse response) throws IOException { //1.獲取數據 //人為構造的數據,實際是要從數據庫中查的 List<User> users=new ArrayList<>(); User user= new User(); for (int i = 0; i <3 ; i++) { user.setName("洪真英"); user.setPassword(123456); users.add(user); } //2.加載模板 Resource resource = new ClassPathResource("template-Excel/exceltTemplate.xlsx"); FileInputStream fis = new FileInputStream(resource.getFile()); //3.根據模板創建工作簿 Workbook wb = new XSSFWorkbook(fis); //4.讀取工作表 Sheet sheet = wb.getSheetAt(0); //5.抽取公共樣式 , 因為前2行 為標題 第三行是數據 下標為2 Row row = sheet.getRow(2); CellStyle styles[] = new CellStyle[row.getLastCellNum()]; Cell cell = null; for (int i = 0; i < row.getLastCellNum(); i++) { cell = row.getCell(i); styles[i] = cell.getCellStyle(); } //6.構造單元格 int rowIndex=2; int indexNumber=1; for (User user1:users) { //創建每一行,同excel的第二行開始 row=sheet.createRow(rowIndex++); //第一列 cell = row.createCell(0); //設置單元格樣式 cell.setCellStyle(styles[0]); //寫入數據 序號 cell.setCellValue(indexNumber++); //第2列 cell = row.createCell(1); cell.setCellStyle(styles[1]); cell.setCellValue(user1.getName()); //第3列 cell = row.createCell(2); cell.setCellStyle(styles[2]); cell.setCellValue(user1.getPassword()); //第4列 自己亂加的一列時間 user對象中沒有 cell = row.createCell(3); cell.setCellStyle(styles[3]); cell.setCellValue(LocalDate.now().toString()); } //7.下載 ByteArrayOutputStream os=new ByteArrayOutputStream(); wb.write(os); new DownloadUtils().download(os,response,"webExcel模板導出.xlsx"); } /** * Excel 報表導出 */ @GetMapping("export") public void export(HttpServletResponse response) throws IOException { //1.創建workbook工作簿 Workbook wb = new XSSFWorkbook(); //2.創建表單Sheet Sheet sheet = wb.createSheet("web"); String[] title="序號,名字,密碼".split(","); //怎么創建數組都行 //3.創建行對象,從0開始 ,創建標題 Row row = sheet.createRow(0); //4.創建單元格,從0開始 Cell cell = null; //標題 /** 標題的第二種實現 * for (int i = 0; i < title.length; i++) { * //4.創建單元格,從0開始 * row.createCell(i); * //5.單元格寫入數據 * cell.setCellValue(title[i]); * } */ int indexTitle=0; for (String s : title) { //4.創建單元格,從0開始 cell = row.createCell(indexTitle++); //5.單元格寫入數據 cell.setCellValue(s); } //人為構造的數據,實際是要從數據庫中查的 List<User> users=new ArrayList<>(); User user= new User(); for (int i = 0; i <3 ; i++) { user.setName("洪真英"); user.setPassword(123456); users.add(user); } int indexContext=1; int index=1; //內容 for (User user1:users) { //創建每一行,同excel的第二行開始 row=sheet.createRow(indexContext++); //第一列 cell = row.createCell(0); //寫入數據 序號 cell.setCellValue(index++); //第2列 cell = row.createCell(1); cell.setCellValue(user1.getName()); //第2列 cell = row.createCell(2); cell.setCellValue(user1.getPassword()); } ByteArrayOutputStream os=new ByteArrayOutputStream(); wb.write(os); new DownloadUtils().download(os,response,"webExcel導出.xlsx"); } /** * excel 文件上傳 * postman 上傳文件 操作指南https://jingyan.baidu.com/article/425e69e614f472be14fc166f.html */ @PostMapping("upload") public String upload(@RequestParam(name = "file") MultipartFile file) throws IOException { //1.解析Excel //1.1.根據Excel文件創建工作簿 Workbook wb = new XSSFWorkbook(file.getInputStream()); //1.2.獲取Sheet Sheet sheet = wb.getSheetAt(0);//參數:索引 //1.3.獲取Sheet中的每一行,和每一個單元格 //2.獲取用戶數據列表 List<User> list = new ArrayList<>(); System.out.println("最后一行的下標 :" + sheet.getLastRowNum()); for (int rowNum = 1; rowNum <= sheet.getLastRowNum(); rowNum++) { Row row = sheet.getRow(rowNum);//根據索引獲取每一個行 // System.out.println("列數"+row.getLastCellNum()); Object[] values = new Object[row.getLastCellNum()]; for (int cellNum = 1; cellNum < row.getLastCellNum(); cellNum++) { Cell cell = row.getCell(cellNum); Object value = getCellValue(cell); values[cellNum] = value; } User user = new User(values); list.add(user); } //3.批量保存用戶 // userService.saveAll(list,companyId,companyName); return "SUCCESS"; } public static Object getCellValue(Cell cell) { //1.獲取到單元格的屬性類型 CellType cellType = cell.getCellType(); //2.根據單元格數據類型獲取數據 Object value = null; switch (cellType) { case STRING: value = cell.getStringCellValue(); break; case BOOLEAN: value = cell.getBooleanCellValue(); break; case NUMERIC: if (DateUtil.isCellDateFormatted(cell)) { //日期格式 value = cell.getDateCellValue(); } else { //數字 value = cell.getNumericCellValue(); } break; case FORMULA: //公式 value = cell.getCellFormula(); break; default: break; } return value; } }
實體類

package com.zhao.domain; import com.zhao.common.util.ExcelAttribute; import com.zhao.common.util.ExcelImportAnnotation; import lombok.Data; import lombok.NoArgsConstructor; import java.text.DecimalFormat; @Data @NoArgsConstructor public class User { @ExcelAttribute(sort = 0) @ExcelImportAnnotation(sort = 2) private String name; @ExcelAttribute(sort = 1) @ExcelImportAnnotation(sort = 3) private Integer password; public User(Object[] args){ /** DecimalFormat 用法 * https://www.jianshu.com/p/b3699d73142e * Integer.valueOf 返回的時包裝類 Integer.parseInt() 返回的是int */ //因為傳進來的args 的賦值是從1開始的 this.name=args[1].toString(); //new DecimalFormat("#").format(args[2]).toString(); //因為從Excel中讀取的數字是double類型的 所以不能用 Integer.valueOf this.password=new Double(args[2].toString()).intValue(); } }
下載工具類

package com.zhao.common.util; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletResponse; import java.io.ByteArrayOutputStream; import java.io.IOException; /** * 用於 Excel下載的工具類 */ public class DownloadUtils { /** * * @param byteArrayOutputStream 輸出字節流 * @param response * @param returnName 輸出到客戶端的文件名 * @throws IOException */ public void download(ByteArrayOutputStream byteArrayOutputStream, HttpServletResponse response, String returnName) throws IOException { response.setContentType("application/octet-stream"); returnName = response.encodeURL(new String(returnName.getBytes(),"iso8859-1")); //保存的文件名,必須和頁面編碼一致,否則亂碼 // response.addHeader("Content-Disposition","attachment;filename=total.xls"); response.addHeader("Content-Disposition","attachment;filename="+returnName); response.setContentLength(byteArrayOutputStream.size()); response.addHeader("Content-Length", "" + byteArrayOutputStream.size()); ServletOutputStream outputStream = response.getOutputStream(); //取得輸出流 byteArrayOutputStream.writeTo(outputStream); //寫到輸出流 byteArrayOutputStream.close(); //關閉 outputStream.flush(); //刷數據 } }
導出注解

package com.zhao.common.util; 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 ExcelAttribute { /** 對應的列名稱 */ String name() default ""; /** 列序號 * 屬性 上short=0 在excel導出時他就是第一列 * */ int sort(); /** 字段類型對應的格式 */ String format() default ""; }
導入注解

package com.zhao.common.util; 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 ExcelImportAnnotation { /** 對應的列名稱 */ String name() default ""; /** 列序號 * 屬性 上short=0 在excel導入時他就是第一列 * */ int sort(); /** 字段類型對應的格式 */ String format() default ""; }
導出工具類

package com.zhao.common.util; import lombok.Getter; import lombok.Setter; import org.apache.poi.ss.usermodel.*; import org.apache.poi.xssf.usermodel.XSSFWorkbook; import javax.servlet.http.HttpServletResponse; import java.io.InputStream; import java.lang.reflect.Field; import java.net.URLEncoder; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; /** * 導出Excel工具類 * 基於模板打印的方式導出: */ @Getter @Setter 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: InputStream:模板的輸入流 objs:數據 fileName:生成的文件名 * */ public void export(HttpServletResponse response,InputStream is, List<T> objs,String fileName) throws Exception { //1.根據模板創建工作簿 XSSFWorkbook workbook = new XSSFWorkbook(is); //2.讀取工作表 Sheet sheet = workbook.getSheetAt(0); //3.提取公共的樣式 CellStyle[] styles = getTemplateStyles(sheet.getRow(styleIndex)); //4.根據數據創建每一行和每一個單元格的數據2 AtomicInteger datasAi = new AtomicInteger(rowIndex); //數字 for (T t : objs) { //datasAi.getAndIncrement() :獲取數字,並++ i++ 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) { if(field.isAnnotationPresent(ExcelAttribute.class)){ field.setAccessible(true); ExcelAttribute ea = field.getAnnotation(ExcelAttribute.class); //如果當前i的值和 屬性上注解的 sort值一致就反射調用它的get方法,也就時 當 i=0時就會找屬性上注解為0的屬性值寫入其值 if(i == ea.sort()) { if(field.get(t) != null) { cell.setCellValue(field.get(t).toString()); } } } } } } 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; } }
導入工具類

package com.zhao.common.util; import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.DateUtil; import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.xssf.usermodel.XSSFWorkbook; import java.io.InputStream; import java.lang.reflect.Field; import java.math.BigDecimal; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.List; /** * Excel 的導入工具類 * ExcelImportAnnotation 導入注解 * @param <T> */ public class ExcelImportUtil<T> { private Class clazz; private Field fields[]; /** 傳入你希望構建的隊象*/ public ExcelImportUtil(Class clazz) { this.clazz = clazz; fields = clazz.getDeclaredFields(); } /** * 基於注解讀取excel * @param is 文件上傳的流信息 * @param rowIndex 讀取數據的起始行 * @param cellIndex 讀取數據的起始單元格位置 * @return */ 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(); System.out.println("一共 "+(sheet.getLastRowNum()+1)+" 行"); for (int rowNum = rowIndex; rowNum <= sheet.getLastRowNum(); rowNum++) { Row row = sheet.getRow(rowNum); entity = (T) clazz.newInstance(); System.out.println("一共 "+row.getLastCellNum()+" 列"); for (int j = cellIndex; j < row.getLastCellNum(); j++) { Cell cell = row.getCell(j); for (Field field : fields) { if(field.isAnnotationPresent(ExcelImportAnnotation.class)){ field.setAccessible(true); ExcelImportAnnotation ea = field.getAnnotation(ExcelImportAnnotation.class); if(j == ea.sort()) { field.set(entity, covertAttrType(field, cell)); } } } } list.add(entity); } } catch (Exception e) { e.printStackTrace(); } return list; } /** * 類型轉換 將cell 單元格格式轉為 字段類型 */ private Object covertAttrType(Field field, Cell cell) throws Exception { // System.out.println(field.getType()); 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(); } // 去除 浮點型 自動加的 .0 if (strCell.endsWith(".0")) { strCell = strCell.substring(0, strCell.indexOf(".")); } return strCell; } case BOOLEAN: return String.valueOf(cell.getBooleanCellValue()); default: return ""; } } }
項目地址:https://gitee.com/richOne/java_poi_operation_example