場景
使用若依前后端分離版實現Excel的導入和導出。
前端:Vue+ElementUI
后端:SpringBoot+POI+Mysql
注:
博客:
https://blog.csdn.net/badao_liumang_qizhi
關注公眾號
霸道的程序猿
獲取編程相關電子書、教程推送與免費下載。
實現
Excel導入
點擊導入按鈕時的效果


選中Excel后


首先是前端頁面,添加導入的dialog
<el-dialog :title="upload.title" :visible.sync="upload.open" width="400px" append-to-body> <el-upload ref="upload" :limit="1" accept=".xlsx, .xls" :headers="upload.headers" :action="upload.url" :disabled="upload.isUploading" :on-progress="handleFileUploadProgress" :on-success="handleFileSuccess" :auto-upload="false" :data="{updateSupport:upload.updateSupport}" drag > <i class="el-icon-upload"></i> <div class="el-upload__text"> 將文件拖到此處,或 <em>點擊上傳</em> </div> <div class="el-upload__tip" slot="tip"> <el-checkbox v-model="upload.updateSupport" />是否更新已經存在的下井次數設置數據 <el-link type="info" style="font-size:12px" @click="downloadTemplate('xjszTemplate.xlsx')" >下載模板</el-link> </div> <div class="el-upload__tip" style="color:red" slot="tip" >提示:僅允許導入“xls”或“xlsx”格式文件!是否全勤中:1代表全勤,0代表固定次數,不得有空值!!</div> </el-upload> <div slot="footer" class="dialog-footer"> <el-button type="primary" @click="submitFileForm">確 定</el-button> <el-button @click="upload.open = false">取 消</el-button> </div> </el-dialog>
通過:visible.sync="upload.open"控制默認隱藏,其中upload是聲明的用於存儲上傳相關的參數的model
需要聲明它
export default { name: "Xjcssz", data() { return { // 導入參數 upload: { // 是否顯示彈出層 open: false, // 彈出層標題 title: "", // 是否禁用上傳 isUploading: false, // 是否更新已經存在的數據 updateSupport: 0, // 設置上傳的請求頭部 headers: { Authorization: "Bearer " + getToken() }, // 上傳的地址 url: process.env.VUE_APP_BASE_API + "/kqgl/xjcssz/importData", },
這里的getToken()是從auth中引入
import { getToken } from "@/utils/auth";
是要獲取登錄的token
export function getToken() { return Cookies.get(TokenKey) }
文件上傳組件使用的是e-upload組件,設置其一些屬性
limit限制只能選擇一個文件
accept限制能選擇的文件類型
headers設置請求頭攜帶token
action設置上傳請求的url
disabled設置正在上傳時禁用
on-progress設置正在上傳時的處理事件
on-success設置上傳成功后的事件
auto-upload設置自動提交為false,用來實現手動提交時才提交
data設置上傳時攜帶的數據
drag表示支持可拖拽
設置on-progress正在上傳時將其禁用
// 文件上傳中處理 handleFileUploadProgress(event, file, fileList) { this.upload.isUploading = true; },
設置on-success上傳成功后關閉上傳窗口並設置上傳可用,然后清除選擇的文件並提示導入結果然后刷新數據。
// 文件上傳成功處理 handleFileSuccess(response, file, fileList) { this.upload.open = false; this.upload.isUploading = false; this.$refs.upload.clearFiles(); this.$alert(response.msg, "導入結果", { dangerouslyUseHTMLString: true }); this.getList(); },
這里是攜帶了參數 是否更新已經存在的數據,將其與勾選框進行雙向數據綁定
<el-checkbox v-model="upload.updateSupport" />是否更新已經存在的下井次數設置數據
並且作為參數在提交時進行傳遞
:data="{updateSupport:upload.updateSupport}"
注意傳遞參數時的格式。
然后點擊確定按鈕時觸發事件
<el-button type="primary" @click="submitFileForm">確 定</el-button>
在事件處理中,通過設置的ref屬性將表單提交
submitFileForm() { this.$refs.upload.submit(); },
此時表單就會提交到指定的url的后台接口。
來到后台接口
@RequestMapping("/importData") @ResponseBody @ApiOperation("導入下井次數設置數據") public AjaxResult importData(@RequestParam MultipartFile file, @RequestParam boolean updateSupport) throws Exception { ExcelUtil<KqXjcssz> util = new ExcelUtil<KqXjcssz>(KqXjcssz.class); List<KqXjcssz> xjcsszList = util.importExcel(file.getInputStream()); //循環插入數據 for (KqXjcssz xjcssz:xjcsszList) { if(xjcssz.getGh()==null) { return AjaxResult.error("存在為空的工號數據"); } xjcssz.setSzrq(new Date()); xjcssz.setSzr(SecurityUtils.getUsername()); //根據工號查詢是否已經存在 Integer count = kqXjcsszService.isExistByGh(xjcssz.getGh()); if(count>0) { //如果設置了更新 if(updateSupport) { kqXjcsszService.updateKqXjcssz(xjcssz); }else { //選擇了不更新 啥也不干 } } else { //之前不存在直接插入 kqXjcsszService.insertKqXjcssz(xjcssz); } } return AjaxResult.success("導入成功"); }
這里的后台接口使用@RequestMapping接收,並且使用@ResponseBody注解響應json數據。
接受請求參數時,文件必須是@RequestParam MultipartFile file,且名稱為file,如果不進行更改指定的話。
然后第二個參數要與傳遞時的參數名一致。
然后調用若依自帶的工具類
ExcelUtil<KqXjcssz> util = new ExcelUtil<KqXjcssz>(KqXjcssz.class); List<KqXjcssz> xjcsszList = util.importExcel(file.getInputStream());
以及實體類上的注解
/** 工號 */ @Excel(name = "工號") private String gh;
等就能實現解析Excel的數據並獲取成對象的list。
這里的導入時的模板建議用下面的導出的EXCEL作為導入模板用。
然后上傳時點擊下載模板時調用公共下載接口。
Excel導出
頁面上添加導出按鈕
<el-button type="warning" icon="el-icon-download" size="mini" @click="handleExport" v-hasPermi="['kqgl:bcgl:export']" >導出</el-button>
導出按鈕對應的處理方法
/** 導出按鈕操作 */ handleExport() { const queryParams = this.queryParams; this.$confirm("是否確認導出所有數據項?", "警告", { confirmButtonText: "確定", cancelButtonText: "取消", type: "warning", }) .then(function () { return exportBcgl(queryParams); }) .then((response) => { this.download(response.msg); }) .catch(function () {}); },
會彈窗提示,點擊確定后執行exportBcgl方法,此方法是從外部js中引入
import { exportBcgl, } from "@/api/kqgl/bcgl";
在js方法中
export function exportBcgl(query) { return request({ url: '/kqgl/bcgl/export', method: 'get', params: query }) }
在此方法中發送get請求給SpringBoot后台接口。
其中request是來自request.js,封裝的axios發送請求的對象。
在對應的SpringBoot后台接口
@GetMapping("/export") public AjaxResult export(KqBcgl kqBcgl) { List<KqBcgl> list = kqBcglService.getBcListByNameToExport(kqBcgl); ExcelUtil<KqBcgl> util = new ExcelUtil<KqBcgl>(KqBcgl.class); return util.exportExcel(list, "bcgl"); }
直接調用若依自帶的Excel工具類就可以實現導出。
其中KqBcgl是對應的業務的實體類,可以使用代碼生成工具去生成。
在實體類中通過添加注解的方式就能實現將此屬性導出,如果不加此注解則不導出
/** 編號 */ @Excel(name = "編號") private String bcbh;
而且注解里面的name屬性就是導出時那列的標題。
關於這個注解還有好多個屬性,具體可以參考其源碼
public @interface Excel { /** * 導出到Excel中的名字. */ public String name() default ""; /** * 日期格式, 如: yyyy-MM-dd */ public String dateFormat() default ""; /** * 讀取內容轉表達式(如:0=男,1=女,2=未知) */ public String readConverterExp() default ""; /** * 導出類型(0數字 1字符串) */ public ColumnType cellType() default ColumnType.STRING; /** * 導出時在excel中每個列的高度 單位為字符 */ public double height() default 14; /** * 導出時在excel中每個列的寬 單位為字符 */ public double width() default 16; /** * 文字后綴,如% 90 變成90% */ public String suffix() default ""; /** * 當值為空時,字段的默認值 */ public String defaultValue() default ""; /** * 提示信息 */ public String prompt() default ""; /** * 設置只能選擇不能輸入的列內容. */ public String[] combo() default {}; /** * 是否導出數據,應對需求:有時我們需要導出一份模板,這是標題需要但內容需要用戶手工填寫. */ public boolean isExport() default true; /** * 另一個類中的屬性名稱,支持多級獲取,以小數點隔開 */ public String targetAttr() default ""; /** * 字段類型(0:導出導入;1:僅導出;2:僅導入) */ Type type() default Type.ALL; public enum Type { ALL(0), EXPORT(1), IMPORT(2); private final int value; Type(int value) { this.value = value; } public int value() { return this.value; } } public enum ColumnType { NUMERIC(0), STRING(1); private final int value; ColumnType(int value) { this.value = value; } public int value() { return this.value; } } }
還有一種情況是,在導出前的查詢數據的方法,如果調用的是和查詢接口一樣的方法。
某些屬性比如某某狀態等需要用到字典表的列。在查詢接口可能就是直接查詢出來,返回值
直接就是1或者2等這些字典的值。然后返回給前端,前端再進行格式化顯示。
但是在導出時必須要顯示對應的字典表的label,所以需要修改查詢數據的方法getBcListByNameToExport
將要查詢的表與字典表相關聯,查詢出其label值作為對應的屬性,如果有多個需要關聯字典表的屬性,則關聯兩次,下面是示例代碼
<select id="getBcListByNameToExport" parameterType="KqBcgl" resultMap="KqBcglResult"> SELECT b.id, b.bcbh, b.bcmc, s.dict_label AS bclx, sfkt, b.xss, b.jgs, b.sfyb, kqts, b.mzxx, b.bz, s1.dict_label AS jxbclx FROM kq_bcgl b LEFT JOIN sys_dict_data s ON b.bclx = s.dict_value AND s.dict_type = "kq_kqgl_bcgl_bclx" LEFT JOIN sys_dict_data s1 ON b.jxbclx = s1.dict_value AND s1.dict_type = "kq_kqgl_bcgl_jxbclx" <where> <if test="bcmc != null and bcmc != ''"> and bcmc LIKE "%"#{bcmc}"%"</if> </where> </select>
那么點擊導出按鈕就能實現導出了


