使用SpringBoot+easyPoi+LayUI实现文件以Excel格式批量上传下载

首先看一下界面
使用SpringBoot+easyPoi+LayUI实现文件以Excel格式批量上传下载_第1张图片
如图所示,通过勾选多选框实现选中,点击批量下载会将数据以Excel的格式批量下载到本地

关于勾选之后是传id数组还是传整个勾选的对象数组,先说结论:
	 应该传的是id数组而不是对象数组 原因如下:
	 1. 我们为什么不传id?因为我们不想查询数据库。
	 2. 但是不查询数据库说明我们所需要打印的数据在前端界面已经展示
	    完全了,
	 3. 界面展示完全的话。我们可以通过直接通过前端把数据导出成
	    Excel表格下载到本地
	 4. 故 我们一般选择通过id数组传递数据 

结论是一回事,但是我两种都写了,传递id数组的方式比较简单。

传递id数组实现批量下载

传递对象数组实现批量下载

emmmmmm,选这种的和我一样都是狼灭
直接开始思路:

  1. 前端传什么给后端?

    应该传Json字符串
    [{“name”:“csq”,“sex”:“man”},
    {“name”:“lll”,“sex”:“woman”}]

  2. 后端的接收的相关问题
    正常接收的话会报错。非法字符问题
java.lang.IllegalArgumentException:Invalid character found 
in the request target. The valid characters are defined in
RFC 7230 and RFC 3986

翻译:非法数据异常:发现无效字符,有效的字符在RFC 7230和RFC 3986中定义

出现这个错误的原因是:我们在前后台交互的时候使用json格式的字段串参数,其中含有“{}”“[]”这些特舒符号,在高版本的tomcat(已知8版本以上报错,7貌似也报)中含有这些字符的请求会被拦截。
解决办法:

  1. 是修改springboot配置文件,降低tomcat版本
    打开本地maven仓库springboot父依赖配置,路径如:D:\mavenRepository\org\springframework\boot\spring-boot-dependencies
    打开2.1.4.RELEASE文件夹查看 spring-boot-dependencies-2.1.4.RELEASE.pom 里面的配置 搜索tomcat.version,显示9.0.17
    使用SpringBoot+easyPoi+LayUI实现文件以Excel格式批量上传下载_第2张图片
    把它改成8.5以下就可以了。但是不推荐,能用高版本就接着用呗,因此我采用方法二
  2. 在springboot中增加配置文件,交由spring工厂管理
@Configuration
public class TomcatConfig {
     

    @Bean
    public TomcatServletWebServerFactory webServerFactory() {
     
        TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();
        factory.addConnectorCustomizers((Connector connector) -> {
     
                connector.setProperty("relaxedPathChars", "\"<>[\\]^`{|}");
                connector.setProperty("relaxedQueryChars", "\"<>[\\]^`{|}");
        });
        return factory;
    }
}
1. 前端代码

我的前端使用的是layui

<div class="layui-fluid">
    <div class="layui-row">
        div>

        <button type="button" class="layui-btn" id="uploads">
            <i class="layui-icon">i>批量上传
        button>

        <button type="button" class="layui-btn" id="download">
            <i class="layui-icon">i>批量下载
        button>

        
        <table id="guruTable" class="layui-table-cell" lay-filter="test">table>
        

    div>
