• jfinal layui easyexcel 实现文件的上传下载


    jfinal  layui easyexcel  这三样开源技术这里就不多介绍了,自行百度了解吧,他们的组合算是一个很高效又不失美观的操作体验。

    操作主要分以下几步:

    1、建立jfinal的操作环境,建议使用作者提供的demo , 创建一个 jfinal + undertow 的运行环境。undertow运行起来很快,不仅方便调试,而且运行稳定。https://www.jfinal.com/doc

    2、引入easyexcel的相关包,我这里使用的是2.0.5版本,网上有很多1.2的版本教程,这里使用的最新的版本,同老版本还是有些区别的,作者提供了相关的demo,可以自己试一下。

    <dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml</artifactId>
    <version>3.17</version>
    </dependency>
    <dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>easyexcel</artifactId>
    <version>2.0.5</version>
    </dependency>
    <dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.8</version>
    <scope>test</scope>
    </dependency>

     3、建立你要导入的数据库表,我这里用的是mysql5.7,并编写你的导入模板。这里就不贴图了,自己亲手做下就行。

    4、分别创建几个类文件 jfinal的controller 、service ,easyexcel使用的 excelData、excelDataListener 文件,当然还有前端访问的excelupload.html页面。

    easyexcel 使用 Data文件来约束模板文件的标题(头文件),导入字段的类型和excel中cell的顺序

    import com.alibaba.excel.annotation.ExcelProperty;
    import com.alibaba.excel.annotation.write.style.ColumnWidth;
    import com.alibaba.excel.annotation.write.style.ContentRowHeight;
    import com.alibaba.excel.annotation.write.style.HeadRowHeight;
    import lombok.Data;
    
    /**
     * 基础数据类.用于基础数据表的导入
     * 这里的排序和excel里面的排序一致
     *
     * @author 
     **/
    @Data //使用注解来格式该文件
    @HeadRowHeight(20) // 作为导出data的时候设置头文件行高
    @ContentRowHeight(20) //作为导出data的时候设置内容行高
    @ColumnWidth(25)//设置行宽
    public class ExcelData {
    
        @ExcelProperty(value = "工号", index = 0) //这里的工号是和excel的标题一致,index 表示第几列数据
        private String agentcode;
        @ExcelProperty(value = "姓名", index = 1)
        private String name;
        @ExcelProperty(value = "手机号", index = 2)
        private String mobile;
        @ExcelProperty(value = "身份证号", index = 3)
        private String idno;
        @ExcelProperty(value = "执业证号", index = 4)
        private String certifno;
        @ExcelProperty(value = "机构代码", index = 5)
        private String agentgroupcode;
        @ExcelProperty(value = "机构名称", index = 6)
        private String agentgroupname;
    
        public String getAgentcode() {
            return agentcode;
        }
    
        public void setAgentcode(String agentcode) {
            this.agentcode = agentcode;
        }
    
        public String getMobile() {
            return mobile;
        }
    
        public void setMobile(String mobile) {
            this.mobile = mobile;
        }
    
        public String getIdno() {
            return idno;
        }
    
        public void setIdno(String idno) {
            this.idno = idno;
        }
    
        public String getCertifno() {
            return certifno;
        }
    
        public void setCertifno(String certifno) {
            this.certifno = certifno;
        }
    
        public String getAgentgroupcode() {
            return agentgroupcode;
        }
    
        public void setAgentgroupcode(String agentgroupcode) {
            this.agentgroupcode = agentgroupcode;
        }
    
        public String getAgentgroupname() {
            return agentgroupname;
        }
    
        public void setAgentgroupname(String agentgroupname) {
            this.agentgroupname = agentgroupname;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    }

    easyexcel的ExcelDataListener 文件 是解析excel时候使用的监听,在读取一行数据的时候都要调用invoke()方法,在解析完excel之后执行 doAfterAllAnalysed() 方法,demo中提供了分批次处理的方法

    public class ImBnExcelDataListener extends AnalysisEventListener<ImpBnExcelData> {
    
        private static final Log log = Log.getLog(ImBnExcelDataListener.class);
        /**
         * 每隔5条存储数据库,实际使用中可以500条,然后清理list ,方便内存回收
         */
        private static final int BATCH_COUNT = 500;
    
        List<ImpBnExcelData> list = new ArrayList<ImpBnExcelData>();
        StringBuilder stringBuilder = new StringBuilder();
    
        @Override
        public void invoke(ImpBnExcelData data, AnalysisContext context) {
            System.out.println("解析到一条数据:{}"+JSON.toJSONString(data));
            list.add(data);
    /*        list.add(data);
            if (list.size() >= BATCH_COUNT) {
                System.out.println("解析到一条数据:{}"+data.getAgentcode());
                saveData(list);
                list.clear();
            }else {
                saveLastData(list);
                list.clear();
            }*/
            //saveDataByOne(data);
            stringBuilder.append("(");
            //BnController BnController =new  BnController();
            String convertdata =convertToStr(data);
            stringBuilder.append(convertdata);
            stringBuilder.append("),");
        }
    
        @Override
        public void doAfterAllAnalysed(AnalysisContext context) {
            String sqlpro = stringBuilder.toString().substring(0,stringBuilder.toString().lastIndexOf(","));
            System.out.println(sqlpro);
            batchInsert(sqlpro);
            //saveDataObj(convertToObj(list));
            System.out.println("所有数据解析完成!");
        }
    
        public String convertToStr(ImpBnExcelData data){
            String convertdata = "'"+data.getAgentcode()+"','"
                    +data.getName()+"','"
                    +data.getMobile()+"','"
                    +data.getIdno()+"','"
                    +data.getCertifno()+"','"
                    +data.getAgentgroupcode()+"','"
                    +data.getAgentgroupname()+"','"
                    +DateUtil.getTodaySecNum()+"','"
                    +DateUtil.getTodaySec()+"'";
            return convertdata;
        }
        public static void batchInsert(String sqlpro) {
            long start = System.currentTimeMillis();
            Config config = DbKit.getConfig("datasource");
            Connection conn = null;
            try {
                conn = config.getConnection();
                conn.setAutoCommit(false);
                StringBuffer stringBuffer = new StringBuffer();
                stringBuffer.append("insert into table (xx,name,mobile,idno,xx,xx,xx,xx,uptime) values ");
                stringBuffer.append(sqlpro);
                PreparedStatement pst = conn.prepareStatement(stringBuffer.toString());
                pst.addBatch();
                pst.executeBatch();
    
                conn.commit();
    
                pst.close();
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
    
            long end = System.currentTimeMillis();
            System.out.println("批量插入需要时间:"+(end - start)); //批量插入需要时间:24675
        }

    这里我使用了合成 insert value 值的方法,将读取的excel拼接成一条 insert into 语句,这样会大大提升批量存储效率,比一条条存要快的多,如果你的mysql接收sql语句的长度够,可以写成一条语句,如果不行就要分批进行存储,或者修改mysql.ini的 参数,将max_allowed_packet的值改大就行,这里我修改到了16M。 jfinal提供了多数据源多配置的方法可以使用 DbKit.getConfig() 或Db.use("")的方法直接使用数据源或直接调用jdbc,方便的不要不要的。

    Controller 文件是jfinal用来做控制转发的文件,设置好路由之后,直接可以用Controller调用相关方法,在web环境下运行改方法。

    public void upbnexcel() {
            AjaxMsg ajaxMsg = new AjaxMsg();
            try {
                String webrootpath = PathKit.getWebRootPath();
                //设置文件上传子目录
                //String path = "uploads/excel/";
                String path =PropKit.get("excel_upload_path");
                UploadFile upload = getFile("file", webrootpath + File.separator + path);
                File file = upload.getFile();
                //获取文件名
                String extName = FileUtils.getFileExt(file.getName());
                //获取文件上传的父目录
                String filePath = upload.getUploadPath();
                //时间命名文件
                String fileName = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()) + extName;
                //重命名原来的文件
                file.renameTo(new File(filePath + fileName));
                long start = System.currentTimeMillis();
                EasyExcel.read(filePath+fileName, ExcelData.class, new ExcelDataListener()).sheet().doRead();
                log.info("导入耗时s:"+String.valueOf((System.currentTimeMillis()-start)/1000));
                ajaxMsg.setState("success");
                ajaxMsg.setMsg("上传成功,耗时"+String.valueOf((System.currentTimeMillis()-start)/1000)+"秒");
            } catch (Exception e) {
                e.printStackTrace();
                ajaxMsg.setState("fail");
                ajaxMsg.setMsg("上传失败:"+e.getMessage());
            }
            renderJson(ajaxMsg);
        }

    通过web方法,先将excel上传到服务器的upload/excel文件夹下,并通过时间进行命名,然后直接调用 EasyExcel.read方法解析并写入数据库,然后通过ajaxMsg返回页面状态提示。这里有个注意

    UploadFile upload = getFile("file", webrootpath + File.separator + path); 中的 "file" 是cos中的约束,必须要这么写,否则会上传失败
    EasyExcel.read 提供了很多读取的方式,可以选取自己需要的方式进行调整。调整后别忘关闭操作流。

    uploadexcel.html页面引入了layui相关框架,引入的包就不罗列了,直接写相关内容

    <body>
    <div id="app" class="layui-form">
        <div class="container">
            <div class="layui-form-item">
                <a class="layui-btn layui-btn-warm" href="模板.xlsx" target="_blank">模板下载</a>
            </div>
            <blockquote class="layui-elem-quote">
            <form class="layui-form" action="">
                <div class="layui-form-item">
                    <div class="layui-inline">
                        <div class="layui-upload">
                            <button type="button" class="layui-btn layui-btn-normal" id="file">选择文件</button>
                            <button type="button" class="layui-btn" id="updo">开始上传</button>
                        </div>
                    </div>
                </div>
            </form>
            </blockquote>
        </div>
    </div>
    </body>
    <script src="../../../static/plugins/layui/layui.js"></script>
    <script>
        //一般直接写在一个js文件中
        layui.use(['layer', 'form', 'upload'], function () {
            var layer = layui.layer
                , form = layui.form
                , upload = layui.upload;
    
            //选完文件后不自动上传
            var uploadInst = upload.render({
                elem: '#file'
                , url: '/upexcel'
                , auto: false
                , accept: 'file' //普通文件
                //,multiple: true
                , bindAction: '#updo'
                , done: function (res) {
                    //上传完毕回调
                    if (res.state == "success") {
                        parent.layer.alert(res.msg);
                    }
                    else {
                        parent.layer.alert(res.msg);
                        return false;
                    }
                }
            });
        })
    }

    下载操作比较简单,注意一下 ajax不能直接下载文件,需要通过 action 或 href 来下载  ,这里我做了两步请求,先通过选择列表中需要下载的项,然后执行id序列化操作,然后再次执行查询和下载操作,才能保存下载的excel文件。

            $("#expdata").on('click', function () {
                var checkStatus = table.checkStatus('tablelist'), data = checkStatus.data;
                var ids = [];
                for (var i = 0; i < data.length; i++) {
                    ids.push(data[i].id);
                }
                console.log(ids);
                $.ajax({
                    //type: 'post',
                    url: '/downExcel',
                    data: {ids: ids},
                    success: function (response) {
                        console.log(response.idstr);
                        window.location.href="/expExcel?idstr="+response.idstr;
                    },
                });
            });
     /**
         * 导出excel
         */
        public void expExcel(){
            try {
                //String[] ids = getParaValues("ids[]");
               String idstr = getPara("idstr");
                HttpServletResponse response=getResponse();
                response.setContentType("application/vnd.ms-excel");
                response.setCharacterEncoding("utf-8");
                // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
                String fileName = URLEncoder.encode("测试", "UTF-8");
                response.setHeader("Content-disposition", "attachment;filename=demo.xlsx");
                EasyExcel.write(response.getOutputStream(), ExcelData.class).sheet("模板").doWrite(downExceldata(idstr));
               // EasyExcel.write(fileName, ImpBnExcelData.class).sheet("模板").doWrite(data());
            }catch (Exception e){
            }
            renderNull();
            //renderFile(file,"demo.xlsx");
        }
      //下载时候首先执行该方法,并将选中的id拆分组合为字符串,再将字符串进行回传
    public void downExcel(){ String[] ids = getParaValues("ids[]"); String idstr = Arrays.toString(ids); idstr = idstr.substring(1, idstr.length() - 1); renderJson("idstr",idstr); } public List<ImpBnExcelData> downExceldata(String idstr){ List<Record> lists =BnService.me().findByIdstr(idstr); List<ImpBnExcelData> bndatalist = new ArrayList<>(); for(Record record : lists) { ImpBnExcelData bnExcelData = new ImpBnExcelData(); ExcelData.setAgentcode(record.getStr("agentcode")); ExcelData.setAgentgroupcode(record.getStr("agentgroupcode")); ExcelData.setAgentgroupname(record.getStr("agentgroupname")); ExcelData.setCertifno(record.getStr("certifno")); ExcelData.setIdno(record.getStr("idno")); ExcelData.setMobile(record.getStr("mobile")); ExcelData.setName(record.getStr("name")); datalist.add(bnExcelData); } return bndatalist; }
     
  • 相关阅读:
    理解RESTful架构
    Javascript闭包
    Javascript立即执行函数
    多个Jboss端口冲突配置;一个Jboss多个server端口配置
    MyEclipse部署Jboss出现java.lang.OutOfMemoryError: PermGen space
    css摘抄
    css 浮动和绝对定位的区别
    搭建第一个web项目:jasperReports+ireport制作pdf报表
    Hibernate的检索方式
    浅谈JavaScript的作用域
  • 原文地址:https://www.cnblogs.com/shej123/p/11692074.html
Copyright © 2020-2023  润新知