實現EasyExcel的導入導出(瀏覽器下載)
實現三個按鈕的功能,但是卻花費了一天的時間包括總結。
使用到的技術:springboot
layui
axios
EasyExcel
mybatis-plus
上傳模板
不需要用到后端的交互,只需要前段<a>
即可
<a href="../static/excel/用戶信息上傳模板.xlsx" style="color:white">上傳模版</a>
參考鏈接:
Excel如何對某一列設置下拉選擇項 https://jingyan.baidu.com/article/f7ff0bfccae0e62e26bb1380.html
下載上傳模板 https://www.bilibili.com/video/BV1dQ4y1A75e?from=search&seid=16041556233389040505
導入數據
使用到EasyExcel
的讀Excel
后端
引入pom.xml 依賴
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>2.2.7</version>
</dependency>
對象
@Data
@AllArgsConstructor
@NoArgsConstructor
public class UserDataExcel {
@ExcelProperty("用戶名")
private String userName;
@ExcelProperty("密碼")
private String password;
@ExcelProperty("姓名")
private String name;
@ExcelProperty("聯系方式")
private String phone;
@ExcelProperty("用戶類型")
private String typeStr;//取得的名字和User不一樣,否則BeanUtils.copyProperties報錯
@ExcelProperty("備注")
private String remark;
}
監聽器
public class UserDataExcelListener extends AnalysisEventListener<UserDataExcel> {
/**
* 每隔5條存儲數據庫,實際使用中可以3000條,然后清理list ,方便內存回收
*/
private static final int BATCH_COUNT = 5;
List<User> list = new ArrayList<>();
/**
* 假設這個是一個DAO,當然有業務邏輯這個也可以是一個service。當然如果不用存儲這個對象沒用。
*/
private UserService userService;
public UserDataExcelListener() {
}
/**
* 如果使用了spring,請使用這個構造方法。每次創建Listener的時候需要把spring管理的類傳進來
*/
public UserDataExcelListener(UserService userService ) {
this.userService = userService;
}
/**
* 這個每一條數據解析都會來調用
*
* @param data
* one row value. Is is same as {@link AnalysisContext#readRowHolder()}
* @param context
*/
//一行行讀取
@Override
public void invoke(UserDataExcel data, AnalysisContext context) {
if(data==null){
throw new DormitoryException(ResultCode.ERROR,"文件數據為空");
}
//進行數據的轉換 第一個參數復制到第二個參數中
User user = new User();
BeanUtils.copyProperties(data,user);
if(!StringUtils.isEmpty(data.getTypeStr())){
switch (data.getTypeStr()){
case "管理員":
user.setType(0);
break;
case "宿管員":
user.setType(1);
break;
case "學生":
user.setType(2);
break;
}
}
System.out.println("將excel的data復制到user,user:"+user);
list.add(user);
// 達到BATCH_COUNT了,需要去存儲一次數據庫,防止數據幾萬條數據在內存,容易OOM
if (list.size() >= BATCH_COUNT) {
saveData();
// 存儲完成清理 list
list.clear();
}
}
/**
* 所有數據解析完成了 都會來調用
*
* @param context
*/
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
// 這里也要保存數據,確保最后遺留的數據也存儲到數據庫
saveData();
}
/**
* 加上存儲數據庫 在監聽器中直接添加
*/
private void saveData() {
userService.saveBatch(list);
}
}
UserController 控制層
@PostMapping("addUsers")
public Result addUsers(@RequestParam("uploadFile") MultipartFile file) throws IOException {
if(file==null){
System.out.println("文件為空");
}
boolean save = userService.addUsers(file);
return save ? Result.ok().mesaage("新增用戶成功"):Result.error().mesaage("新增用戶失敗");
}
UserServiceImpl 業務實現層
需要注意的點,因為監聽器沒有Spring進行管理,所以這邊的處理方式是將UserService
傳入進去
@Override
public boolean addUsers(MultipartFile file) {
try{
InputStream in = file.getInputStream();
EasyExcel.read(in, UserDataExcel.class, new UserDataExcelListener(this)).sheet().doRead();
}catch (Exception e){
e.printStackTrace();
}
return true;
}
經過上面的步驟后,我們就可以先在apipost
中測試接口
apipost
測試MultipartFile
下面有幾個注意點需要注意
前端
<button class="layui-btn layui-btn-sm " lay-event="importData" style="background: #2ecc71" > 導入數據 </button>
使用到了layui
的上傳組件,由於使用到axios
,也簡單地修改了一下upload
的源碼中的axios
upload.render({
elem:'#importExcel',
url:'/user/addUsers',
size : '5000',//文件最大可允許上傳的大小,單位 KB
accept:'file',//允許上傳文件
exts:'xls|xlsx|xlsm|xlt|xltx|xltm',
field:'uploadFile',
headers: {token: store.getToken()},
done:function (result) {//執行上傳請求后的回調。返回三個參數,分別為:res(服務端響應信息)、index(當前文件的索引)、upload(重新上傳的方法,一般在文件上傳失敗后使用)
console.log(result);
if(result.code==0){
layer.msg("Excel導入數據成功",{
},function () {
table.reload("user-table-id");
})
}else{
layer.msg("Excel導入數據失敗",function () {
})
}
}
});
小插曲的Bug,寫在下面這篇博客中。
layui在toolbar使用上傳控件在reload后失效的問題解決
參考鏈接 :
java+layui實現Excel的導入導出 https://www.cnblogs.com/bbllw/p/10800161.html
EasyExcel
文檔 https://www.yuque.com/easyexcel/doc/easyexcel
課程上傳的例子 https://www.bilibili.com/video/BV1dQ4y1A75e?from=search&seid=16041556233389040505
layui的upload文檔說明 https://www.layui.com/doc/modules/upload.html
導出全部
使用到EasyExcel
的寫Excel,這一點也是最難的一點,主要是卡在文件在瀏覽器中下載。
如果直接使用EasyExcel
中簡單寫的例子,只能將xlsx
文件下載到后端的項目文件中,不能在瀏覽器中下載。
后端
@GetMapping("exportAll")
public void exportAll(HttpServletResponse response) throws IOException {
List<UserDataExcel> listExcel = new ArrayList<>();
List<User> list = userService.list();
for(int i = 0;i<list.size();i++){
UserDataExcel dataExcel = new UserDataExcel();
BeanUtils.copyProperties(list.get(i),dataExcel);//小技巧
if(list.get(i).getType()!=null){//處理數據庫中存放int 不是String
switch (list.get(i).getType()){
case 0:
dataExcel.setTypeStr("管理員");
break;
case 1:
dataExcel.setTypeStr("宿管員");
break;
case 2:
dataExcel.setTypeStr("學生");
break;
}
}
listExcel.add(dataExcel);
}
//文件名需要這樣寫,不能在setHeader直接寫中文名,否則下載的文件名字為空,只有后綴
String fileName = new String("用戶信息.xlsx".getBytes(), StandardCharsets.ISO_8859_1);
response.setContentType("application/msexcel");
response.setCharacterEncoding("utf8");
response.setHeader("Content-disposition", "attachment;filename=" + fileName );
EasyExcel.write(response.getOutputStream(), UserDataExcel.class)
.sheet("sheet")
.doWrite(listExcel);
// return Result.ok().mesaage("下載成功"); 不要寫
}
如果加了return Result.ok().mesaage("下載成功");
后端會報錯,但是還是可以正常下載。
org.springframework.http.converter.HttpMessageNotWritableException: No converter for [class com.dj.dormitory.commonutils.Result] with preset Content-Type 'application/msexcel;charset=utf8'
前端
<button class="layui-btn layui-btn-sm " lay-event="exportData" style="background: #27ae60"> 導出全部 </button>
剛開始的時候,自己想直接使用windows.open('/接口地址')
,但是因為項目中用到token,所以就放棄了這個方法。使用了下面的方法
layer.confirm('確定導出所有用戶信息嗎?', {
btn: ['確定', '取消']
}, function(index){
//window.open("http://localhost:8888/dormitory/user/exportAll");
axios({
method: 'get',
url:'/user/exportAll',
responseType: 'blob', // 重要, 限制返回的數據結構為blob格式,方便前端做轉換
}).then(data=>{
const link = document.createElement('a')
const blob = new Blob([data], { type: 'application/vnd.ms-excel' })
link.style.display = 'none'
link.href = URL.createObjectURL(blob)
link.setAttribute('download','用戶信息.xlsx')
document.body.appendChild(link)
link.click()
document.body.removeChild(link)
})
layer.close(index);
}, function(index){
//按鈕【按鈕二】的回調
});
參考鏈接:
學到了 web中的代碼具體應該怎么寫
EasyExcel
web中的寫 https://www.yuque.com/easyexcel/doc/write#afb7324a
了解到window.open("/download");
,可以在瀏覽器中實現成功下載了
EasyExcel實現下載Excel(解決無法從瀏覽器下載問題)https://blog.csdn.net/ruanbigshuai/article/details/108554896
了解到window.open("/download");
最簡單,但是不可以攜帶token
axios實現excel文件下載 https://blog.csdn.net/xuesheng1610748/article/details/83865679
成功幫助到自己的方法三,使用token並且在瀏覽器中實現成功下載了
Vue項目利用axios請求接口下載excel(附前后端代碼) https://blog.csdn.net/asmallprogrammer/article/details/91440793