使用Layui、Axios、Springboot(Java) 實現EasyExcel的導入導出(瀏覽器下載)


實現EasyExcel的導入導出(瀏覽器下載)

實現三個按鈕的功能,但是卻花費了一天的時間包括總結。

image-20210128215145536

使用到的技術: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>

對象

image-20210128220945557

@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 下面有幾個注意點需要注意
image-20210128222642455

前端

<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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM