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; }
 
原文地址:https://www.cnblogs.com/shej123/p/11692074.html