依赖

<?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