導讀
日常開發過程中,經常遇到Excel導入、導出等功能,其中導入邏輯相對麻煩些,還涉及到參數的校驗,然后將錯誤信息批注導出。之前寫過EasyExcel導入(參數校驗,帶批注)(點我直達1、點我直達2)、導出等功能。今天遇到一個需求是,導入、導出還需要帶上圖片,EasyExcel目前還不支持Excel中帶圖片的。Easy Poi支持帶圖片導入、導出,批注等功能,好啦~廢話不多說,下面開始叭~EasyPoi官網,點我直達
項目源碼
添加依賴
<!-- easy poi --> <dependency> <groupId>cn.afterturn</groupId> <artifactId>easypoi-spring-boot-starter</artifactId> <version>4.1.0</version> </dependency> <!-- JSR 303 規范驗證包 --> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-validator</artifactId> <version>5.2.4.Final</version> </dependency>
<!-- 阿里雲OSS --> <dependency> <groupId>com.aliyun.oss</groupId> <artifactId>aliyun-sdk-oss</artifactId> <version>3.10.2</version> </dependency>
友情提示
-
Easy Poi依賴版本大於4.1.0時,導出圖片顯示異常!!!!!這個坑了我好久 嗚嗚嗚嗚
- Easy Poi導入時,支持hibernate的注解,校驗參數
實體類
導入實體類
import cn.afterturn.easypoi.excel.annotation.Excel; import lombok.Data; import javax.validation.constraints.NotNull; import javax.validation.constraints.Pattern; import java.io.Serializable; import java.util.Date; /** * 人員信息Excel導出實體類 * * @Author:chenyanbin */ @Data public class PersonImportExcelDomain implements Serializable { /** * 姓名 */ @Excel(name = "姓名", height = 20, width = 30) @EasyPoiCellAnnotation(cellIndex = 0) @NotNull(message = "姓名不能為空") private String userNick; /** * 性別 * replace:替換枚舉值,1->男;2->女 * suffix:為每個值后,添加后綴 */ @Excel(name = "性別", replace = {"1_男", "2_女"}, suffix = "生") @EasyPoiCellAnnotation(cellIndex = 1) @Pattern(regexp = "男|女", message = "性別不能為空 1->男|2->女") private String sex; /** * 出生日期 */ @Excel(name = "出生日期", databaseFormat = "yyyyMMddHHmmss", importFormat = "yyyy-MM-dd HH:mm:ss", format = "yyyy-MM-dd HH:mm:ss", width = 25) @EasyPoiCellAnnotation(cellIndex = 2) private Date birthday; /** * 頭像 */ @Excel(name = "頭像", type = 2, savePath = "/Users/chenyanbin/upload") @EasyPoiCellAnnotation(cellIndex = 3) @NotNull(message = "頭像不能為空") private String pic; /** * 臨時頭像字節 */ private String tempPicUrl; }
注意:導入時,Easy Poi會將Excel和圖片,下載到宿主機中,此時該實體類中的pic為當前宿主機圖片的絕對路徑,需要將圖片上傳至阿里雲Oss上,並將圖片url賦值到tempPicUrl
導出實體類
package com.yida.excel.domain; import cn.afterturn.easypoi.excel.annotation.Excel; import lombok.Data; import java.io.Serializable; import java.util.Date; /** * 人員信息Excel導出實體類 * @Author:chenyanbin */ @Data public class PersonExportExcelDomain implements Serializable { /** * 姓名 */ @Excel(name = "姓名", height = 20, width = 30) private String userNick; /** * 性別 * replace:替換枚舉值,1->男;2->女 * suffix:為每個值后,添加后綴 */ @Excel(name = "性別", replace = {"男_1", "女_2"}, suffix = "生") private int sex; /** * 出生日期 */ @Excel(name = "出生日期", databaseFormat = "yyyyMMddHHmmss", importFormat = "yyyy-MM-dd HH:mm:ss", format = "yyyy-MM-dd HH:mm:ss",width = 25) private Date birthday; /** * 頭像 */ @Excel(name = "頭像", type = 2, width = 10, height = 10, imageType = 2) private byte[] pic; /** * 臨時頭像地址 */ private String tempPicUrl; }
注意:導出圖片時,需要將網絡圖片轉換成字節數組!做法:將tempPicUrl調用http工具類,轉換成字節數組,賦值到pic
導入校驗參數批注實體類
import lombok.Data; /** * Excel 錯誤批注信息vo * @Author:chenyanbin */ @Data public class ExcelErrorInfoVo { /** * 行索引,從0開始 */ private int rowIndex; /** * 列索引,從0開始 */ private int cellIndex; /** * 錯誤原因 */ private String reasonText; }
工具類
Http工具類
import lombok.extern.slf4j.Slf4j; import java.io.ByteArrayOutputStream; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.URL; /** * Http工具類 * * @Author:chenyanbin */ @Slf4j public class HttpUtil { /** * 獲取網絡圖片轉成字節流 * * @param strUrl 完整圖片地址 * @return 圖片資源數組 */ public static byte[] getNetImgByUrl(String strUrl) { try { URL url = new URL(strUrl); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setRequestMethod("GET"); conn.setConnectTimeout(2 * 1000); // 通過輸入流獲取圖片數據 InputStream inStream = conn.getInputStream(); // 得到圖片的二進制數據 byte[] btImg = readInputStream(inStream); return btImg; } catch (Exception e) { e.printStackTrace(); } return null; } /** * 從輸入流中獲取字節流數據 * * @param inStream 輸入流 * @return 圖片流 */ private static byte[] readInputStream(InputStream inStream) throws Exception { ByteArrayOutputStream outStream = new ByteArrayOutputStream(); // 設置每次讀取緩存區大小 byte[] buffer = new byte[1024 * 10]; int len = 0; while ((len = inStream.read(buffer)) != -1) { outStream.write(buffer, 0, len); } inStream.close(); return outStream.toByteArray(); } }
添加批注工具類
import org.apache.commons.lang3.StringUtils; import org.apache.poi.hssf.usermodel.HSSFClientAnchor; import org.apache.poi.hssf.usermodel.HSSFRichTextString; import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.ss.usermodel.*; import org.apache.poi.xssf.usermodel.XSSFClientAnchor; import org.apache.poi.xssf.usermodel.XSSFRichTextString; import javax.validation.ConstraintViolation; import javax.validation.Validation; import javax.validation.Validator; import java.lang.reflect.Field; import java.util.*; /** * Easy Poi Excel工具類 * * @Author:chenyanbin */ public class EasyPoiExcelUtil { private static Validator validator = Validation.buildDefaultValidatorFactory().getValidator(); /** * 添加批注 * * @param workbook 工作簿 * @param titleRowsIndex 標題的行索引,從0計數 * @param commentStr 批注格式: 0#姓名不能為空__1#學生性別 1:男 2:女__2#出生日期:yyyy-MM-dd__3#圖片不能為空 */ public static void buildComment(Workbook workbook, int titleRowsIndex, String commentStr) { Sheet sheet = workbook.getSheetAt(0); //創建一個圖畫工具 Drawing<?> drawing = sheet.createDrawingPatriarch(); Row row = sheet.getRow(titleRowsIndex); if (StringUtils.isNotBlank(commentStr)) { //解析批注,並傳換成map Map<Integer, String> commentMap = getCommentMap(commentStr); for (Map.Entry<Integer, String> entry : commentMap.entrySet()) { Cell cell = row.getCell(entry.getKey()); //創建批注 Comment comment = drawing.createCellComment(newClientAnchor(workbook)); //輸入批注信息 comment.setString(newRichTextString(workbook, entry.getValue())); //將批注添加到單元格對象中 cell.setCellComment(comment); // //設置單元格背景顏色 // CellStyle cellStyle = workbook.createCellStyle(); // //設置顏色 // cellStyle.setFillForegroundColor(IndexedColors.BLACK1.getIndex()); // //設置實心填充 // cellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND); // cell.setCellStyle(cellStyle); } } } /** * 添加批注 * * @param workbook 工作簿 * @param errorInfoList 批注錯誤集合 */ public static void buildComment(Workbook workbook, List<ExcelErrorInfoVo> errorInfoList) { Sheet sheet = workbook.getSheetAt(0); //創建一個圖畫工具 Drawing<?> drawing = sheet.createDrawingPatriarch(); for (ExcelErrorInfoVo vo : errorInfoList) { Row row = sheet.getRow(vo.getRowIndex()); if (StringUtils.isNotBlank(vo.getReasonText())) { Cell cell = row.getCell(vo.getCellIndex()); //創建批注 Comment comment = drawing.createCellComment(newClientAnchor(workbook)); //輸入批注信息 comment.setString(newRichTextString(workbook, vo.getReasonText())); //將批注添加到單元格對象中 cell.setCellComment(comment); // //設置單元格背景顏色 // CellStyle cellStyle = workbook.createCellStyle(); // //設置顏色 // cellStyle.setFillForegroundColor(IndexedColors.BLACK1.getIndex()); // //設置實心填充 // cellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND); // cell.setCellStyle(cellStyle); } } } /** * 校驗Excel數據 * * @param obj Excel中當前行的數據對象 * @param clz Excel中當前行的數據對象的類 * @param rowIndex 該條記錄對應的行索引 * @return */ public static <T> List<ExcelErrorInfoVo> checkExcelData(T obj, Class<?> clz, int rowIndex) { List<ExcelErrorInfoVo> errorInfoList = new ArrayList<>(); Set<ConstraintViolation<T>> cvSet = validator.validate(obj); Field f = null; for (ConstraintViolation<T> cv : cvSet) { try { f = clz.getDeclaredField(cv.getPropertyPath().toString()); f.setAccessible(true); EasyPoiCellAnnotation annotation = f.getAnnotation(EasyPoiCellAnnotation.class); if (annotation == null) { continue; } int cellIndex = annotation.cellIndex(); ExcelErrorInfoVo vo = new ExcelErrorInfoVo(); vo.setRowIndex(rowIndex); vo.setCellIndex(cellIndex); vo.setReasonText(cv.getMessage()); errorInfoList.add(vo); } catch (NoSuchFieldException e) { } finally { if (f != null) { f.setAccessible(false); } } } return errorInfoList; } /** * 批注信息,默認解析:批注#列索引,比如用戶名不允許重復#0。可覆蓋此方法,解析自定義的批注格式 * * @param commentStr 當前行的所有批注信息 * @return key:列索引,value:對應列的所有批注信息 */ protected static Map<Integer, String> getCommentMap(String commentStr) { //每行的所有單元格的批注都在commentStr里,並用”__”分隔 String[] split = commentStr.split("__"); Map<Integer, String> commentMap = new HashMap<>(); for (String msg : split) { String[] cellMsg = msg.split("#"); //如果當前列沒有批注,會將該列的索引作為key存到map里;已有批注,以“,“分隔繼續拼接 int cellIndex = Integer.parseInt(cellMsg[0]); if (commentMap.get(cellIndex) == null) { commentMap.put(cellIndex, cellMsg[1]); } else { commentMap.replace(cellIndex, commentMap.get(cellIndex) + "," + cellMsg[1]); } } return commentMap; } private static ClientAnchor newClientAnchor(Workbook workbook) { //xls if (workbook instanceof HSSFWorkbook) { return new HSSFClientAnchor(0, 0, 0, 0, (short) 3, 3, (short) 5, 6); } //xlsx else { return new XSSFClientAnchor(0, 0, 0, 0, (short) 3, 3, (short) 5, 6); } } private static RichTextString newRichTextString(Workbook workbook, String msg) { //xls if (workbook instanceof HSSFWorkbook) { return new HSSFRichTextString(msg); } //xlsx else { return new XSSFRichTextString(msg); } } }
自定義注解
import java.lang.annotation.*; @Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public @interface EasyPoiCellAnnotation { /** * 字段索引位置,從0開始計數 * @return */ int cellIndex(); }
阿里雲Oss文件上傳
import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Configuration; /** * 阿里雲oss配置文件 * @Author:chenyanbin */ @Data @Configuration @ConfigurationProperties(prefix = "aliyun.oss") public class OssConfig { private String endpoint; private String accessKeyId; private String accessSecret; private String bucketName; }
import org.springframework.web.multipart.MultipartFile; import java.io.File; /** * 阿里雲oss文件上傳service * @Author:chenyanbin */ public interface OssFileService { /** * 上傳文件 * @param file * @return */ String uploadFile(MultipartFile file); /** * 上傳客戶端本地文件 * @param file * @return */ String uploadClientFile(File file); }
import com.aliyun.oss.OSS; import com.aliyun.oss.OSSClientBuilder; import com.aliyun.oss.model.ObjectMetadata; import com.aliyun.oss.model.PutObjectResult; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.web.multipart.MultipartFile; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; /** * @Author:chenyanbin */ @Service @Slf4j public class OssFileServiceImpl implements OssFileService { @Autowired private OssConfig ossConfig; @Override public String uploadFile(MultipartFile file) { //獲取相關配置 String bucketName = ossConfig.getBucketName(); String endpoint = ossConfig.getEndpoint(); String accessKeyId = ossConfig.getAccessKeyId(); String accessSecret = ossConfig.getAccessSecret(); //創建OSS對象 OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessSecret); //原始文件名稱 xxx.jpg String originalFileName = file.getOriginalFilename(); //JDK8 日期格式化 LocalDateTime ldt = LocalDateTime.now(); DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy/MM/dd"); //文件路徑 String folder = dtf.format(ldt); //拼裝路徑,oss上存儲的路徑 2021/05/16/xxx.jpg String fileName = CommonUtil.generateUUID(); //擴展名 String extension = originalFileName.substring(originalFileName.lastIndexOf(".")); String newFileName = "user/" + folder + "/" + fileName + extension; //推送到oss try { PutObjectResult putObjectResult = ossClient.putObject(bucketName, newFileName, file.getInputStream()); //拼裝返回路徑 if (putObjectResult != null) { String imgUrl = "https://" + bucketName + "." + endpoint + "/" + newFileName; return imgUrl; } } catch (IOException e) { log.error("oss文件上傳失敗:{}", e); } finally { //oss關閉 ossClient.shutdown(); } return null; } @Override public String uploadClientFile(File file) { try { //獲取相關配置 String bucketName = ossConfig.getBucketName(); String endpoint = ossConfig.getEndpoint(); String accessKeyId = ossConfig.getAccessKeyId(); String accessSecret = ossConfig.getAccessSecret(); //創建OSS對象 OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessSecret); //以輸入流的形式上傳文件 InputStream is = new FileInputStream(file); //文件名 String fileName = file.getName(); //文件大小 Long fileSize = file.length(); //創建上傳Object的Metadata ObjectMetadata metadata = new ObjectMetadata(); //上傳的文件的長度 metadata.setContentLength(is.available()); //指定該Object被下載時的網頁的緩存行為 metadata.setCacheControl("no-cache"); //指定該Object下設置Header metadata.setHeader("Pragma", "no-cache"); //指定該Object被下載時的內容編碼格式 metadata.setContentEncoding("utf-8"); //文件的MIME,定義文件的類型及網頁編碼,決定瀏覽器將以什么形式、什么編碼讀取文件。如果用戶沒有指定則根據Key或文件名的擴展名生成, //如果沒有擴展名則填默認值application/octet-stream metadata.setContentType(getContentType(fileName)); //指定該Object被下載時的名稱(指示MINME用戶代理如何顯示附加的文件,打開或下載,及文件名稱) metadata.setContentDisposition("filename/filesize=" + fileName + "/" + fileSize + "Byte."); //JDK8 日期格式化 LocalDateTime ldt = LocalDateTime.now(); DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy/MM/dd"); //文件路徑 String folder = dtf.format(ldt); String newFileName = "user/" + folder + "/" + fileName; //上傳文件 (上傳文件流的形式) PutObjectResult putResult = ossClient.putObject(bucketName, newFileName, is, metadata); String imgUrl = "https://" + bucketName + "." + endpoint + "/" + newFileName; return imgUrl; } catch (Exception e) { } return null; } /** * 通過文件名判斷並獲取OSS服務文件上傳時文件的contentType * * @param fileName 文件名 * @return 文件的contentType */ private String getContentType(String fileName) { //文件的后綴名 String fileExtension = fileName.substring(fileName.lastIndexOf(".")); if (".bmp".equalsIgnoreCase(fileExtension)) { return "image/bmp"; } if (".gif".equalsIgnoreCase(fileExtension)) { return "image/gif"; } if (".jpeg".equalsIgnoreCase(fileExtension) || ".jpg".equalsIgnoreCase(fileExtension) || ".png".equalsIgnoreCase(fileExtension)) { return "image/jpeg"; } if (".html".equalsIgnoreCase(fileExtension)) { return "text/html"; } if (".txt".equalsIgnoreCase(fileExtension)) { return "text/plain"; } if (".vsd".equalsIgnoreCase(fileExtension)) { return "application/vnd.visio"; } if (".ppt".equalsIgnoreCase(fileExtension) || "pptx".equalsIgnoreCase(fileExtension)) { return "application/vnd.ms-powerpoint"; } if (".doc".equalsIgnoreCase(fileExtension) || "docx".equalsIgnoreCase(fileExtension)) { return "application/msword"; } if (".xml".equalsIgnoreCase(fileExtension)) { return "text/xml"; } //默認返回類型 return "image/jpeg"; } }
import com.fasterxml.jackson.databind.ObjectMapper; import lombok.extern.slf4j.Slf4j; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.PrintWriter; import java.net.InetAddress; import java.net.UnknownHostException; import java.security.MessageDigest; import java.util.Random; import java.util.UUID; /** * 公共工具類 * * @Author:chenyanbin */ @Slf4j public class CommonUtil { /** * 生成uuid * * @return */ public static String generateUUID() { return UUID.randomUUID().toString().replaceAll("-", "").substring(0, 32); } }
控制層
import cn.afterturn.easypoi.excel.ExcelExportUtil; import cn.afterturn.easypoi.excel.ExcelImportUtil; import cn.afterturn.easypoi.excel.entity.ExportParams; import cn.afterturn.easypoi.excel.entity.ImportParams; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiParam; import org.apache.commons.lang3.StringUtils; import org.apache.poi.ss.usermodel.Workbook; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletResponse; import java.io.File; import java.io.IOException; import java.net.URLEncoder; import java.util.ArrayList; import java.util.Date; import java.util.List; /** * @Author:chenyanbin */ @RestController @RequestMapping("/api/excel/v1") @Api(tags = "Easy Poi API測試") public class ExcelController { @Autowired OssFileService ossFileService; @ApiOperation("下單Excel模板") @GetMapping("downloadExcelTemplate") public void downloadExcelTemplate(HttpServletResponse response) { //1、數據庫查詢數據,此處模擬數據 List<PersonExportExcelDomain> personExcelList = new ArrayList<>(); String fileName = "學生信息表.xls"; Workbook workbook = ExcelExportUtil.exportExcel(new ExportParams("xxx班學生信息", "學生信息"), PersonExportExcelDomain.class, personExcelList); //標題加批注 EasyPoiExcelUtil.buildComment(workbook, 1, "0#姓名不能為空__1#學生性別 1:男 2:女__2#出生日期:yyyy-MM-dd__3#圖片不能為空"); ServletOutputStream outputStream = null; try { outputStream = response.getOutputStream(); response.setCharacterEncoding("UTF-8"); response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); //mime類型 response.setHeader("Pragma", "No-cache");//設置不要緩存 response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8")); workbook.write(outputStream); outputStream.flush(); } catch (IOException e) { throw new RuntimeException(e); } finally { if (outputStream != null) { try { outputStream.close(); } catch (IOException e) { e.printStackTrace(); } } } } @ApiOperation("導出Excel數據") @GetMapping("exportExcelTemplate") public void exportExcelTemplate(HttpServletResponse response) { //1、數據庫查詢數據,此處模擬數據 List<PersonExportExcelDomain> personExcelList = new ArrayList<>(); //學生:張三 PersonExportExcelDomain person_1 = new PersonExportExcelDomain(); person_1.setUserNick("張三"); person_1.setSex(1); person_1.setBirthday(new Date()); person_1.setTempPicUrl("https://images.cnblogs.com/cnblogs_com/chenyanbin/1560326/o_qianxun.jpg"); personExcelList.add(person_1); //學生:李四 PersonExportExcelDomain person_2 = new PersonExportExcelDomain(); person_2.setUserNick("李四"); person_2.setSex(2); person_2.setBirthday(new Date()); person_2.setTempPicUrl("https://pic.cnblogs.com/face/1988848/20200625143435.png"); personExcelList.add(person_2); //學生:王五 PersonExportExcelDomain person_3 = new PersonExportExcelDomain(); person_3.setUserNick("王五"); person_3.setSex(2); person_3.setBirthday(new Date()); personExcelList.add(person_3); //處理導出Excel圖片 for (PersonExportExcelDomain domain : personExcelList) { if (StringUtils.isNotBlank(domain.getTempPicUrl())) { //將網絡圖片,轉換成文件流 domain.setPic(HttpUtil.getNetImgByUrl(domain.getTempPicUrl())); } } String fileName = "xxx公司人員信息表.xls"; Workbook workbook = ExcelExportUtil.exportExcel(new ExportParams("xxx部門人員表", "部門"), PersonExportExcelDomain.class, personExcelList); //標題加批注 EasyPoiExcelUtil.buildComment(workbook, 1, "0#姓名不能為空__1#性別 1:男 2:女__2#出生日期:yyyy-MM-dd__3#頭像不能為空"); ServletOutputStream outputStream = null; try { outputStream = response.getOutputStream(); response.setCharacterEncoding("UTF-8"); response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); response.setHeader("Pragma", "No-cache"); response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8")); workbook.write(outputStream); outputStream.flush(); } catch (IOException e) { } finally { if (outputStream != null) { try { outputStream.close(); } catch (IOException e) { e.printStackTrace(); } } } } /** * 導入Excel * * @param file * @param response */ @PostMapping("importExcel") @ApiOperation("導入Excel") public void importExcel( @ApiParam(value = "文件上傳", required = true) @RequestPart("file") MultipartFile file, HttpServletResponse response ) throws Exception { //1、導入參數配置 ImportParams params = new ImportParams(); params.setNeedSave(true); params.setTitleRows(1); params.setSaveUrl("/Users/chenyanbin/upload"); //2、獲取Excel數據(Excel中單元格中若存在圖片,EasyPoi會將圖片上傳到本機) List<PersonImportExcelDomain> personList = ExcelImportUtil.importExcel(file.getInputStream(), PersonImportExcelDomain.class, params); //3、處理上傳圖片,轉換至字節流 List<ExcelErrorInfoVo> errorList = new ArrayList<>(); for (int i = 0; i < personList.size(); i++) { //圖片不為空 if (StringUtils.isNotBlank(personList.get(i).getPic())) { String fileUrl = ossFileService.uploadClientFile(new File(personList.get(i).getPic())); personList.get(i).setTempPicUrl(fileUrl); } PersonImportExcelDomain domain = personList.get(i); //4、將校驗失敗的Excel添加至集合中 errorList.addAll(EasyPoiExcelUtil.checkExcelData(domain, PersonImportExcelDomain.class, i + 2)); } //5、Excel數據是否正確 if (errorList.size() == 0) { //數據正確 //TODO 導入數據庫 personList.stream().forEach(System.err::println); } else { String fileName = "學生信息表導入-校驗錯誤.xls"; //數據格式不正確,添加批注導出 Workbook workbook = ExcelExportUtil.exportExcel(new ExportParams("xxx班學生信息", "學生信息"), PersonImportExcelDomain.class, personList); //標題加批注 EasyPoiExcelUtil.buildComment(workbook, errorList); ServletOutputStream outputStream = null; try { outputStream = response.getOutputStream(); response.setCharacterEncoding("UTF-8"); response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); //mime類型 response.setHeader("Pragma", "No-cache");//設置不要緩存 response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8")); workbook.write(outputStream); outputStream.flush(); } catch (IOException e) { throw new RuntimeException(e); } finally { if (outputStream != null) { try { outputStream.close(); } catch (IOException e) { e.printStackTrace(); } } } } } }
演示
下載Excel模塊
標題帶批注
帶圖片導出Excel
導入Excel
參數校驗,帶批注導出
尾聲
如果貼的代碼不全,請聯系我微信~