div>
<script src="layui/layui.js"></script>
<script type="text/javascript" src="layui/js/jquery-1.9.js"></script>
<script>
 layui.use(['table','layer','form','laydate','upload','tree'], function(){
     
        var table = layui.table;
        var layer = layui.layer;
        var form = layui.form;
        var upload = layui.upload;

   //批量下载按钮的点击事件
        $("#download").click(function () {
     
            var checkStatus = table.checkStatus('guruTable'),
                data = checkStatus.data,
                gurus = [];

            console.log(checkStatus.data) ;//获取选中行的数据
            console.log(checkStatus.data.length) ;//获取选中行数量,可作为是否有选中行的条件
            console.log(checkStatus.isAll ) ;//表格是否全选

            /*
            声明前缀和后缀
            */
            var prefix;
            var suffix;

            console.log(checkStatus.data.length-1);
           // console.log(checkStatus.data.size-1);  这种不行,前端数据一般都是数组类型的,长度要用length 否则结果是undefine
           /*
			  要拼接成json类型的数据,第一个数据前面加"[",最后一个数组后面加"]"
		    */
            checkStatus.data.forEach(function(n,i){
     
                if (i === 0){
     
                    prefix = "[";
                    suffix = "";
                } else if (i === checkStatus.data.length-1) {
     
                    suffix = "]";
                    prefix = "";
                } else {
     
                    prefix = "";
                    suffix = "";
                }
                var str = prefix+"{'guruId':'"+n.guruId+"','guruName':'"+n.guruName+"','guruImage':'"+n.guruImage+"','guruNickname':'"+n.guruNickname+"','guruStatus':'"+n.guruStatus+"'}"+suffix;
                console.log("str"+i+" = "+str);
                gurus.push(str);
            });

            console.log("gurus = "+gurus);

            window.location.href = "${pageContext.request.contextPath}/guru/outputGurus?gurus="+gurus;
        });
        
        /执行文件上传实例
        var uploadInst = upload.render({
     
            elem: '#uploads' //绑定元素
            ,url: 'guru/importGurus' //上传接口
            ,accept:'file'
            ,done: function(res){
     
                alert("上传成功");
                table.reload("demo");
                layui.close(uploadInst);
            }
            ,error: function(){
     
                //请求异常回调
            }
        });
//-----------------------  表格组件开始   -------------------------------------
        table.render({
     
            elem: '#guruTable'
            ,size:'lg'
            ,height: 300
            ,url: 'guru/selectAll' //数据接口
            ,page: true //开启分页
            ,limits:[4,8,10]
            ,limit:4
            ,cols: [[ //表头
                {
     type:'checkbox', fixed: 'left'},
                {
     field: 'guruId', title: '上师编号', fixed: 'left'}
                ,{
     field: 'guruName', title: '上师姓名'}
                ,{
     field: 'guruImage', title: '上师图片', sort: true, templet:function (d) {
     
                        return "";
                    }}
                ,{
     field: 'guruNickname', title: '上师法号'}
                ,{
     field: 'guruStatus', title: '上师状态', templet:function (d) {
     
                        if (d.guruStatus === 0){
     
                            return "正常";
                        } else {
     
                            return "已冻结";
                        }

                    }}
            ]]
        });
//-----------------------  表格组件结束   -------------------------------------
</script>
2. 配置springboot的tomcat

@Configuration
public class TomcatConfig {
     
    @Bean
    public TomcatServletWebServerFactory webServerFactory() {
     
        TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();
        factory.addConnectorCustomizers((Connector connector) -> {
     
            connector.setProperty("relaxedPathChars", "\"<>[\\]^`{|}");
            connector.setProperty("relaxedQueryChars", "\"<>[\\]^`{|}");
        });
        return factory;
    }
}

3. 后端代码
/*
  批量下载的代码
*/
   @RequestMapping("outputGurus")
    public void outputGurus(@RequestParam(value = "gurus") String gurus, HttpServletResponse response) throws IOException {
     
	     /*
	     
		     ArrayList list = JSONUtil.toBean(gurus, ArrayList.class);
		     
		     这种转换是不行的,因为gurus是json数组,我们需要用json数组对象接收
	
		     json数组转成字符串需要用JSONArray接收
	     */
        JSONArray objects = new JSONArray(gurus);
        //将json数组转成你想要的数据类型,.to就完事了。
        List<Guru> list = objects.toList(Guru.class);
        //不放心就先打印一下看看拿到了没
        list.forEach(System.out::println);
        // 处理Excel中的图片路径。数据库中存储的是图片名字,需要加上前缀
        list.stream().forEach(guru -> {
     
            guru.setGuruImage("http://localhost:8989/cmfz/img/"+guru.getGuruImage());
       
        });
   
        /**
        easypoi 操作Excel导出导入
         */
        ExportParams exportParams = new ExportParams("所有上师数据", "guru");

        Workbook workbook = ExcelExportUtil.exportExcel(exportParams, Guru.class, list);

        String s = "上师数据"+System.currentTimeMillis()+".xlsx";
//解决H5请求接口的跨域问题
//response.setHeader("Access-Control-Allow-Origin","*");
        response.setHeader("content-disposition","attachment;fileName=" + URLEncoder.encode(s,"utf-8"));
        response.setContentType("application/vnd.ms-excel");
        //通过文件对象写出
        workbook.write(response.getOutputStream());
    }



//上传代码
    @RequestMapping("importGurus")
    public Map piliang(MultipartFile file) throws Exception {
     
        Map<String,Object> map = new HashMap<>(4);
        //将file对象给poi处理
        //通过file对象获取到输入流
        InputStream inputStream = file.getInputStream();

        // 2. 通过poi处理流
        ImportParams importParams = new ImportParams();
        /**
         * setTitleRows(1);设置标题所占的行数
         * setHeadRows(1);设置表头所占的行数
         */
        importParams.setTitleRows(1);
        importParams.setHeadRows(1);

        List<Guru> list = ExcelImportUtil.importExcel(inputStream, Guru.class, importParams);
        list.stream().forEach(guru -> {
     
            String removePrefix = StrUtil.removePrefix(guru.getGuruImage(), "F:\\IdeaProjects\\last-program\\cmfzdemo\\src\\main\\webapp\\img\\");
            guru.setGuruImage(removePrefix);
            System.out.println(guru);
        });
        guruService.saveBatch(list);
        map.put("code",0);
        map.put("msg","success");
        return map;
    }

累了,写博客好累,有空再写传id数组的写法。。。

报错整理

1. ERR_CACHE_READ_FAILURE

准备截界面的图时突然出现的报错ヽ(ー_ー)ノ

使用SpringBoot+easyPoi+LayUI实现文件以Excel格式批量上传下载_第3张图片
口头翻译了一下 大概意思是缓存读取错误…200
重启springboot,表格加载出来了,但是里面的图片没有出来
使用SpringBoot+easyPoi+LayUI实现文件以Excel格式批量上传下载_第4张图片
在这里插入图片描述
ヽ(。_°)ノ 吐了 同样是缓存读取失败,状态码还不一样
原因:Chrome自己的问题,可以选择两种修改方式,我推荐第一种
解决办法1:手动强制刷新Chrome,使Chrome不从缓存中读取数据

Windows和Linux操作系统: Shift+F5 或 Ctrl+Shift+R

Mac OS: Cmd+Shft+R

解决办法2:别问,我也不知道这从哪配的

1. chrome://flags/#enable-simple-cache-backend
2. default -> enable

成功,结果如页面最上面展示

2. ajax提交下载请求没有弹出框

后端用了二进制流来实现,而ajax不支持流形式,可以选择使用window.location.href 或者 表单提交

感谢

一、解决springboot项目请求出现非法字符问题

二、json数组如何转换成string类型

三、spring MVC 前台传数组类型,后台用list类型接收也是可以的

四、前端页面传来数组,后台用对象集合list接收数据的写法

五、Springboot 下载文件

你可能感兴趣的:(实战总结,java,poi,spring,boot)