easyPOI基本用法详解
文章目錄
- easyPOI基本用法
- 1.Excel文件的簡單導(dǎo)入和導(dǎo)出
- 1.1準備工作
- 1.2導(dǎo)入
- 1.3導(dǎo)出
- 1.4圖片的導(dǎo)出
- 1.5圖片的導(dǎo)入
- 1.6excel模板導(dǎo)出文件
- 1.7excel轉(zhuǎn)html
- 2.Word文件導(dǎo)出
- 2.1使用word模板導(dǎo)出
- 2.2使用word模板導(dǎo)出多頁
- 3.excel導(dǎo)入時驗證
- 3.1環(huán)境準備
- 3.2實戰(zhàn)演練
- 3.3注意事項
easyPOI基本用法
參考網(wǎng)址:http://www.wupaas.com/
1.Excel文件的簡單導(dǎo)入和導(dǎo)出
項目源碼:https://github.com/zhongyushi-git/springboot-easypoi.git。后臺在easypoi-demo-admin目錄下,前端在easypoi-demo目錄下。
!!!說明:源碼中可能與下面的介紹的代碼稍有差異,請以源碼為準。
1.1準備工作
1)首先新建一個SpringBoot的項目,搭建基本的環(huán)境訪問數(shù)據(jù),詳見源碼。
2)導(dǎo)入easypoi依賴
定義版本
<easypoi.version>4.1.0</easypoi.version>坐標:這里是以springmvc的坐標導(dǎo)入的,適用大部分功能。如果需求不多,可以直接導(dǎo)入springboot對應(yīng)的坐標,二者選一。選擇依據(jù)就是如果報錯,就換另一種坐標即可。
<!--easypoi--><dependency><groupId>cn.afterturn</groupId><artifactId>easypoi-base</artifactId><version>${easypoi.version}</version></dependency><dependency><groupId>cn.afterturn</groupId><artifactId>easypoi-web</artifactId><version>${easypoi.version}</version></dependency><dependency><groupId>cn.afterturn</groupId><artifactId>easypoi-annotation</artifactId><version>${easypoi.version}</version></dependency>springboot的坐標
<dependency><groupId>cn.afterturn</groupId><artifactId>easypoi-spring-boot-starter</artifactId><version>3.3.0</version> </dependency>3)創(chuàng)建Excel操作的工具類ExcelUtils
package com.example.easypoidemoadmin.utils;import cn.afterturn.easypoi.cache.manager.POICacheManager; import cn.afterturn.easypoi.excel.ExcelExportUtil; import cn.afterturn.easypoi.excel.ExcelImportUtil; import cn.afterturn.easypoi.excel.ExcelXorHtmlUtil; import cn.afterturn.easypoi.excel.entity.ExcelToHtmlParams; import cn.afterturn.easypoi.excel.entity.ExportParams; import cn.afterturn.easypoi.excel.entity.ImportParams; import cn.afterturn.easypoi.excel.entity.TemplateExportParams; import cn.afterturn.easypoi.excel.entity.enmus.ExcelType; import cn.afterturn.easypoi.word.WordExportUtil; import cn.afterturn.easypoi.word.parse.ParseWord07; import org.apache.commons.lang3.StringUtils; import org.apache.poi.ss.usermodel.Workbook; import org.apache.poi.ss.usermodel.WorkbookFactory; import org.apache.poi.xwpf.usermodel.XWPFDocument; import org.springframework.web.multipart.MultipartFile;import javax.servlet.http.HttpServletResponse; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.URLEncoder; import java.util.List; import java.util.Map; import java.util.NoSuchElementException;/*** Excel導(dǎo)入導(dǎo)出工具類*/public class ExcelUtils {/*** excel 導(dǎo)出** @param list 數(shù)據(jù)列表* @param fileName 導(dǎo)出時的excel名稱* @param response*/public static void exportExcel(List<Map<String, Object>> list, String fileName, HttpServletResponse response) throws IOException {defaultExport(list, fileName, response);}/*** 默認的 excel 導(dǎo)出** @param list 數(shù)據(jù)列表* @param fileName 導(dǎo)出時的excel名稱* @param response*/private static void defaultExport(List<Map<String, Object>> list, String fileName, HttpServletResponse response) throws IOException {//把數(shù)據(jù)添加到excel表格中Workbook workbook = ExcelExportUtil.exportExcel(list, ExcelType.HSSF);downLoadExcel(fileName, response, workbook);}/*** excel 導(dǎo)出** @param list 數(shù)據(jù)列表* @param pojoClass pojo類型* @param fileName 導(dǎo)出時的excel名稱* @param response* @param exportParams 導(dǎo)出參數(shù)(標題、sheet名稱、是否創(chuàng)建表頭,表格類型)*/private static void defaultExport(List<?> list, Class<?> pojoClass, String fileName, HttpServletResponse response, ExportParams exportParams) throws IOException {//把數(shù)據(jù)添加到excel表格中Workbook workbook = ExcelExportUtil.exportExcel(exportParams, pojoClass, list);downLoadExcel(fileName, response, workbook);}/*** excel 導(dǎo)出** @param list 數(shù)據(jù)列表* @param pojoClass pojo類型* @param fileName 導(dǎo)出時的excel名稱* @param exportParams 導(dǎo)出參數(shù)(標題、sheet名稱、是否創(chuàng)建表頭,表格類型)* @param response*/public static void exportExcel(List<?> list, Class<?> pojoClass, String fileName, ExportParams exportParams, HttpServletResponse response) throws IOException {defaultExport(list, pojoClass, fileName, response, exportParams);}/*** excel 導(dǎo)出** @param list 數(shù)據(jù)列表* @param title 表格內(nèi)數(shù)據(jù)標題* @param sheetName sheet名稱* @param pojoClass pojo類型* @param fileName 導(dǎo)出時的excel名稱* @param response*/public static void exportExcel(List<?> list, String title, String sheetName, Class<?> pojoClass, String fileName, HttpServletResponse response) throws IOException {defaultExport(list, pojoClass, fileName, response, new ExportParams(title, sheetName, ExcelType.XSSF));}/*** excel 導(dǎo)出** @param list 數(shù)據(jù)列表* @param title 表格內(nèi)數(shù)據(jù)標題* @param sheetName sheet名稱* @param pojoClass pojo類型* @param fileName 導(dǎo)出時的excel名稱* @param isCreateHeader 是否創(chuàng)建表頭* @param response*/public static void exportExcel(List<?> list, String title, String sheetName, Class<?> pojoClass, String fileName, boolean isCreateHeader, HttpServletResponse response) throws IOException {ExportParams exportParams = new ExportParams(title, sheetName, ExcelType.XSSF);exportParams.setCreateHeadRows(isCreateHeader);defaultExport(list, pojoClass, fileName, response, exportParams);}/*** excel下載** @param fileName 下載時的文件名稱* @param response* @param workbook excel數(shù)據(jù)*/private static void downLoadExcel(String fileName, HttpServletResponse response, Workbook workbook) throws IOException {try {response.setCharacterEncoding("UTF-8");response.setHeader("content-Type", "application/vnd.ms-excel");response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName + ".xlsx", "UTF-8"));workbook.write(response.getOutputStream());} catch (Exception e) {throw new IOException(e.getMessage());}}/*** excel 導(dǎo)入** @param file excel文件* @param pojoClass pojo類型* @param <T>* @return*/public static <T> List<T> importExcel(MultipartFile file, Class<T> pojoClass) throws IOException {return importExcel(file, 1, 1, pojoClass);}/*** excel 導(dǎo)入** @param filePath excel文件路徑* @param titleRows 表格內(nèi)數(shù)據(jù)標題行* @param headerRows 表頭行* @param pojoClass pojo類型* @param <T>* @return*/public static <T> List<T> importExcel(String filePath, Integer titleRows, Integer headerRows, Class<T> pojoClass) throws IOException {if (StringUtils.isBlank(filePath)) {return null;}ImportParams params = new ImportParams();params.setTitleRows(titleRows);params.setHeadRows(headerRows);params.setNeedSave(true);params.setSaveUrl("/excel/");try {return ExcelImportUtil.importExcel(new File(filePath), pojoClass, params);} catch (NoSuchElementException e) {throw new IOException("模板不能為空");} catch (Exception e) {throw new IOException(e.getMessage());}}/*** excel 導(dǎo)入** @param file 上傳的文件* @param titleRows 表格內(nèi)數(shù)據(jù)標題行* @param headerRows 表頭行* @param pojoClass pojo類型* @param <T>* @return*/public static <T> List<T> importExcel(MultipartFile file, Integer titleRows, Integer headerRows, Class<T> pojoClass) throws IOException {if (file == null) {return null;}try {return importExcel(file.getInputStream(), titleRows, headerRows, pojoClass);} catch (Exception e) {throw new IOException(e.getMessage());}}/*** excel 導(dǎo)入** @param inputStream 文件輸入流* @param titleRows 表格內(nèi)數(shù)據(jù)標題行* @param headerRows 表頭行* @param pojoClass pojo類型* @param <T>* @return*/public static <T> List<T> importExcel(InputStream inputStream, Integer titleRows, Integer headerRows, Class<T> pojoClass) throws IOException {if (inputStream == null) {return null;}ImportParams params = new ImportParams();params.setTitleRows(titleRows);params.setHeadRows(headerRows);params.setSaveUrl("/excel/");params.setNeedSave(true);try {return ExcelImportUtil.importExcel(inputStream, pojoClass, params);} catch (NoSuchElementException e) {throw new IOException("excel文件不能為空");} catch (Exception e) {throw new IOException(e.getMessage());}} }4)創(chuàng)建數(shù)據(jù)庫db2020及表user,執(zhí)行腳本在根目錄下。
5)excel表格要導(dǎo)入的數(shù)據(jù)文件在項目根路徑的template文件夾下
6)使用vue-cli新建一個vue的項目,并安裝需要的插件。項目對axios進行了封裝,調(diào)用的時候,直接在js中使用即可,詳見源碼。
7)最后一點,要配置文件中加一行配置
#easypoi啟用覆蓋 springmain:allow-bean-definition-overriding: true1.2導(dǎo)入
excel文件的導(dǎo)入,主要就是把文件上傳之后把內(nèi)容讀取出來進行相應(yīng)的操作。
1)編寫controller導(dǎo)入接口,service及dao詳見源碼。
/*** 導(dǎo)入數(shù)據(jù)* @param file* @return* @throws IOException*/@RequestMapping(value = "/import", method = RequestMethod.POST)public CommonResult importExcel(@RequestParam("file") MultipartFile file) throws IOException {List<User> list = ExcelUtils.importExcel(file, User.class);int i = userService.insertByBatch(list);if (i != 0) {return new CommonResult(200, "導(dǎo)入成功");} else {return new CommonResult(444, "導(dǎo)入失敗");}}2)新建User實體類,給屬性添加@Excel注解
package com.example.easypoidemoadmin.entity;import cn.afterturn.easypoi.excel.annotation.Excel; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Data;/*** @dec 用戶實體*/ @Data @TableName(value = "User") public class User {/*** 用戶名*/@TableId(value = "username")@Excel(name = "用戶名",)private String username;/*** 姓名*/@TableField(value = "name")@Excel(name = "姓名")private String name;/*** 年齡*/@TableField(value = "age")@Excel(name = "年齡")private Integer age;/*** 性別,0表示男,1表示女*/@TableField(value = "sex")@Excel(name = "性別",replace = {"男_0", "女_1"})private String sex;/*** 籍貫*/@TableField(value = "address")@Excel(name = "籍貫")private String address; }需要注意的是,上述的導(dǎo)入的excel內(nèi)容必須包含表頭和標題,否則讀取不到內(nèi)容。在性別這里,分別使用數(shù)字代替文字,存儲方便。
3)頁面導(dǎo)入的組件
<el-upload class="upload-demo" action="" :limit="1" :http-request="importExcel" :show-file-list="false" :file-list="fileList"><el-button size="small" type="primary" icon="el-icon-upload">導(dǎo)入</el-button></el-upload>4)頁面導(dǎo)入的方法
//導(dǎo)入importExcel(param) {const formData = new FormData()formData.append('file', param.file)home.upload(formData).then(res => {if (res.code == 200) {this.fileList = []this.$message.success("導(dǎo)入成功")this.getList()} else {this.$message.error("導(dǎo)入失敗")}}).catch(err =>{console.log(err)this.$message.error("導(dǎo)入失敗")})}導(dǎo)入的模板在后臺代碼的項目根目錄下的template目錄下。
5)注意事項
A:excel表格的表頭必須和@Excel的name屬性一樣,否則讀取不到數(shù)據(jù)。
B:若導(dǎo)入的字段包含日期類型,那么需要指定導(dǎo)入時的日期的格式并標明是必導(dǎo)入字段,如下所示,excel的內(nèi)容的日期也需要是這種格式
@Excel(name = "日期",isImportField = "true", importFormat = "yyyy-MM-dd" ,databaseFormat = "yyyy-MM-dd")C:若導(dǎo)出的字段包含日期類型,那么需要指定導(dǎo)出的格式
@Excel(name = "日期",exportFormat = "yyyy-MM-dd", databaseFormat = "yyyy-MM-dd")二者綜合的代碼如下,下一小節(jié)的導(dǎo)出日期就不再說明。
@Excel(name = "日期",isImportField = "true",exportFormat = "yyyy-MM-dd", importFormat = "yyyy-MM-dd" ,databaseFormat = "yyyy-MM-dd")1.3導(dǎo)出
導(dǎo)入就是根據(jù)查詢的條件把查詢結(jié)果先寫到excel表格中,然后下載這個excel即可。
1)編寫controller導(dǎo)出接口,service及dao詳見源碼。
/*** 導(dǎo)出數(shù)據(jù),使用map接收** @param map* @param response* @throws IOException*/@PostMapping("/exportExcel")public void exportExcel(@RequestBody Map<String, Object> map, HttpServletResponse response) throws IOException {IPage<User> iPage = userService.getList((String) map.get("name"), (Integer) map.get("page"), (Integer) map.get("limit"));ExcelUtils.exportExcel(iPage.getRecords(), (String) map.get("title"), (String) map.get("sheetName"), User.class, (String) map.get("fileName"), response);}2)給實體類@Excel注解添加其他屬性
package com.example.easypoidemoadmin.entity;import cn.afterturn.easypoi.excel.annotation.Excel; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Data;/*** @dec 用戶實體*/ @Data @TableName(value = "User") public class User {/*** 用戶名*/@TableId(value = "username")@Excel(name = "用戶名", orderNum = "0", width = 30)private String username;/*** 姓名*/@TableField(value = "name")@Excel(name = "姓名", orderNum = "1", width = 30)private String name;/*** 年齡*/@TableField(value = "age")@Excel(name = "年齡", orderNum = "2", width = 30)private Integer age;/*** 性別,0表示男,1表示女*/@TableField(value = "sex")@Excel(name = "性別", orderNum = "3", width = 30,replace = {"男_0", "女_1"})private String sex;/*** 籍貫*/@TableField(value = "address")@Excel(name = "籍貫", orderNum = "4", width = 30)private String address; }3)頁面導(dǎo)出的方法
//導(dǎo)出exportExcel() {this.downloadLoading = truehome.exportExcel({title: '用戶基本信息',sheetName: '用戶信息',fileName: '用戶信息表',name: this.pageData.name,page: this.pageData.page,limit: this.pageData.limit,}).then(res => {//使用js下載文件fileDownload(res, '用戶信息表.xlsx')}).finally(() => {this.downloadLoading = false;});},這里使用到了js-file-download插件,它是用來幫助下載文件的。當下載文件時,很多時候都是在地址欄輸入url后瀏覽器自動幫忙下載,但是要統(tǒng)一請求方式,就把返回的二進制文件交給js-file-download進行處理后再下載。需要注意的是,這個導(dǎo)出的請求,我封裝了一個單獨的方法,需要指定響應(yīng)的方式,否則無法下載后的文件是空的,方法截圖如下:
1.4圖片的導(dǎo)出
有了上面的導(dǎo)出基礎(chǔ),圖片的導(dǎo)出就很簡單了。
1)新建一個實體類,用于和上面的實體類區(qū)分
package com.example.easypoidemoadmin.entity;import cn.afterturn.easypoi.excel.annotation.Excel; import lombok.Data;/*** @dec 描述*/ @Data public class Company {@Excel(name = "公司名稱",width =20)private String name;/*** type為 2 表示字段類型為圖片* imageType為 1 表示從file讀取*/@Excel(name = "公司logo",width =20,type = 2,imageType = 1)private String logo;@Excel(name = "公司介紹",width =100)private String dec;public Company(String name,String logo,String dec){this.name=name;this.logo=logo;this.dec=dec;} }2)創(chuàng)建接口,圖片請自行下載。
/*** 圖片的導(dǎo)出** @param response* @throws IOException*/@PostMapping("/imgexport")public void imgExport(HttpServletResponse response,@RequestBody Map<String, Object> map) throws IOException {List<Company> list = new ArrayList<>();//圖片的路徑自定義,但必須要正確list.add(new Company("百度", "E:/img/1.jpg", "百度一下你就知道"));list.add(new Company("騰訊", "E:/img/3.jpg", "騰訊qq,交流的世界"));list.add(new Company("阿里巴巴", "E:/img/2.jpg", "阿里巴巴,馬云的驕傲"));String fileName = map.get("fileName").toString();ExcelUtils.exportExcel(list, fileName, fileName, Company.class, fileName, response);}3)在頁面添加導(dǎo)出的按鈕,點擊按鈕即可進行下載,下載的文件如圖
1.5圖片的導(dǎo)入
1)給Company對象加上無參構(gòu)造,否則會出現(xiàn)異常
public Company(){}2)導(dǎo)入接口
/*** 導(dǎo)入圖片* @param file* @return* @throws IOException*/@PostMapping("/imgimport")public CommonResult imgImport(@RequestParam("file") MultipartFile file) throws IOException {List<Company> list = ExcelUtils.importExcel(file, Company.class);return new CommonResult(200,"導(dǎo)入成功",list);}3)參考excel的導(dǎo)入,添加一個導(dǎo)入的按鈕和請求的方法,詳見源碼
4)點擊excel圖片上傳,把上一步導(dǎo)出的文件進行導(dǎo)入,看到瀏覽器返回的數(shù)據(jù)如圖
1.6excel模板導(dǎo)出文件
也可以使用固定的模板來導(dǎo)出excel。
1)在工具類添加方法
/*** 根據(jù)模板生成excel后導(dǎo)出* @param templatePath 模板路徑* @param map 數(shù)據(jù)集合* @param fileName 文件名* @param response* @throws IOException*/public static void exportExcel(TemplateExportParams templatePath, Map<String, Object> map,String fileName, HttpServletResponse response) throws IOException {Workbook workbook = ExcelExportUtil.exportExcel(templatePath, map);downLoadExcel(fileName, response, workbook);}2)編寫模板excel。截圖如下,模板文件在項目根路徑的template文件夾下:
在兩個大括號里寫對應(yīng)的數(shù)據(jù)名稱。$fe用來遍歷數(shù)據(jù),fe的寫法 fe標志 : list數(shù)據(jù) 單個元素數(shù)據(jù)(默認t,不需要寫) {{$fe: maplist t.id }}
3)接口
/*** 使用模板excel導(dǎo)出** @param response* @throws Exception*/@PostMapping("/excelTemplate")public void makeExcelTemplate(HttpServletResponse response, @RequestBody Map<String, Object> param) throws Exception {TemplateExportParams templatePath = new TemplateExportParams("E:/excel/用戶信息文件模板.xls");Map<String, Object> map = new HashMap<>();SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");map.put("date", sdf.format(new Date()));map.put("user", "admin");IPage<User> ipages = userService.getList("", 1, 10);map.put("userList", ipages.getRecords());ExcelUtils.exportExcel(templatePath, map, param.get("fileName").toString(), response);}在接口中,指定模板文件的路徑,然后給定數(shù)據(jù),map的key值要和模板的值保持一致。
4)頁面添加按鈕和請求方法,見源碼。點擊即可下載。
1.7excel轉(zhuǎn)html
1)在工具類添加方法
/*** excel轉(zhuǎn)html預(yù)覽* @param filePath 文件路徑* @param response* @throws Exception*/public static void excelToHtml(String filePath,HttpServletResponse response) throws Exception{ExcelToHtmlParams params = new ExcelToHtmlParams(WorkbookFactory.create(POICacheManager.getFile(filePath)),true);response.getOutputStream().write(ExcelXorHtmlUtil.excelToHtml(params).getBytes());}2)編寫接口
/*** EXCEL轉(zhuǎn)html預(yù)覽*/@GetMapping("previewExcel")public void excelToHtml(HttpServletResponse response) throws Exception {ExcelUtils.excelToHtml("E:/excel/用戶信息導(dǎo)入模板.xlsx",response);}3)頁面添加按鈕和請求方法,見源碼。點擊即可在彈框中顯示。
2.Word文件導(dǎo)出
2.1使用word模板導(dǎo)出
1)導(dǎo)入easypoi-base的依賴
<dependency><groupId>cn.afterturn</groupId><artifactId>easypoi-base</artifactId><version>${easypoi.version}</version></dependency>2)在工具類加兩個方法
/*** word下載** @param fileName 下載時的文件名稱* @param response* @param doc*/private static void downLoadWord(String fileName, HttpServletResponse response, XWPFDocument doc) throws IOException {try {response.setCharacterEncoding("UTF-8");response.setHeader("content-Type", "application/msword");response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName + ".docx" , "UTF-8"));doc.write(response.getOutputStream());} catch (Exception e) {throw new IOException(e.getMessage());}}/*** word模板導(dǎo)出* @param map* @param templatePath* @param fileName* @param response* @throws Exception*/public static void WordTemplateExport(Map<String, Object> map,String templatePath,String fileName,HttpServletResponse response) throws Exception {XWPFDocument doc = WordExportUtil.exportWord07(templatePath, map);downLoadWord(fileName,response,doc);}3)接口,模板文件在項目根路徑的template文件夾下,圖片自定義下載(注意:如果要設(shè)置圖片,必須把導(dǎo)入的jar的版本改為3.3.0,否則會報錯,原因是新版本沒有這個實體類):
/*** 使用模板word導(dǎo)出數(shù)據(jù)* @param param* @param response*/@PostMapping("/wordTemplate")public void makeWordTemplate(@RequestBody Map<String, Object> param,HttpServletResponse response) {Map<String, Object> map = new HashMap<>();map.put("name", "張三");map.put("nativePlace", "湖北武漢");map.put("age", "20");map.put("nation", "漢族");map.put("phone", "15685654524");map.put("experience", "湖北武漢,工作三年,java工程師");map.put("evaluate", "優(yōu)秀,善良,老實");//設(shè)置圖片,如果無圖片,不設(shè)置即可WordImageEntity image = new WordImageEntity();image.setHeight(200);image.setWidth(150);image.setUrl("E:/excel/pic.jpg");image.setType(WordImageEntity.URL);map.put("picture", image);try {ExcelUtils.WordTemplateExport(map,"E:/excel/個人簡歷模板.docx",param.get("fileName").toString(),response);} catch (Exception e) {e.printStackTrace();}}4)頁面添加按鈕和請求方法,見源碼。點擊即可下載。上面案例導(dǎo)出時有圖片,如果不需要圖片,可不設(shè)置圖片路徑即可。
2.2使用word模板導(dǎo)出多頁
單模板生成多頁數(shù)據(jù)在合適的場景也是需要的,比如一個訂單詳情信息模板,但是有很多訂單,需要導(dǎo)入到一個word里面。
1)在工具類添加方法
/*** word模板導(dǎo)出多頁* @param list* @param templatePath* @param fileName* @param response* @throws Exception*/public static void WordTemplateExportMorePage(List<Map<String, Object>> list, String templatePath, String fileName, HttpServletResponse response) throws Exception {XWPFDocument doc = new ParseWord07().parseWord(templatePath, list);downLoadWord(fileName, response, doc);}2)接口
/*** word模板導(dǎo)出多頁* @param param* @param response*/@PostMapping("/wordTemplateMorePage")public void makeWordTemplateMorePage(@RequestBody Map<String, Object> param, HttpServletResponse response) {List<Map<String, Object>> list=new ArrayList<>();for (int i = 0; i < 5; i++) {Map<String, Object> person = new HashMap<>();person.put("name", "張三"+i);person.put("nativePlace", "湖北武漢"+i);person.put("age", 20+i);person.put("nation", "漢族");person.put("phone", "15685654524");person.put("experience", "湖北武漢,工作三年,java工程師");person.put("evaluate", "優(yōu)秀,善良,老實");person.put("picture", "");list.add(person);}try {ExcelUtils.WordTemplateExportMorePage(list, "E:/excel/個人簡歷模板.docx", param.get("fileName").toString(), response);} catch (Exception e) {e.printStackTrace();}}3)頁面添加按鈕和請求方法,見源碼。點擊即可下載。
3.excel導(dǎo)入時驗證
有時候需要在導(dǎo)入時先驗證數(shù)據(jù)的合法性再進行導(dǎo)出,為了演示的完整性,需要使用新的頁面進行導(dǎo)入操作。步驟如下:
3.1環(huán)境準備
1)新建表student
CREATE TABLE `student` (`id` int(11) NOT NULL AUTO_INCREMENT,`name` varchar(20) DEFAULT NULL COMMENT '姓名',`age` int(11) DEFAULT NULL COMMENT '年齡',`birth` date DEFAULT NULL COMMENT '出生日期',PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8;2)在ExcelUtils工具類添加方法(標紅)
package com.example.easypoidemoadmin.utils;import cn.afterturn.easypoi.cache.manager.POICacheManager; import cn.afterturn.easypoi.excel.ExcelExportUtil; import cn.afterturn.easypoi.excel.ExcelImportUtil; import cn.afterturn.easypoi.excel.ExcelXorHtmlUtil; import cn.afterturn.easypoi.excel.entity.ExcelToHtmlParams; import cn.afterturn.easypoi.excel.entity.ExportParams; import cn.afterturn.easypoi.excel.entity.ImportParams; import cn.afterturn.easypoi.excel.entity.TemplateExportParams; import cn.afterturn.easypoi.excel.entity.enmus.ExcelType; import cn.afterturn.easypoi.excel.entity.result.ExcelImportResult; import cn.afterturn.easypoi.word.WordExportUtil; import cn.afterturn.easypoi.word.parse.ParseWord07; import org.apache.commons.lang3.StringUtils; import org.apache.poi.ss.usermodel.Workbook; import org.apache.poi.ss.usermodel.WorkbookFactory; import org.apache.poi.xwpf.usermodel.XWPFDocument; import org.springframework.web.multipart.MultipartFile;import javax.servlet.http.HttpServletResponse; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.URLEncoder; import java.util.List; import java.util.Map; import java.util.NoSuchElementException;/*** Excel導(dǎo)入導(dǎo)出工具類*/public class ExcelUtils {/*** excel 導(dǎo)出** @param list 數(shù)據(jù)列表* @param fileName 導(dǎo)出時的excel名稱* @param response*/public static void exportExcel(List<Map<String, Object>> list, String fileName, HttpServletResponse response) throws IOException {defaultExport(list, fileName, response);}/*** 默認的 excel 導(dǎo)出** @param list 數(shù)據(jù)列表* @param fileName 導(dǎo)出時的excel名稱* @param response*/private static void defaultExport(List<Map<String, Object>> list, String fileName, HttpServletResponse response) throws IOException {//把數(shù)據(jù)添加到excel表格中Workbook workbook = ExcelExportUtil.exportExcel(list, ExcelType.HSSF);downLoadExcel(fileName, response, workbook);}/*** excel 導(dǎo)出** @param list 數(shù)據(jù)列表* @param pojoClass pojo類型* @param fileName 導(dǎo)出時的excel名稱* @param response* @param exportParams 導(dǎo)出參數(shù)(標題、sheet名稱、是否創(chuàng)建表頭,表格類型)*/private static void defaultExport(List<?> list, Class<?> pojoClass, String fileName, HttpServletResponse response, ExportParams exportParams) throws IOException {//把數(shù)據(jù)添加到excel表格中Workbook workbook = ExcelExportUtil.exportExcel(exportParams, pojoClass, list);downLoadExcel(fileName, response, workbook);}/*** excel 導(dǎo)出** @param list 數(shù)據(jù)列表* @param pojoClass pojo類型* @param fileName 導(dǎo)出時的excel名稱* @param exportParams 導(dǎo)出參數(shù)(標題、sheet名稱、是否創(chuàng)建表頭,表格類型)* @param response*/public static void exportExcel(List<?> list, Class<?> pojoClass, String fileName, ExportParams exportParams, HttpServletResponse response) throws IOException {defaultExport(list, pojoClass, fileName, response, exportParams);}/*** excel 導(dǎo)出** @param list 數(shù)據(jù)列表* @param title 表格內(nèi)數(shù)據(jù)標題* @param sheetName sheet名稱* @param pojoClass pojo類型* @param fileName 導(dǎo)出時的excel名稱* @param response*/public static void exportExcel(List<?> list, String title, String sheetName, Class<?> pojoClass, String fileName, HttpServletResponse response) throws IOException {defaultExport(list, pojoClass, fileName, response, new ExportParams(title, sheetName, ExcelType.XSSF));}/*** 根據(jù)模板生成excel后導(dǎo)出** @param templatePath 模板路徑* @param map 數(shù)據(jù)集合* @param fileName 文件名* @param response* @throws IOException*/public static void exportExcel(TemplateExportParams templatePath, Map<String, Object> map, String fileName, HttpServletResponse response) throws IOException {Workbook workbook = ExcelExportUtil.exportExcel(templatePath, map);downLoadExcel(fileName, response, workbook);}/*** excel 導(dǎo)出** @param list 數(shù)據(jù)列表* @param title 表格內(nèi)數(shù)據(jù)標題* @param sheetName sheet名稱* @param pojoClass pojo類型* @param fileName 導(dǎo)出時的excel名稱* @param isCreateHeader 是否創(chuàng)建表頭* @param response*/public static void exportExcel(List<?> list, String title, String sheetName, Class<?> pojoClass, String fileName, boolean isCreateHeader, HttpServletResponse response) throws IOException {ExportParams exportParams = new ExportParams(title, sheetName, ExcelType.XSSF);exportParams.setCreateHeadRows(isCreateHeader);defaultExport(list, pojoClass, fileName, response, exportParams);}/*** excel下載** @param fileName 下載時的文件名稱* @param response* @param workbook excel數(shù)據(jù)*/private static void downLoadExcel(String fileName, HttpServletResponse response, Workbook workbook) throws IOException {try {response.setCharacterEncoding("UTF-8");response.setHeader("content-Type", "application/vnd.ms-excel");response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName + ".xlsx", "UTF-8"));workbook.write(response.getOutputStream());} catch (Exception e) {throw new IOException(e.getMessage());}}/*** word下載** @param fileName 下載時的文件名稱* @param response* @param doc*/private static void downLoadWord(String fileName, HttpServletResponse response, XWPFDocument doc) throws IOException {try {response.setCharacterEncoding("UTF-8");response.setHeader("content-Type", "application/msword");response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName + ".docx", "UTF-8"));doc.write(response.getOutputStream());} catch (Exception e) {throw new IOException(e.getMessage());}}/*** excel 導(dǎo)入** @param file excel文件* @param pojoClass pojo類型* @param <T>* @return*/public static <T> List<T> importExcel(MultipartFile file, Class<T> pojoClass) throws IOException {return importExcel(file, 1, 1, pojoClass);}/*** excel 導(dǎo)入** @param filePath excel文件路徑* @param titleRows 表格內(nèi)數(shù)據(jù)標題行* @param headerRows 表頭行* @param pojoClass pojo類型* @param <T>* @return*/public static <T> List<T> importExcel(String filePath, Integer titleRows, Integer headerRows, Class<T> pojoClass) throws IOException {if (StringUtils.isBlank(filePath)) {return null;}ImportParams params = new ImportParams();params.setTitleRows(titleRows);params.setHeadRows(headerRows);params.setNeedSave(true);params.setSaveUrl("/excel/");try {return ExcelImportUtil.importExcel(new File(filePath), pojoClass, params);} catch (NoSuchElementException e) {throw new IOException("模板不能為空");} catch (Exception e) {throw new IOException(e.getMessage());}}/*** excel 導(dǎo)入** @param file 上傳的文件* @param titleRows 表格內(nèi)數(shù)據(jù)標題行* @param headerRows 表頭行* @param pojoClass pojo類型* @param <T>* @return*/public static <T> List<T> importExcel(MultipartFile file, Integer titleRows, Integer headerRows, Class<T> pojoClass) throws IOException {if (file == null) {return null;}try {return importExcel(file.getInputStream(), titleRows, headerRows, pojoClass);} catch (Exception e) {throw new IOException(e.getMessage());}}/*** excel 導(dǎo)入** @param inputStream 文件輸入流* @param titleRows 表格內(nèi)數(shù)據(jù)標題行* @param headerRows 表頭行* @param pojoClass pojo類型* @param <T>* @return*/public static <T> List<T> importExcel(InputStream inputStream, Integer titleRows, Integer headerRows, Class<T> pojoClass) throws IOException {if (inputStream == null) {return null;}ImportParams params = new ImportParams();params.setTitleRows(titleRows);params.setHeadRows(headerRows);params.setSaveUrl("/excel/");params.setNeedSave(true);try {return ExcelImportUtil.importExcel(inputStream, pojoClass, params);} catch (NoSuchElementException e) {throw new IOException("excel文件不能為空");} catch (Exception e) {throw new IOException(e.getMessage());}}/*** excel轉(zhuǎn)html預(yù)覽** @param filePath 文件路徑* @param response* @throws Exception*/public static void excelToHtml(String filePath, HttpServletResponse response) throws Exception {ExcelToHtmlParams params = new ExcelToHtmlParams(WorkbookFactory.create(POICacheManager.getFile(filePath)), true);response.getOutputStream().write(ExcelXorHtmlUtil.excelToHtml(params).getBytes());}/*** word模板導(dǎo)出** @param map* @param templatePath* @param fileName* @param response* @throws Exception*/public static void WordTemplateExport(Map<String, Object> map, String templatePath, String fileName, HttpServletResponse response) throws Exception {XWPFDocument doc = WordExportUtil.exportWord07(templatePath, map);downLoadWord(fileName, response, doc);}/*** word模板導(dǎo)出多頁** @param list* @param templatePath* @param fileName* @param response* @throws Exception*/public static void WordTemplateExportMorePage(List<Map<String, Object>> list, String templatePath, String fileName, HttpServletResponse response) throws Exception {XWPFDocument doc = new ParseWord07().parseWord(templatePath, list);downLoadWord(fileName, response, doc);}/*** excel 導(dǎo)入,有錯誤信息** @param file 上傳的文件* @param pojoClass pojo類型* @param <T>* @return*/public static <T> ExcelImportResult<T> importExcelMore(MultipartFile file, Class<T> pojoClass) throws IOException {if (file == null) {return null;}try {return importExcelMore(file.getInputStream(), pojoClass);} catch (Exception e) {throw new IOException(e.getMessage());}}/*** excel 導(dǎo)入** @param inputStream 文件輸入流* @param pojoClass pojo類型* @param <T>* @return*/private static <T> ExcelImportResult<T> importExcelMore(InputStream inputStream, Class<T> pojoClass) throws IOException {if (inputStream == null) {return null;}ImportParams params = new ImportParams();params.setTitleRows(1);//表格內(nèi)數(shù)據(jù)標題行params.setHeadRows(1);//表頭行params.setSaveUrl("/excel/");params.setNeedSave(true);params.setNeedVerify(true);try {return ExcelImportUtil.importExcelMore(inputStream, pojoClass, params);} catch (NoSuchElementException e) {throw new IOException("excel文件不能為空");} catch (Exception e) {throw new IOException(e.getMessage());}} }3)導(dǎo)入驗證構(gòu)造器的依賴
<dependency><groupId>org.hibernate</groupId><artifactId>hibernate-validator</artifactId><version>5.4.0.Final</version></dependency>4)創(chuàng)建easypoi的工具類
package com.example.easypoidemoadmin.utils;import cn.afterturn.easypoi.excel.annotation.Excel; import org.apache.commons.lang3.StringUtils;import java.lang.reflect.Field; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Proxy; import java.util.Map;/*** easypoi工具類,* 使用new方式創(chuàng)建對象并使用** @param <T>*/ public class EasyPoiTool<T> {/*** 需要被反射的對象,使用泛型規(guī)范傳入對象*/public T t;/*** 修改注解@Excel的屬性值* @param attributeName* @param columnName* @param targetValue* @throws Exception*/public void changeAttribute(String attributeName, String columnName, Object targetValue) throws Exception {if (t == null) {throw new ClassNotFoundException("未找到目標類");}if (StringUtils.isEmpty(attributeName)) {throw new NullPointerException("傳入的注解屬性為空");}if (StringUtils.isEmpty(columnName)) {throw new NullPointerException("傳入的屬性列名為空");}//獲取目標對象的屬性值Field field = t.getClass().getDeclaredField(columnName);//獲取注解反射對象Excel excelAnion = field.getAnnotation(Excel.class);//獲取代理InvocationHandler invocationHandler = Proxy.getInvocationHandler(excelAnion);Field excelField = invocationHandler.getClass().getDeclaredField("memberValues");excelField.setAccessible(true);Map memberValues = (Map) excelField.get(invocationHandler);memberValues.put(attributeName, targetValue);} }3.2實戰(zhàn)演練
需求:對導(dǎo)入的學(xué)生信息進行驗證,驗證通過后才能導(dǎo)入。要求學(xué)生姓名不能為空,出生日期必須是yyyy-MM-dd格式,年齡必須合法。導(dǎo)入后把驗證未通過的信息通過excel方式再下載到本地。
1)新建學(xué)生對象,添加注解驗證并實現(xiàn)IExcelModel接口
package com.example.easypoidemoadmin.entity;import cn.afterturn.easypoi.excel.annotation.Excel; import cn.afterturn.easypoi.handler.inter.IExcelModel; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import com.fasterxml.jackson.annotation.JsonFormat; import lombok.Data;import javax.validation.constraints.NotNull; import javax.validation.constraints.Pattern; import java.util.Date;@Data @TableName(value = "student") public class Student implements IExcelModel {/*** id*/@TableId(value = "id", type = IdType.AUTO)private Integer id;/*** 姓名*/@TableField(value = "name")@Excel(name = "姓名", width = 20)@NotNull(message = "姓名不能為空")private String name;/*** 年齡*/@TableField(value = "age")private Integer age;/*** 年齡驗證*/@TableField(exist = false)@Excel(name = "年齡")@NotNull(message = "年齡不能為空")@Pattern(regexp = "^(?:[1-9][0-9]?|1[01][0-9]|120)$", message = "年齡必須是整數(shù),且在1-120之間")private String ageStr;/*** 出生日期*/@TableField(value = "birth")@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd")private Date birth;/*** 出生日期驗證*/@TableField(exist = false)@Excel(name = "出生日期", isImportField = "true", importFormat = "yyyy-MM-dd", databaseFormat = "yyyy-MM-dd", width = 30)@NotNull(message = "出生日期不能為空")@Pattern(regexp = "^\\d{4}-\\d{1,2}-\\d{1,2}$", message = "日期格式必須是yyyy-MM-dd格式,如2020-01-01")private String birthStr;//錯誤信息@TableField(exist = false)@Excel(name = "錯誤信息", width = 50, isColumnHidden = true)private String errorMsg;}實現(xiàn)此接口的原因是獲取其驗證的錯誤信息,并將其映射到字段errorMsg上,當對象不包含此字段時,就看不到錯誤信息。
2)新建接口StudentController
package com.example.easypoidemoadmin.controller;import cn.afterturn.easypoi.excel.entity.result.ExcelImportResult; import com.baomidou.mybatisplus.core.metadata.IPage; import com.example.easypoidemoadmin.entity.CommonResult; import com.example.easypoidemoadmin.entity.Student; import com.example.easypoidemoadmin.service.StudentService; import com.example.easypoidemoadmin.utils.EasyPoiTool; import com.example.easypoidemoadmin.utils.ExcelUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile;import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Map;@RestController @RequestMapping("/api/student") public class StudentController {@Autowiredprivate StudentService studentService;/*** 查詢用戶信息列表** @param name* @param page* @param limit* @return*/@GetMapping("/list")public CommonResult getList(String name, Integer page, Integer limit) {IPage<Student> iPage = studentService.getList(name, page, limit);return new CommonResult(200, "查詢信息成功", iPage.getRecords(), iPage.getTotal());}/*** 導(dǎo)入學(xué)生信息** @param file* @param response* @return*/@PostMapping("/upload")public CommonResult upload(@RequestParam("file") MultipartFile file, HttpServletResponse response) {try {ExcelImportResult<Student> importResult = ExcelUtils.importExcelMore(file, Student.class);//驗證通過的數(shù)據(jù)List<Student> list = importResult.getList();//驗證未通過的數(shù)據(jù)List<Student> failList = importResult.getFailList();studentService.insertBatch(list);if (failList != null && failList.size() > 0) {//修改導(dǎo)出的日期格式EasyPoiTool<Student> easyPoiUtil = new EasyPoiTool<>();easyPoiUtil.t = failList.get(0);//展示錯誤的列easyPoiUtil.changeAttribute("isColumnHidden", "errorMsg", false);//設(shè)置導(dǎo)出的格式easyPoiUtil.changeAttribute("exportFormat", "birthStr", "");//導(dǎo)出excelString title = "導(dǎo)入異常的數(shù)據(jù)";ExcelUtils.exportExcel(failList, title, title, Student.class, title, response);return null;}return new CommonResult(200, "信息導(dǎo)入成功");} catch (Exception e) {e.printStackTrace();return new CommonResult(444, "信息導(dǎo)入失敗");}}@PostMapping("/exportTemplate")public void exportTemplate(@RequestBody Map<String, Object> map, HttpServletResponse response) throws IOException {List<Student> list = new ArrayList<>();ExcelUtils.exportExcel(list, (String) map.get("title"), (String) map.get("sheetName"), Student.class, (String) map.get("fileName"), response);} }對于后面的service和dao詳見源碼。
3)導(dǎo)入的頁面見源碼,這里主要說明導(dǎo)入的方法,在導(dǎo)入后需要根據(jù)返回的數(shù)據(jù)判斷是否有錯誤的信息,如果有則下載錯誤信息,若沒有則顯示成功。
importExcel(param) {const file = param.fileif (file.name.lastIndexOf('.') < 0) {this.$message.error('上傳文件只能是xls、xlsx格式!')return}const testMsg = file.name.substring(file.name.lastIndexOf('.') + 1).toLowerCase()const extensionXLS = testMsg == 'xls'const extensionXLSX = testMsg == 'xlsx'if (!extensionXLS && !extensionXLSX) {this.$message.error('上傳文件只能是xls、xlsx格式!')return}const isLt2M = file.size / 1024 / 1024 < 2if (!isLt2M) {this.$message.error('上傳文件不能超過 2MB!')return}this.importLoading = trueconst formData = new FormData()formData.append('file', param.file)student.upload(formData).then(res => {if (!res.code) {this.$message.error("部分數(shù)據(jù)導(dǎo)入失敗,數(shù)據(jù)已下載到本地,請查看!")fileDownload(res, '導(dǎo)入異常的數(shù)據(jù).xlsx')this.fileList = []this.getList()} else if (res.code == 200) {this.$message.success("導(dǎo)入成功")this.fileList = []this.getList()} else {this.$message.error("導(dǎo)入失敗")}}).catch(err => {console.log(err)this.$message.error("導(dǎo)入失敗")}).finally(()=>{this.importLoading = false})},也就是說對于這個上傳的請求,當返回的內(nèi)容是json字符串時就是成功的,沒有錯誤的數(shù)據(jù),若不是則返回的是arraybuff類型的數(shù)據(jù),需要直接下載。
3.3注意事項
1)由于需要進行驗證,因此在工具類中必須要設(shè)置ImportParams的needVerify為true;
2)easypoi是使用springboot對應(yīng)的版本,對于spring的版本,驗證在這里可能不生效;
3)對于驗證構(gòu)造器hibernate的版本,springboot2對應(yīng)的版本必須是5及以上,否則錯誤信息不會顯示;
4)對應(yīng)上傳的方法,響應(yīng)類型必須是arraybuff,否則下載的excel無法打開
5)要顯示錯誤的信息,必須設(shè)置errorMsg上@Excel注解的isColumnHidden為false
6)在@Excel中沒有設(shè)置導(dǎo)出(exportFormat)的日期格式,而是在需要導(dǎo)出的時候再通過反射的方式(調(diào)用EasyPoiUtil的方法)設(shè)置。若提前設(shè)置了,在導(dǎo)入時,輸入的格式不正確,在導(dǎo)出錯誤信息時則會拋出異常。
7)其自帶的正則驗證,要求字段的類型必須是字符串類型,其他類型會發(fā)生異常。因此,需要設(shè)置兩個字段,一個映射數(shù)據(jù)庫的字段,一個用于導(dǎo)出和導(dǎo)出。當然也可以使用兩個類進行分布對應(yīng)。
8)當需要獲取錯誤的行號時,讓實體類繼承IExcelDataModel類并添加int類型的rowNum屬性即可。
就是這么簡單,你學(xué)廢了嗎?感覺有用的話,給筆者點個贊吧 !
總結(jié)
以上是生活随笔為你收集整理的easyPOI基本用法详解的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: javascript精要(2)-<scr
- 下一篇: erlang虚拟机精要(2)-异步信号时